xref: /reactos/sdk/lib/crt/startup/crtexe.c (revision 845faec4)
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 #ifndef __clang__ /* FIXME: CORE-14042 */
132   if (__globallocalestatus == -1)
133     {
134     }
135 #endif
136   return 0;
137 }
138 
139 static void __cdecl
140 pre_cpp_init (void)
141 {
142   startinfo.newmode = _newmode;
143 
144 #ifdef WPRFLAG
145   argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
146 #else
147   argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
148 #endif
149 }
150 
151 static int __cdecl __tmainCRTStartup (void);
152 
153 int __cdecl WinMainCRTStartup (void);
154 
155 int __cdecl WinMainCRTStartup (void)
156 {
157   int ret = 255;
158 #ifdef __SEH__
159   asm ("\t.l_startw:\n"
160     "\t.seh_handler __C_specific_handler, @except\n"
161     "\t.seh_handlerdata\n"
162     "\t.long 1\n"
163     "\t.rva .l_startw, .l_endw, _gnu_exception_handler ,.l_endw\n"
164     "\t.text"
165     );
166 #endif
167   mingw_app_type = 1;
168   __security_init_cookie ();
169   ret = __tmainCRTStartup ();
170 #ifdef __SEH__
171   asm ("\tnop\n"
172     "\t.l_endw: nop\n");
173 #endif
174   return ret;
175 }
176 
177 int __cdecl mainCRTStartup (void);
178 
179 #ifdef _WIN64
180 int __mingw_init_ehandler (void);
181 #endif
182 
183 int __cdecl mainCRTStartup (void)
184 {
185   int ret = 255;
186 #ifdef __SEH__
187   asm ("\t.l_start:\n"
188     "\t.seh_handler __C_specific_handler, @except\n"
189     "\t.seh_handlerdata\n"
190     "\t.long 1\n"
191     "\t.rva .l_start, .l_end, _gnu_exception_handler ,.l_end\n"
192     "\t.text"
193     );
194 #endif
195   mingw_app_type = 0;
196   __security_init_cookie ();
197   ret = __tmainCRTStartup ();
198 #ifdef __SEH__
199   asm ("\tnop\n"
200     "\t.l_end: nop\n");
201 #endif
202   return ret;
203 }
204 
205 static
206 __declspec(noinline)
207 int __cdecl
208 __tmainCRTStartup (void)
209 {
210   _TCHAR *lpszCommandLine = NULL;
211   STARTUPINFO StartupInfo;
212   WINBOOL inDoubleQuote = FALSE;
213   memset (&StartupInfo, 0, sizeof (STARTUPINFO));
214 
215 #ifndef _WIN64
216   /* We need to make sure that this function is build with frame-pointer
217      and that we align the stack to 16 bytes for the sake of SSE ops in main
218      or in functions inlined into main.  */
219   lpszCommandLine = (_TCHAR *) alloca (32);
220   memset (lpszCommandLine, 0xcc, 32);
221 #ifdef __GNUC__
222   asm  __volatile__  ("andl $-16, %%esp" : : : "%esp");
223 #endif
224 #endif
225 
226   if (mingw_app_type)
227     GetStartupInfo (&StartupInfo);
228   {
229     void *lock_free = NULL;
230     void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
231     int nested = FALSE;
232     while((lock_free = InterlockedCompareExchangePointer ((volatile PVOID *) &__native_startup_lock,
233 							  fiberid, 0)) != 0)
234       {
235 	if (lock_free == fiberid)
236 	  {
237 	    nested = TRUE;
238 	    break;
239 	  }
240 	Sleep(1000);
241       }
242     if (__native_startup_state == __initializing)
243       {
244 	_amsg_exit (31);
245       }
246     else if (__native_startup_state == __uninitialized)
247       {
248 	__native_startup_state = __initializing;
249 	_initterm ((_PVFV *)(void *)__xi_a, (_PVFV *)(void *) __xi_z);
250       }
251     else
252       has_cctor = 1;
253 
254     if (__native_startup_state == __initializing)
255       {
256 	_initterm (__xc_a, __xc_z);
257 	__native_startup_state = __initialized;
258       }
259     _ASSERTE(__native_startup_state == __initialized);
260     if (! nested)
261       (VOID)InterlockedExchangePointer ((volatile PVOID *) &__native_startup_lock, 0);
262 
263     if (__dyn_tls_init_callback != NULL)
264       __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
265 
266     _pei386_runtime_relocator ();
267     __mingw_oldexcpt_handler = SetUnhandledExceptionFilter (_gnu_exception_handler);
268 #ifdef _WIN64
269     __mingw_init_ehandler ();
270 #endif
271     __mingw_prepare_except_for_msvcr80_and_higher ();
272 
273     _fpreset ();
274 
275     if (mingw_app_type)
276       {
277 #ifdef WPRFLAG
278 	lpszCommandLine = (_TCHAR *) _wcmdln;
279 #else
280 	lpszCommandLine = (char *) _acmdln;
281 #endif
282 	while (*lpszCommandLine > SPACECHAR || (*lpszCommandLine && inDoubleQuote))
283 	  {
284 	    if (*lpszCommandLine == DQUOTECHAR)
285 	      inDoubleQuote = !inDoubleQuote;
286 #ifdef _MBCS
287 	    if (_ismbblead (*lpszCommandLine))
288 	      {
289 		if (lpszCommandLine) /* FIXME: Why this check? Should I check for *lpszCommandLine != 0 too? */
290 		  lpszCommandLine++;
291 	      }
292 #endif
293 	    ++lpszCommandLine;
294 	  }
295 	while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
296 	  lpszCommandLine++;
297 
298 	__mingw_winmain_hInstance = (HINSTANCE) &__ImageBase;
299 	__mingw_winmain_lpCmdLine = lpszCommandLine;
300 	__mingw_winmain_nShowCmd = StartupInfo.dwFlags & STARTF_USESHOWWINDOW ?
301 				    StartupInfo.wShowWindow : SW_SHOWDEFAULT;
302       }
303     duplicate_ppstrings (argc, &argv);
304     __main ();
305 #ifdef WPRFLAG
306     __winitenv = envp;
307     /* C++ initialization.
308        gcc inserts this call automatically for a function called main, but not for wmain.  */
309     mainret = wmain (argc, argv, envp);
310 #else
311     __initenv = envp;
312     mainret = main (argc, argv, envp);
313 #endif
314     if (!managedapp)
315       exit (mainret);
316 
317     if (has_cctor == 0)
318       _cexit ();
319   }
320   return mainret;
321 }
322 
323 extern int mingw_initltsdrot_force;
324 extern int mingw_initltsdyn_force;
325 extern int mingw_initltssuo_force;
326 extern int mingw_initcharmax;
327 
328 static int __cdecl
329 check_managed_app (void)
330 {
331   PIMAGE_DOS_HEADER pDOSHeader;
332   PIMAGE_NT_HEADERS pPEHeader;
333   PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
334   PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
335 
336   /* Force to be linked.  */
337   mingw_initltsdrot_force=1;
338   mingw_initltsdyn_force=1;
339   mingw_initltssuo_force=1;
340   mingw_initcharmax=1;
341 
342   pDOSHeader = (PIMAGE_DOS_HEADER) &__ImageBase;
343   if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
344     return 0;
345 
346   pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader + pDOSHeader->e_lfanew);
347   if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
348     return 0;
349 
350   pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32) &pPEHeader->OptionalHeader;
351   switch (pNTHeader32->Magic)
352     {
353     case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
354       if (pNTHeader32->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
355 	return 0;
356       return !! pNTHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
357     case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
358       pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
359       if (pNTHeader64->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
360 	return 0;
361       return !! pNTHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
362     }
363   return 0;
364 }
365 
366 #ifdef WPRFLAG
367 static size_t wbytelen(const wchar_t *p)
368 {
369 	size_t ret = 1;
370 	while (*p!=0) {
371 		ret++,++p;
372 	}
373 	return ret*2;
374 }
375 static void duplicate_ppstrings (int ac, wchar_t ***av)
376 {
377 	wchar_t **avl;
378 	int i;
379 	wchar_t **n = (wchar_t **) malloc (sizeof (wchar_t *) * (ac + 1));
380 
381 	avl=*av;
382 	for (i=0; i < ac; i++)
383 	  {
384 		size_t l = wbytelen (avl[i]);
385 		n[i] = (wchar_t *) malloc (l);
386 		memcpy (n[i], avl[i], l);
387 	  }
388 	n[i] = NULL;
389 	*av = n;
390 }
391 #else
392 static void duplicate_ppstrings (int ac, char ***av)
393 {
394 	char **avl;
395 	int i;
396 	char **n = (char **) malloc (sizeof (char *) * (ac + 1));
397 
398 	avl=*av;
399 	for (i=0; i < ac; i++)
400 	  {
401 		size_t l = strlen (avl[i]) + 1;
402 		n[i] = (char *) malloc (l);
403 		memcpy (n[i], avl[i], l);
404 	  }
405 	n[i] = NULL;
406 	*av = n;
407 }
408 #endif
409 
410 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
411 #define __UNUSED_PARAM_1(x) x
412 #else
413 #define __UNUSED_PARAM_1	__UNUSED_PARAM
414 #endif
415 static void __cdecl
416 __mingw_invalidParameterHandler (const wchar_t * __UNUSED_PARAM_1(expression),
417 				 const wchar_t * __UNUSED_PARAM_1(function),
418 				 const wchar_t * __UNUSED_PARAM_1(file),
419 				 unsigned int    __UNUSED_PARAM_1(line),
420 				 uintptr_t __UNUSED_PARAM(pReserved))
421 {
422 #ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
423   wprintf(L"Invalid parameter detected in function %s. File: %s Line: %u\n", function, file, line);
424   wprintf(L"Expression: %s\n", expression);
425 #endif
426 }
427 
428 HANDLE __mingw_get_msvcrt_handle(void);
429 
430 static void __cdecl
431 __mingw_prepare_except_for_msvcr80_and_higher (void)
432 {
433   _invalid_parameter_handler (*fIPH)(_invalid_parameter_handler) = NULL;
434 
435   fIPH = (void*)GetProcAddress (__mingw_get_msvcrt_handle(), "_set_invalid_parameter_handler");
436   if (fIPH)
437     (*fIPH)(__mingw_invalidParameterHandler);
438 }
439