summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2018-01-23 00:24:26 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-01-23 00:24:26 +0000
commitd00d38b36be0fd25399256d0cebdd71625aea2b6 (patch)
treeb32e0212754398814e0f825783eec448cc712249 /linker/linker.cpp
parent86a2fba164cb87375b81b6873f7399e92073ea32 (diff)
parentb7feec74547f84559a1467aca02708ff61346d2a (diff)
Merge "linker: add experimental support for SHT_RELR sections."
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r--linker/linker.cpp65
1 files changed, 60 insertions, 5 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 63415d8d9..05efc5500 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2595,6 +2595,35 @@ bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Wor
return true;
}
+// 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
+bool soinfo::relocate_relr() {
+ ElfW(Relr)* begin = relr_;
+ ElfW(Relr)* end = relr_ + relr_count_;
+
+ ElfW(Addr) offset = 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);
+ }
+ r_offset += sizeof(ElfW(Addr));
+ }
+ }
+ return true;
+}
+
#if !defined(__mips__)
#if defined(USE_RELA)
static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
@@ -3151,7 +3180,7 @@ bool soinfo::prelink_image() {
}
break;
- // ignored (see DT_RELCOUNT comments for details)
+ // Ignored (see DT_RELCOUNT comments for details).
case DT_RELACOUNT:
break;
@@ -3212,6 +3241,25 @@ bool soinfo::prelink_image() {
return false;
#endif
+ case DT_RELR:
+ relr_ = reinterpret_cast<ElfW(Relr)*>(load_bias + d->d_un.d_ptr);
+ break;
+
+ case DT_RELRSZ:
+ relr_count_ = d->d_un.d_val / sizeof(ElfW(Relr));
+ break;
+
+ case DT_RELRENT:
+ if (d->d_un.d_val != sizeof(ElfW(Relr))) {
+ DL_ERR("invalid DT_RELRENT: %zd", static_cast<size_t>(d->d_un.d_val));
+ return false;
+ }
+ break;
+
+ // Ignored (see DT_RELCOUNT comments for details).
+ case DT_RELRCOUNT:
+ break;
+
case DT_INIT:
init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
@@ -3504,16 +3552,23 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
}
}
+ if (relr_ != nullptr) {
+ DEBUG("[ relocating %s relr ]", get_realpath());
+ if (!relocate_relr()) {
+ return false;
+ }
+ }
+
#if defined(USE_RELA)
if (rela_ != nullptr) {
- DEBUG("[ relocating %s ]", get_realpath());
+ DEBUG("[ relocating %s rela ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
return false;
}
}
if (plt_rela_ != nullptr) {
- DEBUG("[ relocating %s plt ]", get_realpath());
+ DEBUG("[ relocating %s plt rela ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
return false;
@@ -3521,14 +3576,14 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
}
#else
if (rel_ != nullptr) {
- DEBUG("[ relocating %s ]", get_realpath());
+ DEBUG("[ relocating %s rel ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
return false;
}
}
if (plt_rel_ != nullptr) {
- DEBUG("[ relocating %s plt ]", get_realpath());
+ DEBUG("[ relocating %s plt rel ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
return false;