diff options
Diffstat (limited to 'linker/linker_main.cpp')
-rw-r--r-- | linker/linker_main.cpp | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index bea2e3c82..8ba947f31 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -32,6 +32,7 @@ #include <sys/auxv.h> #include "linker_debug.h" +#include "linker_debuggerd.h" #include "linker_cfi.h" #include "linker_gdb_support.h" #include "linker_globals.h" @@ -39,6 +40,8 @@ #include "linker_tls.h" #include "linker_utils.h" +#include "private/bionic_auxv.h" +#include "private/bionic_call_ifunc_resolver.h" #include "private/bionic_globals.h" #include "private/bionic_tls.h" #include "private/KernelArgumentBlock.h" @@ -46,9 +49,6 @@ #include "android-base/unique_fd.h" #include "android-base/strings.h" #include "android-base/stringprintf.h" -#ifdef __ANDROID__ -#include "debuggerd/handler.h" -#endif #include <async_safe/log.h> #include <bionic/libc_init_common.h> @@ -311,15 +311,7 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load __system_properties_init(); // may use 'environ' // Register the debuggerd signal handler. -#ifdef __ANDROID__ - debuggerd_callbacks_t callbacks = { - .get_abort_message = []() { - return __libc_shared_globals()->abort_msg; - }, - .post_dump = ¬ify_gdb_of_libraries, - }; - debuggerd_init(&callbacks); -#endif + linker_debuggerd_init(); g_linker_logger.ResetState(); @@ -575,6 +567,39 @@ static void set_bss_vma_name(soinfo* si) { } } +// TODO: There is a similar ifunc resolver calling loop in libc_init_static.cpp, but that version +// uses weak symbols, which don't work in the linker prior to its relocation. This version also +// supports a load bias. When we stop supporting the gold linker in the NDK, then maybe we can use +// non-weak definitions and merge the two loops. +#if defined(USE_RELA) +extern __LIBC_HIDDEN__ ElfW(Rela) __rela_iplt_start[], __rela_iplt_end[]; + +static void call_ifunc_resolvers(ElfW(Addr) load_bias) { + for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias); + ElfW(Addr) resolver = r->r_addend + load_bias; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#else +extern __LIBC_HIDDEN__ ElfW(Rel) __rel_iplt_start[], __rel_iplt_end[]; + +static void call_ifunc_resolvers(ElfW(Addr) load_bias) { + for (ElfW(Rel) *r = __rel_iplt_start; r != __rel_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias); + ElfW(Addr) resolver = *offset + load_bias; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#endif + +// Usable before ifunc resolvers have been called. This function is compiled with -ffreestanding. +static void linker_memclr(void* dst, size_t cnt) { + for (size_t i = 0; i < cnt; ++i) { + reinterpret_cast<char*>(dst)[i] = '\0'; + } +} + // Detect an attempt to run the linker on itself. e.g.: // /system/bin/linker64 /system/bin/linker64 // Use priority-1 to run this constructor before other constructors. @@ -608,7 +633,8 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& linker_so); extern "C" ElfW(Addr) __linker_init(void* raw_args) { // Initialize TLS early so system calls and errno work. KernelArgumentBlock args(raw_args); - bionic_tcb temp_tcb = {}; + bionic_tcb temp_tcb __attribute__((uninitialized)); + linker_memclr(&temp_tcb, sizeof(temp_tcb)); __libc_init_main_thread_early(args, &temp_tcb); // When the linker is run by itself (rather than as an interpreter for @@ -626,11 +652,15 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); + // string.h functions must not be used prior to calling the linker's ifunc resolvers. + const ElfW(Addr) load_bias = get_elf_exec_load_bias(elf_hdr); + call_ifunc_resolvers(load_bias); + soinfo tmp_linker_so(nullptr, nullptr, nullptr, 0, 0); tmp_linker_so.base = linker_addr; tmp_linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); - tmp_linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); + tmp_linker_so.load_bias = load_bias; tmp_linker_so.dynamic = nullptr; tmp_linker_so.phdr = phdr; tmp_linker_so.phnum = elf_hdr->e_phnum; |