diff --git a/libc/Android.mk b/libc/Android.mk index 301be371f..c7828cfd6 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 0e2d31ea9..cc587975d 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 __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 5106d9e0a..63e58a6d2 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 __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 38a05fc21..fd225e006 100644 --- a/libc/bionic/getauxval.cpp +++ b/libc/bionic/getauxval.cpp @@ -32,17 +32,13 @@ #include #include -__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 similarity index 82% rename from libc/bionic/libc_init_common.c rename to libc/bionic/libc_init_common.cpp index 86e1eb574..6b4ae2c90 100644 --- a/libc/bionic/libc_init_common.c +++ b/libc/bionic/libc_init_common.cpp @@ -30,29 +30,31 @@ #include #include #include +#include #include #include #include "pthread_internal.h" #include "atexit.h" +#include "KernelArgumentBlock.h" #include "libc_init_common.h" #include #include #include -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 char** environ; -/* from asm/page.h */ +// Declared in . 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(""); // 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] : ""; - 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(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 c55594b98..23ac30554 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 +#include -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 3a7e8e23c..000000000 --- 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 -#include -#include -#include -#include -#include "atexit.h" -#include "libc_init_common.h" -#include - -/* 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 000000000..af03fb05f --- /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 +#include +#include +#include +#include +#include "atexit.h" +#include "KernelArgumentBlock.h" +#include "libc_init_common.h" +#include + +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(__get_tls()); + KernelArgumentBlock** args_slot = &reinterpret_cast(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 similarity index 56% rename from libc/bionic/libc_init_static.c rename to libc/bionic/libc_init_static.cpp index 24a4397a8..e5506d1f1 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 +#include #include +#include #include #include -#include -#include -#include "pthread_internal.h" -#include "atexit.h" -#include "libc_init_common.h" - -#include -#include -#include #include +#include + +#include "atexit.h" +#include "bionic_tls.h" +#include "KernelArgumentBlock.h" +#include "libc_init_common.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; + Elf32_Phdr* phdr_start = reinterpret_cast(getauxval(AT_PHDR)); + unsigned long int phdr_ct = getauxval(AT_PHNUM); - phdr_start = (Elf32_Phdr *) getauxval(AT_PHDR); - 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; } + + 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(reinterpret_cast(seg_page_start), seg_page_end - seg_page_start, PROT_READ); + } } -__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; +__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); - __libc_init_tls(NULL); + KernelArgumentBlock args(raw_args); + __libc_init_common(args); - /* Initialize the C runtime environment */ - __libc_init_common(elfdata); + apply_gnu_relro(); - apply_gnu_relro(); + // Several Linux ABIs don't pass the onexit pointer, and the ones that + // do never use it. Therefore, we ignore it. - /* Several Linux ABIs don't pass the onexit pointer, and the ones that - * do never use it. Therefore, we ignore it. - */ + call_array(structors->preinit_array); + call_array(structors->init_array); - /* pre-init array. */ - call_array(structors->preinit_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 != NULL) { + __cxa_atexit(__libc_fini,structors->fini_array,NULL); + } - // call static constructors - call_array(structors->init_array); - - argc = (int) *elfdata; - argv = (char**)(elfdata + 1); - envp = argv + argc + 1; - - /* 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)); + 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 000000000..d77726733 --- /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 +#include +#include + +// 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(raw_args); + argc = static_cast(*args); + argv = reinterpret_cast(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(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 f661ccf24..920f5067b 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 1b23565dd..39df2e130 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 diff --git a/linker/arch/x86/begin.c b/linker/arch/x86/begin.c index 4f3e0ab3a..cdc98e065 100755 --- a/linker/arch/x86/begin.c +++ b/linker/arch/x86/begin.c @@ -26,24 +26,23 @@ * SUCH DAMAGE. */ -#include +#include -extern unsigned __linker_init(unsigned int *elfdata); +extern unsigned __linker_init(void* raw_args); -__attribute__((visibility("hidden"))) -void _start() { +__LIBC_HIDDEN__ void _start() { void (*start)(void); - void* elfdata = (void*) ((uintptr_t) __builtin_frame_address(0) + sizeof(void*)); - start = (void(*)(void))__linker_init(elfdata); + void* raw_args = (void*) ((uintptr_t) __builtin_frame_address(0) + sizeof(void*)); + start = (void(*)(void))__linker_init(raw_args); /* linker init returns (%eax) the _entry address in the main image */ - /* entry point expects sp to point to elfdata */ + /* entry point expects sp to point to raw_args */ __asm__ ( "mov %0, %%esp\n\t" "jmp *%1\n\t" - : : "r"(elfdata), "r"(start) : + : : "r"(raw_args), "r"(start) : ); /* Unreachable */ diff --git a/linker/linker.cpp b/linker/linker.cpp index 502035bd5..77c29a1d6 100755 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -42,6 +42,7 @@ // Private C library headers. #include #include +#include #include #include @@ -1771,15 +1772,8 @@ static bool soinfo_link_image(soinfo* si) { * fixed it's own GOT. It is safe to make references to externs * and other non-local data at this point. */ -static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linker_base) -{ - static soinfo linker_soinfo; - - int argc = (int) *elfdata; - char **argv = (char**) (elfdata + 1); - unsigned *vecs = (unsigned*) (argv + argc + 1); - - /* NOTE: we store the elfdata pointer on a special location +static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigned linker_base) { + /* NOTE: we store the args pointer on a special location * of the temporary TLS area in order to pass it to * the C Library's runtime initializer. * @@ -1787,7 +1781,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke * to point to a different location to ensure that no other * shared library constructor can access it. */ - __libc_init_tls(elfdata); + __libc_init_tls(&args); #if TIMING struct timeval t0, t1; @@ -1795,7 +1789,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke #endif // Initialize environment functions, and get to the ELF aux vectors table. - vecs = linker_env_init(vecs); + linker_env_init(args); debugger_init(); @@ -1815,9 +1809,8 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke } INFO("[ android linker & debugger ]\n"); - DEBUG("elfdata @ 0x%08x\n", (unsigned)elfdata); - soinfo* si = soinfo_alloc(argv[0]); + soinfo* si = soinfo_alloc(args.argv[0]); if (si == NULL) { exit(EXIT_FAILURE); } @@ -1827,7 +1820,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke link_map* map = &(si->linkmap); map->l_addr = 0; - map->l_name = argv[0]; + map->l_name = args.argv[0]; map->l_prev = NULL; map->l_next = NULL; @@ -1841,9 +1834,11 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke * Don't use soinfo_alloc(), because the linker shouldn't * be on the soinfo list. */ - strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name); + static soinfo linker_soinfo; + strlcpy(linker_soinfo.name, "/system/bin/linker", sizeof(linker_soinfo.name)); linker_soinfo.flags = 0; linker_soinfo.base = linker_base; + /* * Set the dynamic field in the link map otherwise gdb will complain with * the following: @@ -1851,42 +1846,29 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke * expected address (wrong library or version mismatch?) */ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base; - Elf32_Phdr *phdr = - (Elf32_Phdr *)((unsigned char *) linker_base + elf_hdr->e_phoff); + Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, &linker_soinfo.dynamic, NULL, NULL); insert_soinfo_into_debug_map(&linker_soinfo); - /* extract information passed from the kernel */ - while (vecs[0] != 0){ - switch(vecs[0]){ - case AT_PHDR: - si->phdr = (Elf32_Phdr*) vecs[1]; - break; - case AT_PHNUM: - si->phnum = (int) vecs[1]; - break; - case AT_ENTRY: - si->entry = vecs[1]; - break; - } - vecs += 2; - } + // Extract information passed from the kernel. + si->phdr = reinterpret_cast(args.getauxval(AT_PHDR)); + si->phnum = args.getauxval(AT_PHNUM); + si->entry = args.getauxval(AT_ENTRY); /* Compute the value of si->base. We can't rely on the fact that * the first entry is the PHDR because this will not be true * for certain executables (e.g. some in the NDK unit test suite) */ - int nn; si->base = 0; si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = 0; - for ( nn = 0; nn < si->phnum; nn++ ) { - if (si->phdr[nn].p_type == PT_PHDR) { - si->load_bias = (Elf32_Addr)si->phdr - si->phdr[nn].p_vaddr; - si->base = (Elf32_Addr) si->phdr - si->phdr[nn].p_offset; - break; - } + for (int i = 0; i < si->phnum; ++i) { + if (si->phdr[i].p_type == PT_PHDR) { + si->load_bias = reinterpret_cast(si->phdr) - si->phdr[i].p_vaddr; + si->base = reinterpret_cast(si->phdr) - si->phdr[i].p_offset; + break; + } } si->dynamic = (unsigned *)-1; si->refcount = 1; @@ -1920,13 +1902,13 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke #if TIMING gettimeofday(&t1,NULL); - PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) ( + PRINT("LINKER TIME: %s: %d microseconds\n", e.argv[0], (int) ( (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec) )); #endif #if STATS - PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0], + PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", e.argv[0], linker_stats.count[kRelocAbsolute], linker_stats.count[kRelocRelative], linker_stats.count[kRelocCopy], @@ -1946,7 +1928,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke } } } - PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4); + PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", e.argv[0], count, count * 4); } #endif @@ -1958,31 +1940,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke return si->entry; } -/* - * Find the value of AT_BASE passed to us by the kernel. This is the load - * location of the linker. - */ -static unsigned find_linker_base(unsigned **elfdata) { - int argc = (int) *elfdata; - char **argv = (char**) (elfdata + 1); - unsigned *vecs = (unsigned*) (argv + argc + 1); - while (vecs[0] != 0) { - vecs++; - } - - /* The end of the environment block is marked by two NULL pointers */ - vecs++; - - while(vecs[0]) { - if (vecs[0] == AT_BASE) { - return vecs[1]; - } - vecs += 2; - } - - return 0; // should never happen -} - /* Compute the load-bias of an existing executable. This shall only * be used to compute the load bias of an executable or shared library * that was loaded by the kernel itself. @@ -2018,39 +1975,41 @@ get_elf_exec_load_bias(const Elf32_Ehdr* elf) * relocations, any attempt to reference an extern variable, extern * function, or other GOT reference will generate a segfault. */ -extern "C" unsigned __linker_init(unsigned **elfdata) { - unsigned linker_addr = find_linker_base(elfdata); - Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr; - Elf32_Phdr *phdr = - (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff); +extern "C" unsigned __linker_init(void* raw_args) { + KernelArgumentBlock args(raw_args); - soinfo linker_so; - memset(&linker_so, 0, sizeof(soinfo)); + unsigned linker_addr = args.getauxval(AT_BASE); - linker_so.base = linker_addr; - linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); - linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); - linker_so.dynamic = (unsigned *) -1; - linker_so.phdr = phdr; - linker_so.phnum = elf_hdr->e_phnum; - linker_so.flags |= FLAG_LINKER; + Elf32_Ehdr *elf_hdr = (Elf32_Ehdr*) linker_addr; + Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff); - if (!soinfo_link_image(&linker_so)) { - // It would be nice to print an error message, but if the linker - // can't link itself, there's no guarantee that we'll be able to - // call write() (because it involves a GOT reference). - // - // This situation should never occur unless the linker itself - // is corrupt. - exit(EXIT_FAILURE); - } + soinfo linker_so; + memset(&linker_so, 0, sizeof(soinfo)); - // We have successfully fixed our own relocations. It's safe to run - // the main part of the linker now. - unsigned start_address = __linker_init_post_relocation(elfdata, linker_addr); + linker_so.base = linker_addr; + linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); + linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); + linker_so.dynamic = (unsigned*) -1; + linker_so.phdr = phdr; + linker_so.phnum = elf_hdr->e_phnum; + linker_so.flags |= FLAG_LINKER; - set_soinfo_pool_protection(PROT_READ); + if (!soinfo_link_image(&linker_so)) { + // It would be nice to print an error message, but if the linker + // can't link itself, there's no guarantee that we'll be able to + // call write() (because it involves a GOT reference). + // + // This situation should never occur unless the linker itself + // is corrupt. + exit(EXIT_FAILURE); + } - // Return the address that the calling assembly stub should jump to. - return start_address; + // We have successfully fixed our own relocations. It's safe to run + // the main part of the linker now. + unsigned start_address = __linker_init_post_relocation(args, linker_addr); + + set_soinfo_pool_protection(PROT_READ); + + // Return the address that the calling assembly stub should jump to. + return start_address; } diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp index 8ae5a9d1d..edc659a03 100644 --- a/linker/linker_environ.cpp +++ b/linker/linker_environ.cpp @@ -33,6 +33,8 @@ #include #include +#include + static char** _envp; static bool _AT_SECURE_value = true; @@ -40,21 +42,18 @@ bool get_AT_SECURE() { return _AT_SECURE_value; } -static void __init_AT_SECURE(unsigned* auxv) { +static void __init_AT_SECURE(KernelArgumentBlock& args) { // Check auxv for AT_SECURE first to see if program is setuid, setgid, // has file caps, or caused a SELinux/AppArmor domain transition. - for (unsigned* v = auxv; v[0]; v += 2) { - if (v[0] == AT_SECURE) { - // Kernel told us whether to enable secure mode. - _AT_SECURE_value = v[1]; - return; - } - } + bool kernel_supplied_AT_SECURE; + _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE); // We don't support ancient kernels. - const char* msg = "FATAL: kernel did not supply AT_SECURE\n"; - write(2, msg, strlen(msg)); - exit(EXIT_FAILURE); + if (!kernel_supplied_AT_SECURE) { + const char* msg = "FATAL: kernel did not supply AT_SECURE\n"; + write(2, msg, strlen(msg)); + exit(EXIT_FAILURE); + } } // Check if the environment variable definition at 'envstr' @@ -164,22 +163,12 @@ static void __sanitize_environment_variables() { dst[0] = NULL; } -unsigned* linker_env_init(unsigned* environment_and_aux_vectors) { +void linker_env_init(KernelArgumentBlock& args) { // Store environment pointer - can't be NULL. - _envp = reinterpret_cast(environment_and_aux_vectors); + _envp = args.envp; - // Skip over all environment variable definitions. - // The end of the environment block is marked by two NULL pointers. - unsigned* aux_vectors = environment_and_aux_vectors; - while (aux_vectors[0] != 0) { - ++aux_vectors; - } - ++aux_vectors; - - __init_AT_SECURE(aux_vectors); + __init_AT_SECURE(args); __sanitize_environment_variables(); - - return aux_vectors; } const char* linker_env_get(const char* name) { diff --git a/linker/linker_environ.h b/linker/linker_environ.h index d808728c7..cd7a65b84 100644 --- a/linker/linker_environ.h +++ b/linker/linker_environ.h @@ -29,10 +29,10 @@ #ifndef LINKER_ENVIRON_H #define LINKER_ENVIRON_H -// Call this function before anything else. 'environment_and_aux_vectors' -// must point to the environment block in the ELF data block. The function -// returns the start of the aux vectors after the environment block. -extern unsigned* linker_env_init(unsigned* environment_and_aux_vectors); +struct KernelArgumentBlock; + +// Call this function before any of the other functions in this header file. +extern void linker_env_init(KernelArgumentBlock& args); // Returns the value of environment variable 'name' if defined and not // empty, or NULL otherwise. @@ -41,4 +41,4 @@ extern const char* linker_env_get(const char* name); // Returns the value of this program's AT_SECURE variable. extern bool get_AT_SECURE(); -#endif /* LINKER_ENVIRON_H */ +#endif // LINKER_ENVIRON_H