OSDN Git Service

c2077024c6dcf598c193ff1d54b7e1a851441c72
[mingw/mingw-org-wsl.git] / mingwrt / crt1.c
1 /*
2  * crt1.c
3  * This file has no copyright assigned and is placed in the Public Domain.
4  * This file is a part of the mingw-runtime package.
5  * No warranty is given; refer to the file DISCLAIMER within the package.
6  *
7  * Source code for the startup proceedures used by all programs. This code
8  * is compiled to make crt1.o, which should be located in the library path.
9  *
10  */
11
12 /* Hide the declaration of _fmode with dllimport attribute in stdlib.h to
13  * avoid problems with older GCC.
14  */
15 #define __IN_MINGW_RUNTIME
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <io.h>
19 #include <process.h>
20 #include <float.h>
21 #define WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #include <signal.h>
24
25 #include "cpu_features.h"
26
27 extern void __main ();
28 extern void _pei386_runtime_relocator (void);
29
30 /* Main program entry point, and argument initialization hook.
31  */
32 extern int main (int, char **, char **);
33 extern void _setargv (void);
34
35 int    _argc = 0;
36 char **_argv = NULL;
37
38 /* NOTE: Thanks to Pedro A. Aranda Gutiirrez <paag@tid.es> for pointing
39  * this out: the GetMainArgs() function, (provided by CRTDLL.DDL, as an
40  * argument initialization hook), takes a fourth argument (an int), which
41  * controls the globbing of the command line; if it is non-zero the command
42  * line will be globbed (e.g. *.* will be expanded to a list, separated by
43  * spaces, of all files in the startup directory).
44  *
45  * We determine how globbing should be performed, by inspection of the two
46  * least significant bits of the global int variable _CRT_glob, (defined in
47  * the mingw32 library, with a default value of 2).  If this pair of bits
48  * represent a value of 2 or more, the new MinGW globbing algorithm, (as
49  * implemented by function _setargv() in setargv.c), will be applied; for
50  * values of one or zero, _setargv() will delegate the globbing function to
51  * the _mingw32_init_mainargs() callback function implemented below, and so
52  * invoking the Microsoft GetMainArgs() algorithm, with its fourth argument
53  * set to one or zero, to match the least significant bit of _CRT_glob.
54  *
55  * The mingw32 library default value of 2 for _CRT_glob enables command line
56  * globbing using the MinGW algorithm.  If you prefer to adopt the Microsoft
57  * algorithm, you should define _CRT_glob as a global variable, by including
58  * a line in one of your own source code files, like this:
59  *
60  *    int _CRT_glob = 1;
61  *
62  * Alternatively, if you prefer to disable globbing, and do all command line
63  * processing yourself, (and so evade possible bogons in the Microsoft or in
64  * the MinGW globbing code), include a similar line in one of your own source
65  * code files, defining _CRT_glob with a value of zero, like this:
66  *
67  *    int _CRT_glob = 0;
68  */
69 extern int _CRT_glob;
70
71 #ifdef __MSVCRT__
72 /* In MSVCRT.DLL, Microsoft's initialization hook is called __getmainargs(),
73  * and it expects a further structure argument, (which we don't use, but pass
74  * it as a dummy, with a declared size of zero in its first and only field).
75  */
76 typedef struct { int newmode; } _startupinfo;
77 extern void __getmainargs( int *, char ***, char ***, int, _startupinfo * );
78
79 #else
80 /* In CRTDLL.DLL, the initialization hook is called __GetMainArgs().
81  */
82 extern void __GetMainArgs( int *, char ***, char ***, int );
83 #endif
84
85 void _mingw32_init_mainargs()
86 {
87   /* This is the old start-up mechanism, in which we use a start-up
88    * hook provided by Microsoft's runtime library to initialize the
89    * argument and environment vectors.
90    *
91    * Note that the preferred method for accessing the environment
92    * vector is via a direct pointer retrieved from the runtime DLL,
93    * using a system call declared in stdlib.h; thus, we don't need
94    * to preserve the pointer returned by the start-up hook, so we
95    * may simply capture it locally, and subsequently discard it.
96    */
97   char **dummy_envp;
98
99 # define _CRT_GLOB_OPT  _CRT_glob & __CRT_GLOB_USE_MSVCRT__
100 # ifdef __MSVCRT__
101     /* The MSVCRT.DLL start-up hook requires this invocation
102      * protocol...
103      */
104     _startupinfo start_info = { 0 };
105     __getmainargs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT, &start_info );
106
107 # else
108     /* ...while a somewhat simpler protocol is applicable, in
109      * the case of the CRTDLL.DLL version.
110      */
111     __GetMainArgs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT );
112 # endif
113 }
114
115 /* TLS initialization hook.
116  */
117 extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
118
119 /* Must have the correct app type for MSVCRT.
120  */
121 #ifdef __MSVCRT__
122 # define __UNKNOWN_APP    0
123 # define __CONSOLE_APP    1
124 # define __GUI_APP        2
125
126 __MINGW_IMPORT void __set_app_type(int);
127
128 #endif /* __MSVCRT__ */
129
130 /* Global _fmode for this .exe, (not the one in msvcrt.dll).
131  *
132  * The default is set in txtmode.o in libmingw32.a
133  * Override the dllimport'd declarations in stdlib.h
134  */
135 #undef _fmode
136 extern int _fmode;
137 #ifdef __MSVCRT__
138 extern int* __p__fmode(void); /* To access the dll _fmode */
139 #endif
140
141 /*
142  * Setup the default file handles to have the _CRT_fmode mode, as well as
143  * any new files created by the user.
144  */
145 extern int _CRT_fmode;
146
147 static void
148 _mingw32_init_fmode (void)
149 {
150   /* Don't set the std file mode if the user hasn't set any value for it.
151    */
152   if (_CRT_fmode)
153   {
154     _fmode = _CRT_fmode;
155
156     /* This overrides the default file mode settings for stdin,
157      * stdout and stderr. At first I thought you would have to
158      * test with isatty, but it seems that the DOS console at
159      * least is smart enough to handle _O_BINARY stdout and
160      * still display correctly.
161      */
162     if (stdin) _setmode (_fileno (stdin), _CRT_fmode);
163     if (stdout) _setmode (_fileno (stdout), _CRT_fmode);
164     if (stderr) _setmode (_fileno (stderr), _CRT_fmode);
165   }
166
167   /* Now sync the dll _fmode to the one for this .exe.
168    */
169 # ifdef __MSVCRT__
170     *__p__fmode() = _fmode;
171 # else
172     *_imp___fmode_dll = _fmode;
173 # endif
174 }
175
176 /* This function will be called when a trap occurs.  Thanks to
177  * Jacob Navia for this contribution.
178  */
179 static CALLBACK long
180 _gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
181 {
182   void (*old_handler) (int);
183   long action = EXCEPTION_CONTINUE_SEARCH;
184   int reset_fpu = 0;
185
186   switch (exception_data->ExceptionRecord->ExceptionCode)
187     {
188     case EXCEPTION_ACCESS_VIOLATION:
189       /* test if the user has set SIGSEGV */
190       old_handler = signal (SIGSEGV, SIG_DFL);
191       if (old_handler == SIG_IGN)
192         {
193           /* this is undefined if the signal was raised by anything other
194              than raise ().  */
195           signal (SIGSEGV, SIG_IGN);
196           action = EXCEPTION_CONTINUE_EXECUTION;
197         }
198       else if (old_handler != SIG_DFL)
199         {
200           /* This means 'old' is a user defined function. Call it */
201           (*old_handler) (SIGSEGV);
202           action = EXCEPTION_CONTINUE_EXECUTION;
203         }
204       break;
205
206     case EXCEPTION_ILLEGAL_INSTRUCTION:
207     case EXCEPTION_PRIV_INSTRUCTION:
208       /* test if the user has set SIGILL */
209       old_handler = signal (SIGILL, SIG_DFL);
210       if (old_handler == SIG_IGN)
211         {
212           /* this is undefined if the signal was raised by anything other
213              than raise ().  */
214           signal (SIGILL, SIG_IGN);
215           action = EXCEPTION_CONTINUE_EXECUTION;
216         }
217       else if (old_handler != SIG_DFL)
218         {
219           /* This means 'old' is a user defined function. Call it */
220           (*old_handler) (SIGILL);
221           action = EXCEPTION_CONTINUE_EXECUTION;
222         }
223       break;
224
225     case EXCEPTION_FLT_INVALID_OPERATION:
226     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
227     case EXCEPTION_FLT_DENORMAL_OPERAND:
228     case EXCEPTION_FLT_OVERFLOW:
229     case EXCEPTION_FLT_UNDERFLOW:
230     case EXCEPTION_FLT_INEXACT_RESULT:
231       reset_fpu = 1;
232       /* fall through. */
233
234     case EXCEPTION_INT_DIVIDE_BY_ZERO:
235       /* test if the user has set SIGFPE */
236       old_handler = signal (SIGFPE, SIG_DFL);
237       if (old_handler == SIG_IGN)
238         {
239           signal (SIGFPE, SIG_IGN);
240           if (reset_fpu)
241             _fpreset ();
242           action = EXCEPTION_CONTINUE_EXECUTION;
243         }
244       else if (old_handler != SIG_DFL)
245         {
246           /* This means 'old' is a user defined function. Call it */
247           (*old_handler) (SIGFPE);
248           action = EXCEPTION_CONTINUE_EXECUTION;
249         }
250       break;
251
252     default:
253       break;
254     }
255   return action;
256 }
257
258 /* The function mainCRTStartup is the entry point for all console programs.
259  */
260 static void  __MINGW_ATTRIB_NORETURN
261 __mingw_CRTStartup (void)
262 {
263   int nRet;
264
265   /* Initialize TLS callback.
266    */
267   if (__dyn_tls_init_callback != NULL)
268     __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
269
270   /* Set up the top-level exception handler so that signal handling
271    * works as expected. The mapping between ANSI/POSIX signals and
272    * Win32 SE is not 1-to-1, so caveat emptor.
273    *
274    */
275   SetUnhandledExceptionFilter (_gnu_exception_handler);
276
277   /* Initialize floating point unit.
278    */
279   __cpu_features_init ();       /* Do we have SSE, etc.*/
280   _fpreset ();                  /* Supplied by the runtime library. */
281
282   /* Set up __argc, __argv and _environ.
283    */
284   _setargv ();
285
286   /* Sets the default file mode.
287    * If _CRT_fmode is set, also set mode for stdin, stdout
288    * and stderr, as well
289    * NOTE: DLLs don't do this because that would be rude!
290    */
291   _mingw32_init_fmode ();
292
293   /* Adust references to dllimported data that have non-zero offsets.
294    */
295   _pei386_runtime_relocator ();
296
297   /* Align the stack to 16 bytes for the sake of SSE ops in main
298    * or in functions inlined into main.
299    */
300   asm  __volatile__  ("andl $-16, %%esp" : : : "%esp");
301
302    /* From libgcc.a, __main calls global class constructors via
303       __do_global_ctors, This in turn  registers  __do_global_dtors
304       as the first entry of the app's atexit table.  We do this
305       explicitly at app startup rather than rely on gcc to generate
306       the call in main's  prologue, since main may be imported from a dll
307       which has its own __do_global_ctors.  */
308     __main ();
309
310   /* Call the main function. If the user does not supply one
311    * the one in the 'libmingw32.a' library will be linked in, and
312    * that one calls WinMain. See main.c in the 'lib' dir
313    * for more details.
314    */
315   nRet = main (_argc, _argv, environ);
316
317   /* Perform exit processing for the C library. This means
318    * flushing output and calling 'atexit' registered functions.
319    */
320   _cexit ();
321
322   ExitProcess (nRet);
323 }
324
325 /*
326  * The function mainCRTStartup is the entry point for all console programs.
327  */
328 void
329 mainCRTStartup (void)
330 {
331 #ifdef __MSVCRT__
332   __set_app_type (__CONSOLE_APP);
333 #endif
334   __mingw_CRTStartup ();
335 }
336
337 /*
338  * For now the GUI startup function is the same as the console one.
339  * This simply gets rid of the annoying warning about not being able
340  * to find WinMainCRTStartup when linking GUI applications.
341  */
342 void
343 WinMainCRTStartup (void)
344 {
345 #ifdef __MSVCRT__
346   __set_app_type (__GUI_APP);
347 #endif
348   __mingw_CRTStartup ();
349 }
350
351 /*
352  *  We force use of library version of atexit, which is only
353  *  visible in import lib as _imp__atexit
354  */
355 extern int (*_imp__atexit)(void (*)(void));
356 int atexit (void (* pfn )(void) )
357 {
358   return ( (*_imp__atexit)(pfn));
359 }
360
361 /* Likewise for non-ANSI _onexit */
362 extern _onexit_t (*_imp___onexit)(_onexit_t);
363 _onexit_t
364 _onexit (_onexit_t pfn )
365 {
366   return (*_imp___onexit)(pfn);
367 }