summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-01-27 00:00:17 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-01-27 00:00:17 +0000
commit2e2a8930e5f9eb2d9ea4fdb61f746c6f2e2048ac (patch)
tree8adca0f4df67038588d4dbe7095204498e2f4dce /linker/linker.cpp
parent97d1c75ca5125f8e1dc6db32af1d22807fca1950 (diff)
parentf16b65932bb7adb1568a3a1e11ffa750d18e30ae (diff)
Merge "linker: simpler encoding for SHT_RELR sections."
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r--linker/linker.cpp49
1 files changed, 32 insertions, 17 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0b8d5ee3d..3f898bab5 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2614,31 +2614,46 @@ bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Wor
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(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);
+ 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;
+ }
+
+ // 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;
}