OSDN Git Service

Make floating point environment more robust.
[mingw/mingw-org-wsl.git] / mingwrt / crt1.c
1 /*
2  * crt1.c
3  *
4  * Source code for the startup procedures used by all programs.  This
5  * code is compiled to crt1.o, which is located in the library path.
6  *
7  * $Id$
8  *
9  * Written by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
10  * Copyright (C) 1997, 1999, 2002-2007, 2009, 2010, 2014, 2016,
11  *   2017, MinGW.org Project.
12  *
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice, this permission notice, and the following
22  * disclaimer shall be included in all copies or substantial portions of
23  * the Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *
33  */
34 #define __IN_MINGW_RUNTIME
35 /* Hide the declaration of _fmode(), with its dllimport attribute in
36  * <stdlib.h>, to avoid problems with older GCC.
37  */
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <io.h>
41 #include <process.h>
42 #include <fenv.h>
43
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #include <signal.h>
47
48 #include "cpu_features.h"
49
50 extern void __main ();
51 extern void _pei386_runtime_relocator (void);
52
53 /* Main program entry point, and argument initialization hook.
54  */
55 extern int main (int, char **, char **);
56 extern void _setargv (void);
57
58 int    _argc = 0;
59 char **_argv = NULL;
60
61 /* NOTE: Thanks to Pedro A. Aranda Gutiirrez <paag@tid.es> for pointing
62  * this out: the GetMainArgs() function, (provided by CRTDLL.DDL, as an
63  * argument initialization hook), takes a fourth argument (an int), which
64  * controls the globbing of the command line; if it is non-zero the command
65  * line will be globbed (e.g. *.* will be expanded to a list, separated by
66  * spaces, of all files in the startup directory).
67  *
68  * We determine how globbing should be performed, by inspection of the two
69  * least significant bits of the global int variable _CRT_glob, (defined in
70  * the mingw32 library, with a default value of 2).  If this pair of bits
71  * represent a value of 2 or more, the new MinGW globbing algorithm, (as
72  * implemented by function _setargv() in setargv.c), will be applied; for
73  * values of one or zero, _setargv() will delegate the globbing function to
74  * the _mingw32_init_mainargs() callback function implemented below, and so
75  * invoking the Microsoft GetMainArgs() algorithm, with its fourth argument
76  * set to one or zero, to match the least significant bit of _CRT_glob.
77  *
78  * The mingw32 library default value of 2 for _CRT_glob enables command line
79  * globbing using the MinGW algorithm.  If you prefer to adopt the Microsoft
80  * algorithm, you should define _CRT_glob as a global variable, by including
81  * a line in one of your own source code files, like this:
82  *
83  *    int _CRT_glob = 1;
84  *
85  * Alternatively, if you prefer to disable globbing, and do all command line
86  * processing yourself, (and so evade possible bogons in the Microsoft or in
87  * the MinGW globbing code), include a similar line in one of your own source
88  * code files, defining _CRT_glob with a value of zero, like this:
89  *
90  *    int _CRT_glob = 0;
91  */
92 extern int _CRT_glob;
93
94 #ifdef __MSVCRT__
95 /* In MSVCRT.DLL, Microsoft's initialization hook is called __getmainargs(),
96  * and it expects a further structure argument, (which we don't use, but pass
97  * it as a dummy, with a declared size of zero in its first and only field).
98  */
99 typedef struct { int newmode; } _startupinfo;
100 extern void __getmainargs( int *, char ***, char ***, int, _startupinfo * );
101
102 #else
103 /* In CRTDLL.DLL, the initialization hook is called __GetMainArgs().
104  */
105 extern void __GetMainArgs( int *, char ***, char ***, int );
106 #endif
107
108 void _mingw32_init_mainargs()
109 { /* This is the old start-up mechanism, in which we use a start-up
110    * hook provided by Microsoft's runtime library to initialize the
111    * argument and environment vectors.
112    *
113    * Note that the preferred method for accessing the environment
114    * vector is via a direct pointer retrieved from the runtime DLL,
115    * using a system call declared in stdlib.h; thus, we don't need
116    * to preserve the pointer returned by the start-up hook, so we
117    * may simply capture it locally, and subsequently discard it.
118    */
119   char **dummy_envp;
120
121 # define _CRT_GLOB_OPT  _CRT_glob & __CRT_GLOB_USE_MSVCRT__
122 # ifdef __MSVCRT__
123   /* The MSVCRT.DLL start-up hook requires this invocation
124    * protocol...
125    */
126   _startupinfo start_info = { 0 };
127   __getmainargs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT, &start_info );
128
129 # else
130   /* ...while a somewhat simpler protocol is applicable, in
131    * the case of the CRTDLL.DLL version.
132    */
133   __GetMainArgs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT );
134 # endif
135 }
136
137 /* TLS initialization hook.
138  */
139 extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
140
141 /* Must have the correct app type for MSVCRT.
142  */
143 #ifdef __MSVCRT__
144 # define __UNKNOWN_APP    0
145 # define __CONSOLE_APP    1
146 # define __GUI_APP        2
147
148 __MINGW_IMPORT void __set_app_type(int);
149
150 #endif /* __MSVCRT__ */
151
152 /* Global _fmode for this .exe, (not the one in msvcrt.dll).
153  *
154  * The default is set in txtmode.o in libmingw32.a
155  * Override the dllimport'd declarations in stdlib.h
156  */
157 #undef _fmode
158 extern int _fmode;
159 #ifdef __MSVCRT__
160 extern int* __p__fmode(void); /* To access the dll _fmode */
161 #endif
162
163 /* Setup the default file handles to have the _CRT_fmode mode,
164  * as well as any new files created by the user.
165  */
166 extern int _CRT_fmode;
167
168 static void
169 _mingw32_init_fmode (void)
170 { /* Don't set the std file mode if the user hasn't set any
171    * value for it.
172    */
173   if (_CRT_fmode)
174   {
175     _fmode = _CRT_fmode;
176
177     /* This overrides the default file mode settings for stdin,
178      * stdout and stderr. At first I thought you would have to
179      * test with isatty, but it seems that the DOS console at
180      * least is smart enough to handle _O_BINARY stdout and
181      * still display correctly.
182      */
183     if (stdin) _setmode (_fileno (stdin), _CRT_fmode);
184     if (stdout) _setmode (_fileno (stdout), _CRT_fmode);
185     if (stderr) _setmode (_fileno (stderr), _CRT_fmode);
186   }
187
188   /* Now sync the dll _fmode to the one for this .exe.
189    */
190 # ifdef __MSVCRT__
191   *__p__fmode() = _fmode;
192 # else
193   *_imp___fmode_dll = _fmode;
194 # endif
195 }
196
197 /* This function will be called when a trap occurs.  Thanks to
198  * Jacob Navia for this contribution.
199  */
200 static CALLBACK long
201 _gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
202 {
203   void (*old_handler) (int);
204   long action = EXCEPTION_CONTINUE_SEARCH;
205   int reset_fpu = 0;
206
207   switch (exception_data->ExceptionRecord->ExceptionCode)
208   {
209     case EXCEPTION_ACCESS_VIOLATION:
210       /* Test if the user has set SIGSEGV
211        */
212       old_handler = signal (SIGSEGV, SIG_DFL);
213       if (old_handler == SIG_IGN)
214       { /* This is undefined if the signal was raised by
215          * anything other than raise()
216          */
217         signal (SIGSEGV, SIG_IGN);
218         action = EXCEPTION_CONTINUE_EXECUTION;
219       }
220       else if (old_handler != SIG_DFL)
221       { /* This means 'old_handler' is a user defined
222          * function.  Call it
223          */
224         (*old_handler) (SIGSEGV);
225         action = EXCEPTION_CONTINUE_EXECUTION;
226       }
227       break;
228
229     case EXCEPTION_ILLEGAL_INSTRUCTION:
230     case EXCEPTION_PRIV_INSTRUCTION:
231       /* Test if the user has set SIGILL
232        */
233       old_handler = signal (SIGILL, SIG_DFL);
234       if (old_handler == SIG_IGN)
235       { /* This is undefined if the signal was raised by
236          * anything other than raise()
237          */
238         signal (SIGILL, SIG_IGN);
239         action = EXCEPTION_CONTINUE_EXECUTION;
240       }
241       else if (old_handler != SIG_DFL)
242       { /* This means 'old_handler' is a user defined
243          * function.  Call it
244          */
245         (*old_handler) (SIGILL);
246         action = EXCEPTION_CONTINUE_EXECUTION;
247       }
248       break;
249
250     case EXCEPTION_FLT_INVALID_OPERATION:
251     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
252     case EXCEPTION_FLT_DENORMAL_OPERAND:
253     case EXCEPTION_FLT_OVERFLOW:
254     case EXCEPTION_FLT_UNDERFLOW:
255     case EXCEPTION_FLT_INEXACT_RESULT:
256       reset_fpu = 1;
257       /* fall through. */
258
259     case EXCEPTION_INT_DIVIDE_BY_ZERO:
260       /* Test if the user has set SIGFPE
261        */
262       old_handler = signal (SIGFPE, SIG_DFL);
263       if (old_handler == SIG_IGN)
264       {
265         signal (SIGFPE, SIG_IGN);
266         if (reset_fpu)
267           fesetenv (FE_DFL_ENV);
268         action = EXCEPTION_CONTINUE_EXECUTION;
269       }
270       else if (old_handler != SIG_DFL)
271       { /* This means 'old_handler' is a user defined
272          * function.  Call it
273          */
274         (*old_handler) (SIGFPE);
275         action = EXCEPTION_CONTINUE_EXECUTION;
276       }
277   }
278   return action;
279 }
280
281 /* During application start-up, we establish the default configuration
282  * for the FPU.  MSVCRT.DLL provides the _fpreset() function to perform
283  * the appropriate initialization, but it sets the default operation to
284  * be in IEEE-754 8-byte mode, whereas we prefer IEEE-754 10-byte mode,
285  * to better support GCC's 10-byte long doubles; nevertheless, we offer
286  * the option, via the _CRT_fenv global variable, to establish either
287  * one of these modes as initial default, it should be set to either
288  * FE_PD64_ENV, (defined in <fenv.h>, reflecting the 64-bit precision
289  * of the 10-byte mode, and established as default for _CRT_fenv within
290  * the runtime library), or overridden by a setting of FE_PD53_ENV, in
291  * user code, like this:
292  *
293  *   #include <fenv.h>
294  *   const fenv_t *_CRT_fenv = FE_PD53_ENV;
295  *
296  * (or by linking with CRT_fp8.o), to select the 53-bit precision of
297  * the 8-byte mode.
298  *
299  * Whichever of these assignments, i.e. FE_PD64_ENV or FE_PD53_ENV, is
300  * in effect when the following __mingw_CRTStartup() function is invoked,
301  * will cause FE_DFL_ENV to be mapped to one or other of the predefined
302  * environments, FE_PC64_ENV or FE_PC53_ENV, respectively.
303  */
304 extern const fenv_t *_CRT_fenv;
305
306 /* The function mainCRTStartup(), (defined below), is the entry point
307  * for all console programs, it is, primarily, a wrapper around the
308  * following __mingw_CRTStartup() helper function.
309  */
310 static __MINGW_ATTRIB_NORETURN  void __mingw_CRTStartup (void)
311 {
312   int nRet;
313
314   /* Initialize TLS callback.
315    */
316   if (__dyn_tls_init_callback != NULL)
317     __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
318
319   /* Set up the top-level exception handler so that signal handling
320    * works as expected. The mapping between ANSI/POSIX signals and
321    * Win32 SE is not 1-to-1, so caveat emptor.
322    *
323    */
324   SetUnhandledExceptionFilter (_gnu_exception_handler);
325
326   /* Initialize the floating point unit.
327    */
328   __cpu_features_init ();       /* Do we have SSE, etc. */
329   fesetenv (_CRT_fenv);         /* Supplied by the runtime library. */
330
331   /* Set up __argc, __argv and _environ.
332    */
333   _setargv ();
334
335   /* Set the default file mode.  If _CRT_fmode is set, also set mode
336    * for stdin, stdout and stderr, as well.  NOTE: DLLs don't do this
337    * because that would be rude!
338    */
339   _mingw32_init_fmode ();
340
341   /* Adust references to dllimported data that have non-zero offsets.
342    */
343   _pei386_runtime_relocator ();
344
345   /* Align the stack to 16 bytes for the sake of SSE ops in main
346    * or in functions inlined into main.
347    */
348   asm  __volatile__  ("andl $-16, %%esp" : : : "%esp");
349
350   /* From libgcc.a, __main() calls global class constructors via
351    * __do_global_ctors(); this in turn registers __do_global_dtors()
352    * as the first entry of the application's atexit() table.  We do
353    * this explicitly at application startup rather than rely on GCC
354    * to generate the call in main()'s prologue, since main() may be
355    * imported from a DLL which has its own __do_global_ctors()
356    */
357   __main ();
358
359   /* Call the main() function. If the user does not supply one
360    * the one in the 'libmingw32.a' library will be linked in, and
361    * that one calls WinMain().  See main.c in the 'lib' directory
362    * for more details.
363    */
364   nRet = main (_argc, _argv, environ);
365
366   /* Perform exit processing for the C library. This means flushing
367    * output and calling atexit() registered functions.
368    */
369   _cexit ();
370
371   ExitProcess (nRet);
372 }
373
374 /* The function mainCRTStartup() is the entry point for all console
375  * programs.
376  */
377 void
378 mainCRTStartup (void)
379 {
380 #ifdef __MSVCRT__
381   __set_app_type (__CONSOLE_APP);
382 #endif
383   __mingw_CRTStartup ();
384 }
385
386 /* For now the GUI startup function is the same as the console one.
387  * This simply gets rid of the annoying warning about not being able
388  * to find WinMainCRTStartup when linking GUI applications.
389  */
390 void
391 WinMainCRTStartup (void)
392 {
393 #ifdef __MSVCRT__
394   __set_app_type (__GUI_APP);
395 #endif
396   __mingw_CRTStartup ();
397 }
398
399 /* We force use of library version of atexit(), which is only
400  * visible in import lib as _imp__atexit
401  */
402 extern int (*_imp__atexit)(void (*)(void));
403 int atexit (void (* pfn )(void)){ return (*_imp__atexit)(pfn); }
404
405 /* Likewise for non-ANSI _onexit()
406  */
407 extern _onexit_t (*_imp___onexit)(_onexit_t);
408 _onexit_t _onexit (_onexit_t pfn){ return (*_imp___onexit)(pfn); }
409
410 /* $RCSfile$: end of file */