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