1bd193bedff77131ff5e7623ee4a250fcdd572e3
[reactos.git] / sdk / lib / crt / startup / 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.PD 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 *** __MINGW_IMP_SYMBOL(__winitenv);
26 #define __winitenv (* __MINGW_IMP_SYMBOL(__winitenv))
27 #endif
28
29 #ifndef __initenv
30 extern char *** __MINGW_IMP_SYMBOL(__initenv);
31 #define __initenv (* __MINGW_IMP_SYMBOL(__initenv))
32 #endif
33
34 /* Hack, for bug in ld. Will be removed soon. */
35 #if defined(__GNUC__)
36 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
37 #endif
38
39 /* This symbol is defined by ld. */
40 extern IMAGE_DOS_HEADER __ImageBase;
41
42 extern void __cdecl _fpreset (void);
43 #define SPACECHAR _T(' ')
44 #define DQUOTECHAR _T('\"')
45
46 extern int * __MINGW_IMP_SYMBOL(_fmode);
47 extern int * __MINGW_IMP_SYMBOL(_commode);
48
49 #undef _fmode
50 extern int _fmode;
51 extern int * __MINGW_IMP_SYMBOL(_commode);
52 #define _commode (* __MINGW_IMP_SYMBOL(_commode))
53 extern int _dowildcard;
54
55 extern _CRTIMP void __cdecl _initterm(_PVFV *, _PVFV *);
56
57 static int __cdecl check_managed_app (void);
58
59 extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[];
60 extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[];
61 extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
62 extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[];
63
64 /* TLS initialization hook. */
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 HINSTANCE __mingw_winmain_hInstance;
73 _TCHAR *__mingw_winmain_lpCmdLine;
74 DWORD __mingw_winmain_nShowCmd;
75
76 static int argc;
77 extern void __main(void);
78 #ifdef WPRFLAG
79 static wchar_t **argv;
80 static wchar_t **envp;
81 #else
82 static char **argv;
83 static char **envp;
84 #endif
85
86 static int argret;
87 static int mainret=0;
88 static int managedapp;
89 static int has_cctor = 0;
90 static _startupinfo startinfo;
91 extern LPTOP_LEVEL_EXCEPTION_FILTER __mingw_oldexcpt_handler;
92
93 extern void _pei386_runtime_relocator (void);
94 long CALLBACK _gnu_exception_handler (EXCEPTION_POINTERS * exception_data);
95 #ifdef WPRFLAG
96 static void duplicate_ppstrings (int ac, wchar_t ***av);
97 #else
98 static void duplicate_ppstrings (int ac, char ***av);
99 #endif
100
101 static int __cdecl pre_c_init (void);
102 static void __cdecl pre_cpp_init (void);
103 static void __cdecl __mingw_prepare_except_for_msvcr80_and_higher (void);
104 _CRTALLOC(".CRT$XIAA") _PIFV mingw_pcinit = pre_c_init;
105 _CRTALLOC(".CRT$XCAA") _PVFV mingw_pcppinit = pre_cpp_init;
106
107 extern int _MINGW_INSTALL_DEBUG_MATHERR;
108
109 static int __cdecl
110 pre_c_init (void)
111 {
112 managedapp = check_managed_app ();
113 if (mingw_app_type)
114 __set_app_type(_GUI_APP);
115 else
116 __set_app_type (_CONSOLE_APP);
117 __onexitbegin = __onexitend = (_PVFV *) _encode_pointer ((_PVFV *)(-1));
118
119 * __MINGW_IMP_SYMBOL(_fmode) = _fmode;
120 * __MINGW_IMP_SYMBOL(_commode) = _commode;
121
122 #ifdef WPRFLAG
123 _wsetargv();
124 #else
125 _setargv();
126 #endif
127 if (_MINGW_INSTALL_DEBUG_MATHERR == 1)
128 {
129 __setusermatherr (_matherr);
130 }
131
132 if (__globallocalestatus == -1)
133 {
134 }
135 return 0;
136 }
137
138 static void __cdecl
139 pre_cpp_init (void)
140 {
141 startinfo.newmode = _newmode;
142
143 #ifdef WPRFLAG
144 argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
145 #else
146 argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
147 #endif
148 }
149
150 static int __cdecl __tmainCRTStartup (void);
151
152 int __cdecl WinMainCRTStartup (void);
153
154 int __cdecl WinMainCRTStartup (void)
155 {
156 int ret = 255;
157 #ifdef __SEH__
158 asm ("\t.l_startw:\n"
159 "\t.seh_handler __C_specific_handler, @except\n"
160 "\t.seh_handlerdata\n"
161 "\t.long 1\n"
162 "\t.rva .l_startw, .l_endw, _gnu_exception_handler ,.l_endw\n"
163 "\t.text"
164 );
165 #endif
166 mingw_app_type = 1;
167 __security_init_cookie ();
168 ret = __tmainCRTStartup ();
169 #ifdef __SEH__
170 asm ("\tnop\n"
171 "\t.l_endw: nop\n");
172 #endif
173 return ret;
174 }
175
176 int __cdecl mainCRTStartup (void);
177
178 #ifdef _WIN64
179 int __mingw_init_ehandler (void);
180 #endif
181
182 int __cdecl mainCRTStartup (void)
183 {
184 int ret = 255;
185 #ifdef __SEH__
186 asm ("\t.l_start:\n"
187 "\t.seh_handler __C_specific_handler, @except\n"
188 "\t.seh_handlerdata\n"
189 "\t.long 1\n"
190 "\t.rva .l_start, .l_end, _gnu_exception_handler ,.l_end\n"
191 "\t.text"
192 );
193 #endif
194 mingw_app_type = 0;
195 __security_init_cookie ();
196 ret = __tmainCRTStartup ();
197 #ifdef __SEH__
198 asm ("\tnop\n"
199 "\t.l_end: nop\n");
200 #endif
201 return ret;
202 }
203
204 static
205 __declspec(noinline)
206 int __cdecl
207 __tmainCRTStartup (void)
208 {
209 _TCHAR *lpszCommandLine = NULL;
210 STARTUPINFO StartupInfo;
211 WINBOOL inDoubleQuote = FALSE;
212 memset (&StartupInfo, 0, sizeof (STARTUPINFO));
213
214 #ifndef _WIN64
215 /* We need to make sure that this function is build with frame-pointer
216 and that we align the stack to 16 bytes for the sake of SSE ops in main
217 or in functions inlined into main. */
218 lpszCommandLine = (_TCHAR *) alloca (32);
219 memset (lpszCommandLine, 0xcc, 32);
220 #ifdef __GNUC__
221 asm __volatile__ ("andl $-16, %%esp" : : : "%esp");
222 #endif
223 #endif
224
225 if (mingw_app_type)
226 GetStartupInfo (&StartupInfo);
227 {
228 void *lock_free = NULL;
229 void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
230 int nested = FALSE;
231 while((lock_free = InterlockedCompareExchangePointer ((volatile PVOID *) &__native_startup_lock,
232 fiberid, 0)) != 0)
233 {
234 if (lock_free == fiberid)
235 {
236 nested = TRUE;
237 break;
238 }
239 Sleep(1000);
240 }
241 if (__native_startup_state == __initializing)
242 {
243 _amsg_exit (31);
244 }
245 else if (__native_startup_state == __uninitialized)
246 {
247 __native_startup_state = __initializing;
248 _initterm ((_PVFV *)(void *)__xi_a, (_PVFV *)(void *) __xi_z);
249 }
250 else
251 has_cctor = 1;
252
253 if (__native_startup_state == __initializing)
254 {
255 _initterm (__xc_a, __xc_z);
256 __native_startup_state = __initialized;
257 }
258 _ASSERTE(__native_startup_state == __initialized);
259 if (! nested)
260 (VOID)InterlockedExchangePointer ((volatile PVOID *) &__native_startup_lock, 0);
261
262 if (__dyn_tls_init_callback != NULL)
263 __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
264
265 _pei386_runtime_relocator ();
266 __mingw_oldexcpt_handler = SetUnhandledExceptionFilter (_gnu_exception_handler);
267 #ifdef _WIN64
268 __mingw_init_ehandler ();
269 #endif
270 __mingw_prepare_except_for_msvcr80_and_higher ();
271
272 _fpreset ();
273
274 if (mingw_app_type)
275 {
276 #ifdef WPRFLAG
277 lpszCommandLine = (_TCHAR *) _wcmdln;
278 #else
279 lpszCommandLine = (char *) _acmdln;
280 #endif
281 while (*lpszCommandLine > SPACECHAR || (*lpszCommandLine && inDoubleQuote))
282 {
283 if (*lpszCommandLine == DQUOTECHAR)
284 inDoubleQuote = !inDoubleQuote;
285 #ifdef _MBCS
286 if (_ismbblead (*lpszCommandLine))
287 {
288 if (lpszCommandLine) /* FIXME: Why this check? Should I check for *lpszCommandLine != 0 too? */
289 lpszCommandLine++;
290 }
291 #endif
292 ++lpszCommandLine;
293 }
294 while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
295 lpszCommandLine++;
296
297 __mingw_winmain_hInstance = (HINSTANCE) &__ImageBase;
298 __mingw_winmain_lpCmdLine = lpszCommandLine;
299 __mingw_winmain_nShowCmd = StartupInfo.dwFlags & STARTF_USESHOWWINDOW ?
300 StartupInfo.wShowWindow : SW_SHOWDEFAULT;
301 }
302 duplicate_ppstrings (argc, &argv);
303 __main ();
304 #ifdef WPRFLAG
305 __winitenv = envp;
306 /* C++ initialization.
307 gcc inserts this call automatically for a function called main, but not for wmain. */
308 mainret = wmain (argc, argv, envp);
309 #else
310 __initenv = envp;
311 mainret = main (argc, argv, envp);
312 #endif
313 if (!managedapp)
314 exit (mainret);
315
316 if (has_cctor == 0)
317 _cexit ();
318 }
319 return mainret;
320 }
321
322 extern int mingw_initltsdrot_force;
323 extern int mingw_initltsdyn_force;
324 extern int mingw_initltssuo_force;
325 extern int mingw_initcharmax;
326
327 static int __cdecl
328 check_managed_app (void)
329 {
330 PIMAGE_DOS_HEADER pDOSHeader;
331 PIMAGE_NT_HEADERS pPEHeader;
332 PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
333 PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
334
335 /* Force to be linked. */
336 mingw_initltsdrot_force=1;
337 mingw_initltsdyn_force=1;
338 mingw_initltssuo_force=1;
339 mingw_initcharmax=1;
340
341 pDOSHeader = (PIMAGE_DOS_HEADER) &__ImageBase;
342 if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
343 return 0;
344
345 pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader + pDOSHeader->e_lfanew);
346 if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
347 return 0;
348
349 pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32) &pPEHeader->OptionalHeader;
350 switch (pNTHeader32->Magic)
351 {
352 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
353 if (pNTHeader32->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
354 return 0;
355 return !! pNTHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
356 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
357 pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
358 if (pNTHeader64->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
359 return 0;
360 return !! pNTHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
361 }
362 return 0;
363 }
364
365 #ifdef WPRFLAG
366 static size_t wbytelen(const wchar_t *p)
367 {
368 size_t ret = 1;
369 while (*p!=0) {
370 ret++,++p;
371 }
372 return ret*2;
373 }
374 static void duplicate_ppstrings (int ac, wchar_t ***av)
375 {
376 wchar_t **avl;
377 int i;
378 wchar_t **n = (wchar_t **) malloc (sizeof (wchar_t *) * (ac + 1));
379
380 avl=*av;
381 for (i=0; i < ac; i++)
382 {
383 size_t l = wbytelen (avl[i]);
384 n[i] = (wchar_t *) malloc (l);
385 memcpy (n[i], avl[i], l);
386 }
387 n[i] = NULL;
388 *av = n;
389 }
390 #else
391 static void duplicate_ppstrings (int ac, char ***av)
392 {
393 char **avl;
394 int i;
395 char **n = (char **) malloc (sizeof (char *) * (ac + 1));
396
397 avl=*av;
398 for (i=0; i < ac; i++)
399 {
400 size_t l = strlen (avl[i]) + 1;
401 n[i] = (char *) malloc (l);
402 memcpy (n[i], avl[i], l);
403 }
404 n[i] = NULL;
405 *av = n;
406 }
407 #endif
408
409 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
410 #define __UNUSED_PARAM_1(x) x
411 #else
412 #define __UNUSED_PARAM_1 __UNUSED_PARAM
413 #endif
414 static void __cdecl
415 __mingw_invalidParameterHandler (const wchar_t * __UNUSED_PARAM_1(expression),
416 const wchar_t * __UNUSED_PARAM_1(function),
417 const wchar_t * __UNUSED_PARAM_1(file),
418 unsigned int __UNUSED_PARAM_1(line),
419 uintptr_t __UNUSED_PARAM(pReserved))
420 {
421 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
422 wprintf(L"Invalid parameter detected in function %s. File: %s Line: %u\n", function, file, line);
423 wprintf(L"Expression: %s\n", expression);
424 #endif
425 }
426
427 HANDLE __mingw_get_msvcrt_handle(void);
428
429 static void __cdecl
430 __mingw_prepare_except_for_msvcr80_and_higher (void)
431 {
432 _invalid_parameter_handler (*fIPH)(_invalid_parameter_handler) = NULL;
433
434 fIPH = (void*)GetProcAddress (__mingw_get_msvcrt_handle(), "_set_invalid_parameter_handler");
435 if (fIPH)
436 (*fIPH)(__mingw_invalidParameterHandler);
437 }