aboutsummaryrefslogtreecommitdiff
path: root/winsup/mingw/dllcrt1.c
blob: dda8a24c71be069d73f56784b22b514d81d05c14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * dllcrt1.c
 * 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.
 *
 * Initialization code for DLLs.
 *
 */
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <process.h>
#include <errno.h>
#include <windows.h>

/* 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));
}