OSDN Git Service

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