aboutsummaryrefslogtreecommitdiff
path: root/linker/linker_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linker/linker_main.cpp')
-rw-r--r--linker/linker_main.cpp75
1 files changed, 20 insertions, 55 deletions
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 9e5be345d..2a690e9a0 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -39,7 +39,6 @@
#include "linker_globals.h"
#include "linker_phdr.h"
#include "linker_relocate.h"
-#include "linker_relocs.h"
#include "linker_tls.h"
#include "linker_utils.h"
@@ -597,66 +596,31 @@ static void set_bss_vma_name(soinfo* si) {
}
}
+// TODO: There is a similar ifunc resolver calling loop in libc_init_static.cpp, but that version
+// uses weak symbols, which don't work in the linker prior to its relocation. This version also
+// supports a load bias. When we stop supporting the gold linker in the NDK, then maybe we can use
+// non-weak definitions and merge the two loops.
#if defined(USE_RELA)
-using RelType = ElfW(Rela);
-const unsigned kRelTag = DT_RELA;
-const unsigned kRelSzTag = DT_RELASZ;
-#else
-using RelType = ElfW(Rel);
-const unsigned kRelTag = DT_REL;
-const unsigned kRelSzTag = DT_RELSZ;
-#endif
+extern __LIBC_HIDDEN__ ElfW(Rela) __rela_iplt_start[], __rela_iplt_end[];
-extern __LIBC_HIDDEN__ ElfW(Ehdr) __ehdr_start;
-
-static void call_ifunc_resolvers_for_section(RelType* begin, RelType* end) {
- auto ehdr = reinterpret_cast<ElfW(Addr)>(&__ehdr_start);
- for (RelType *r = begin; r != end; ++r) {
- if (ELFW(R_TYPE)(r->r_info) != R_GENERIC_IRELATIVE) {
- continue;
- }
- ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(ehdr + r->r_offset);
-#if defined(USE_RELA)
- ElfW(Addr) resolver = ehdr + r->r_addend;
-#else
- ElfW(Addr) resolver = ehdr + *offset;
-#endif
+static void call_ifunc_resolvers(ElfW(Addr) load_bias) {
+ for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) {
+ ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias);
+ ElfW(Addr) resolver = r->r_addend + load_bias;
*offset = __bionic_call_ifunc_resolver(resolver);
}
}
+#else
+extern __LIBC_HIDDEN__ ElfW(Rel) __rel_iplt_start[], __rel_iplt_end[];
-static void call_ifunc_resolvers() {
- // Find the IRELATIVE relocations using the DT_JMPREL and DT_PLTRELSZ, or DT_RELA? and DT_RELA?SZ
- // dynamic tags.
- 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) {
- if (phdr[i].p_type != PT_DYNAMIC) {
- continue;
- }
- auto *dyn = reinterpret_cast<ElfW(Dyn)*>(ehdr + phdr[i].p_vaddr);
- ElfW(Addr) pltrel = 0, pltrelsz = 0, rel = 0, relsz = 0;
- for (size_t j = 0, size = phdr[i].p_filesz / sizeof(ElfW(Dyn)); j != size; ++j) {
- 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;
- }
- }
- if (pltrel && pltrelsz) {
- call_ifunc_resolvers_for_section(reinterpret_cast<RelType*>(ehdr + pltrel),
- reinterpret_cast<RelType*>(ehdr + pltrel + pltrelsz));
- }
- if (rel && relsz) {
- call_ifunc_resolvers_for_section(reinterpret_cast<RelType*>(ehdr + rel),
- reinterpret_cast<RelType*>(ehdr + rel + relsz));
- }
+static void call_ifunc_resolvers(ElfW(Addr) load_bias) {
+ for (ElfW(Rel) *r = __rel_iplt_start; r != __rel_iplt_end; ++r) {
+ ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias);
+ ElfW(Addr) resolver = *offset + load_bias;
+ *offset = __bionic_call_ifunc_resolver(resolver);
}
}
+#endif
// Usable before ifunc resolvers have been called. This function is compiled with -ffreestanding.
static void linker_memclr(void* dst, size_t cnt) {
@@ -718,13 +682,14 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
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();
+ const ElfW(Addr) load_bias = get_elf_exec_load_bias(elf_hdr);
+ call_ifunc_resolvers(load_bias);
soinfo tmp_linker_so(nullptr, nullptr, nullptr, 0, 0);
tmp_linker_so.base = linker_addr;
tmp_linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
- tmp_linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
+ tmp_linker_so.load_bias = load_bias;
tmp_linker_so.dynamic = nullptr;
tmp_linker_so.phdr = phdr;
tmp_linker_so.phnum = elf_hdr->e_phnum;