aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Prichard <rprichard@google.com>2024-04-04 03:05:35 -0700
committerRyan Prichard <rprichard@google.com>2024-04-04 03:23:04 -0700
commit2a901e69373c09d5563a5c0a24a3083ff7f6808a (patch)
treefddd0ef679fedcd094a27f7c48f2468d68b84bd3
parent2931c646d9f1a01cfa55584a1a467e3271e34830 (diff)
downloadbionic-2a901e69373c09d5563a5c0a24a3083ff7f6808a.tar.gz
Call relocate_relr before the ifunc resolvers
Previously, on RISC-V, the static hwcap variable in __bionic_call_ifunc_resolver resulted in a call to __cxa_guard_acquire, which used a GOT access to __stack_chk_guard, but the GOT hadn't yet been initialized. Fix this problem by applying RELR relocations earlier. Bug: http://b/330725041 Test: lunch aosp_cf_riscv64_phone-trunk_staging-eng; boot device Change-Id: Ib10fdcc0d2c1b875eba6bc5e0115a6768d6f25ee
-rw-r--r--linker/linker.cpp12
-rw-r--r--linker/linker.h1
-rw-r--r--linker/linker_main.cpp48
-rw-r--r--linker/linker_relocate.cpp8
-rw-r--r--linker/linker_soinfo.h2
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.