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