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