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