2000-02-18 03:38:33 +08:00
|
|
|
/*
|
|
|
|
* dllcrt1.c
|
2004-04-21 06:49:32 +08:00
|
|
|
* This file has no copyright assigned and is placed in the Public Domain.
|
|
|
|
* This file is a part of the mingw-runtime package.
|
|
|
|
* No warranty is given; refer to the file DISCLAIMER within the package.
|
2000-02-18 03:38:33 +08:00
|
|
|
*
|
|
|
|
* Initialization code for DLLs.
|
|
|
|
*
|
|
|
|
*/
|
2002-06-13 18:20:48 +08:00
|
|
|
#include <stdlib.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <io.h>
|
|
|
|
#include <process.h>
|
2002-06-13 18:20:48 +08:00
|
|
|
#include <errno.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <windows.h>
|
|
|
|
|
2010-01-26 06:58:03 +08:00
|
|
|
/* TLS initialization hook. */
|
|
|
|
extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/* 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
|
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
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**);
|
|
|
|
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID);
|
|
|
|
|
2003-01-01 18:00:39 +08:00
|
|
|
extern void _pei386_runtime_relocator (void);
|
2002-06-13 18:20:48 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
BOOL WINAPI
|
|
|
|
DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
|
|
{
|
|
|
|
BOOL bRet;
|
|
|
|
|
|
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
|
|
{
|
2003-01-01 18:00:39 +08:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf ("%s: DLL_PROCESS_ATTACH (%d)\n", __FUNCTION__);
|
|
|
|
#endif
|
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
/* 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;
|
|
|
|
|
2010-01-26 06:58:03 +08:00
|
|
|
/* Initialize TLS callback. */
|
|
|
|
if (__dyn_tls_init_callback != NULL)
|
|
|
|
{
|
|
|
|
__dyn_tls_init_callback (hDll, DLL_THREAD_ATTACH, lpReserved);
|
|
|
|
}
|
|
|
|
|
2003-01-01 18:00:39 +08:00
|
|
|
/* Adust references to dllimported data (from other DLL's)
|
|
|
|
that have non-zero offsets. */
|
|
|
|
_pei386_runtime_relocator ();
|
2002-06-13 18:20:48 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
#ifdef __GNUC__
|
2002-06-13 18:20:48 +08:00
|
|
|
/* 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 */
|
2000-02-18 03:38:33 +08:00
|
|
|
__main ();
|
2002-06-13 18:20:48 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
#endif
|
2002-06-13 18:20:48 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
/*
|
2002-06-13 18:20:48 +08:00
|
|
|
* Call the user-supplied DllMain subroutine.
|
|
|
|
* This has to come after initialization of atexit table and
|
|
|
|
* registration of global constructors.
|
2000-02-18 03:38:33 +08:00
|
|
|
* NOTE: DllMain is optional, so libmingw32.a includes a stub
|
|
|
|
* which will be used if the user does not supply one.
|
|
|
|
*/
|
2002-06-13 18:20:48 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
bRet = DllMain (hDll, dwReason, lpReserved);
|
2002-06-13 18:20:48 +08:00
|
|
|
/* Handle case where DllMain returns FALSE on attachment attempt. */
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
if ( (dwReason == DLL_PROCESS_ATTACH) && !bRet)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-06-13 18:20:48 +08:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf ("%s: DLL_PROCESS_ATTACH failed, cleaning up\n", __FUNCTION__);
|
2000-02-18 03:38:33 +08:00
|
|
|
#endif
|
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
__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 ();
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/*
|
2002-06-13 18:20:48 +08:00
|
|
|
* 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.
|
2000-02-18 03:38:33 +08:00
|
|
|
*/
|
2002-06-13 18:20:48 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
int
|
2002-06-13 18:20:48 +08:00
|
|
|
atexit (p_atexit_fn pfn )
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-06-13 18:20:48 +08:00
|
|
|
#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 );
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2002-06-13 18:20:48 +08:00
|
|
|
/*
|
|
|
|
* 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));
|
|
|
|
}
|