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