Commit | Line | Data |
7a958ec3 |
1 | /* |
2 | * gstartup.c |
3 | * |
4 | * Startup file for GCC/Mingw32 builds |
5 | * (replaces gcc's default c:\egcs\...\{crt1.o,dllcrt1.o}) |
6 | * |
7 | * This file is taken from the Mingw32 package. |
8 | * Created by Colin Peters for Mingw32 |
9 | * Modified by Mumit Khan |
10 | * |
11 | * History with Perl: |
12 | * Added (in modified form) to Perl standard distribution to fix |
13 | * problems linking against PerlCRT or MSVCRT |
14 | * -- Benjamin Stuhl <sho_pi@hotmail.com> 10-17-1999 |
15 | */ |
16 | |
17 | #include <stdlib.h> |
18 | #include <stdio.h> |
19 | #include <io.h> |
20 | #include <fcntl.h> |
21 | #include <process.h> |
22 | #include <float.h> |
23 | #include <windows.h> |
24 | #include <signal.h> |
25 | |
26 | /* |
27 | * Access to a standard 'main'-like argument count and list. Also included |
28 | * is a table of environment variables. |
29 | */ |
30 | int _argc; |
31 | char **_argv; |
32 | |
33 | extern int _CRT_glob; |
34 | |
35 | #ifdef __MSVCRT__ |
36 | typedef struct { |
37 | int newmode; |
38 | } _startupinfo; |
39 | extern void __getmainargs (int *, char ***, char ***, int, _startupinfo *); |
40 | #else |
41 | extern void __GetMainArgs (int *, char ***, char ***, int); |
42 | #endif |
43 | |
44 | /* |
45 | * Initialize the _argc, _argv and environ variables. |
46 | */ |
47 | static void |
48 | _mingw32_init_mainargs () |
49 | { |
50 | /* The environ variable is provided directly in stdlib.h through |
51 | * a dll function call. */ |
52 | char **dummy_environ; |
53 | #ifdef __MSVCRT__ |
54 | _startupinfo start_info; |
55 | start_info.newmode = 0; |
56 | #endif |
57 | |
58 | /* |
59 | * Microsoft's runtime provides a function for doing just that. |
60 | */ |
61 | #ifdef __MSVCRT__ |
62 | (void) __getmainargs (&_argc, &_argv, &dummy_environ, _CRT_glob, |
63 | &start_info); |
64 | #else |
65 | /* CRTDLL version */ |
66 | (void) __GetMainArgs (&_argc, &_argv, &dummy_environ, _CRT_glob); |
67 | #endif |
68 | } |
69 | |
70 | #if defined(EXESTARTUP) /* gcrt0.o - startup for an executable */ |
71 | |
72 | extern int main (int, char **, char **); |
73 | |
74 | /* |
75 | * Must have the correct app type for MSVCRT. |
76 | */ |
77 | |
78 | #ifdef __MSVCRT__ |
79 | #define __UNKNOWN_APP 0 |
80 | #define __CONSOLE_APP 1 |
81 | #define __GUI_APP 2 |
82 | __MINGW_IMPORT void __set_app_type(int); |
83 | #endif /* __MSVCRT__ */ |
84 | |
85 | /* |
86 | * Setup the default file handles to have the _CRT_fmode mode, as well as |
87 | * any new files created by the user. |
88 | */ |
89 | extern unsigned int _CRT_fmode; |
90 | |
91 | static void |
92 | _mingw32_init_fmode () |
93 | { |
94 | /* Don't set the file mode if the user hasn't set any value for it. */ |
95 | if (_CRT_fmode) |
96 | { |
97 | _fmode = _CRT_fmode; |
98 | |
99 | /* |
100 | * This overrides the default file mode settings for stdin, |
101 | * stdout and stderr. At first I thought you would have to |
102 | * test with isatty, but it seems that the DOS console at |
103 | * least is smart enough to handle _O_BINARY stdout and |
104 | * still display correctly. |
105 | */ |
106 | if (stdin) |
107 | { |
108 | _setmode (_fileno (stdin), _CRT_fmode); |
109 | } |
110 | if (stdout) |
111 | { |
112 | _setmode (_fileno (stdout), _CRT_fmode); |
113 | } |
114 | if (stderr) |
115 | { |
116 | _setmode (_fileno (stderr), _CRT_fmode); |
117 | } |
118 | } |
119 | } |
120 | |
121 | /* This function will be called when a trap occurs. Thanks to Jacob |
122 | Navia for his contribution. */ |
123 | static CALLBACK long |
124 | _gnu_exception_handler (EXCEPTION_POINTERS * exception_data) |
125 | { |
126 | void (*old_handler) (int); |
127 | long action = EXCEPTION_CONTINUE_SEARCH; |
128 | int reset_fpu = 0; |
129 | |
130 | switch (exception_data->ExceptionRecord->ExceptionCode) |
131 | { |
132 | case EXCEPTION_ACCESS_VIOLATION: |
133 | /* test if the user has set SIGSEGV */ |
134 | old_handler = signal (SIGSEGV, SIG_DFL); |
135 | if (old_handler == SIG_IGN) |
136 | { |
137 | /* this is undefined if the signal was raised by anything other |
138 | than raise (). */ |
139 | signal (SIGSEGV, SIG_IGN); |
140 | action = EXCEPTION_CONTINUE_EXECUTION; |
141 | } |
142 | else if (old_handler != SIG_DFL) |
143 | { |
144 | /* This means 'old' is a user defined function. Call it */ |
145 | (*old_handler) (SIGSEGV); |
146 | action = EXCEPTION_CONTINUE_EXECUTION; |
147 | } |
148 | break; |
149 | |
150 | case EXCEPTION_FLT_INVALID_OPERATION: |
151 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: |
152 | case EXCEPTION_FLT_DENORMAL_OPERAND: |
153 | case EXCEPTION_FLT_OVERFLOW: |
154 | case EXCEPTION_FLT_UNDERFLOW: |
155 | case EXCEPTION_FLT_INEXACT_RESULT: |
156 | reset_fpu = 1; |
157 | /* fall through. */ |
158 | |
159 | case EXCEPTION_INT_DIVIDE_BY_ZERO: |
160 | /* test if the user has set SIGFPE */ |
161 | old_handler = signal (SIGFPE, SIG_DFL); |
162 | if (old_handler == SIG_IGN) |
163 | { |
164 | signal (SIGFPE, SIG_IGN); |
165 | if (reset_fpu) |
166 | _fpreset (); |
167 | action = EXCEPTION_CONTINUE_EXECUTION; |
168 | } |
169 | else if (old_handler != SIG_DFL) |
170 | { |
171 | /* This means 'old' is a user defined function. Call it */ |
172 | (*old_handler) (SIGFPE); |
173 | action = EXCEPTION_CONTINUE_EXECUTION; |
174 | } |
175 | break; |
176 | |
177 | default: |
178 | break; |
179 | } |
180 | return action; |
181 | } |
182 | |
183 | /* |
184 | * The function mainCRTStartup is the entry point for all console programs. |
185 | */ |
186 | static int |
187 | __mingw_CRTStartup () |
188 | { |
189 | int nRet; |
190 | |
191 | /* |
192 | * Set up the top-level exception handler so that signal handling |
193 | * works as expected. The mapping between ANSI/POSIX signals and |
194 | * Win32 SE is not 1-to-1, so caveat emptore. |
195 | * |
196 | */ |
197 | SetUnhandledExceptionFilter (_gnu_exception_handler); |
198 | |
199 | /* |
200 | * Initialize floating point unit. |
201 | */ |
202 | _fpreset (); /* Supplied by the runtime library. */ |
203 | |
204 | /* |
205 | * Set up __argc, __argv and _environ. |
206 | */ |
207 | _mingw32_init_mainargs (); |
208 | |
209 | /* |
210 | * Sets the default file mode for stdin, stdout and stderr, as well |
211 | * as files later opened by the user, to _CRT_fmode. |
212 | * NOTE: DLLs don't do this because that would be rude! |
213 | */ |
214 | _mingw32_init_fmode (); |
215 | |
216 | /* |
217 | * Call the main function. If the user does not supply one |
218 | * the one in the 'libmingw32.a' library will be linked in, and |
219 | * that one calls WinMain. See main.c in the 'lib' dir |
220 | * for more details. |
221 | */ |
222 | nRet = main (_argc, _argv, environ); |
223 | |
224 | /* |
225 | * Perform exit processing for the C library. This means |
226 | * flushing output and calling 'atexit' registered functions. |
227 | */ |
228 | _cexit (); |
229 | |
230 | ExitProcess (nRet); |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | /* |
236 | * The function mainCRTStartup is the entry point for all console programs. |
237 | */ |
238 | int |
239 | mainCRTStartup () |
240 | { |
241 | #ifdef __MSVCRT__ |
242 | __set_app_type (__CONSOLE_APP); |
243 | #endif |
244 | __mingw_CRTStartup (); |
245 | return 0; |
246 | } |
247 | |
248 | /* |
249 | * For now the GUI startup function is the same as the console one. |
250 | * This simply gets rid of the annoying warning about not being able |
251 | * to find WinMainCRTStartup when linking GUI applications. |
252 | */ |
253 | int |
254 | WinMainCRTStartup () |
255 | { |
256 | #ifdef __MSVCRT__ |
257 | __set_app_type (__GUI_APP); |
258 | #endif |
259 | __mingw_CRTStartup (); |
260 | } |
261 | |
262 | #elif defined(DLLSTARTUP) /* dllcrt0.o - startup for a DLL */ |
263 | |
264 | /* Unlike normal crt1, I don't initialize the FPU, because the process |
265 | * should have done that already. I also don't set the file handle modes, |
266 | * because that would be rude. */ |
267 | |
268 | #ifdef __GNUC__ |
269 | extern void __main (); |
270 | extern void __do_global_dtors (); |
271 | #endif |
272 | |
273 | extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID); |
274 | |
275 | BOOL WINAPI |
276 | DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) |
277 | { |
278 | BOOL bRet; |
279 | |
280 | if (dwReason == DLL_PROCESS_ATTACH) |
281 | { |
282 | _mingw32_init_mainargs (); |
283 | |
284 | #ifdef __GNUC__ |
285 | /* From libgcc.a, calls global class constructors. */ |
286 | __main (); |
287 | #endif |
288 | } |
289 | |
290 | /* |
291 | * Call the user-supplied DllMain subroutine |
292 | * NOTE: DllMain is optional, so libmingw32.a includes a stub |
293 | * which will be used if the user does not supply one. |
294 | */ |
295 | bRet = DllMain (hDll, dwReason, lpReserved); |
296 | |
297 | #ifdef __GNUC__ |
298 | if (dwReason == DLL_PROCESS_DETACH) |
299 | { |
300 | /* From libgcc.a, calls global class destructors. */ |
301 | __do_global_dtors (); |
302 | } |
303 | #endif |
304 | |
305 | return bRet; |
306 | } |
307 | |
308 | /* |
309 | * For the moment a dummy atexit. Atexit causes problems in DLLs, especially |
310 | * if they are dynamically loaded. For now atexit inside a DLL does nothing. |
311 | * NOTE: We need this even if the DLL author never calls atexit because |
312 | * the global constructor function __do_global_ctors called from __main |
313 | * will attempt to register __do_global_dtors using atexit. |
314 | * Thanks to Andrey A. Smirnov for pointing this one out. |
315 | */ |
316 | int |
317 | atexit (void (*pfn) ()) |
318 | { |
319 | return 0; |
320 | } |
321 | |
322 | #else |
323 | #error No startup target! |
324 | #endif /* EXESTARTUP */ |