Implement TLS_DTPMOD and TLS_DTPREL relocations

Generalize the omitted symbol and missing-TLS-segment behaviors to all TLS
relocations.

R_GENERIC_TLS_DTPMOD is a module ID, which starts at 1 for the executable.

R_GENERIC_TLS_DTPREL is an offset from the start of a module to a specific
TLS symbol.

binutils currently disagrees with Bionic about the values of
R_AARCH64_TLS_DTPMOD64 and R_AARCH64_TLS_DTPREL64, so disable
DTPMOD/DTPREL for now on arm64.

Bug: http://b/78026329
Test: bionic unit tests (Tests for dynamic TLS will be added later)
Change-Id: I05c28d6a1036bdd6127f605036679b7475689445
This commit is contained in:
Ryan Prichard 2019-01-22 22:49:22 -08:00
parent ea41ab0548
commit 3b463cf7f4

View file

@ -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);