Sync with trunk head (part 1 of 2)
[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 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 ***_imp____winitenv;
27 #define __winitenv (*_imp____winitenv)
28 #endif
29
30 #ifndef __initenv
31 extern char ***_imp____initenv;
32 #define __initenv (*_imp____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 *_imp___fmode;
47 extern int *_imp___commode;
48
49 #undef _fmode
50 extern int _fmode;
51 extern int *_imp___commode;
52 #define _commode (*_imp___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 static int argc;
78 #ifdef WPRFLAG
79 extern void __main(void);
80 static wchar_t **argv;
81 static wchar_t **envp;
82 #else
83 static char **argv;
84 static char **envp;
85 #endif
86
87 static int argret;
88 static int mainret=0;
89 static int managedapp;
90 static int has_cctor = 0;
91 static _startupinfo startinfo;
92
93 extern void _pei386_runtime_relocator (void);
94 static long CALLBACK _gnu_exception_handler (EXCEPTION_POINTERS * exception_data);
95 //static LONG __mingw_vex(EXCEPTION_POINTERS * exception_data);
96 #ifdef WPRFLAG
97 static void duplicate_ppstrings (int ac, wchar_t ***av);
98 #else
99 static void duplicate_ppstrings (int ac, char ***av);
100 #endif
101
102 static int __cdecl pre_c_init (void);
103 static void __cdecl pre_cpp_init (void);
104
105 _CRTALLOC(".CRT$XIAA") _PIFV mingw_pcinit = pre_c_init;
106 _CRTALLOC(".CRT$XCAA") _PVFV mingw_pcppinit = pre_cpp_init;
107
108 static int __cdecl
109 pre_c_init (void)
110 {
111 managedapp = check_managed_app ();
112 if (mingw_app_type)
113 __set_app_type(_GUI_APP);
114 else
115 __set_app_type (_CONSOLE_APP);
116 __onexitbegin = __onexitend = (_PVFV *) _encode_pointer ((_PVFV *)(-1));
117
118 *_imp___fmode = _fmode;
119 *_imp___commode = _commode;
120
121 #ifdef WPRFLAG
122 _wsetargv();
123 #else
124 _setargv();
125 #endif
126 if (_MINGW_INSTALL_DEBUG_MATHERR)
127 {
128 if (! __defaultmatherr)
129 {
130 __setusermatherr (_matherr);
131 __defaultmatherr = 1;
132 }
133 }
134
135 if (__globallocalestatus == -1)
136 {
137 }
138 return 0;
139 }
140
141 static void __cdecl
142 pre_cpp_init (void)
143 {
144 startinfo.newmode = _newmode;
145
146 #ifdef WPRFLAG
147 argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
148 #else
149 argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
150 #endif
151 }
152
153 static int __tmainCRTStartup (void);
154
155 int WinMainCRTStartup (void)
156 {
157 mingw_app_type = 1;
158 __security_init_cookie ();
159 return __tmainCRTStartup ();
160 }
161
162 int mainCRTStartup (void)
163 {
164 mingw_app_type = 0;
165 __security_init_cookie ();
166 return __tmainCRTStartup ();
167 }
168
169
170 __declspec(noinline) int
171 __tmainCRTStartup (void)
172 {
173 _TCHAR *lpszCommandLine = NULL;
174 STARTUPINFO StartupInfo;
175 BOOL inDoubleQuote = FALSE;
176 memset (&StartupInfo, 0, sizeof (STARTUPINFO));
177
178 if (mingw_app_type)
179 GetStartupInfo (&StartupInfo);
180 {
181 void *lock_free = NULL;
182 void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
183 int nested = FALSE;
184 while((lock_free = InterlockedCompareExchangePointer ((volatile PVOID *) &__native_startup_lock,
185 fiberid, 0)) != 0)
186 {
187 if (lock_free == fiberid)
188 {
189 nested = TRUE;
190 break;
191 }
192 Sleep(1000);
193 }
194 if (__native_startup_state == __initializing)
195 {
196 _amsg_exit (31);
197 }
198 else if (__native_startup_state == __uninitialized)
199 {
200 __native_startup_state = __initializing;
201 _initterm ((_PVFV *)(void *)__xi_a, (_PVFV *)(void *) __xi_z);
202 }
203 else
204 has_cctor = 1;
205
206 if (__native_startup_state == __initializing)
207 {
208 _initterm (__xc_a, __xc_z);
209 __native_startup_state = __initialized;
210 }
211 _ASSERTE(__native_startup_state == __initialized);
212 if (! nested)
213 (VOID)InterlockedExchangePointer ((volatile PVOID *) &__native_startup_lock, 0);
214
215 if (__dyn_tls_init_callback != NULL && _IsNonwritableInCurrentImage ((PBYTE) &__dyn_tls_init_callback))
216 __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
217
218 _pei386_runtime_relocator ();
219
220 #if defined(__i386__) || defined(_M_IX86)
221 __writefsdword(0, 0xffffffff);
222 #endif
223 //AddVectoredExceptionHandler (0, (PVECTORED_EXCEPTION_HANDLER)__mingw_vex);
224 SetUnhandledExceptionFilter (_gnu_exception_handler);
225
226 _fpreset ();
227
228 if (mingw_app_type)
229 {
230 #ifdef WPRFLAG
231 lpszCommandLine = (_TCHAR *) _wcmdln;
232 #else
233 lpszCommandLine = (char *) _acmdln;
234 #endif
235 while (*lpszCommandLine > SPACECHAR || (*lpszCommandLine&&inDoubleQuote))
236 {
237 if (*lpszCommandLine == DQUOTECHAR)
238 inDoubleQuote = !inDoubleQuote;
239 #ifdef _MBCS
240 if (_ismbblead (*lpszCommandLine))
241 {
242 if (lpszCommandLine)
243 lpszCommandLine++;
244 }
245 #endif
246 ++lpszCommandLine;
247 }
248 while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
249 lpszCommandLine++;
250
251 #ifdef WPRFLAG
252 /* C++ initialization.
253 gcc inserts this call automatically for a function called main, but not for wmain. */
254 __main ();
255 mainret = wmain (
256 (int) (StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT),
257 (wchar_t **) lpszCommandLine, (wchar_t **) (HINSTANCE) &__ImageBase);
258 #else
259 mainret = main (
260 (int) (StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT),
261 (char **) lpszCommandLine, (char **) (HINSTANCE) &__ImageBase);
262 #endif
263 }
264 else
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 }
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
403 default:
404 break;
405 }
406 return action;
407 }
408
409 #if 0
410 static LONG __mingw_vex(EXCEPTION_POINTERS * exception_data)
411 {
412 /* TODO this is not chainablem, therefore need rewrite. Disabled the ill code. */
413 #if 0
414 #ifdef _WIN64
415 __asm__ __volatile__ (
416 "movq %gs:0,%rax" "\n\t"
417 "orq %rax,%rax\n\t"
418 "jz l1\n\t"
419 "jmp *8(%rax)\n\r"
420 "l1:\n\t"
421 "nop\n");
422 #else
423 __asm__ __volatile__ (
424 "movl %fs:0,%eax" "\n\t"
425 "orl %eax,%eax\n\t"
426 "jz l1\n\t"
427 "jmp *4(%eax)\n\r"
428 "l1:\n\t"
429 "nop\n");
430 #endif
431 #endif
432 return _gnu_exception_handler(exception_data);
433 }
434 #endif
435
436 #ifdef WPRFLAG
437
438 static size_t wbytelen(const wchar_t *p)
439 {
440 size_t ret = 1;
441 while (*p!=0) {
442 ret++,++p;
443 }
444 return ret*2;
445 }
446 static void duplicate_ppstrings (int ac, wchar_t ***av)
447 {
448 wchar_t **avl;
449 int i;
450 wchar_t **n = (wchar_t **) malloc (sizeof (wchar_t *) * (ac + 1));
451
452 avl=*av;
453 for (i=0; i < ac; i++)
454 {
455 int l = wbytelen (avl[i]);
456 n[i] = (wchar_t *) malloc (l);
457 memcpy (n[i], avl[i], l);
458 }
459 n[i] = NULL;
460 *av = n;
461 }
462 #else
463 static void duplicate_ppstrings (int ac, char ***av)
464 {
465 char **avl;
466 int i;
467 char **n = (char **) malloc (sizeof (char *) * (ac + 1));
468
469 avl=*av;
470 for (i=0; i < ac; i++)
471 {
472 int l = strlen (avl[i]) + 1;
473 n[i] = (char *) malloc (l);
474 memcpy (n[i], avl[i], l);
475 }
476 n[i] = NULL;
477 *av = n;
478 }
479 #endif