/* * dllcrt1.c * * Initialization code for DLLs. * * This file is part of the Mingw32 package. * * Contributors: * Created by Colin Peters * DLL support adapted from Gunther Ebert * Maintained by Mumit Khan * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAMED. This includes but is not limited to warrenties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * $Revision$ * $Author$ * $Date$ * */ #include #include #include #include #include #include /* Unlike normal crt1, I don't initialize the FPU, because the process * should have done that already. I also don't set the file handle modes, * because that would be rude. */ #ifdef __GNUC__ extern void __main (); extern void __do_global_dtors (); #endif typedef void (* p_atexit_fn )(void); static p_atexit_fn* first_atexit; static p_atexit_fn* next_atexit; static void __dll_exit (void); /* This is based on the function in the Wine project's exit.c */ p_atexit_fn __dllonexit (p_atexit_fn, p_atexit_fn**, p_atexit_fn**); extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID); extern void _pei386_runtime_relocator (void); BOOL WINAPI DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { BOOL bRet; if (dwReason == DLL_PROCESS_ATTACH) { #ifdef DEBUG printf ("%s: DLL_PROCESS_ATTACH (%d)\n", __FUNCTION__); #endif /* Initialize private atexit table for this dll. 32 is min size required by ANSI */ first_atexit = (p_atexit_fn*) malloc (32 * sizeof (p_atexit_fn)); if (first_atexit == NULL ) /* can't allocate memory */ { errno=ENOMEM; return FALSE; } *first_atexit = NULL; next_atexit = first_atexit; /* Adust references to dllimported data (from other DLL's) that have non-zero offsets. */ _pei386_runtime_relocator (); #ifdef __GNUC__ /* From libgcc.a, __main calls global class constructors, __do_global_ctors, which registers __do_global_dtors as the first entry of the private atexit table we have just initialised */ __main (); #endif } /* * Call the user-supplied DllMain subroutine. * This has to come after initialization of atexit table and * registration of global constructors. * NOTE: DllMain is optional, so libmingw32.a includes a stub * which will be used if the user does not supply one. */ bRet = DllMain (hDll, dwReason, lpReserved); /* Handle case where DllMain returns FALSE on attachment attempt. */ if ( (dwReason == DLL_PROCESS_ATTACH) && !bRet) { #ifdef DEBUG printf ("%s: DLL_PROCESS_ATTACH failed, cleaning up\n", __FUNCTION__); #endif __dll_exit (); /* Cleanup now. This will set first_atexit to NULL so we know we've cleaned up */ } if (dwReason == DLL_PROCESS_DETACH) { #ifdef DEBUG printf ("%s: DLL_PROCESS_DETACH (%d)\n", __FUNCTION__); #endif /* If not attached, return FALSE. Cleanup already done above if failed attachment attempt. */ if (! first_atexit ) bRet = FALSE; else /* * We used to call __do_global_dtors () here. This is * no longer necessary since __do_global_dtors is now * registered at start (last out) of private atexit table. */ __dll_exit (); } return bRet; } static void __dll_exit(void) /* Run LIFO terminators registered in private atexit table */ { if ( first_atexit ) { p_atexit_fn* __last = next_atexit - 1; while ( __last >= first_atexit ) { if ( *__last != NULL ) { #ifdef DEBUG printf ("%s: Calling exit function 0x%x from 0x%x\n", __FUNCTION__, (unsigned)(*__last),(unsigned)__last); #endif (**__last) (); } __last--; } free ( first_atexit ) ; first_atexit = NULL ; } /* Make sure output buffers opened by DllMain or atexit-registered functions are flushed before detaching, otherwise we can have problems with redirected output. */ fflush (NULL); } /* * The atexit exported from msvcrt.dll causes problems in DLLs. * Here, we override the exported version of atexit with one that passes the * private table initialised in DllMainCRTStartup to __dllonexit. * That means we have to hide the mscvrt.dll atexit because the * atexit defined here gets __dllonexit from the same lib. */ int atexit (p_atexit_fn pfn ) { #ifdef DEBUG printf ("%s: registering exit function 0x%x at 0x%x\n", __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit); #endif return (__dllonexit (pfn, &first_atexit, &next_atexit) == NULL ? -1 : 0 ); } /* * Likewise for non-ANSI function _onexit that may be called by * code in the dll. */ _onexit_t _onexit (_onexit_t pfn ) { #ifdef DEBUG printf ("%s: registering exit function 0x%x at 0x%x\n", __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit); #endif return ((_onexit_t) __dllonexit ((p_atexit_fn)pfn, &first_atexit, &next_atexit)); }