diff options
author | Ryan Prichard <rprichard@google.com> | 2024-04-04 22:27:34 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-04-04 22:27:34 +0000 |
commit | 1d141ce1c81a0a1fa71ae47f19d12aaca0e8f819 (patch) | |
tree | 584dea4a3696fed14b68d724bb70321f2c9a2e4a | |
parent | e5640666968f8cf57ee5f7ece24ae10a4e431a44 (diff) | |
parent | 2a901e69373c09d5563a5c0a24a3083ff7f6808a (diff) | |
download | bionic-1d141ce1c81a0a1fa71ae47f19d12aaca0e8f819.tar.gz |
Merge "Call relocate_relr before the ifunc resolvers" into main
-rw-r--r-- | linker/linker.cpp | 12 | ||||
-rw-r--r-- | linker/linker.h | 1 | ||||
-rw-r--r-- | linker/linker_main.cpp | 48 | ||||
-rw-r--r-- | linker/linker_relocate.cpp | 8 | ||||
-rw-r--r-- | linker/linker_soinfo.h | 2 |
5 files changed, 44 insertions, 27 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index f813c1a68..8b467a376 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2788,7 +2788,7 @@ bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Wor return true; } -void soinfo::apply_relr_reloc(ElfW(Addr) offset) { +static void apply_relr_reloc(ElfW(Addr) offset, ElfW(Addr) load_bias) { ElfW(Addr) address = offset + load_bias; *reinterpret_cast<ElfW(Addr)*>(address) += load_bias; } @@ -2796,20 +2796,18 @@ void soinfo::apply_relr_reloc(ElfW(Addr) offset) { // Process relocations in SHT_RELR section (experimental). // Details of the encoding are described in this post: // https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ -bool soinfo::relocate_relr() { - ElfW(Relr)* begin = relr_; - ElfW(Relr)* end = relr_ + relr_count_; +bool relocate_relr(const ElfW(Relr)* begin, const ElfW(Relr)* end, ElfW(Addr) load_bias) { constexpr size_t wordsize = sizeof(ElfW(Addr)); ElfW(Addr) base = 0; - for (ElfW(Relr)* current = begin; current < end; ++current) { + for (const ElfW(Relr)* current = begin; current < end; ++current) { ElfW(Relr) entry = *current; ElfW(Addr) offset; if ((entry&1) == 0) { // Even entry: encodes the offset for next relocation. offset = static_cast<ElfW(Addr)>(entry); - apply_relr_reloc(offset); + apply_relr_reloc(offset, load_bias); // Set base offset for subsequent bitmap entries. base = offset + wordsize; continue; @@ -2820,7 +2818,7 @@ bool soinfo::relocate_relr() { while (entry != 0) { entry >>= 1; if ((entry&1) != 0) { - apply_relr_reloc(offset); + apply_relr_reloc(offset, load_bias); } offset += wordsize; } diff --git a/linker/linker.h b/linker/linker.h index 275182fd4..ac2222d47 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -179,6 +179,7 @@ struct address_space_params { int get_application_target_sdk_version(); ElfW(Versym) find_verdef_version_index(const soinfo* si, const version_info* vi); bool validate_verdef_section(const soinfo* si); +bool relocate_relr(const ElfW(Relr)* begin, const ElfW(Relr)* end, ElfW(Addr) load_bias); struct platform_properties { #if defined(__aarch64__) diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index b1fa9796d..77769f553 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -635,9 +635,10 @@ static void call_ifunc_resolvers_for_section(RelType* begin, RelType* end) { } } -static void call_ifunc_resolvers() { - // Find the IRELATIVE relocations using the DT_JMPREL and DT_PLTRELSZ, or - // DT_RELA/DT_RELASZ (DT_REL/DT_RELSZ on ILP32). +static void relocate_linker() { + // The linker should only have relative relocations (in RELR) and IRELATIVE + // relocations. Find the IRELATIVE relocations using the DT_JMPREL and + // DT_PLTRELSZ, or DT_RELA/DT_RELASZ (DT_REL/DT_RELSZ on ILP32). auto ehdr = reinterpret_cast<ElfW(Addr)>(&__ehdr_start); auto* phdr = reinterpret_cast<ElfW(Phdr)*>(ehdr + __ehdr_start.e_phoff); for (size_t i = 0; i != __ehdr_start.e_phnum; ++i) { @@ -645,21 +646,33 @@ static void call_ifunc_resolvers() { continue; } auto *dyn = reinterpret_cast<ElfW(Dyn)*>(ehdr + phdr[i].p_vaddr); - ElfW(Addr) pltrel = 0, pltrelsz = 0, rel = 0, relsz = 0; + ElfW(Addr) relr = 0, relrsz = 0, pltrel = 0, pltrelsz = 0, rel = 0, relsz = 0; for (size_t j = 0, size = phdr[i].p_filesz / sizeof(ElfW(Dyn)); j != size; ++j) { + const auto tag = dyn[j].d_tag; + const auto val = dyn[j].d_un.d_ptr; // We don't currently handle IRELATIVE relocations in DT_ANDROID_REL[A]. // We disabled DT_ANDROID_REL[A] at build time; verify that it was actually disabled. - CHECK(dyn[j].d_tag != DT_ANDROID_REL && dyn[j].d_tag != DT_ANDROID_RELA); - if (dyn[j].d_tag == DT_JMPREL) { - pltrel = dyn[j].d_un.d_ptr; - } else if (dyn[j].d_tag == DT_PLTRELSZ) { - pltrelsz = dyn[j].d_un.d_ptr; - } else if (dyn[j].d_tag == kRelTag) { - rel = dyn[j].d_un.d_ptr; - } else if (dyn[j].d_tag == kRelSzTag) { - relsz = dyn[j].d_un.d_ptr; + CHECK(tag != DT_ANDROID_REL && tag != DT_ANDROID_RELA); + if (tag == DT_RELR || tag == DT_ANDROID_RELR) { + relr = val; + } else if (tag == DT_RELRSZ || tag == DT_ANDROID_RELRSZ) { + relrsz = val; + } else if (tag == DT_JMPREL) { + pltrel = val; + } else if (tag == DT_PLTRELSZ) { + pltrelsz = val; + } else if (tag == kRelTag) { + rel = val; + } else if (tag == kRelSzTag) { + relsz = val; } } + // Apply RELR relocations first so that the GOT is initialized for ifunc + // resolvers. + if (relr && relrsz) { + relocate_relr(reinterpret_cast<ElfW(Relr*)>(ehdr + relr), + reinterpret_cast<ElfW(Relr*)>(ehdr + relr + relrsz), ehdr); + } if (pltrel && pltrelsz) { call_ifunc_resolvers_for_section(reinterpret_cast<RelType*>(ehdr + pltrel), reinterpret_cast<RelType*>(ehdr + pltrel + pltrelsz)); @@ -737,8 +750,12 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); - // string.h functions must not be used prior to calling the linker's ifunc resolvers. - call_ifunc_resolvers(); + // Relocate the linker. This step will initialize the GOT, which is needed for + // accessing non-hidden global variables. (On some targets, the stack + // protector uses GOT accesses rather than TLS.) Relocating the linker will + // also call the linker's ifunc resolvers so that string.h functions can be + // used. + relocate_linker(); soinfo tmp_linker_so(nullptr, nullptr, nullptr, 0, 0); @@ -750,7 +767,6 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { tmp_linker_so.phnum = elf_hdr->e_phnum; tmp_linker_so.set_linker_flag(); - // Prelink the linker so we can access linker globals. if (!tmp_linker_so.prelink_image()) __linker_cannot_link(args.argv[0]); if (!tmp_linker_so.link_image(SymbolLookupList(&tmp_linker_so), &tmp_linker_so, nullptr, nullptr)) __linker_cannot_link(args.argv[0]); diff --git a/linker/linker_relocate.cpp b/linker/linker_relocate.cpp index 40299e980..85f7b3aab 100644 --- a/linker/linker_relocate.cpp +++ b/linker/linker_relocate.cpp @@ -609,9 +609,13 @@ bool soinfo::relocate(const SymbolLookupList& lookup_list) { relocator.tlsdesc_args = &tlsdesc_args_; relocator.tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer(); - if (relr_ != nullptr) { + // The linker already applied its RELR relocations in an earlier pass, so + // skip the RELR relocations for the linker. + if (relr_ != nullptr && !is_linker()) { DEBUG("[ relocating %s relr ]", get_realpath()); - if (!relocate_relr()) { + const ElfW(Relr)* begin = relr_; + const ElfW(Relr)* end = relr_ + relr_count_; + if (!relocate_relr(begin, end, load_bias)) { return false; } } diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h index a5d31d58c..9a13af2a6 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -384,8 +384,6 @@ struct soinfo { private: bool relocate(const SymbolLookupList& lookup_list); - bool relocate_relr(); - void apply_relr_reloc(ElfW(Addr) offset); // This part of the structure is only available // when FLAG_NEW_SOINFO is set in this->flags. |