Sync with trunk (48237)
[reactos.git] / lib / 3rdparty / mingw / crtexe.c
1 /**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the w64 mingw-runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7 #undef CRTDLL
8 #ifndef _DLL
9 #define _DLL
10 #endif
11
12 #define SPECIAL_CRTEXE
13
14 #include <oscalls.h>
15 #include <internal.h>
16 #include <process.h>
17 #include <signal.h>
18 #include <math.h>
19 #include <stdlib.h>
20 #include <tchar.h>
21 #include <sect_attribs.h>
22 #include <locale.h>
23 #include <intrin.h>
24
25 #ifndef __winitenv
26 extern wchar_t *** __MINGW_IMP_SYMBOL(__winitenv);
27 #define __winitenv (* __MINGW_IMP_SYMBOL(__winitenv))
28 #endif
29
30 #ifndef __initenv
31 extern char *** __MINGW_IMP_SYMBOL(__initenv);
32 #define __initenv (* __MINGW_IMP_SYMBOL(__initenv))
33 #endif
34
35 /* Hack, for bug in ld. Will be removed soon. */
36 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
37 /* This symbol is defined by ld. */
38 extern IMAGE_DOS_HEADER __ImageBase;
39
40 extern void _fpreset (void);
41 #define SPACECHAR _T(' ')
42 #define DQUOTECHAR _T('\"')
43
44 __declspec(dllimport) void __setusermatherr(int (__cdecl *)(struct _exception *));
45
46 extern int * __MINGW_IMP_SYMBOL(_fmode);
47 extern int * __MINGW_IMP_SYMBOL(_commode);
48
49 extern int * __MINGW_IMP_SYMBOL(_commode);
50 #define _commode (* __MINGW_IMP_SYMBOL(_commode))
51 extern int _dowildcard;
52
53 #if defined(__GNUC__)
54 int _MINGW_INSTALL_DEBUG_MATHERR __attribute__((weak)) = 0;
55 #else
56 int _MINGW_INSTALL_DEBUG_MATHERR = 0;
57 #endif
58 extern int __defaultmatherr;
59 extern _CRTIMP void __cdecl _initterm(_PVFV *, _PVFV *);
60
61 static int __cdecl check_managed_app (void);
62
63 extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[];
64 extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[];
65 extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
66 extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[];
67
68 /* TLS initialization hook. */
69 extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
70
71 extern _PVFV *__onexitbegin;
72 extern _PVFV *__onexitend;
73
74 extern int mingw_app_type;
75
76 HINSTANCE __mingw_winmain_hInstance;
77 _TCHAR *__mingw_winmain_lpCmdLine;
78 DWORD __mingw_winmain_nShowCmd;
79
80 static int argc;
81 #ifdef WPRFLAG
82 extern void __main(void);
83 static wchar_t **argv;
84 static wchar_t **envp;
85 #else
86 static char **argv;
87 static char **envp;
88 #endif
89
90 static int argret;
91 static int mainret=0;
92 static int managedapp;
93 static int has_cctor = 0;
94 static _startupinfo startinfo;
95 static LPTOP_LEVEL_EXCEPTION_FILTER __mingw_oldexcpt_handler = NULL;
96
97 extern void _pei386_runtime_relocator (void);
98 static long CALLBACK _gnu_exception_handler (EXCEPTION_POINTERS * exception_data);
99 #ifdef WPRFLAG
100 static void duplicate_ppstrings (int ac, wchar_t ***av);
101 #else
102 static void duplicate_ppstrings (int ac, char ***av);
103 #endif
104
105 static int __cdecl pre_c_init (void);
106 static void __cdecl pre_cpp_init (void);
107 static void __cdecl __mingw_prepare_except_for_msvcr80_and_higher (void);
108 _CRTALLOC(".CRT$XIAA") _PIFV mingw_pcinit = pre_c_init;
109 _CRTALLOC(".CRT$XCAA") _PVFV mingw_pcppinit = pre_cpp_init;
110
111 static int __cdecl
112 pre_c_init (void)
113 {
114 managedapp = check_managed_app ();
115 if (mingw_app_type)
116 __set_app_type(_GUI_APP);
117 else
118 __set_app_type (_CONSOLE_APP);
119 __onexitbegin = __onexitend = (_PVFV *) _encode_pointer ((_PVFV *)(-1));
120
121 * __MINGW_IMP_SYMBOL(_fmode) = _fmode;
122 * __MINGW_IMP_SYMBOL(_commode) = _commode;
123
124 #ifdef WPRFLAG
125 _wsetargv();
126 #else
127 _setargv();
128 #endif
129 if (_MINGW_INSTALL_DEBUG_MATHERR)
130 {
131 if (! __defaultmatherr)
132 {
133 __setusermatherr (_matherr);
134 __defaultmatherr = 1;
135 }
136 }
137
138 if (__globallocalestatus == -1)
139 {
140 }
141 return 0;
142 }
143
144 static void __cdecl
145 pre_cpp_init (void)
146 {
147 startinfo.newmode = _newmode;
148
149 #ifdef WPRFLAG
150 argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
151 #else
152 argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
153 #endif
154 }
155
156 static int __tmainCRTStartup (void);
157
158 int WinMainCRTStartup (void);
159
160 int WinMainCRTStartup (void)
161 {
162 mingw_app_type = 1;
163 __security_init_cookie ();
164 return __tmainCRTStartup ();
165 }
166
167 int mainCRTStartup (void);
168
169 #ifdef _WIN64
170 int __mingw_init_ehandler (void);
171 #endif
172
173 int mainCRTStartup (void)
174 {
175 mingw_app_type = 0;
176 __security_init_cookie ();
177 return __tmainCRTStartup ();
178 }
179
180 static
181 __declspec(noinline) int
182 __tmainCRTStartup (void)
183 {
184 _TCHAR *lpszCommandLine = NULL;
185 STARTUPINFO StartupInfo;
186 WINBOOL inDoubleQuote = FALSE;
187 memset (&StartupInfo, 0, sizeof (STARTUPINFO));
188
189 if (mingw_app_type)
190 GetStartupInfo (&StartupInfo);
191 {
192 void *lock_free = NULL;
193 void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
194 int nested = FALSE;
195 while((lock_free = InterlockedCompareExchangePointer ((volatile PVOID *) &__native_startup_lock,
196 fiberid, 0)) != 0)
197 {
198 if (lock_free == fiberid)
199 {
200 nested = TRUE;
201 break;
202 }
203 Sleep(1000);
204 }
205 if (__native_startup_state == __initializing)
206 {
207 _amsg_exit (31);
208 }
209 else if (__native_startup_state == __uninitialized)
210 {
211 __native_startup_state = __initializing;
212 _initterm ((_PVFV *)(void *)__xi_a, (_PVFV *)(void *) __xi_z);
213 }
214 else
215 has_cctor = 1;
216
217 if (__native_startup_state == __initializing)
218 {
219 _initterm (__xc_a, __xc_z);
220 __native_startup_state = __initialized;
221 }
222 _ASSERTE(__native_startup_state == __initialized);
223 if (! nested)
224 (VOID)InterlockedExchangePointer ((volatile PVOID *) &__native_startup_lock, 0);
225
226 if (__dyn_tls_init_callback != NULL)
227 __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
228
229 _pei386_runtime_relocator ();
230 __mingw_oldexcpt_handler = SetUnhandledExceptionFilter (_gnu_exception_handler);
231 #ifdef _WIN64
232 __mingw_init_ehandler ();
233 #endif
234 __mingw_prepare_except_for_msvcr80_and_higher ();
235
236 _fpreset ();
237
238 if (mingw_app_type)
239 {
240 #ifdef WPRFLAG
241 lpszCommandLine = (_TCHAR *) _wcmdln;
242 #else
243 lpszCommandLine = (char *) _acmdln;
244 #endif
245 while (*lpszCommandLine > SPACECHAR || (*lpszCommandLine&&inDoubleQuote))
246 {
247 if (*lpszCommandLine == DQUOTECHAR)
248 inDoubleQuote = !inDoubleQuote;
249 #ifdef _MBCS
250 if (_ismbblead (*lpszCommandLine))
251 {
252 if (lpszCommandLine) /* FIXME: Why this check? Should I check for *lpszCommandLine != 0 too? */
253 lpszCommandLine++;
254 }
255 #endif
256 ++lpszCommandLine;
257 }
258 while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
259 lpszCommandLine++;
260
261 __mingw_winmain_hInstance = (HINSTANCE) &__ImageBase;
262 __mingw_winmain_lpCmdLine = lpszCommandLine;
263 __mingw_winmain_nShowCmd = StartupInfo.dwFlags & STARTF_USESHOWWINDOW ?
264 StartupInfo.wShowWindow : SW_SHOWDEFAULT;
265 }
266 duplicate_ppstrings (argc, &argv);
267 #ifdef WPRFLAG
268 __winitenv = envp;
269 /* C++ initialization.
270 gcc inserts this call automatically for a function called main, but not for wmain. */
271 __main ();
272 mainret = wmain (argc, argv, envp);
273 #else
274 __initenv = envp;
275 mainret = main (argc, argv, envp);
276 #endif
277 if (!managedapp)
278 exit (mainret);
279
280 if (has_cctor == 0)
281 _cexit ();
282 }
283 return mainret;
284 }
285
286 extern int mingw_initltsdrot_force;
287 extern int mingw_initltsdyn_force;
288 extern int mingw_initltssuo_force;
289 extern int mingw_initcharmax;
290
291 static int __cdecl
292 check_managed_app (void)
293 {
294 PIMAGE_DOS_HEADER pDOSHeader;
295 PIMAGE_NT_HEADERS pPEHeader;
296 PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
297 PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
298
299 /* Force to be linked. */
300 mingw_initltsdrot_force=1;
301 mingw_initltsdyn_force=1;
302 mingw_initltssuo_force=1;
303 mingw_initcharmax=1;
304
305 pDOSHeader = (PIMAGE_DOS_HEADER) &__ImageBase;
306 if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
307 return 0;
308
309 pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader + pDOSHeader->e_lfanew);
310 if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
311 return 0;
312
313 pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32) &pPEHeader->OptionalHeader;
314 switch (pNTHeader32->Magic)
315 {
316 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
317 if (pNTHeader32->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
318 return 0;
319 return !! pNTHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
320 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
321 pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
322 if (pNTHeader64->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
323 return 0;
324 return !! pNTHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
325 }
326 return 0;
327 }
328
329 static long CALLBACK
330 _gnu_exception_handler (EXCEPTION_POINTERS *exception_data)
331 {
332 void (*old_handler) (int);
333 long action = EXCEPTION_CONTINUE_SEARCH;
334 int reset_fpu = 0;
335
336 switch (exception_data->ExceptionRecord->ExceptionCode)
337 {
338 case EXCEPTION_ACCESS_VIOLATION:
339 /* test if the user has set SIGSEGV */
340 old_handler = signal (SIGSEGV, SIG_DFL);
341 if (old_handler == SIG_IGN)
342 {
343 /* this is undefined if the signal was raised by anything other
344 than raise (). */
345 signal (SIGSEGV, SIG_IGN);
346 action = EXCEPTION_CONTINUE_EXECUTION;
347 }
348 else if (old_handler != SIG_DFL)
349 {
350 /* This means 'old' is a user defined function. Call it */
351 (*old_handler) (SIGSEGV);
352 action = EXCEPTION_CONTINUE_EXECUTION;
353 }
354 break;
355
356 case EXCEPTION_ILLEGAL_INSTRUCTION:
357 case EXCEPTION_PRIV_INSTRUCTION:
358 /* test if the user has set SIGILL */
359 old_handler = signal (SIGILL, SIG_DFL);
360 if (old_handler == SIG_IGN)
361 {
362 /* this is undefined if the signal was raised by anything other
363 than raise (). */
364 signal (SIGILL, SIG_IGN);
365 action = EXCEPTION_CONTINUE_EXECUTION;
366 }
367 else if (old_handler != SIG_DFL)
368 {
369 /* This means 'old' is a user defined function. Call it */
370 (*old_handler) (SIGILL);
371 action = EXCEPTION_CONTINUE_EXECUTION;
372 }
373 break;
374
375 case EXCEPTION_FLT_INVALID_OPERATION:
376 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
377 case EXCEPTION_FLT_DENORMAL_OPERAND:
378 case EXCEPTION_FLT_OVERFLOW:
379 case EXCEPTION_FLT_UNDERFLOW:
380 case EXCEPTION_FLT_INEXACT_RESULT:
381 reset_fpu = 1;
382 /* fall through. */
383
384 case EXCEPTION_INT_DIVIDE_BY_ZERO:
385 /* test if the user has set SIGFPE */
386 old_handler = signal (SIGFPE, SIG_DFL);
387 if (old_handler == SIG_IGN)
388 {
389 signal (SIGFPE, SIG_IGN);
390 if (reset_fpu)
391 _fpreset ();
392 action = EXCEPTION_CONTINUE_EXECUTION;
393 }
394 else if (old_handler != SIG_DFL)
395 {
396 /* This means 'old' is a user defined function. Call it */
397 (*old_handler) (SIGFPE);
398 action = EXCEPTION_CONTINUE_EXECUTION;
399 }
400 break;
401 #ifdef _WIN64
402 case EXCEPTION_DATATYPE_MISALIGNMENT:
403 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
404 case EXCEPTION_FLT_STACK_CHECK:
405 case EXCEPTION_INT_OVERFLOW:
406 case EXCEPTION_INVALID_HANDLE:
407 /*case EXCEPTION_POSSIBLE_DEADLOCK: */
408 action = EXCEPTION_CONTINUE_EXECUTION;
409 break;
410 #endif
411 default:
412 break;
413 }
414
415 if (action == EXCEPTION_CONTINUE_SEARCH && __mingw_oldexcpt_handler)
416 action = (*__mingw_oldexcpt_handler)(exception_data);
417 return action;
418 }
419
420 #ifdef WPRFLAG
421 static size_t wbytelen(const wchar_t *p)
422 {
423 size_t ret = 1;
424 while (*p!=0) {
425 ret++,++p;
426 }
427 return ret*2;
428 }
429 static void duplicate_ppstrings (int ac, wchar_t ***av)
430 {
431 wchar_t **avl;
432 int i;
433 wchar_t **n = (wchar_t **) malloc (sizeof (wchar_t *) * (ac + 1));
434
435 avl=*av;
436 for (i=0; i < ac; i++)
437 {
438 int l = wbytelen (avl[i]);
439 n[i] = (wchar_t *) malloc (l);
440 memcpy (n[i], avl[i], l);
441 }
442 n[i] = NULL;
443 *av = n;
444 }
445 #else
446 static void duplicate_ppstrings (int ac, char ***av)
447 {
448 char **avl;
449 int i;
450 char **n = (char **) malloc (sizeof (char *) * (ac + 1));
451
452 avl=*av;
453 for (i=0; i < ac; i++)
454 {
455 int l = strlen (avl[i]) + 1;
456 n[i] = (char *) malloc (l);
457 memcpy (n[i], avl[i], l);
458 }
459 n[i] = NULL;
460 *av = n;
461 }
462 #endif
463
464 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
465 #define __UNUSED_PARAM_1(x) x
466 #else
467 #define __UNUSED_PARAM_1 __UNUSED_PARAM
468 #endif
469 static void
470 __mingw_invalidParameterHandler (const wchar_t * __UNUSED_PARAM_1(expression),
471 const wchar_t * __UNUSED_PARAM_1(function),
472 const wchar_t * __UNUSED_PARAM_1(file),
473 unsigned int __UNUSED_PARAM_1(line),
474 uintptr_t __UNUSED_PARAM(pReserved))
475 {
476 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
477 wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
478 wprintf(L"Expression: %s\n", expression);
479 #endif
480 }
481
482 static void __cdecl
483 __mingw_prepare_except_for_msvcr80_and_higher (void)
484 {
485 _invalid_parameter_handler (*fIPH)(_invalid_parameter_handler) = NULL;
486 HMODULE hmsv = GetModuleHandleA ("msvcr80.dll");
487 if(!hmsv)
488 hmsv = GetModuleHandleA ("msvcr70.dll");
489 if (!hmsv)
490 hmsv = GetModuleHandleA ("msvcrt.dll");
491 if (!hmsv)
492 hmsv = LoadLibraryA ("msvcrt.dll");
493 if (!hmsv)
494 return;
495 fIPH = (_invalid_parameter_handler (*)(_invalid_parameter_handler))
496 GetProcAddress (hmsv, "_set_invalid_parameter_handler");
497 if (fIPH)
498 (*fIPH)(__mingw_invalidParameterHandler);
499 }