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