From 742982d3a086473427e71089a6c9ba8df0c365e6 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 30 May 2018 22:32:17 -0700 Subject: [PATCH] Avoid post-reloc GOT usage in __linker_init A GOT lookup happening prior to soinfo::link_image causes a segfault. With -O0, the compiler moves GOT lookups from after __linker_init's link_image call to the start of __linker_init. Rename the existing __linker_init_post_relocation to linker_main, then extract the existing post-link_image code to a new __linker_init_post_relocation function. Bug: http://b/80503879 Test: /data/nativetest64/bionic-unit-tests/bionic-unit-tests Test: manual Change-Id: If8a470f8360acbe35e2a308b0fbff570de6131cf --- linker/linker_main.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index 331f83171..1a0d1642b 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -228,12 +228,7 @@ static void __linker_cannot_link(const char* argv0) { _exit(EXIT_FAILURE); } -/* - * This code is called after the linker has linked itself and - * fixed it's own GOT. It is safe to make references to externs - * and other non-local data at this point. - */ -static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) { +static ElfW(Addr) linker_main(KernelArgumentBlock& args) { ProtectedDataGuard guard; #if TIMING @@ -498,6 +493,11 @@ static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { return 0; } +static ElfW(Addr) __attribute__((noinline)) +__linker_init_post_relocation(KernelArgumentBlock& args, + ElfW(Addr) linker_addr, + soinfo& linker_so); + /* * This is the entry point for the linker, called from begin.S. This * method is responsible for fixing the linker's own relocations, and @@ -531,7 +531,6 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { linker_addr += reinterpret_cast(raw_args); #endif - ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff); @@ -556,6 +555,19 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { // functions at this point. if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]); + return __linker_init_post_relocation(args, linker_addr, linker_so); +} + +/* + * This code is called after the linker has linked itself and fixed its own + * GOT. It is safe to make references to externs and other non-local data at + * this point. The compiler sometimes moves GOT references earlier in a + * function, so avoid inlining this function (http://b/80503879). + */ +static ElfW(Addr) __attribute__((noinline)) +__linker_init_post_relocation(KernelArgumentBlock& args, + ElfW(Addr) linker_addr, + soinfo& linker_so) { // Initialize the main thread (including TLS, so system calls really work). __libc_init_main_thread(args); @@ -580,6 +592,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { // // This happens when user tries to run 'adb shell /system/bin/linker' // see also https://code.google.com/p/android/issues/detail?id=63174 + ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); if (reinterpret_cast(&_start) == entry_point) { async_safe_format_fd(STDOUT_FILENO, "This is %s, the helper program for dynamic executables.\n", @@ -595,10 +608,8 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { sonext = solist = get_libdl_info(kLinkerPath, linker_so, linker_link_map); g_default_namespace.add_soinfo(solist); - // We have successfully fixed our own relocations. It's safe to run - // the main part of the linker now. args.abort_message_ptr = &g_abort_message; - ElfW(Addr) start_address = __linker_init_post_relocation(args); + ElfW(Addr) start_address = linker_main(args); INFO("[ Jumping to _start (%p)... ]", reinterpret_cast(start_address));