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