diff options
author | Elliott Hughes <enh@google.com> | 2013-02-07 19:48:16 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2013-02-07 19:48:17 +0000 |
commit | 2f41531ff9f48dbdaf2ba711e14c669031728e99 (patch) | |
tree | ae8b9be038220ed0d4cba96453560676d8bd4699 /libc | |
parent | d4187efd7f9c30ffaff4738862e3d08be27a52e9 (diff) | |
parent | 42b2c6a5eed5e4ef35315b8cd32d1355f12a69b6 (diff) | |
download | bionic-2f41531ff9f48dbdaf2ba711e14c669031728e99.zip bionic-2f41531ff9f48dbdaf2ba711e14c669031728e99.tar.gz bionic-2f41531ff9f48dbdaf2ba711e14c669031728e99.tar.bz2 |
Merge "Clean up the argc/argv/envp/auxv handling."
Diffstat (limited to 'libc')
-rw-r--r-- | libc/Android.mk | 8 | ||||
-rw-r--r-- | libc/arch-arm/bionic/crtbegin.c | 30 | ||||
-rwxr-xr-x | libc/arch-x86/bionic/crtbegin.c | 29 | ||||
-rw-r--r-- | libc/bionic/getauxval.cpp | 8 | ||||
-rw-r--r-- | libc/bionic/libc_init_common.cpp (renamed from libc/bionic/libc_init_common.c) | 50 | ||||
-rw-r--r-- | libc/bionic/libc_init_common.h | 29 | ||||
-rw-r--r-- | libc/bionic/libc_init_dynamic.c | 127 | ||||
-rw-r--r-- | libc/bionic/libc_init_dynamic.cpp | 115 | ||||
-rw-r--r-- | libc/bionic/libc_init_static.cpp (renamed from libc/bionic/libc_init_static.c) | 105 | ||||
-rw-r--r-- | libc/private/KernelArgumentBlock.h | 76 | ||||
-rw-r--r-- | libc/private/bionic_tls.h | 2 | ||||
-rw-r--r-- | libc/stdlib/atexit.h | 4 |
12 files changed, 301 insertions, 282 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 301be37..c7828cf 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -177,7 +177,6 @@ libc_common_src_files := \ bionic/isatty.c \ bionic/issetugid.c \ bionic/ldexp.c \ - bionic/libc_init_common.c \ bionic/logd_write.c \ bionic/lseek64.c \ bionic/md5.c \ @@ -275,6 +274,7 @@ libc_bionic_src_files := \ bionic/__fgets_chk.cpp \ bionic/getauxval.cpp \ bionic/getcwd.cpp \ + bionic/libc_init_common.cpp \ bionic/libgen.cpp \ bionic/__memcpy_chk.cpp \ bionic/__memmove_chk.cpp \ @@ -824,7 +824,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(libc_arch_static_src_files) \ $(libc_static_common_src_files) \ - bionic/libc_init_static.c + bionic/libc_init_static.cpp LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_CFLAGS := $(libc_common_cflags) \ @@ -849,7 +849,7 @@ LOCAL_SRC_FILES := \ $(libc_static_common_src_files) \ bionic/dlmalloc.c \ bionic/malloc_debug_common.cpp \ - bionic/libc_init_static.c + bionic/libc_init_static.cpp LOCAL_CFLAGS := $(libc_common_cflags) \ -DLIBC_STATIC \ @@ -883,7 +883,7 @@ LOCAL_SRC_FILES := \ bionic/dlmalloc.c \ bionic/malloc_debug_common.cpp \ bionic/pthread_debug.cpp \ - bionic/libc_init_dynamic.c + bionic/libc_init_dynamic.cpp ifeq ($(TARGET_ARCH),arm) LOCAL_NO_CRT := true diff --git a/libc/arch-arm/bionic/crtbegin.c b/libc/arch-arm/bionic/crtbegin.c index 0e2d31e..cc58797 100644 --- a/libc/arch-arm/bionic/crtbegin.c +++ b/libc/arch-arm/bionic/crtbegin.c @@ -26,21 +26,8 @@ * SUCH DAMAGE. */ -typedef struct -{ - void (**preinit_array)(void); - void (**init_array)(void); - void (**fini_array)(void); -} structors_array_t; - -extern int main(int argc, char **argv, char **env); - -extern void __libc_init( - unsigned int *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors -); +#include "../../bionic/libc_init_common.h" +#include <stddef.h> __attribute__ ((section (".preinit_array"))) void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1; @@ -51,17 +38,14 @@ void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1; __attribute__ ((section (".fini_array"))) void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1; -__attribute__((visibility("hidden"))) -void _start() { +__LIBC_HIDDEN__ void _start() { structors_array_t array; - void *elfdata; - array.preinit_array = &__PREINIT_ARRAY__; - array.init_array = &__INIT_ARRAY__; - array.fini_array = &__FINI_ARRAY__; + array.init_array = &__INIT_ARRAY__; + array.fini_array = &__FINI_ARRAY__; - elfdata = __builtin_frame_address(0) + sizeof(void *); - __libc_init(elfdata, (void *) 0, &main, &array); + void* raw_args = __builtin_frame_address(0) + sizeof(void*); + __libc_init(raw_args, NULL, &main, &array); } #include "__dso_handle.h" diff --git a/libc/arch-x86/bionic/crtbegin.c b/libc/arch-x86/bionic/crtbegin.c index 5106d9e..63e58a6 100755 --- a/libc/arch-x86/bionic/crtbegin.c +++ b/libc/arch-x86/bionic/crtbegin.c @@ -26,21 +26,8 @@ * SUCH DAMAGE. */ -typedef struct -{ - void (**preinit_array)(void); - void (**init_array)(void); - void (**fini_array)(void); -} structors_array_t; - -extern int main(int argc, char **argv, char **env); - -extern void __libc_init( - unsigned int *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors -); +#include "../../bionic/libc_init_common.h" +#include <stddef.h> __attribute__ ((section (".preinit_array"))) void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1; @@ -51,18 +38,16 @@ void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1; __attribute__ ((section (".fini_array"))) void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1; -__attribute__((visibility("hidden"))) +__LIBC_HIDDEN__ __attribute__((force_align_arg_pointer)) void _start() { structors_array_t array; - void *elfdata; - array.preinit_array = &__PREINIT_ARRAY__; - array.init_array = &__INIT_ARRAY__; - array.fini_array = &__FINI_ARRAY__; + array.init_array = &__INIT_ARRAY__; + array.fini_array = &__FINI_ARRAY__; - elfdata = __builtin_frame_address(0) + sizeof(void *); - __libc_init(elfdata, (void *) 0, &main, &array); + void* raw_args = __builtin_frame_address(0) + sizeof(void*); + __libc_init(raw_args, NULL, &main, &array); } #include "__dso_handle.h" diff --git a/libc/bionic/getauxval.cpp b/libc/bionic/getauxval.cpp index 38a05fc..fd225e0 100644 --- a/libc/bionic/getauxval.cpp +++ b/libc/bionic/getauxval.cpp @@ -32,17 +32,13 @@ #include <private/bionic_auxv.h> #include <elf.h> -__LIBC_HIDDEN__ -Elf32_auxv_t* __libc_auxv = NULL; +__LIBC_HIDDEN__ Elf32_auxv_t* __libc_auxv = NULL; extern "C" unsigned long int getauxval(unsigned long int type) { - Elf32_auxv_t* v; - - for (v = __libc_auxv; v->a_type != AT_NULL; v++) { + for (Elf32_auxv_t* v = __libc_auxv; v->a_type != AT_NULL; ++v) { if (v->a_type == type) { return v->a_un.a_val; } } - return 0; } diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.cpp index 86e1eb5..6b4ae2c 100644 --- a/libc/bionic/libc_init_common.c +++ b/libc/bionic/libc_init_common.cpp @@ -30,29 +30,31 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <unistd.h> #include <elf.h> #include <asm/page.h> #include "pthread_internal.h" #include "atexit.h" +#include "KernelArgumentBlock.h" #include "libc_init_common.h" #include <bionic_tls.h> #include <errno.h> #include <private/bionic_auxv.h> -extern unsigned __get_sp(void); -extern pid_t gettid(void); +extern "C" unsigned __get_sp(void); +extern "C" int __system_properties_init(void); -char* __progname; +// Not public, but well-known in the BSDs. +char* __progname; + +// Declared in <unistd.h> char** environ; -/* from asm/page.h */ +// Declared in <asm/page.h>. unsigned int __page_size = PAGE_SIZE; unsigned int __page_shift = PAGE_SHIFT; - -int __system_properties_init(void); - /* Init TLS for the initial thread. Called by the linker _before_ libc is mapped * in memory. Beware: all writes to libc globals from this function will * apply to linker-private copies and will not be visible from libc later on. @@ -61,10 +63,10 @@ int __system_properties_init(void); * stores the pointer in TLS, but does not add it to pthread's gThreadList. This * has to be done later from libc itself (see __libc_init_common). * - * This function also stores the elf_data argument in a specific TLS slot to be later + * This function also stores a pointer to the kernel argument block in a TLS slot to be * picked up by the libc constructor. */ -void __libc_init_tls(unsigned** elf_data) { +extern "C" void __libc_init_tls(void* kernel_argument_block) { unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; unsigned stack_size = 128 * 1024; unsigned stack_bottom = stack_top - stack_size; @@ -78,33 +80,21 @@ void __libc_init_tls(unsigned** elf_data) { static void* tls_area[BIONIC_TLS_SLOTS]; __init_tls(tls_area, &thread); - tls_area[TLS_SLOT_BIONIC_PREINIT] = elf_data; + tls_area[TLS_SLOT_BIONIC_PREINIT] = kernel_argument_block; } -void __libc_init_common(uintptr_t* elf_data) { - int argc = *elf_data; - char** argv = (char**) (elf_data + 1); - char** envp = argv + argc + 1; +void __libc_init_common(KernelArgumentBlock& args) { + // Initialize various globals. + environ = args.envp; + errno = 0; + __libc_auxv = args.auxv; + __progname = args.argv[0] ? args.argv[0] : const_cast<char*>("<unknown>"); // Get the main thread from TLS and add it to the thread list. pthread_internal_t* main_thread = __get_thread(); main_thread->allocated_on_heap = false; _pthread_internal_add(main_thread); - // Set various globals. - errno = 0; - __progname = argv[0] ? argv[0] : "<unknown>"; - environ = envp; - - // The auxiliary vector is at the end of the environment block - while(*envp != NULL) { - envp++; - } - /* The end of the environment block is marked by two NULL pointers */ - envp++; - - __libc_auxv = (Elf32_auxv_t*) envp; - __system_properties_init(); // Requires 'environ'. } @@ -116,7 +106,7 @@ void __libc_init_common(uintptr_t* elf_data) { * entry in the list has value -1, the last one has value 0. */ void __libc_fini(void* array) { - void** fini_array = array; + void** fini_array = reinterpret_cast<void**>(array); const size_t minus1 = ~(size_t)0; /* ensure proper sign extension */ /* Sanity check - first entry must be -1 */ @@ -135,7 +125,7 @@ void __libc_fini(void* array) { /* Now call each destructor in reverse order. */ while (count > 0) { - void (*func)() = (void (*)) fini_array[--count]; + void (*func)() = (void (*)()) fini_array[--count]; /* Sanity check, any -1 in the list is ignored */ if ((size_t)func == minus1) { diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h index c55594b..23ac305 100644 --- a/libc/bionic/libc_init_common.h +++ b/libc/bionic/libc_init_common.h @@ -28,16 +28,29 @@ #ifndef LIBC_INIT_COMMON_H #define LIBC_INIT_COMMON_H -#include <stdint.h> +#include <sys/cdefs.h> -typedef struct -{ - void (**preinit_array)(void); - void (**init_array)(void); - void (**fini_array)(void); +typedef struct { + void (**preinit_array)(void); + void (**init_array)(void); + void (**fini_array)(void); } structors_array_t; -extern void __libc_init_common(uintptr_t *elfdata); -extern void __libc_fini(void* finit_array); +__BEGIN_DECLS + +extern int main(int argc, char** argv, char** env); + +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void), + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors); +void __libc_fini(void* finit_array); + +__END_DECLS + +#if defined(__cplusplus) +struct KernelArgumentBlock; +void __libc_init_common(KernelArgumentBlock& args); +#endif #endif diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c deleted file mode 100644 index 3a7e8e2..0000000 --- a/libc/bionic/libc_init_dynamic.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * libc_init_dynamic.c - * - * This source files provides two important functions for dynamic - * executables: - * - * - a C runtime initializer (__libc_preinit), which is called by - * the dynamic linker when libc.so is loaded. This happens before - * any other initializer (e.g. static C++ constructors in other - * shared libraries the program depends on). - * - * - a program launch function (__libc_init), which is called after - * all dynamic linking has been performed. Technically, it is called - * from arch-$ARCH/bionic/crtbegin_dynamic.S which is itself called - * by the dynamic linker after all libraries have been loaded and - * initialized. - */ - -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <elf.h> -#include "atexit.h" -#include "libc_init_common.h" -#include <bionic_tls.h> - -/* We flag the __libc_preinit function as a constructor to ensure - * that its address is listed in libc.so's .init_array section. - * This ensures that the function is called by the dynamic linker - * as soon as the shared library is loaded. - */ -void __attribute__((constructor)) __libc_preinit(void); - -void __libc_preinit(void) -{ - /* Read the ELF data pointer from a special slot of the - * TLS area, then call __libc_init_common with it. - * - * Note that: - * - we clear the slot so no other initializer sees its value. - * - __libc_init_common() will change the TLS area so the old one - * won't be accessible anyway. - */ - void** tls_area = (void**)__get_tls(); - unsigned* elfdata = tls_area[TLS_SLOT_BIONIC_PREINIT]; - - tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL; - - __libc_init_common(elfdata); - - /* Setup pthread routines accordingly to the environment. - * Requires system properties - */ - extern void pthread_debug_init(void); - pthread_debug_init(); - - /* Setup malloc routines accordingly to the environment. - * Requires system properties - */ - extern void malloc_debug_init(void); - malloc_debug_init(); -} - -void __libc_postfini(void) -{ - extern void malloc_debug_fini(void); - malloc_debug_fini(); -} - -/* This function is called from the executable's _start entry point - * (see arch-$ARCH/bionic/crtbegin_dynamic.S), which is itself - * called by the dynamic linker after it has loaded all shared - * libraries the executable depends on. - * - * Note that the dynamic linker has also run all constructors in the - * executable at this point. - */ -__noreturn void __libc_init(uintptr_t *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors) -{ - int argc = (int)*elfdata; - char** argv = (char**)(elfdata + 1); - char** envp = argv + argc + 1; - - /* Several Linux ABIs don't pass the onexit pointer, and the ones that - * do never use it. Therefore, we ignore it. - */ - - /* The executable may have its own destructors listed in its .fini_array - * so we need to ensure that these are called when the program exits - * normally. - */ - if (structors->fini_array) - __cxa_atexit(__libc_fini,structors->fini_array,NULL); - - exit(slingshot(argc, argv, envp)); -} diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp new file mode 100644 index 0000000..af03fb0 --- /dev/null +++ b/libc/bionic/libc_init_dynamic.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * libc_init_dynamic.c + * + * This source files provides two important functions for dynamic + * executables: + * + * - a C runtime initializer (__libc_preinit), which is called by + * the dynamic linker when libc.so is loaded. This happens before + * any other initializer (e.g. static C++ constructors in other + * shared libraries the program depends on). + * + * - a program launch function (__libc_init), which is called after + * all dynamic linking has been performed. Technically, it is called + * from arch-$ARCH/bionic/crtbegin_dynamic.S which is itself called + * by the dynamic linker after all libraries have been loaded and + * initialized. + */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <elf.h> +#include "atexit.h" +#include "KernelArgumentBlock.h" +#include "libc_init_common.h" +#include <bionic_tls.h> + +extern "C" { + extern void pthread_debug_init(void); + extern void malloc_debug_init(void); + extern void malloc_debug_fini(void); +}; + +// We flag the __libc_preinit function as a constructor to ensure +// that its address is listed in libc.so's .init_array section. +// This ensures that the function is called by the dynamic linker +// as soon as the shared library is loaded. +void __attribute__((constructor)) __libc_preinit(void); + +void __libc_preinit() { + // Read the kernel argument block pointer from TLS. + void* tls = const_cast<void*>(__get_tls()); + KernelArgumentBlock** args_slot = &reinterpret_cast<KernelArgumentBlock**>(tls)[TLS_SLOT_BIONIC_PREINIT]; + KernelArgumentBlock* args = *args_slot; + + // Clear the slot so no other initializer sees its value. + // __libc_init_common() will change the TLS area so the old one won't be accessible anyway. + *args_slot = NULL; + + __libc_init_common(*args); + + // Hooks for the debug malloc and pthread libraries to let them know that we're starting up. + pthread_debug_init(); + malloc_debug_init(); +} + +void __libc_postfini() { + // A hook for the debug malloc library to let it know that we're shutting down. + malloc_debug_fini(); +} + +// This function is called from the executable's _start entry point +// (see arch-$ARCH/bionic/crtbegin_dynamic.S), which is itself +// called by the dynamic linker after it has loaded all shared +// libraries the executable depends on. +// +// Note that the dynamic linker has also run all constructors in the +// executable at this point. +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void), + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors) { + + KernelArgumentBlock args(raw_args); + + // Several Linux ABIs don't pass the onexit pointer, and the ones that + // do never use it. Therefore, we ignore it. + + // The executable may have its own destructors listed in its .fini_array + // so we need to ensure that these are called when the program exits + // normally. + if (structors->fini_array) { + __cxa_atexit(__libc_fini,structors->fini_array,NULL); + } + + exit(slingshot(args.argc, args.argv, args.envp)); +} diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.cpp index 24a4397..e5506d1 100644 --- a/libc/bionic/libc_init_static.c +++ b/libc/bionic/libc_init_static.cpp @@ -37,19 +37,20 @@ * arrays that must be run before the program's 'main' routine is launched. */ +#include <elf.h> +#include <errno.h> #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <stdint.h> -#include <elf.h> -#include "pthread_internal.h" +#include <sys/auxv.h> +#include <sys/mman.h> + #include "atexit.h" +#include "bionic_tls.h" +#include "KernelArgumentBlock.h" #include "libc_init_common.h" - -#include <bionic_tls.h> -#include <errno.h> -#include <sys/mman.h> -#include <sys/auxv.h> +#include "pthread_internal.h" // Returns the address of the page containing address 'x'. #define PAGE_START(x) ((x) & PAGE_MASK) @@ -58,71 +59,53 @@ // itself at the start of a page. #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1)) -static void call_array(void(**list)()) -{ - // First element is -1, list is null-terminated - while (*++list) { - (*list)(); - } +static void call_array(void(**list)()) { + // First element is -1, list is null-terminated + while (*++list) { + (*list)(); + } } static void apply_gnu_relro() { - Elf32_Phdr *phdr_start; - unsigned long int phdr_ct; - Elf32_Phdr *phdr; - - phdr_start = (Elf32_Phdr *) getauxval(AT_PHDR); - phdr_ct = getauxval(AT_PHNUM); + Elf32_Phdr* phdr_start = reinterpret_cast<Elf32_Phdr*>(getauxval(AT_PHDR)); + unsigned long int phdr_ct = getauxval(AT_PHNUM); - for (phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) { - if (phdr->p_type != PT_GNU_RELRO) - continue; - - Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr); - Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz); - - // Check return value here? What do we do if we fail? - mprotect((void *) seg_page_start, - seg_page_end - seg_page_start, - PROT_READ); + for (Elf32_Phdr* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) { + if (phdr->p_type != PT_GNU_RELRO) { + continue; } -} -__noreturn void __libc_init(uintptr_t *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors) -{ - int argc; - char **argv, **envp; + Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr); + Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz); - __libc_init_tls(NULL); - - /* Initialize the C runtime environment */ - __libc_init_common(elfdata); + // Check return value here? What do we do if we fail? + mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, PROT_READ); + } +} - apply_gnu_relro(); +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void), + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors) { + __libc_init_tls(NULL); - /* Several Linux ABIs don't pass the onexit pointer, and the ones that - * do never use it. Therefore, we ignore it. - */ + KernelArgumentBlock args(raw_args); + __libc_init_common(args); - /* pre-init array. */ - call_array(structors->preinit_array); + apply_gnu_relro(); - // call static constructors - call_array(structors->init_array); + // Several Linux ABIs don't pass the onexit pointer, and the ones that + // do never use it. Therefore, we ignore it. - argc = (int) *elfdata; - argv = (char**)(elfdata + 1); - envp = argv + argc + 1; + call_array(structors->preinit_array); + call_array(structors->init_array); - /* The executable may have its own destructors listed in its .fini_array - * so we need to ensure that these are called when the program exits - * normally. - */ - if (structors->fini_array) - __cxa_atexit(__libc_fini,structors->fini_array,NULL); + // The executable may have its own destructors listed in its .fini_array + // so we need to ensure that these are called when the program exits + // normally. + if (structors->fini_array != NULL) { + __cxa_atexit(__libc_fini,structors->fini_array,NULL); + } - exit(slingshot(argc, argv, envp)); + exit(slingshot(args.argc, args.argv, args.envp)); } diff --git a/libc/private/KernelArgumentBlock.h b/libc/private/KernelArgumentBlock.h new file mode 100644 index 0000000..d777267 --- /dev/null +++ b/libc/private/KernelArgumentBlock.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KERNEL_ARGUMENT_BLOCK_H +#define KERNEL_ARGUMENT_BLOCK_H + +#include <elf.h> +#include <stdint.h> +#include <sys/auxv.h> + +// When the kernel starts the dynamic linker, it passes a pointer to a block +// of memory containing argc, the argv array, the environment variable array, +// and the array of ELF aux vectors. This class breaks that block up into its +// constituents for easy access. +class KernelArgumentBlock { + public: + KernelArgumentBlock(void* raw_args) { + uint32_t* args = reinterpret_cast<uint32_t*>(raw_args); + argc = static_cast<int>(*args); + argv = reinterpret_cast<char**>(args + 1); + envp = argv + argc + 1; + + // Skip over all environment variable definitions to find aux vector. + // The end of the environment block is marked by two NULL pointers. + char** p = envp; + while (*p != NULL) { + ++p; + } + ++p; // Skip second NULL; + + auxv = reinterpret_cast<Elf32_auxv_t*>(p); + } + + // Similar to ::getauxval but doesn't require the libc global variables to be set up, + // so it's safe to call this really early on. This function also lets you distinguish + // between the inability to find the given type and its value just happening to be 0. + unsigned long getauxval(unsigned long type, bool* found_match = NULL) { + for (Elf32_auxv_t* v = auxv; v->a_type != AT_NULL; ++v) { + if (v->a_type == type) { + if (found_match != NULL) { + *found_match = true; + } + return v->a_un.a_val; + } + } + if (found_match != NULL) { + *found_match = false; + } + return 0; + } + + int argc; + char** argv; + char** envp; + Elf32_auxv_t* auxv; + + private: + // Disallow copy and assignment. + KernelArgumentBlock(const KernelArgumentBlock&); + void operator=(const KernelArgumentBlock&); +}; + +#endif // KERNEL_ARGUMENT_BLOCK_H diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index f661ccf..920f506 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -134,7 +134,7 @@ extern void* __get_tls( void ); extern void* __get_stack_base(int *p_stack_size); /* Initialize the TLS. */ -extern void __libc_init_tls(unsigned** elfdata); +extern void __libc_init_tls(void* kernel_argument_block); __END_DECLS diff --git a/libc/stdlib/atexit.h b/libc/stdlib/atexit.h index 1b23565..39df2e1 100644 --- a/libc/stdlib/atexit.h +++ b/libc/stdlib/atexit.h @@ -44,8 +44,12 @@ struct atexit { } fns[1]; /* the table itself */ }; +__BEGIN_DECLS + extern int __atexit_invalid; extern struct atexit *__atexit; /* points to head of LIFO stack */ int __cxa_atexit(void (*)(void *), void *, void *); void __cxa_finalize(void *); + +__END_DECLS |