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