OSDN Git Service

Adjust repository version following WSL-5.2.2 release.
[mingw/mingw-org-wsl.git] / mingwrt / dllcrt1.c
1 /*
2  * dllcrt1.c
3  * This file has no copyright assigned and is placed in the Public Domain.
4  * This file is a part of the mingw-runtime package.
5  * No warranty is given; refer to the file DISCLAIMER within the package.
6  *
7  * Initialization code for DLLs.
8  *
9  */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <io.h>
13 #include <process.h>
14 #include <errno.h>
15 #include <windows.h>
16
17 /* TLS initialization hook. */
18 extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
19
20 /* Unlike normal crt1, I don't initialize the FPU, because the process
21  * should have done that already. I also don't set the file handle modes,
22  * because that would be rude. */
23
24 #ifdef  __GNUC__
25 extern void __main ();
26 extern void __do_global_dtors ();
27 #endif
28
29 typedef void (* p_atexit_fn )(void);
30 static p_atexit_fn* first_atexit;
31 static p_atexit_fn* next_atexit;
32
33 static void
34 __dll_exit (void);
35
36 /* This  is based on the function in the Wine project's exit.c */
37 p_atexit_fn __dllonexit (p_atexit_fn, p_atexit_fn**, p_atexit_fn**);
38
39
40 extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID);
41
42 extern void _pei386_runtime_relocator (void);
43
44 BOOL WINAPI
45 DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
46 {
47   BOOL bRet;
48
49   if (dwReason == DLL_PROCESS_ATTACH)
50     {
51
52 #ifdef DEBUG
53       printf ("%s: DLL_PROCESS_ATTACH (%d)\n", __FUNCTION__);
54 #endif
55
56       /* Initialize private atexit table for this dll.
57          32 is min size required by ANSI */
58
59       first_atexit = (p_atexit_fn*) malloc (32 * sizeof (p_atexit_fn));
60       if (first_atexit == NULL ) /* can't allocate memory */
61         {
62           errno=ENOMEM;
63           return FALSE;
64         }
65       *first_atexit =  NULL;
66       next_atexit = first_atexit;
67
68       /* Initialize TLS callback.  */
69       if (__dyn_tls_init_callback != NULL)
70         {
71           __dyn_tls_init_callback (hDll, DLL_THREAD_ATTACH, lpReserved);
72         }
73
74       /* Adust references to dllimported data (from other DLL's)
75          that have non-zero offsets.  */
76       _pei386_runtime_relocator ();
77
78 #ifdef  __GNUC__
79       /* From libgcc.a, __main calls global class constructors,
80          __do_global_ctors, which registers __do_global_dtors
81          as the first entry of the private atexit table we
82          have just initialised  */
83       __main ();
84
85 #endif
86    }
87
88   /*
89    * Call the user-supplied DllMain subroutine.
90    * This has to come after initialization of atexit table and
91    * registration of global constructors.
92    * NOTE: DllMain is optional, so libmingw32.a includes a stub
93    *       which will be used if the user does not supply one.
94    */
95
96   bRet = DllMain (hDll, dwReason, lpReserved);
97   /* Handle case where DllMain returns FALSE on attachment attempt.  */
98
99   if ( (dwReason == DLL_PROCESS_ATTACH) && !bRet)
100     {
101 #ifdef DEBUG
102       printf ("%s: DLL_PROCESS_ATTACH failed, cleaning up\n", __FUNCTION__);
103 #endif
104
105       __dll_exit ();     /* Cleanup now. This will set first_atexit to NULL so we
106                             know we've cleaned up       */
107     }
108
109   if (dwReason == DLL_PROCESS_DETACH)
110     {
111 #ifdef DEBUG
112       printf ("%s: DLL_PROCESS_DETACH (%d)\n", __FUNCTION__);
113 #endif
114       /* If not attached, return FALSE. Cleanup already done above
115          if failed attachment attempt. */
116       if  (! first_atexit )
117         bRet = FALSE;
118       else
119         /*
120          * We used to call __do_global_dtors () here. This is
121          * no longer necessary since  __do_global_dtors is now
122          * registered at start (last out) of private atexit table.
123          */
124         __dll_exit ();
125     }
126   return bRet;
127 }
128
129 static
130 void
131 __dll_exit(void)
132 /* Run LIFO terminators registered in private atexit table */
133 {
134   if ( first_atexit )
135     {
136       p_atexit_fn* __last = next_atexit - 1;
137       while ( __last >= first_atexit )
138         {
139           if ( *__last != NULL )
140             {
141 #ifdef DEBUG
142               printf ("%s: Calling exit function  0x%x from 0x%x\n",
143                       __FUNCTION__, (unsigned)(*__last),(unsigned)__last);
144 #endif
145               (**__last) ();
146             }
147           __last--;
148         }
149       free ( first_atexit ) ;
150       first_atexit = NULL ;
151     }
152     /*
153        Make sure output buffers opened by DllMain or
154        atexit-registered functions are flushed before detaching,
155        otherwise we can have problems with redirected output.
156      */
157     fflush (NULL);
158 }
159
160 /*
161  * The atexit exported from msvcrt.dll causes problems in DLLs.
162  * Here, we override the exported version of atexit with one that passes the
163  * private table initialised in DllMainCRTStartup to __dllonexit.
164  * That means we have to hide the mscvrt.dll atexit because the
165  * atexit defined here gets __dllonexit from the same lib.
166  */
167
168 int
169 atexit (p_atexit_fn pfn )
170 {
171 #ifdef DEBUG
172   printf ("%s: registering exit function  0x%x at 0x%x\n",
173           __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit);
174 #endif
175   return (__dllonexit (pfn,  &first_atexit, &next_atexit)
176           == NULL ? -1  : 0 );
177 }
178
179 /*
180  * Likewise for non-ANSI function _onexit that may be called by
181  * code in the dll.
182  */
183
184 _onexit_t
185 _onexit (_onexit_t pfn )
186 {
187 #ifdef DEBUG
188   printf ("%s: registering exit function  0x%x at 0x%x\n",
189           __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit);
190 #endif
191   return ((_onexit_t) __dllonexit ((p_atexit_fn)pfn,  &first_atexit, &next_atexit));
192 }