| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 1998-2016 Free Software Foundation, Inc. | 
 | 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 | 
 | 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. | 
 | 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 | 
 | 12 |    Lesser General Public License for more details. | 
 | 13 |  | 
 | 14 |    You should have received a copy of the GNU Lesser General Public | 
 | 15 |    License along with the GNU C Library; if not, see | 
 | 16 |    <http://www.gnu.org/licenses/>.  */ | 
 | 17 |  | 
 | 18 | #include <assert.h> | 
 | 19 | #include <stdlib.h> | 
 | 20 | #include <stdio.h> | 
 | 21 | #include <unistd.h> | 
 | 22 | #include <ldsodefs.h> | 
 | 23 | #include <exit-thread.h> | 
 | 24 |  | 
 | 25 | extern void __libc_init_first (int argc, char **argv, char **envp); | 
 | 26 | #ifndef SHARED | 
 | 27 | extern void __libc_csu_irel (void); | 
 | 28 | #endif | 
 | 29 |  | 
 | 30 | extern int __libc_multiple_libcs; | 
 | 31 |  | 
 | 32 | #include <tls.h> | 
 | 33 | #ifndef SHARED | 
 | 34 | # include <dl-osinfo.h> | 
 | 35 | extern void __pthread_initialize_minimal (void); | 
 | 36 | # ifndef THREAD_SET_STACK_GUARD | 
 | 37 | /* Only exported for architectures that don't store the stack guard canary | 
 | 38 |    in thread local area.  */ | 
 | 39 | uintptr_t __stack_chk_guard attribute_relro; | 
 | 40 | # endif | 
 | 41 | # ifndef  THREAD_SET_POINTER_GUARD | 
 | 42 | /* Only exported for architectures that don't store the pointer guard | 
 | 43 |    value in thread local area.  */ | 
 | 44 | uintptr_t __pointer_chk_guard_local | 
 | 45 | 	attribute_relro attribute_hidden __attribute__ ((nocommon)); | 
 | 46 | # endif | 
 | 47 | #endif | 
 | 48 |  | 
 | 49 | #ifdef HAVE_PTR_NTHREADS | 
 | 50 | /* We need atomic operations.  */ | 
 | 51 | # include <atomic.h> | 
 | 52 | #endif | 
 | 53 |  | 
 | 54 |  | 
 | 55 | #ifndef SHARED | 
 | 56 | # include <link.h> | 
 | 57 | # include <dl-irel.h> | 
 | 58 |  | 
 | 59 | # ifdef ELF_MACHINE_IRELA | 
 | 60 | #  define IREL_T	ElfW(Rela) | 
 | 61 | #  define IPLT_START	__rela_iplt_start | 
 | 62 | #  define IPLT_END	__rela_iplt_end | 
 | 63 | #  define IREL		elf_irela | 
 | 64 | # elif defined ELF_MACHINE_IREL | 
 | 65 | #  define IREL_T	ElfW(Rel) | 
 | 66 | #  define IPLT_START	__rel_iplt_start | 
 | 67 | #  define IPLT_END	__rel_iplt_end | 
 | 68 | #  define IREL		elf_irel | 
 | 69 | # endif | 
 | 70 |  | 
 | 71 | static void | 
 | 72 | apply_irel (void) | 
 | 73 | { | 
 | 74 | # ifdef IREL | 
 | 75 |   /* We use weak references for these so that we'll still work with a linker | 
 | 76 |      that doesn't define them.  Such a linker doesn't support IFUNC at all | 
 | 77 |      and so uses won't work, but a statically-linked program that doesn't | 
 | 78 |      use any IFUNC symbols won't have a problem.  */ | 
 | 79 |   extern const IREL_T IPLT_START[] __attribute__ ((weak)); | 
 | 80 |   extern const IREL_T IPLT_END[] __attribute__ ((weak)); | 
 | 81 |   for (const IREL_T *ipltent = IPLT_START; ipltent < IPLT_END; ++ipltent) | 
 | 82 |     IREL (ipltent); | 
 | 83 | # endif | 
 | 84 | } | 
 | 85 | #endif | 
 | 86 |  | 
 | 87 |  | 
 | 88 | #ifdef LIBC_START_MAIN | 
 | 89 | # ifdef LIBC_START_DISABLE_INLINE | 
 | 90 | #  define STATIC static | 
 | 91 | # else | 
 | 92 | #  define STATIC static inline __attribute__ ((always_inline)) | 
 | 93 | # endif | 
 | 94 | #else | 
 | 95 | # define STATIC | 
 | 96 | # define LIBC_START_MAIN __libc_start_main | 
 | 97 | #endif | 
 | 98 |  | 
 | 99 | #ifdef MAIN_AUXVEC_ARG | 
 | 100 | /* main gets passed a pointer to the auxiliary.  */ | 
 | 101 | # define MAIN_AUXVEC_DECL	, void * | 
 | 102 | # define MAIN_AUXVEC_PARAM	, auxvec | 
 | 103 | #else | 
 | 104 | # define MAIN_AUXVEC_DECL | 
 | 105 | # define MAIN_AUXVEC_PARAM | 
 | 106 | #endif | 
 | 107 |  | 
 | 108 | STATIC int LIBC_START_MAIN (int (*main) (int, char **, char ** | 
 | 109 | 					 MAIN_AUXVEC_DECL), | 
 | 110 | 			    int argc, | 
 | 111 | 			    char **argv, | 
 | 112 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | 
 | 113 | 			    ElfW(auxv_t) *auxvec, | 
 | 114 | #endif | 
 | 115 | 			    __typeof (main) init, | 
 | 116 | 			    void (*fini) (void), | 
 | 117 | 			    void (*rtld_fini) (void), | 
 | 118 | 			    void *stack_end) | 
 | 119 |      __attribute__ ((noreturn)); | 
 | 120 |  | 
 | 121 |  | 
 | 122 | /* Note: the fini parameter is ignored here for shared library.  It | 
 | 123 |    is registered with __cxa_atexit.  This had the disadvantage that | 
 | 124 |    finalizers were called in more than one place.  */ | 
 | 125 | STATIC int | 
 | 126 | LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), | 
 | 127 | 		 int argc, char **argv, | 
 | 128 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | 
 | 129 | 		 ElfW(auxv_t) *auxvec, | 
 | 130 | #endif | 
 | 131 | 		 __typeof (main) init, | 
 | 132 | 		 void (*fini) (void), | 
 | 133 | 		 void (*rtld_fini) (void), void *stack_end) | 
 | 134 | { | 
 | 135 |   /* Result of the 'main' function.  */ | 
 | 136 |   int result; | 
 | 137 |  | 
 | 138 |   __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; | 
 | 139 |  | 
 | 140 | #ifndef SHARED | 
 | 141 |   char **ev = &argv[argc + 1]; | 
 | 142 |  | 
 | 143 |   __environ = ev; | 
 | 144 |  | 
 | 145 |   /* Store the lowest stack address.  This is done in ld.so if this is | 
 | 146 |      the code for the DSO.  */ | 
 | 147 |   __libc_stack_end = stack_end; | 
 | 148 |  | 
 | 149 | # ifdef HAVE_AUX_VECTOR | 
 | 150 |   /* First process the auxiliary vector since we need to find the | 
 | 151 |      program header to locate an eventually present PT_TLS entry.  */ | 
 | 152 | #  ifndef LIBC_START_MAIN_AUXVEC_ARG | 
 | 153 |   ElfW(auxv_t) *auxvec; | 
 | 154 |   { | 
 | 155 |     char **evp = ev; | 
 | 156 |     while (*evp++ != NULL) | 
 | 157 |       ; | 
 | 158 |     auxvec = (ElfW(auxv_t) *) evp; | 
 | 159 |   } | 
 | 160 | #  endif | 
 | 161 |   _dl_aux_init (auxvec); | 
 | 162 |   if (GL(dl_phdr) == NULL) | 
 | 163 | # endif | 
 | 164 |     { | 
 | 165 |       /* Starting from binutils-2.23, the linker will define the | 
 | 166 |          magic symbol __ehdr_start to point to our own ELF header | 
 | 167 |          if it is visible in a segment that also includes the phdrs. | 
 | 168 |          So we can set up _dl_phdr and _dl_phnum even without any | 
 | 169 |          information from auxv.  */ | 
 | 170 |  | 
 | 171 |       extern const ElfW(Ehdr) __ehdr_start | 
 | 172 | 	__attribute__ ((weak, visibility ("hidden"))); | 
 | 173 |       if (&__ehdr_start != NULL) | 
 | 174 |         { | 
 | 175 |           assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); | 
 | 176 |           GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; | 
 | 177 |           GL(dl_phnum) = __ehdr_start.e_phnum; | 
 | 178 |         } | 
 | 179 |     } | 
 | 180 |  | 
 | 181 | # ifdef DL_SYSDEP_OSCHECK | 
 | 182 |   if (!__libc_multiple_libcs) | 
 | 183 |     { | 
 | 184 |       /* This needs to run to initiliaze _dl_osversion before TLS | 
 | 185 | 	 setup might check it.  */ | 
 | 186 |       DL_SYSDEP_OSCHECK (__libc_fatal); | 
 | 187 |     } | 
 | 188 | # endif | 
 | 189 |  | 
 | 190 |   /* Perform IREL{,A} relocations.  */ | 
 | 191 |   apply_irel (); | 
 | 192 |  | 
 | 193 |   /* Initialize the thread library at least a bit since the libgcc | 
 | 194 |      functions are using thread functions if these are available and | 
 | 195 |      we need to setup errno.  */ | 
 | 196 |   __pthread_initialize_minimal (); | 
 | 197 |  | 
 | 198 |   /* Set up the stack checker's canary.  */ | 
 | 199 |   uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random); | 
 | 200 | # ifdef THREAD_SET_STACK_GUARD | 
 | 201 |   THREAD_SET_STACK_GUARD (stack_chk_guard); | 
 | 202 | # else | 
 | 203 |   __stack_chk_guard = stack_chk_guard; | 
 | 204 | # endif | 
 | 205 |  | 
 | 206 |   /* Set up the pointer guard value.  */ | 
 | 207 |   uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random, | 
 | 208 | 							 stack_chk_guard); | 
 | 209 | # ifdef THREAD_SET_POINTER_GUARD | 
 | 210 |   THREAD_SET_POINTER_GUARD (pointer_chk_guard); | 
 | 211 | # else | 
 | 212 |   __pointer_chk_guard_local = pointer_chk_guard; | 
 | 213 | # endif | 
 | 214 |  | 
 | 215 | #endif | 
 | 216 |  | 
 | 217 |   /* Register the destructor of the dynamic linker if there is any.  */ | 
 | 218 |   if (__glibc_likely (rtld_fini != NULL)) | 
 | 219 |     __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL); | 
 | 220 |  | 
 | 221 | #ifndef SHARED | 
 | 222 |   /* Call the initializer of the libc.  This is only needed here if we | 
 | 223 |      are compiling for the static library in which case we haven't | 
 | 224 |      run the constructors in `_dl_start_user'.  */ | 
 | 225 |   __libc_init_first (argc, argv, __environ); | 
 | 226 |  | 
 | 227 |   /* Register the destructor of the program, if any.  */ | 
 | 228 |   if (fini) | 
 | 229 |     __cxa_atexit ((void (*) (void *)) fini, NULL, NULL); | 
 | 230 |  | 
 | 231 |   /* Some security at this point.  Prevent starting a SUID binary where | 
 | 232 |      the standard file descriptors are not opened.  We have to do this | 
 | 233 |      only for statically linked applications since otherwise the dynamic | 
 | 234 |      loader did the work already.  */ | 
 | 235 |   if (__builtin_expect (__libc_enable_secure, 0)) | 
 | 236 |     __libc_check_standard_fds (); | 
 | 237 | #endif | 
 | 238 |  | 
 | 239 |   /* Call the initializer of the program, if any.  */ | 
 | 240 | #ifdef SHARED | 
 | 241 |   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) | 
 | 242 |     GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]); | 
 | 243 | #endif | 
 | 244 |   if (init) | 
 | 245 |     (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
 | 246 |  | 
 | 247 | #ifdef SHARED | 
 | 248 |   /* Auditing checkpoint: we have a new object.  */ | 
 | 249 |   if (__glibc_unlikely (GLRO(dl_naudit) > 0)) | 
 | 250 |     { | 
 | 251 |       struct audit_ifaces *afct = GLRO(dl_audit); | 
 | 252 |       struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded; | 
 | 253 |       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) | 
 | 254 | 	{ | 
 | 255 | 	  if (afct->preinit != NULL) | 
 | 256 | 	    afct->preinit (&head->l_audit[cnt].cookie); | 
 | 257 |  | 
 | 258 | 	  afct = afct->next; | 
 | 259 | 	} | 
 | 260 |     } | 
 | 261 | #endif | 
 | 262 |  | 
 | 263 | #ifdef SHARED | 
 | 264 |   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) | 
 | 265 |     GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]); | 
 | 266 | #endif | 
 | 267 |  | 
 | 268 | #ifndef SHARED | 
 | 269 |   _dl_debug_initialize (0, LM_ID_BASE); | 
 | 270 | #endif | 
 | 271 | #ifdef HAVE_CLEANUP_JMP_BUF | 
 | 272 |   /* Memory for the cancellation buffer.  */ | 
 | 273 |   struct pthread_unwind_buf unwind_buf; | 
 | 274 |  | 
 | 275 |   int not_first_call; | 
 | 276 |   not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); | 
 | 277 |   if (__glibc_likely (! not_first_call)) | 
 | 278 |     { | 
 | 279 |       struct pthread *self = THREAD_SELF; | 
 | 280 |  | 
 | 281 |       /* Store old info.  */ | 
 | 282 |       unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); | 
 | 283 |       unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); | 
 | 284 |  | 
 | 285 |       /* Store the new cleanup handler info.  */ | 
 | 286 |       THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); | 
 | 287 |  | 
 | 288 |       /* Run the program.  */ | 
 | 289 |       result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
 | 290 |     } | 
 | 291 |   else | 
 | 292 |     { | 
 | 293 |       /* Remove the thread-local data.  */ | 
 | 294 | # ifdef SHARED | 
 | 295 |       PTHFCT_CALL (ptr__nptl_deallocate_tsd, ()); | 
 | 296 | # else | 
 | 297 |       extern void __nptl_deallocate_tsd (void) __attribute ((weak)); | 
 | 298 |       __nptl_deallocate_tsd (); | 
 | 299 | # endif | 
 | 300 |  | 
 | 301 |       /* One less thread.  Decrement the counter.  If it is zero we | 
 | 302 | 	 terminate the entire process.  */ | 
 | 303 |       result = 0; | 
 | 304 | # ifdef SHARED | 
 | 305 |       unsigned int *ptr = __libc_pthread_functions.ptr_nthreads; | 
 | 306 | #  ifdef PTR_DEMANGLE | 
 | 307 |       PTR_DEMANGLE (ptr); | 
 | 308 | #  endif | 
 | 309 | # else | 
 | 310 |       extern unsigned int __nptl_nthreads __attribute ((weak)); | 
 | 311 |       unsigned int *const ptr = &__nptl_nthreads; | 
 | 312 | # endif | 
 | 313 |  | 
 | 314 |       if (! atomic_decrement_and_test (ptr)) | 
 | 315 | 	/* Not much left to do but to exit the thread, not the process.  */ | 
 | 316 | 	__exit_thread (); | 
 | 317 |     } | 
 | 318 | #else | 
 | 319 |   /* Nothing fancy, just call the function.  */ | 
 | 320 |   result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
 | 321 | #endif | 
 | 322 |  | 
 | 323 |   exit (result); | 
 | 324 | } |