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
diff --git a/linker/linker.cpp b/linker/linker.cpp
index f813c1a..8b467a3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2788,7 +2788,7 @@
   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 @@
 // 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 @@
     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 275182f..ac2222d 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -179,6 +179,7 @@
 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 b1fa979..77769f5 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -635,9 +635,10 @@
   }
 }
 
-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 @@
       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 @@
   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 @@
   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 40299e9..85f7b3a 100644
--- a/linker/linker_relocate.cpp
+++ b/linker/linker_relocate.cpp
@@ -609,9 +609,13 @@
   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 a5d31d5..9a13af2 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -384,8 +384,6 @@
 
  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.