diff options
Diffstat (limited to 'libc/misc/internals/__uClibc_main.c')
-rw-r--r-- | libc/misc/internals/__uClibc_main.c | 247 |
1 files changed, 203 insertions, 44 deletions
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 3876c7606..cbde28b59 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -1,5 +1,7 @@ +/* vi: set sw=4 ts=4: */ /* - * Copyright (C) Feb 2001 Manuel Novoa III + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2001 by Manuel Novoa III <mjn3@uclibc.org> * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -13,13 +15,10 @@ * avoided in the static library case. */ -#define getgid __getgid -#define getuid __getuid -#define getegid __getegid -#define geteuid __geteuid - -#define _ERRNO_H #include <features.h> +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ +#define _ERRNO_H +#endif #include <unistd.h> #include <stdlib.h> #include <string.h> @@ -32,22 +31,56 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/sysmacros.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <pthread-functions.h> +#include <not-cancel.h> +#endif + +libc_hidden_proto(exit) + +#ifdef __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__ +libc_hidden_proto(strrchr) +#endif +#ifdef __ARCH_USE_MMU__ +libc_hidden_proto(memcpy) +libc_hidden_proto(getgid) +libc_hidden_proto(getuid) +libc_hidden_proto(getegid) +libc_hidden_proto(geteuid) +libc_hidden_proto(fstat) +libc_hidden_proto(abort) + +extern __typeof(open) __libc_open; +libc_hidden_proto(__libc_open) +extern __typeof(fcntl) __libc_fcntl; +libc_hidden_proto(__libc_fcntl) +#endif #ifndef SHARED void *__libc_stack_end=NULL; -#ifdef __UCLIBC_HAS_SSP__ -#include <dl-osinfo.h> -#ifndef THREAD_SET_STACK_GUARD +# ifdef __UCLIBC_HAS_SSP__ +# include <dl-osinfo.h> +# ifndef THREAD_SET_STACK_GUARD /* Only exported for architectures that don't store the stack guard canary * in thread local area. */ -#include <stdint.h> +# include <stdint.h> +uintptr_t stack_chk_guard; /* for gcc-4.1 non-TLS */ uintptr_t __stack_chk_guard attribute_relro; /* for gcc-3.x + Etoh ssp */ +# ifdef __UCLIBC_HAS_SSP_COMPAT__ +# ifdef __HAVE_SHARED__ strong_alias(__stack_chk_guard,__guard) -#endif -#endif +# else +uintptr_t __guard attribute_relro; +# endif +# endif +# elif defined __UCLIBC_HAS_SSP_COMPAT__ +uintptr_t __guard attribute_relro; +# endif +# endif #endif /* !SHARED */ @@ -64,6 +97,20 @@ extern void weak_function _locale_init(void) attribute_hidden; extern void weak_function __pthread_initialize_minimal(void); #endif +#ifdef __UCLIBC_CTOR_DTOR__ +extern void _dl_app_init_array(void); +extern void _dl_app_fini_array(void); +# ifndef SHARED +/* These magic symbols are provided by the linker. */ +extern void (*__preinit_array_start []) (void) attribute_hidden; +extern void (*__preinit_array_end []) (void) attribute_hidden; +extern void (*__init_array_start []) (void) attribute_hidden; +extern void (*__init_array_end []) (void) attribute_hidden; +extern void (*__fini_array_start []) (void) attribute_hidden; +extern void (*__fini_array_end []) (void) attribute_hidden; +# endif +#endif + attribute_hidden const char *__uclibc_progname = NULL; #ifdef __UCLIBC_HAS___PROGNAME__ strong_alias (__uclibc_progname, __progname) @@ -75,39 +122,45 @@ strong_alias (__progname_full, program_invocation_name) #endif /* - * Declare the __environ global variable and create a weak alias environ. - * Note: Apparently we must initialize __environ to ensure that the weak + * Declare the __environ global variable and create a strong alias environ. + * Note: Apparently we must initialize __environ to ensure that the strong * environ symbol is also included. */ char **__environ = 0; -weak_alias(__environ, environ) +strong_alias(__environ,environ) +/* TODO: don't export __pagesize; we cant now because libpthread uses it */ size_t __pagesize = 0; #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 #endif -#ifdef __ARCH_HAS_MMU__ - +#ifdef __ARCH_USE_MMU__ static void __check_one_fd(int fd, int mode) { - /* Check if the specified fd is already open */ - if (unlikely(__fcntl(fd, F_GETFD)==-1 && *(__errno_location())==EBADF)) - { - /* The descriptor is probably not open, so try to use /dev/null */ - struct stat st; - int nullfd = __open(_PATH_DEVNULL, mode); - /* /dev/null is major=1 minor=3. Make absolutely certain - * that is in fact the device that we have opened and not - * some other wierd file... */ - if ( (nullfd!=fd) || __fstat(fd, &st) || !S_ISCHR(st.st_mode) || - (st.st_rdev != makedev(1, 3))) + /* Check if the specified fd is already open */ + if (unlikely(fcntl(fd, F_GETFD)==-1 && *(__errno_location())==EBADF)) { - /* Somebody is trying some trickery here... */ - abort(); + /* The descriptor is probably not open, so try to use /dev/null */ + struct stat st; + +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ + int nullfd = open(_PATH_DEVNULL, mode); +#else + int nullfd = open_not_cancel (_PATH_DEVNULL, mode, 0); +#endif + + /* /dev/null is major=1 minor=3. Make absolutely certain + * that is in fact the device that we have opened and not + * some other wierd file... */ + if ((nullfd != fd) || fstat(fd, &st) || !S_ISCHR(st.st_mode) || + (st.st_rdev != makedev(1, 3))) + { + /* Somebody is trying some trickery here... */ + abort(); + } } - } } static int __check_suid(void) @@ -140,6 +193,8 @@ static int __check_suid(void) * __uClibc_main. */ +extern void __uClibc_init(void); +libc_hidden_proto(__uClibc_init) void __uClibc_init(void) { static int been_there_done_that = 0; @@ -164,11 +219,17 @@ void __uClibc_init(void) #ifndef SHARED # ifdef __UCLIBC_HAS_SSP__ /* Set up the stack checker's canary. */ - uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard(); + stack_chk_guard = _dl_setup_stack_chk_guard(); # ifdef THREAD_SET_STACK_GUARD THREAD_SET_STACK_GUARD (stack_chk_guard); +# ifdef __UCLIBC_HAS_SSP_COMPAT__ + __guard = stack_chk_guard; +# endif # else __stack_chk_guard = stack_chk_guard; +# if !defined __HAVE_SHARED__ && defined __UCLIBC_HAS_SSP_COMPAT__ + __guard = stack_chk_guard; +# endif # endif # endif #endif @@ -187,6 +248,7 @@ void __uClibc_init(void) _stdio_init(); } +libc_hidden_def(__uClibc_init) #ifdef __UCLIBC_CTOR_DTOR__ void attribute_hidden (*__app_fini)(void) = NULL; @@ -194,20 +256,47 @@ void attribute_hidden (*__app_fini)(void) = NULL; void attribute_hidden (*__rtld_fini)(void) = NULL; +extern void __uClibc_fini(void); +libc_hidden_proto(__uClibc_fini) +void __uClibc_fini(void) +{ +#ifdef __UCLIBC_CTOR_DTOR__ +# ifdef SHARED + _dl_app_fini_array(); +# else + size_t i = __fini_array_end - __fini_array_start; + while (i-- > 0) + (*__fini_array_start [i]) (); +# endif + if (__app_fini != NULL) + (__app_fini)(); +#endif + if (__rtld_fini != NULL) + (__rtld_fini)(); +} +libc_hidden_def(__uClibc_fini) + /* __uClibc_main is the new main stub for uClibc. This function is * called from crt1 (version 0.9.28 or newer), after ALL shared libraries * are initialized, just before we call the application's main function. */ -void attribute_noreturn -__uClibc_main(int (*main)(int, char **, char **), int argc, +void __uClibc_main(int (*main)(int, char **, char **), int argc, + char **argv, void (*app_init)(void), void (*app_fini)(void), + void (*rtld_fini)(void), void *stack_end) attribute_noreturn; +void __uClibc_main(int (*main)(int, char **, char **), int argc, char **argv, void (*app_init)(void), void (*app_fini)(void), void (*rtld_fini)(void), void *stack_end) { -#ifdef __ARCH_HAS_MMU__ +#ifdef __ARCH_USE_MMU__ unsigned long *aux_dat; ElfW(auxv_t) auxvt[AT_EGID + 1]; #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + /* Result of the 'main' function. */ + int result; +#endif + #ifndef SHARED __libc_stack_end = stack_end; #endif @@ -224,7 +313,7 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, __environ = &argv[argc]; } -#ifdef __ARCH_HAS_MMU__ +#ifdef __ARCH_USE_MMU__ /* Pull stuff from the ELF header when possible */ aux_dat = (unsigned long*)__environ; while (*aux_dat) { @@ -234,7 +323,7 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, while (*aux_dat) { ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat; if (auxv_entry->a_type <= AT_EGID) { - __memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t))); + memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t))); } aux_dat += 2; } @@ -245,7 +334,7 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, * __uClibc_init() regardless, to be sure the right thing happens. */ __uClibc_init(); -#ifdef __ARCH_HAS_MMU__ +#ifdef __ARCH_USE_MMU__ /* Make certain getpagesize() gives the correct answer */ __pagesize = (auxvt[AT_PAGESZ].a_un.a_val)? auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE; @@ -264,7 +353,7 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, #ifdef __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__ __progname_full = *argv; - __progname = __strrchr(*argv, '/'); + __progname = strrchr(*argv, '/'); if (__progname != NULL) ++__progname; else @@ -277,10 +366,31 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, /* Arrange for the application's dtors to run before we exit. */ __app_fini = app_fini; +# ifndef SHARED + /* For dynamically linked executables the preinit array is executed by + the dynamic linker (before initializing any shared object). + For static executables, preinit happens rights before init. */ + { + const size_t size = __preinit_array_end - __preinit_array_start; + size_t i; + for (i = 0; i < size; i++) + (*__preinit_array_start [i]) (); + } +# endif /* Run all the application's ctors now. */ if (app_init!=NULL) { app_init(); } +# ifdef SHARED + _dl_app_init_array(); +# else + { + const size_t size = __init_array_end - __init_array_start; + size_t i; + for (i = 0; i < size; i++) + (*__init_array_start [i]) (); + } +# endif #endif /* Note: It is possible that any initialization done above could @@ -294,8 +404,57 @@ __uClibc_main(int (*main)(int, char **, char **), int argc, if (likely(__h_errno_location!=NULL)) *(__h_errno_location()) = 0; - /* - * Finally, invoke application's main and then exit. - */ - __exit(main(argc, argv, __environ)); +#if defined HAVE_CLEANUP_JMP_BUF && defined __UCLIBC_HAS_THREADS_NATIVE__ + /* Memory for the cancellation buffer. */ + struct pthread_unwind_buf unwind_buf; + + int not_first_call; + not_first_call = + setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + if (__builtin_expect (! not_first_call, 1)) + { + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); + + /* Run the program. */ + result = main (argc, argv, __environ); + } + else + { + /* Remove the thread-local data. */ +# ifdef SHARED + __libc_pthread_functions.ptr__nptl_deallocate_tsd (); +# else + extern void __nptl_deallocate_tsd (void) __attribute ((weak)); + __nptl_deallocate_tsd (); +# endif + + /* One less thread. Decrement the counter. If it is zero we + terminate the entire process. */ + result = 0; +# ifdef SHARED + unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads; +# else + extern unsigned int __nptl_nthreads __attribute ((weak)); + unsigned int *const ptr = &__nptl_nthreads; +# endif + + if (! atomic_decrement_and_test (ptr)) + /* Not much left to do but to exit the thread, not the process. */ + __exit_thread (0); + } + + exit (result); +#else + /* + * Finally, invoke application's main and then exit. + */ + exit (main (argc, argv, __environ)); +#endif } |