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