aboutsummaryrefslogtreecommitdiffstats
path: root/linker/linker_main.cpp
diff options
context:
space:
mode:
authorDimitry Ivanov <dimitry@google.com>2017-03-23 16:17:15 -0700
committerDimitry Ivanov <dimitry@google.com>2017-03-23 17:12:59 -0700
commit9b1cc4bb9cd84c2a52b8183a418e9dbb41f59959 (patch)
tree30c02abec3509a67589add48341d475c78e71f4e /linker/linker_main.cpp
parente98d1e68ce37bb9238e3c50ea6b01d1057adb2eb (diff)
downloadandroid_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.cpp35
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().