Back to index

glibc  2.9
libc-start.c
Go to the documentation of this file.
00001 /* Copyright (C) 1998-2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <unistd.h>
00022 #include <ldsodefs.h>
00023 #include <bp-start.h>
00024 #include <bp-sym.h>
00025 
00026 extern void __libc_init_first (int argc, char **argv, char **envp);
00027 
00028 extern int __libc_multiple_libcs;
00029 
00030 #include <tls.h>
00031 #ifndef SHARED
00032 # include <dl-osinfo.h>
00033 extern void __pthread_initialize_minimal (void);
00034 # ifndef THREAD_SET_STACK_GUARD
00035 /* Only exported for architectures that don't store the stack guard canary
00036    in thread local area.  */
00037 uintptr_t __stack_chk_guard attribute_relro;
00038 # endif
00039 #endif
00040 
00041 #ifdef HAVE_PTR_NTHREADS
00042 /* We need atomic operations.  */
00043 # include <atomic.h>
00044 #endif
00045 
00046 
00047 #ifdef LIBC_START_MAIN
00048 # ifdef LIBC_START_DISABLE_INLINE
00049 #  define STATIC static
00050 # else
00051 #  define STATIC static inline __attribute__ ((always_inline))
00052 # endif
00053 #else
00054 # define STATIC
00055 # define LIBC_START_MAIN BP_SYM (__libc_start_main)
00056 #endif
00057 
00058 #ifdef MAIN_AUXVEC_ARG
00059 /* main gets passed a pointer to the auxiliary.  */
00060 # define MAIN_AUXVEC_DECL   , void *
00061 # define MAIN_AUXVEC_PARAM  , auxvec
00062 #else
00063 # define MAIN_AUXVEC_DECL
00064 # define MAIN_AUXVEC_PARAM
00065 #endif
00066 
00067 STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
00068                                     MAIN_AUXVEC_DECL),
00069                          int argc,
00070                          char *__unbounded *__unbounded ubp_av,
00071 #ifdef LIBC_START_MAIN_AUXVEC_ARG
00072                          ElfW(auxv_t) *__unbounded auxvec,
00073 #endif
00074                          __typeof (main) init,
00075                          void (*fini) (void),
00076                          void (*rtld_fini) (void),
00077                          void *__unbounded stack_end)
00078      __attribute__ ((noreturn));
00079 
00080 
00081 /* Note: the fini parameter is ignored here for shared library.  It
00082    is registered with __cxa_atexit.  This had the disadvantage that
00083    finalizers were called in more than one place.  */
00084 STATIC int
00085 LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
00086                int argc, char *__unbounded *__unbounded ubp_av,
00087 #ifdef LIBC_START_MAIN_AUXVEC_ARG
00088                ElfW(auxv_t) *__unbounded auxvec,
00089 #endif
00090                __typeof (main) init,
00091                void (*fini) (void),
00092                void (*rtld_fini) (void), void *__unbounded stack_end)
00093 {
00094 #if __BOUNDED_POINTERS__
00095   char **argv;
00096 #else
00097 # define argv ubp_av
00098 #endif
00099 
00100   /* Result of the 'main' function.  */
00101   int result;
00102 
00103   __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
00104 
00105 #ifndef SHARED
00106   char *__unbounded *__unbounded ubp_ev = &ubp_av[argc + 1];
00107 
00108   INIT_ARGV_and_ENVIRON;
00109 
00110   /* Store the lowest stack address.  This is done in ld.so if this is
00111      the code for the DSO.  */
00112   __libc_stack_end = stack_end;
00113 
00114 # ifdef HAVE_AUX_VECTOR
00115   /* First process the auxiliary vector since we need to find the
00116      program header to locate an eventually present PT_TLS entry.  */
00117 #  ifndef LIBC_START_MAIN_AUXVEC_ARG
00118   ElfW(auxv_t) *__unbounded auxvec;
00119   {
00120     char *__unbounded *__unbounded evp = ubp_ev;
00121     while (*evp++ != NULL)
00122       ;
00123     auxvec = (ElfW(auxv_t) *__unbounded) evp;
00124   }
00125 #  endif
00126   _dl_aux_init (auxvec);
00127 # endif
00128 # ifdef DL_SYSDEP_OSCHECK
00129   if (!__libc_multiple_libcs)
00130     {
00131       /* This needs to run to initiliaze _dl_osversion before TLS
00132         setup might check it.  */
00133       DL_SYSDEP_OSCHECK (__libc_fatal);
00134     }
00135 # endif
00136 
00137   /* Initialize the thread library at least a bit since the libgcc
00138      functions are using thread functions if these are available and
00139      we need to setup errno.  */
00140   __pthread_initialize_minimal ();
00141 
00142   /* Set up the stack checker's canary.  */
00143   uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard ();
00144 # ifdef THREAD_SET_STACK_GUARD
00145   THREAD_SET_STACK_GUARD (stack_chk_guard);
00146 # else
00147   __stack_chk_guard = stack_chk_guard;
00148 # endif
00149 #endif
00150 
00151   /* Register the destructor of the dynamic linker if there is any.  */
00152   if (__builtin_expect (rtld_fini != NULL, 1))
00153     __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
00154 
00155 #ifndef SHARED
00156   /* Call the initializer of the libc.  This is only needed here if we
00157      are compiling for the static library in which case we haven't
00158      run the constructors in `_dl_start_user'.  */
00159   __libc_init_first (argc, argv, __environ);
00160 
00161   /* Register the destructor of the program, if any.  */
00162   if (fini)
00163     __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
00164 
00165   /* Some security at this point.  Prevent starting a SUID binary where
00166      the standard file descriptors are not opened.  We have to do this
00167      only for statically linked applications since otherwise the dynamic
00168      loader did the work already.  */
00169   if (__builtin_expect (__libc_enable_secure, 0))
00170     __libc_check_standard_fds ();
00171 #endif
00172 
00173   /* Call the initializer of the program, if any.  */
00174 #ifdef SHARED
00175   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
00176     GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
00177 #endif
00178   if (init)
00179     (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
00180 
00181 #ifdef SHARED
00182   /* Auditing checkpoint: we have a new object.  */
00183   if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
00184     {
00185       struct audit_ifaces *afct = GLRO(dl_audit);
00186       struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
00187       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
00188        {
00189          if (afct->preinit != NULL)
00190            afct->preinit (&head->l_audit[cnt].cookie);
00191 
00192          afct = afct->next;
00193        }
00194     }
00195 #endif
00196 
00197 #ifdef SHARED
00198   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
00199     GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
00200 #endif
00201 
00202 #ifdef HAVE_CLEANUP_JMP_BUF
00203   /* Memory for the cancellation buffer.  */
00204   struct pthread_unwind_buf unwind_buf;
00205 
00206   int not_first_call;
00207   not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
00208   if (__builtin_expect (! not_first_call, 1))
00209     {
00210       struct pthread *self = THREAD_SELF;
00211 
00212       /* Store old info.  */
00213       unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
00214       unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
00215 
00216       /* Store the new cleanup handler info.  */
00217       THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
00218 
00219       /* Run the program.  */
00220       result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
00221     }
00222   else
00223     {
00224       /* Remove the thread-local data.  */
00225 # ifdef SHARED
00226       PTHFCT_CALL (ptr__nptl_deallocate_tsd, ());
00227 # else
00228       extern void __nptl_deallocate_tsd (void) __attribute ((weak));
00229       __nptl_deallocate_tsd ();
00230 # endif
00231 
00232       /* One less thread.  Decrement the counter.  If it is zero we
00233         terminate the entire process.  */
00234       result = 0;
00235 # ifdef SHARED
00236       unsigned int *ptr = __libc_pthread_functions.ptr_nthreads;
00237       PTR_DEMANGLE (ptr);
00238 # else
00239       extern unsigned int __nptl_nthreads __attribute ((weak));
00240       unsigned int *const ptr = &__nptl_nthreads;
00241 # endif
00242 
00243       if (! atomic_decrement_and_test (ptr))
00244        /* Not much left to do but to exit the thread, not the process.  */
00245        __exit_thread (0);
00246     }
00247 #else
00248   /* Nothing fancy, just call the function.  */
00249   result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
00250 #endif
00251 
00252   exit (result);
00253 }