Merge to trunk HEAD(r36856)
[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 _CRTIMP 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=0;
72 static int mainret=0;
73 static int managedapp=0;
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 #ifndef WPRFLAG
106 _dowildcard = 1;
107 #endif
108
109 if (! __defaultmatherr)
110 __setusermatherr (_matherr);
111
112 if (__globallocalestatus == -1)
113 {
114 }
115 return 0;
116 }
117
118 static void __cdecl
119 pre_cpp_init (void)
120 {
121 startinfo.newmode = _newmode;
122 #ifdef WPRFLAG
123 argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
124 #else
125 argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
126 #endif
127
128 }
129
130 static int __mingw_CRTStartup (void);
131
132 #ifdef WPRFLAG
133 int wWinMainCRTStartup (void)
134 #else
135 int WinMainCRTStartup (void)
136 #endif
137 {
138 mingw_app_type = 1;
139 __security_init_cookie ();
140 return __mingw_CRTStartup ();
141 }
142
143 #ifdef WPRFLAG
144 int wmainCRTStartup (void)
145 #else
146 int mainCRTStartup (void)
147 #endif
148 {
149 mingw_app_type = 0;
150 __security_init_cookie ();
151 return __mingw_CRTStartup ();
152 }
153
154
155 __declspec(noinline) int
156 __mingw_CRTStartup (void)
157 {
158 _TCHAR *lpszCommandLine = NULL;
159 STARTUPINFO StartupInfo;
160 BOOL inDoubleQuote = FALSE;
161 memset (&StartupInfo, 0, sizeof (STARTUPINFO));
162 int nested = FALSE;
163
164 if (mingw_app_type)
165 GetStartupInfo (&StartupInfo);
166 {
167 #if 0 //not ready for this yet
168 void *lock_free = NULL;
169 void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
170 while((lock_free = InterlockedCompareExchangePointer ((volatile PVOID *) &__native_startup_lock,
171 fiberid, 0)) != 0)
172 {
173 if (lock_free == fiberid)
174 {
175 nested = TRUE;
176 break;
177 }
178 Sleep(1000);
179 }
180 #endif
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
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 return _gnu_exception_handler(exception_data);
426 }
427 #endif
428
429 #ifdef WPRFLAG
430
431 static size_t wbytelen(const wchar_t *p)
432 {
433 size_t ret = 1;
434 while (*p!=0) {
435 ret++,++p;
436 }
437 return ret*2;
438 }
439 static void duplicate_ppstrings (int ac, wchar_t ***av)
440 {
441 wchar_t **avl;
442 int i;
443 wchar_t **n = (wchar_t **) malloc (sizeof (wchar_t *) * (ac + 1));
444
445 avl=*av;
446 for (i=0; i < ac; i++)
447 {
448 int l = wbytelen (avl[i]);
449 n[i] = (wchar_t *) malloc (l);
450 memcpy (n[i], avl[i], l);
451 }
452 n[i] = NULL;
453 *av = n;
454 }
455 #else
456 static void duplicate_ppstrings (int ac, char ***av)
457 {
458 char **avl;
459 int i;
460 char **n = (char **) malloc (sizeof (char *) * (ac + 1));
461
462 avl=*av;
463 for (i=0; i < ac; i++)
464 {
465 int l = strlen (avl[i]) + 1;
466 n[i] = (char *) malloc (l);
467 memcpy (n[i], avl[i], l);
468 }
469 n[i] = NULL;
470 *av = n;
471 }
472 #endif