summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r--linker/linker.cpp54
1 files changed, 42 insertions, 12 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8a28bad0c..4dcdf7e89 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2722,7 +2722,11 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
soinfo* lsi = nullptr;
if (sym == 0) {
- // Do nothing.
+ // By convention in ld.bfd and lld, an omitted symbol on a TLS relocation
+ // is a reference to the current module.
+ if (is_tls_reloc(type)) {
+ lsi = this;
+ }
} else if (ELF_ST_BIND(symtab_[sym].st_info) == STB_LOCAL && is_tls_reloc(type)) {
// In certain situations, the Gold linker accesses a TLS symbol using a
// relocation to an STB_LOCAL symbol in .dynsym of either STT_SECTION or
@@ -2830,6 +2834,11 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
sym_name, get_realpath());
return false;
}
+ if (lsi->get_tls() == nullptr) {
+ DL_ERR("TLS relocation refers to symbol \"%s\" in solib \"%s\" with no TLS segment",
+ sym_name, lsi->get_realpath());
+ return false;
+ }
sym_addr = s->st_value;
} else {
if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
@@ -2916,16 +2925,12 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
MARK(rel->r_offset);
{
ElfW(Addr) tpoff = 0;
- if (sym == 0) {
- // By convention in ld.bfd and lld, an omitted symbol
- // (ELFW(R_SYM) == 0) refers to the local module.
- lsi = this;
- }
if (lsi == nullptr) {
// Unresolved weak relocation. Leave tpoff at 0 to resolve
// &weak_tls_symbol to __get_tls().
- } else if (soinfo_tls* lsi_tls = lsi->get_tls()) {
- const TlsModule& mod = get_tls_module(lsi_tls->module_id);
+ } else {
+ CHECK(lsi->get_tls() != nullptr); // We rejected a missing TLS segment above.
+ const TlsModule& mod = get_tls_module(lsi->get_tls()->module_id);
if (mod.static_offset != SIZE_MAX) {
tpoff += mod.static_offset - tls_tp_base;
} else {
@@ -2933,10 +2938,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
sym_name, lsi->get_realpath(), get_realpath());
return false;
}
- } else {
- DL_ERR("TLS relocation refers to symbol \"%s\" in solib \"%s\" with no TLS segment",
- sym_name, lsi->get_realpath());
- return false;
}
tpoff += sym_addr + addend;
TRACE_TYPE(RELO, "RELO TLS_TPREL %16p <- %16p %s\n",
@@ -2946,6 +2947,35 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
}
break;
+#if !defined(__aarch64__)
+ // Omit support for DTPMOD/DTPREL on arm64, at least until
+ // http://b/123385182 is fixed. arm64 uses TLSDESC instead.
+ case R_GENERIC_TLS_DTPMOD:
+ count_relocation(kRelocRelative);
+ MARK(rel->r_offset);
+ {
+ size_t module_id = 0;
+ if (lsi == nullptr) {
+ // Unresolved weak relocation. Evaluate the module ID to 0.
+ } else {
+ CHECK(lsi->get_tls() != nullptr); // We rejected a missing TLS segment above.
+ module_id = lsi->get_tls()->module_id;
+ }
+ TRACE_TYPE(RELO, "RELO TLS_DTPMOD %16p <- %zu %s\n",
+ reinterpret_cast<void*>(reloc), module_id, sym_name);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = module_id;
+ }
+ break;
+ case R_GENERIC_TLS_DTPREL:
+ count_relocation(kRelocRelative);
+ MARK(rel->r_offset);
+ TRACE_TYPE(RELO, "RELO TLS_DTPREL %16p <- %16p %s\n",
+ reinterpret_cast<void*>(reloc),
+ reinterpret_cast<void*>(sym_addr + addend), sym_name);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+ break;
+#endif // !defined(__aarch64__)
+
#if defined(__aarch64__)
case R_AARCH64_ABS64:
count_relocation(kRelocAbsolute);