linker: Process RELR relocations before ANDROID_REL[A].
ANDROID_REL[A] need to be processed after RELR in case it contains
an IRELATIVE relocation with a resolver that accesses data relocated
by RELR.
Bug: 331466607
Change-Id: I50865e67fc1492d75324ef3cb9defef3f8b88421
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 6ac79cf..ad8462a 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -478,6 +478,16 @@
OS private use constants for RELR, nor for ELF files using packed
relocations.
+Prior to API level 35, there was a bug that caused RELR relocations to
+be applied after packed relocations. This meant that ifunc resolvers
+referenced by `R_*_IRELATIVE` relocations in the packed relocation
+section would have been able to read globals with RELR relocations
+before they were relocated. The version of `lld` in the NDK has never
+produced binaries affected by this bug, but third-party toolchains
+should make sure not to store `R_*_IRELATIVE` relocations in packed
+relocation sections in order to maintain compatibility with API levels
+below 35.
+
You can read more about relative relocations
and their long and complicated history at
https://maskray.me/blog/2021-10-31-relative-relocations-and-relr.
diff --git a/linker/linker_relocate.cpp b/linker/linker_relocate.cpp
index 080570d..40299e9 100644
--- a/linker/linker_relocate.cpp
+++ b/linker/linker_relocate.cpp
@@ -609,6 +609,13 @@
relocator.tlsdesc_args = &tlsdesc_args_;
relocator.tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer();
+ if (relr_ != nullptr) {
+ DEBUG("[ relocating %s relr ]", get_realpath());
+ if (!relocate_relr()) {
+ return false;
+ }
+ }
+
if (android_relocs_ != nullptr) {
// check signature
if (android_relocs_size_ > 3 &&
@@ -630,13 +637,6 @@
}
}
- if (relr_ != nullptr) {
- DEBUG("[ relocating %s relr ]", get_realpath());
- if (!relocate_relr()) {
- return false;
- }
- }
-
#if defined(USE_RELA)
if (rela_ != nullptr) {
DEBUG("[ relocating %s rela ]", get_realpath());