]>
Commit | Line | Data |
---|---|---|
11bf311e | 1 | /* Copyright (C) 1998-2003, 2004, 2005, 2006 Free Software Foundation, Inc. |
7dea968e UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
7dea968e UD |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
7dea968e | 13 | |
41bdb6e2 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
7dea968e | 18 | |
3db52d94 | 19 | #include <stdlib.h> |
dde2652b | 20 | #include <stdio.h> |
3db52d94 | 21 | #include <unistd.h> |
a42195db | 22 | #include <ldsodefs.h> |
ab95290c UD |
23 | #include <bp-start.h> |
24 | #include <bp-sym.h> | |
3db52d94 | 25 | |
31161268 UD |
26 | extern void __libc_init_first (int argc, char **argv, char **envp); |
27 | ||
31161268 UD |
28 | extern int __libc_multiple_libcs; |
29 | ||
7ae4abe9 | 30 | #include <tls.h> |
4fb7a71f | 31 | #ifndef SHARED |
dde2652b | 32 | # include <dl-osinfo.h> |
11bf311e | 33 | extern void __pthread_initialize_minimal (void); |
35f1e827 UD |
34 | # ifndef THREAD_SET_STACK_GUARD |
35 | /* Only exported for architectures that don't store the stack guard canary | |
36 | in thread local area. */ | |
37 | uintptr_t __stack_chk_guard attribute_relro; | |
38 | # endif | |
4fb7a71f AJ |
39 | #endif |
40 | ||
47202270 UD |
41 | #ifdef HAVE_PTR_NTHREADS |
42 | /* We need atomic operations. */ | |
43 | # include <atomic.h> | |
44 | #endif | |
45 | ||
17427edd | 46 | |
2b089f21 | 47 | #ifdef LIBC_START_MAIN |
11986c68 UD |
48 | # ifdef LIBC_START_DISABLE_INLINE |
49 | # define STATIC static | |
50 | # else | |
51 | # define STATIC static inline __attribute__ ((always_inline)) | |
52 | # endif | |
2b089f21 RM |
53 | #else |
54 | # define STATIC | |
55 | # define LIBC_START_MAIN BP_SYM (__libc_start_main) | |
56 | #endif | |
57 | ||
2b089f21 | 58 | #ifdef MAIN_AUXVEC_ARG |
09d65ff3 UD |
59 | /* main gets passed a pointer to the auxiliary. */ |
60 | # define MAIN_AUXVEC_DECL , void * | |
61 | # define MAIN_AUXVEC_PARAM , auxvec | |
62 | #else | |
63 | # define MAIN_AUXVEC_DECL | |
64 | # define MAIN_AUXVEC_PARAM | |
2b089f21 RM |
65 | #endif |
66 | ||
09d65ff3 UD |
67 | STATIC int LIBC_START_MAIN (int (*main) (int, char **, char ** |
68 | MAIN_AUXVEC_DECL), | |
2b089f21 RM |
69 | int argc, |
70 | char *__unbounded *__unbounded ubp_av, | |
71 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | |
72 | ElfW(auxv_t) *__unbounded auxvec, | |
73 | #endif | |
2b089f21 | 74 | __typeof (main) init, |
2b089f21 RM |
75 | void (*fini) (void), |
76 | void (*rtld_fini) (void), | |
77 | void *__unbounded stack_end) | |
17427edd | 78 | __attribute__ ((noreturn)); |
a828c2f5 | 79 | |
9dcafc55 | 80 | |
43c59a70 UD |
81 | /* Note: the fini parameter is ignored here for shared library. It |
82 | is registered with __cxa_atexit. This had the disadvantage that | |
83 | finalizers were called in more than one place. */ | |
2b089f21 | 84 | STATIC int |
09d65ff3 | 85 | LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), |
2b089f21 RM |
86 | int argc, char *__unbounded *__unbounded ubp_av, |
87 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | |
88 | ElfW(auxv_t) *__unbounded auxvec, | |
89 | #endif | |
2b089f21 | 90 | __typeof (main) init, |
2b089f21 RM |
91 | void (*fini) (void), |
92 | void (*rtld_fini) (void), void *__unbounded stack_end) | |
7dea968e | 93 | { |
ab95290c UD |
94 | #if __BOUNDED_POINTERS__ |
95 | char **argv; | |
96 | #else | |
97 | # define argv ubp_av | |
98 | #endif | |
99 | ||
7ae4abe9 UD |
100 | /* Result of the 'main' function. */ |
101 | int result; | |
102 | ||
7ae4abe9 | 103 | __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; |
c0fb8a56 | 104 | |
3fb2606a | 105 | #ifndef SHARED |
4f657581 RM |
106 | char *__unbounded *__unbounded ubp_ev = &ubp_av[argc + 1]; |
107 | ||
ab95290c UD |
108 | INIT_ARGV_and_ENVIRON; |
109 | ||
ea4f25a7 UD |
110 | /* Store the lowest stack address. This is done in ld.so if this is |
111 | the code for the DSO. */ | |
c0fb8a56 | 112 | __libc_stack_end = stack_end; |
31161268 | 113 | |
8a30f00f UD |
114 | # ifdef HAVE_AUX_VECTOR |
115 | /* First process the auxiliary vector since we need to find the | |
116 | program header to locate an eventually present PT_TLS entry. */ | |
2b089f21 RM |
117 | # ifndef LIBC_START_MAIN_AUXVEC_ARG |
118 | ElfW(auxv_t) *__unbounded auxvec; | |
119 | { | |
7eecc0c2 | 120 | char *__unbounded *__unbounded evp = ubp_ev; |
97026947 UD |
121 | while (*evp++ != NULL) |
122 | ; | |
2b089f21 RM |
123 | auxvec = (ElfW(auxv_t) *__unbounded) evp; |
124 | } | |
125 | # endif | |
126 | _dl_aux_init (auxvec); | |
8a30f00f | 127 | # endif |
dde2652b RM |
128 | # ifdef DL_SYSDEP_OSCHECK |
129 | if (!__libc_multiple_libcs) | |
130 | { | |
131 | /* This needs to run to initiliaze _dl_osversion before TLS | |
132 | setup might check it. */ | |
133 | DL_SYSDEP_OSCHECK (__libc_fatal); | |
134 | } | |
135 | # endif | |
8a30f00f | 136 | |
4fb7a71f AJ |
137 | /* Initialize the thread library at least a bit since the libgcc |
138 | functions are using thread functions if these are available and | |
11bf311e UD |
139 | we need to setup errno. */ |
140 | __pthread_initialize_minimal (); | |
db33f7d4 | 141 | #endif |
a828c2f5 | 142 | |
35f1e827 UD |
143 | # ifndef SHARED |
144 | /* Set up the stack checker's canary. */ | |
145 | uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (); | |
146 | # ifdef THREAD_SET_STACK_GUARD | |
147 | THREAD_SET_STACK_GUARD (stack_chk_guard); | |
148 | # else | |
149 | __stack_chk_guard = stack_chk_guard; | |
150 | # endif | |
151 | #endif | |
152 | ||
3db52d94 | 153 | /* Register the destructor of the dynamic linker if there is any. */ |
cf197e41 | 154 | if (__builtin_expect (rtld_fini != NULL, 1)) |
c08bc50a | 155 | __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL); |
3db52d94 | 156 | |
43c59a70 | 157 | #ifndef SHARED |
dacc8ffa UD |
158 | /* Call the initializer of the libc. This is only needed here if we |
159 | are compiling for the static library in which case we haven't | |
160 | run the constructors in `_dl_start_user'. */ | |
31161268 UD |
161 | __libc_init_first (argc, argv, __environ); |
162 | ||
43c59a70 UD |
163 | /* Register the destructor of the program, if any. */ |
164 | if (fini) | |
165 | __cxa_atexit ((void (*) (void *)) fini, NULL, NULL); | |
166 | ||
9946f75a UD |
167 | /* Some security at this point. Prevent starting a SUID binary where |
168 | the standard file descriptors are not opened. We have to do this | |
169 | only for statically linked applications since otherwise the dynamic | |
170 | loader did the work already. */ | |
171 | if (__builtin_expect (__libc_enable_secure, 0)) | |
172 | __libc_check_standard_fds (); | |
173 | #endif | |
174 | ||
4194bc66 | 175 | /* Call the initializer of the program, if any. */ |
b5567b2a | 176 | #ifdef SHARED |
afdca0f2 | 177 | if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) |
154d10bd | 178 | GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]); |
31161268 | 179 | #endif |
4194bc66 | 180 | if (init) |
04395c90 | 181 | (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM); |
3db52d94 | 182 | |
9dcafc55 UD |
183 | #ifdef SHARED |
184 | /* Auditing checkpoint: we have a new object. */ | |
185 | if (__builtin_expect (GLRO(dl_naudit) > 0, 0)) | |
186 | { | |
187 | struct audit_ifaces *afct = GLRO(dl_audit); | |
188 | struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded; | |
189 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) | |
190 | { | |
191 | if (afct->preinit != NULL) | |
192 | afct->preinit (&head->l_audit[cnt].cookie); | |
193 | ||
194 | afct = afct->next; | |
195 | } | |
196 | } | |
197 | #endif | |
198 | ||
b5567b2a | 199 | #ifdef SHARED |
afdca0f2 | 200 | if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) |
154d10bd | 201 | GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]); |
31161268 UD |
202 | #endif |
203 | ||
09d65ff3 UD |
204 | #ifdef HAVE_CLEANUP_JMP_BUF |
205 | /* Memory for the cancellation buffer. */ | |
206 | struct pthread_unwind_buf unwind_buf; | |
207 | ||
208 | int not_first_call; | |
209 | not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); | |
210 | if (__builtin_expect (! not_first_call, 1)) | |
7ae4abe9 | 211 | { |
09d65ff3 | 212 | struct pthread *self = THREAD_SELF; |
7ae4abe9 | 213 | |
09d65ff3 UD |
214 | /* Store old info. */ |
215 | unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); | |
216 | unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); | |
2b089f21 | 217 | |
09d65ff3 UD |
218 | /* Store the new cleanup handler info. */ |
219 | THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); | |
220 | ||
221 | /* Run the program. */ | |
222 | result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | |
7ae4abe9 | 223 | } |
7ae4abe9 | 224 | else |
47202270 | 225 | { |
3fa21fd8 UD |
226 | /* Remove the thread-local data. */ |
227 | # ifdef SHARED | |
228 | __libc_pthread_functions.ptr__nptl_deallocate_tsd (); | |
229 | # else | |
230 | extern void __nptl_deallocate_tsd (void) __attribute ((weak)); | |
231 | __nptl_deallocate_tsd (); | |
232 | # endif | |
233 | ||
47202270 UD |
234 | /* One less thread. Decrement the counter. If it is zero we |
235 | terminate the entire process. */ | |
236 | result = 0; | |
09d65ff3 | 237 | # ifdef SHARED |
9cfe5381 | 238 | unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads; |
09d65ff3 | 239 | # else |
9cfe5381 RM |
240 | extern unsigned int __nptl_nthreads __attribute ((weak)); |
241 | unsigned int *const ptr = &__nptl_nthreads; | |
09d65ff3 | 242 | # endif |
47202270 UD |
243 | |
244 | if (! atomic_decrement_and_test (ptr)) | |
47202270 UD |
245 | /* Not much left to do but to exit the thread, not the process. */ |
246 | __exit_thread (0); | |
247 | } | |
09d65ff3 UD |
248 | #else |
249 | /* Nothing fancy, just call the function. */ | |
250 | result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | |
7ae4abe9 UD |
251 | #endif |
252 | ||
253 | exit (result); | |
7dea968e | 254 | } |