9edbf8e1233fce594b291ce0fd2a723dd9dc1953
[jlayton/glibc.git] / sysdeps / generic / libc-start.c
1 /* Copyright (C) 1998-2003, 2004 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, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <ldsodefs.h>
23 #include <bp-start.h>
24 #include <bp-sym.h>
25
26 extern void __libc_init_first (int argc, char **argv, char **envp);
27
28 extern int __libc_multiple_libcs;
29
30 #include <tls.h>
31 #ifndef SHARED
32 # include <dl-osinfo.h>
33 extern void __pthread_initialize_minimal (void)
34 # if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
35      __attribute__ ((weak))
36 # endif
37      ;
38 #endif
39
40 #ifdef HAVE_PTR_NTHREADS
41 /* We need atomic operations.  */
42 # include <atomic.h>
43 #endif
44
45
46 #ifdef LIBC_START_MAIN
47 # ifdef LIBC_START_DISABLE_INLINE
48 #  define STATIC static
49 # else
50 #  define STATIC static inline __attribute__ ((always_inline))
51 # endif
52 #else
53 # define STATIC
54 # define LIBC_START_MAIN BP_SYM (__libc_start_main)
55 #endif
56
57 #ifdef MAIN_AUXVEC_ARG
58 /* main gets passed a pointer to the auxiliary.  */
59 # define MAIN_AUXVEC_DECL       , void *
60 # define MAIN_AUXVEC_PARAM      , auxvec
61 #else
62 # define MAIN_AUXVEC_DECL
63 # define MAIN_AUXVEC_PARAM
64 #endif
65
66 STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
67                                          MAIN_AUXVEC_DECL),
68                             int argc,
69                             char *__unbounded *__unbounded ubp_av,
70 #ifdef LIBC_START_MAIN_AUXVEC_ARG
71                             ElfW(auxv_t) *__unbounded auxvec,
72 #endif
73 #ifdef INIT_MAIN_ARGS
74                             __typeof (main) init,
75 #else
76                             void (*init) (void),
77 #endif
78                             void (*fini) (void),
79                             void (*rtld_fini) (void),
80                             void *__unbounded stack_end)
81      __attribute__ ((noreturn));
82
83 STATIC int
84 LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
85                  int argc, char *__unbounded *__unbounded ubp_av,
86 #ifdef LIBC_START_MAIN_AUXVEC_ARG
87                  ElfW(auxv_t) *__unbounded auxvec,
88 #endif
89 #ifdef INIT_MAIN_ARGS
90                  __typeof (main) init,
91 #else
92                  void (*init) (void),
93 #endif
94                  void (*fini) (void),
95                  void (*rtld_fini) (void), void *__unbounded stack_end)
96 {
97   char *__unbounded *__unbounded ubp_ev = &ubp_av[argc + 1];
98 #if __BOUNDED_POINTERS__
99   char **argv;
100 #else
101 # define argv ubp_av
102 #endif
103
104   /* Result of the 'main' function.  */
105   int result;
106
107   __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
108
109   INIT_ARGV_and_ENVIRON;
110
111 #ifndef SHARED
112   /* Store the lowest stack address.  This is done in ld.so if this is
113      the code for the DSO.  */
114   __libc_stack_end = stack_end;
115
116 # ifdef HAVE_AUX_VECTOR
117   /* First process the auxiliary vector since we need to find the
118      program header to locate an eventually present PT_TLS entry.  */
119 #  ifndef LIBC_START_MAIN_AUXVEC_ARG
120   ElfW(auxv_t) *__unbounded auxvec;
121   {
122     char *__unbounded *__unbounded evp = ubp_ev;
123     while (*evp++ != NULL)
124       ;
125     auxvec = (ElfW(auxv_t) *__unbounded) evp;
126   }
127 #  endif
128   _dl_aux_init (auxvec);
129 # endif
130 # ifdef DL_SYSDEP_OSCHECK
131   if (!__libc_multiple_libcs)
132     {
133       /* This needs to run to initiliaze _dl_osversion before TLS
134          setup might check it.  */
135       DL_SYSDEP_OSCHECK (__libc_fatal);
136     }
137 # endif
138
139   /* Initialize the thread library at least a bit since the libgcc
140      functions are using thread functions if these are available and
141      we need to setup errno.  If there is no thread library and we
142      handle TLS the function is defined in the libc to initialized the
143      TLS handling.  */
144 # if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
145   if (__pthread_initialize_minimal)
146 # endif
147     __pthread_initialize_minimal ();
148 #endif
149
150   /* Register the destructor of the dynamic linker if there is any.  */
151   if (__builtin_expect (rtld_fini != NULL, 1))
152     __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
153
154   /* Call the initializer of the libc.  This is only needed here if we
155      are compiling for the static library in which case we haven't
156      run the constructors in `_dl_start_user'.  */
157 #ifndef SHARED
158   __libc_init_first (argc, argv, __environ);
159 #endif
160
161   /* Register the destructor of the program, if any.  */
162   if (fini)
163     __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
164
165 #ifndef SHARED
166   /* Some security at this point.  Prevent starting a SUID binary where
167      the standard file descriptors are not opened.  We have to do this
168      only for statically linked applications since otherwise the dynamic
169      loader did the work already.  */
170   if (__builtin_expect (__libc_enable_secure, 0))
171     __libc_check_standard_fds ();
172 #endif
173
174   /* Call the initializer of the program, if any.  */
175 #ifdef SHARED
176   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
177     _dl_debug_printf ("\ninitialize program: %s\n\n", argv[0]);
178 #endif
179   if (init)
180     (*init) (
181 #ifdef INIT_MAIN_ARGS
182              argc, argv, __environ MAIN_AUXVEC_PARAM
183 #endif
184              );
185
186 #ifdef SHARED
187   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
188     _dl_debug_printf ("\ntransferring control: %s\n\n", argv[0]);
189 #endif
190
191 #ifdef HAVE_CLEANUP_JMP_BUF
192   /* Memory for the cancellation buffer.  */
193   struct pthread_unwind_buf unwind_buf;
194
195   int not_first_call;
196   not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
197   if (__builtin_expect (! not_first_call, 1))
198     {
199       struct pthread *self = THREAD_SELF;
200
201       /* Store old info.  */
202       unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
203       unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
204
205       /* Store the new cleanup handler info.  */
206       THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
207
208       /* Run the program.  */
209       result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
210     }
211   else
212     {
213       /* One less thread.  Decrement the counter.  If it is zero we
214          terminate the entire process.  */
215       result = 0;
216 # ifdef SHARED
217       int *const ptr = __libc_pthread_functions.ptr_nthreads;
218 # else
219       extern int __nptl_nthreads __attribute ((weak));
220       int *const ptr = &__nptl_nthreads;
221 # endif
222
223       if (! atomic_decrement_and_test (ptr))
224         /* Not much left to do but to exit the thread, not the process.  */
225         __exit_thread (0);
226     }
227 #else
228   /* Nothing fancy, just call the function.  */
229   result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
230 #endif
231
232   exit (result);
233 }