1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7#include <internal.h>
8#include <excpt.h>
9#include <process.h>
10#include <signal.h>
11#include <math.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <tchar.h>
15#include <sect_attribs.h>
16#include <locale.h>
17#include <float.h>
18#include <corecrt_startup.h>
19
20#if defined(__SEH__) && (!defined(__clang__) || __clang_major__ >= 7)
21#define SEH_INLINE_ASM
22#ifdef __arm__
23#define ASM_SEH_EXCEPT "%%except"
24#else
25#define ASM_SEH_EXCEPT "@except"
26#endif
27#ifdef __arm64ec__
28#define ASM_SEH_PREFIX "\"#"
29#define ASM_SEH_SUFFIX "\""
30#else
31#define ASM_SEH_PREFIX ""
32#define ASM_SEH_SUFFIX ""
33#endif
34#endif
35
36extern IMAGE_DOS_HEADER __ImageBase;
37
38int *__cdecl __p__commode(void);
39
40#undef _fmode
41extern int _fmode;
42#undef _commode
43extern int _commode;
44extern int _dowildcard;
45extern int __globallocalestatus;
46
47static int __cdecl check_managed_app (void);
48
49extern _PIFV __xi_a[];
50extern _PIFV __xi_z[];
51extern _PVFV __xc_a[];
52extern _PVFV __xc_z[];
53
54
55/* TLS initialization hook. */
56extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
57
58extern int __mingw_app_type;
59
60static int argc;
61extern void __main(void);
62static _TCHAR **argv;
63static _TCHAR **envp;
64
65static int managedapp;
66static int has_cctor = 0;
67
68extern void _pei386_runtime_relocator (void);
69EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler (struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
70#if defined(__x86_64__) && !defined(SEH_INLINE_ASM)
71int __mingw_init_ehandler (void);
72#endif
73static int duplicate_ppstrings (int ac, _TCHAR ***av);
74
75extern int _MINGW_INSTALL_DEBUG_MATHERR;
76
77#ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
78#define __UNUSED_PARAM_1(x) x
79#else
80#define __UNUSED_PARAM_1 __UNUSED_PARAM
81#endif
82static void
83__mingw_invalidParameterHandler (const wchar_t * __UNUSED_PARAM_1(expression),
84 const wchar_t * __UNUSED_PARAM_1(function),
85 const wchar_t * __UNUSED_PARAM_1(file),
86 unsigned int __UNUSED_PARAM_1(line),
87 uintptr_t __UNUSED_PARAM(pReserved))
88{
89#ifdef __MINGW_SHOW_INVALID_PARAMETER_EXCEPTION
90 wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
91 wprintf(L"Expression: %s\n", expression);
92#endif
93}
94
95#define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C' | (1U << 29))
96
97#if defined(__i386__) || defined(_X86_)
98/* We need to make sure that we align the stack to 16 bytes for the sake of SSE */
99__attribute__((force_align_arg_pointer))
100#endif
101static LONG WINAPI
102cpp_unhandled_exception_filter (EXCEPTION_POINTERS *exception_data)
103{
104 /* C++ gcc SEH exception is thrown by the libgcc __cxa_throw() function
105 * (which calls _Unwind_RaiseException()) or _Unwind_ForcedUnwind() function
106 * as a normal continuable SEH exception with the STATUS_GCC_THROW (0x20474343)
107 * or STATUS_GCC_FORCED (0x22474343) exception code via the WinAPI RaiseException()
108 * call. Both _Unwind_RaiseException() and _Unwind_ForcedUnwind() are expected
109 * to return back to the caller (for example __cxa_throw()) if the exception
110 * was not handled. So if the gcc SEH exception reaches the application
111 * top-level exception handler then handler needs to return execution back to
112 * the place which called the RaiseException(). This is done by returning the
113 * EXCEPTION_CONTINUE_EXECUTION value from the handler itself.
114 * This is needed for proper propagation of unhandled C++ gcc exceptions
115 * into the std::terminate() call or into the application handler
116 * registered by the std::set_terminate() call.
117 */
118 if ((exception_data->ExceptionRecord->ExceptionCode & 0x20ffffff) == GCC_MAGIC &&
119 !(exception_data->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE))
120 return EXCEPTION_CONTINUE_EXECUTION;
121
122 return EXCEPTION_CONTINUE_SEARCH;
123}
124
125static void
126safe_flush (void)
127{
128 fflush (NULL);
129}
130
131static int __tmainCRTStartup (void);
132
133int WinMainCRTStartup (void);
134__attribute__((used)) /* required due to GNU LD bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30300 */
135int WinMainCRTStartup (void)
136{
137 __mingw_app_type = 1;
138 return __tmainCRTStartup ();
139}
140
141int mainCRTStartup (void);
142__attribute__((used)) /* required due to GNU LD bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30300 */
143int mainCRTStartup (void)
144{
145 __mingw_app_type = 0;
146 return __tmainCRTStartup ();
147}
148
149static
150#if defined(__i386__) || defined(_X86_)
151/* We need to make sure that we align the stack to 16 bytes for the sake of SSE
152 opts in main or in functions called from main. */
153__attribute__((force_align_arg_pointer))
154#endif
155__declspec(noinline) int
156__tmainCRTStartup (void)
157{
158 /* Registration of SEH error handler __mingw_SEH_error_handler used for
159 * delivering SEH exceptions to registered CRT signal handlers. */
160#if defined(__i386__)
161 EXCEPTION_REGISTRATION_RECORD exception_record = {
162 .Next = (EXCEPTION_REGISTRATION_RECORD *)__readfsdword (0),
163 .Handler = (PEXCEPTION_ROUTINE)(INT_PTR)__mingw_SEH_error_handler,
164 };
165 __writefsdword (0, (DWORD)&exception_record); /* dynamically register SEH error handler, it is active until manually unregistered */
166#elif defined(SEH_INLINE_ASM)
167 asm volatile (".seh_handler " ASM_SEH_PREFIX "%c0" ASM_SEH_SUFFIX ", " ASM_SEH_EXCEPT :: "i" (__mingw_SEH_error_handler)); /* statically register SEH error handler, it is active only in the current function */
168#elif defined(__x86_64__)
169 __mingw_init_ehandler (); /* dynamically register SEH error handler for all functions, it is active until program terminates */
170#else
171#error unsupported platform
172#endif
173
174 void *lock_free = NULL;
175 void *fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase;
176 BOOL nested = FALSE;
177 _startupinfo startinfo;
178 int ret = 0;
179 while((lock_free = InterlockedCompareExchangePointer (&__native_startup_lock,
180 fiberid, NULL)) != 0)
181 {
182 if (lock_free == fiberid)
183 {
184 nested = TRUE;
185 break;
186 }
187 Sleep(1000);
188 }
189 if (__native_startup_state == __initializing)
190 {
191 _amsg_exit (31);
192 }
193 else if (__native_startup_state == __uninitialized)
194 {
195 __native_startup_state = __initializing;
196
197 /* Before the UCRT stderr could be opened in full buffering
198 * mode, for example when output goes to a pipe.
199 *
200 * The C standard disallows full buffering on stderr. Note
201 * that line buffering is the same as full buffering in the
202 * Windows CRT, so we have to disable buffering altogether.
203 */
204 setvbuf (stderr, NULL, _IONBF, 0);
205
206 /* The C RunTime library flushes stdio streams in response to
207 * DLL_PROCESS_DETACH. This is not entirely safe; other DLLs
208 * may cause instant termination during process shutdown.
209 * Here we add an exit handler to flush streams safely.
210 */
211 if (atexit (safe_flush) != 0)
212 abort ();
213
214 _pei386_runtime_relocator ();
215 _set_invalid_parameter_handler (__mingw_invalidParameterHandler);
216 _fpreset ();
217
218 managedapp = check_managed_app ();
219 if (__mingw_app_type)
220 __set_app_type (_GUI_APP);
221 else
222 __set_app_type (_CONSOLE_APP);
223
224 *__p__fmode () = _fmode;
225 *__p__commode () = _commode;
226
227#ifdef _UNICODE
228 ret = _wsetargv ();
229#else
230 ret = _setargv ();
231#endif
232 if (ret < 0)
233 _amsg_exit (8); /* _RT_SPACEARG */
234
235 if (_MINGW_INSTALL_DEBUG_MATHERR == 1)
236 __setusermatherr (_matherr);
237
238 if (__globallocalestatus == -1)
239 _configthreadlocale (-1);
240
241 if (_initterm_e (__xi_a, __xi_z) != 0)
242 _amsg_exit (10); /* _RT_ABORT */
243
244 startinfo.newmode = _newmode;
245#ifdef _UNICODE
246 ret = __wgetmainargs (&argc, &argv, &envp, _dowildcard, &startinfo);
247#else
248 ret = __getmainargs (&argc, &argv, &envp, _dowildcard, &startinfo);
249#endif
250 if (ret < 0)
251 _amsg_exit (8); /* _RT_SPACEARG */
252
253 ret = duplicate_ppstrings (argc, &argv);
254 if (ret != 0)
255 _amsg_exit (8); /* _RT_SPACEARG */
256
257 SetUnhandledExceptionFilter (cpp_unhandled_exception_filter);
258 _initterm (__xc_a, __xc_z);
259 __main (); /* C++ initialization. */
260
261 __native_startup_state = __initialized;
262 }
263 else
264 has_cctor = 1;
265 if (! nested)
266 (VOID)InterlockedExchangePointer (&__native_startup_lock, NULL);
267
268 if (__dyn_tls_init_callback != NULL)
269 __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
270
271#ifdef _UNICODE
272 __winitenv = envp;
273#else
274 __initenv = envp;
275#endif
276 ret = _tmain (argc, argv, envp);
277 if (!managedapp)
278 exit (ret);
279
280 if (has_cctor == 0)
281 _cexit ();
282
283#if defined(__i386__)
284 __writefsdword (0, (DWORD)exception_record.Next); /* dynamically unregister SEH error handler */
285#endif
286 return ret;
287}
288
289extern int __mingw_initltsdrot_force;
290extern int __mingw_initltsdyn_force;
291extern int __mingw_initltssuo_force;
292
293static int __cdecl
294check_managed_app (void)
295{
296 PIMAGE_DOS_HEADER pDOSHeader;
297 PIMAGE_NT_HEADERS pPEHeader;
298 PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
299 PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
300
301 /* Force to be linked. */
302 __mingw_initltsdrot_force=1;
303 __mingw_initltsdyn_force=1;
304 __mingw_initltssuo_force=1;
305
306 pDOSHeader = (PIMAGE_DOS_HEADER) &__ImageBase;
307 if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
308 return 0;
309
310 pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader + pDOSHeader->e_lfanew);
311 if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
312 return 0;
313
314 pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32) &pPEHeader->OptionalHeader;
315 switch (pNTHeader32->Magic)
316 {
317 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
318 if (pNTHeader32->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
319 return 0;
320 return !! pNTHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
321 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
322 pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
323 if (pNTHeader64->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
324 return 0;
325 return !! pNTHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
326 }
327 return 0;
328}
329
330static int duplicate_ppstrings (int ac, _TCHAR ***av)
331{
332 _TCHAR **avl;
333 int i;
334 _TCHAR **n = (_TCHAR **) malloc (sizeof (_TCHAR *) * (ac + 1));
335 if (!n) return 1;
336
337 avl=*av;
338 for (i=0; i < ac; i++)
339 {
340 size_t l = sizeof (_TCHAR) * (_tcslen (avl[i]) + 1);
341 n[i] = (_TCHAR *) malloc (l);
342 if (!n[i]) return 1;
343 memcpy (n[i], avl[i], l);
344 }
345 n[i] = NULL;
346 *av = n;
347 return 0;
348}
349
350int __cdecl atexit (_PVFV func)
351{
352 /*
353 * msvcrt def file renames the real atexit() function to _crt_atexit().
354 * UCRT provides atexit() function only under name _crt_atexit().
355 * So redirect call to _crt_atexit() function.
356 */
357 return _crt_atexit(func);
358}
359
360char __mingw_module_is_dll = 0;