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