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
This commit is contained in:
Ryan Prichard 2018-05-30 22:32:17 -07:00
parent fe55c272ad
commit 742982d3a0
1 changed files with 21 additions and 10 deletions

View File

@ -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));