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