xref: /illumos-gate/usr/src/lib/crt/common/common-crt.c (revision 0245b61fd282e95735b173b8d95be0d6688163b4)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2016, Richard Lowe.
14  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
15  */
16 
17 /*
18  * That of the CRT startup routine which itself may be implemented in C.
19  */
20 
21 #include <sys/feature_tests.h>
22 #include <sys/types.h>
23 
24 #include <stdlib.h>
25 #include <synch.h>
26 #include <unistd.h>
27 
28 #pragma weak _DYNAMIC
29 extern uintptr_t _DYNAMIC;
30 
31 #pragma weak environ = _environ
32 char **_environ = NULL;
33 char **___Argv = NULL;
34 
35 extern int main(int argc, char **argv, char **envp);
36 extern void _init(void);
37 extern void _fini(void);
38 
39 #pragma weak __start_crt_compiler
40 extern int __start_crt_compiler(int argc, char **argv);
41 
42 #if defined(__x86)
43 int __longdouble_used = 0;
44 extern void __fpstart(void);
45 #endif
46 
47 #if defined(__i386)		/* Not amd64 */
48 #pragma weak __fsr_init_value
49 extern long __fsr_init_value;
50 extern void __fsr(uintptr_t);
51 #endif
52 
53 
54 /*
55  * Defined here for ABI reasons, must match the definition in libc.
56  * If it cannot, a new symbol must be created.
57  */
58 mutex_t __environ_lock = DEFAULTMUTEX;
59 
60 void
61 _start_crt(int argc, char **argv, void (*exit_handler)(void))
62 {
63 	int ret = 0;
64 
65 	/*
66 	 * On x86, we check whether we're a dynamic executable to see whether
67 	 * we'll receive an exit_handler.
68 	 *
69 	 * On SPARC, we just need to check whether the handler was NULL.
70 	 */
71 #if defined(__x86)
72 	if (&_DYNAMIC != NULL)
73 		(void) atexit(exit_handler);
74 #elif defined(__sparc)
75 	if (exit_handler != NULL)
76 		(void) atexit(exit_handler);
77 #endif
78 
79 	(void) atexit(_fini);
80 
81 	_environ = argv + (argc + 1);
82 	___Argv = argv;
83 
84 	/*
85 	 * __start_crt_compiler() provides a hook for compilers to perform
86 	 * extra initialisation before main() is called. For example, gcc uses
87 	 * this to initialise profiling code for objects built with its -pg
88 	 * option by linking in an extra object that provides this function.
89 	 *
90 	 * This mechanism replaces the earlier separate gcrt1.o.
91 	 *
92 	 * If __start_crt_compiler() returns a non-zero value, then the
93 	 * process will exit with that value, without main() being called.
94 	 */
95 	if (&__start_crt_compiler != NULL)
96 		ret = __start_crt_compiler(argc, argv);
97 
98 	if (ret == 0) {
99 #if defined(__x86)
100 		__fpstart();
101 #endif
102 #if defined(__i386)		/* Not amd64 */
103 		/*
104 		 * Note that Studio cc(1) sets the _value of the symbol_, that
105 		 * is, its address.  Not the value _at_ that address.
106 		 */
107 		__fsr((uintptr_t)&__fsr_init_value);
108 #endif
109 		_init();
110 		ret = main(argc, argv, _environ);
111 	}
112 	exit(ret);
113 	_exit(ret);
114 }
115