[SDK][CRT] Fix _ismbblead undefined error on MSVC
[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 #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 }