diff options
author | Dimitry Ivanov <dimitry@google.com> | 2017-03-23 16:17:15 -0700 |
---|---|---|
committer | Dimitry Ivanov <dimitry@google.com> | 2017-03-23 17:12:59 -0700 |
commit | 9b1cc4bb9cd84c2a52b8183a418e9dbb41f59959 (patch) | |
tree | 30c02abec3509a67589add48341d475c78e71f4e /linker/linker_main.cpp | |
parent | e98d1e68ce37bb9238e3c50ea6b01d1057adb2eb (diff) | |
download | android_bionic-9b1cc4bb9cd84c2a52b8183a418e9dbb41f59959.tar.gz android_bionic-9b1cc4bb9cd84c2a52b8183a418e9dbb41f59959.tar.bz2 android_bionic-9b1cc4bb9cd84c2a52b8183a418e9dbb41f59959.zip |
loader: stop relying on AT_BASE
android loader should not rely on the fact
that AT_BASE is set because kernel currently
does not set it when linker is run standalone
(The linker does not have PT_INTERP set)
This commit replaces AT_BASE with calculated value.
Bug: http://b/30739481
Bug: http://b/35890756
Test: run bionic-unit-tests --gtest_filter=dl*
Change-Id: Ic2eb73e4452624b1f2e05f46e99e4c17df0bbc3f
Diffstat (limited to 'linker/linker_main.cpp')
-rw-r--r-- | linker/linker_main.cpp | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index d037a1832..f976ef9a9 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -481,26 +481,20 @@ static void __linker_cannot_link(const char* argv0) { extern "C" ElfW(Addr) __linker_init(void* raw_args) { KernelArgumentBlock args(raw_args); - ElfW(Addr) linker_addr = args.getauxval(AT_BASE); + // AT_BASE is set to 0 in the case when linker is run by iself + // so in order to link the linker it needs to calcuate AT_BASE + // using information at hand. The trick below takes advantage + // of the fact that the value of linktime_addr before relocations + // are run is an offset and this can be used to calculate AT_BASE. + static uintptr_t linktime_addr = reinterpret_cast<uintptr_t>(&linktime_addr); + ElfW(Addr) linker_addr = reinterpret_cast<uintptr_t>(&linktime_addr) - linktime_addr; + 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); soinfo linker_so(nullptr, nullptr, nullptr, 0, 0); - // If the linker is not acting as PT_INTERP entry_point is equal to - // _start. Which means that the linker is running as an executable and - // already linked by PT_INTERP. - // - // This happens when user tries to run 'adb shell /system/bin/linker' - // see also https://code.google.com/p/android/issues/detail?id=63174 - if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { - __libc_format_fd(STDOUT_FILENO, - "This is %s, the helper program for dynamic executables.\n", - args.argv[0]); - exit(0); - } - 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); @@ -547,6 +541,19 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { // Initialize the linker's own global variables linker_so.call_constructors(); + // If the linker is not acting as PT_INTERP entry_point is equal to + // _start. Which means that the linker is running as an executable and + // already linked by PT_INTERP. + // + // This happens when user tries to run 'adb shell /system/bin/linker' + // see also https://code.google.com/p/android/issues/detail?id=63174 + if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { + __libc_format_fd(STDOUT_FILENO, + "This is %s, the helper program for dynamic executables.\n", + args.argv[0]); + exit(0); + } + // Initialize static variables. Note that in order to // get correct libdl_info we need to call constructors // before get_libdl_info(). |