linker: simpler encoding for SHT_RELR sections.
This change modifies the encoding used in SHT_RELR sections to a simpler
version that gives better results. This encoding was suggested by Andrew
Grieve and is described in this post on generic-abi@googlegroups.com:
https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ
Bug: None
Test: Built image for marlin, flashed on device, ran arm and
aarch64 binaries containing '.relr.dyn' sections using
the new encoding.
Change-Id: I266affe0fbad91dc375995985a221cb02499447b
diff --git a/libc/include/elf.h b/libc/include/elf.h
index bda11f5..a8d62db 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -194,13 +194,9 @@
Elf64_Word vna_next;
} Elf64_Vernaux;
-/* Relocation table entry for relative (in section of type SHT_RELR). */
+/* Relocation table entry for relative (in section of type SHT_RELR). */
typedef Elf32_Word Elf32_Relr;
typedef Elf64_Xword Elf64_Relr;
-#define ELF32_R_JUMP(val) ((val) >> 24)
-#define ELF32_R_BITS(val) ((val) & 0xffffff)
-#define ELF64_R_JUMP(val) ((val) >> 56)
-#define ELF64_R_BITS(val) ((val) & 0xffffffffffffff)
/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html */
#define DF_ORIGIN 0x00000001
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 05efc55..7489721 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2595,31 +2595,46 @@
return true;
}
+void soinfo::apply_relr_reloc(ElfW(Addr) offset) {
+ ElfW(Addr) address = offset + load_bias;
+ *reinterpret_cast<ElfW(Addr)*>(address) += load_bias;
+}
+
// Process relocations in SHT_RELR section (experimental).
-// See the original proposal for details of the encoding:
-// - https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+// 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_;
+ constexpr size_t wordsize = sizeof(ElfW(Addr));
- ElfW(Addr) offset = 0;
+ ElfW(Addr) base = 0;
for (ElfW(Relr)* current = begin; current < end; ++current) {
- ElfW(Addr) jump = ELFW(R_JUMP)(*current);
- ElfW(Addr) bits = ELFW(R_BITS)(*current);
- offset += jump * sizeof(ElfW(Addr));
- if (jump == 0) {
- ++current;
- offset = *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);
+ // Set base offset for subsequent bitmap entries.
+ base = offset + wordsize;
+ continue;
}
- ElfW(Addr) r_offset = offset;
- for (; bits != 0; bits >>= 1) {
- if ((bits&1) != 0) {
- ElfW(Addr) reloc = static_cast<ElfW(Addr)>(r_offset + load_bias);
- ElfW(Addr) addend = *reinterpret_cast<ElfW(Addr)*>(reloc);
- *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
+
+ // Odd entry: encodes bitmap for relocations starting at base.
+ offset = base;
+ while (entry != 0) {
+ entry >>= 1;
+ if ((entry&1) != 0) {
+ apply_relr_reloc(offset);
}
- r_offset += sizeof(ElfW(Addr));
+ offset += wordsize;
}
+
+ // Advance base offset by 63 words for 64-bit platforms,
+ // or 31 words for 32-bit platforms.
+ base += (8*wordsize - 1) * wordsize;
}
return true;
}
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index cb607a9..447c7c3 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -310,6 +310,7 @@
bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group, const soinfo_list_t& local_group);
bool relocate_relr();
+ void apply_relr_reloc(ElfW(Addr) offset);
private:
// This part of the structure is only available