diff options
author | Ryan Prichard <rprichard@google.com> | 2018-05-30 22:32:17 -0700 |
---|---|---|
committer | Ryan Prichard <rprichard@google.com> | 2018-05-31 17:04:52 -0700 |
commit | 742982d3a086473427e71089a6c9ba8df0c365e6 (patch) | |
tree | a713d5bdf5bd92c6f7ab91179be346e941666626 /linker/linker_main.cpp | |
parent | fe55c272adf89ecf14c5aa068119bfadf2c28457 (diff) |
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
Diffstat (limited to 'linker/linker_main.cpp')
-rw-r--r-- | linker/linker_main.cpp | 31 |
1 files 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<uintptr_t>(raw_args); #endif - ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(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<ElfW(Addr)>(&_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<void*>(start_address)); |