diff options
author | Ryan Prichard <rprichard@google.com> | 2019-01-17 23:10:51 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-01-17 23:10:51 +0000 |
commit | 9a238653c1a32a7bd046aba8411e7400dda8367e (patch) | |
tree | 726605d697cad7873e090acdb5014164ce42f5d6 /linker/linker.cpp | |
parent | 1f6adf5863b53c8a9139eef256e87d998f7130d4 (diff) | |
parent | fb8730d49586f29868b5697d6a8c74aa9a4847d0 (diff) |
Merge changes Ia08e1b5c,I60e589dd,Ib7edb665,Ibf1bf5ec,Ibd623857
* changes:
Handle R_GENERIC_TLS_TPREL relocations
Avoid a dlopen abort on an invalid TLS alignment
Initialize static TLS memory using module list
Record TLS modules and layout static TLS memory
StaticTlsLayout: add exe/tcb and solib layout
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r-- | linker/linker.cpp | 116 |
1 files changed, 101 insertions, 15 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index c5701dd5b..6687d235e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -65,8 +65,10 @@ #include "linker_phdr.h" #include "linker_relocs.h" #include "linker_reloc_iterators.h" +#include "linker_tls.h" #include "linker_utils.h" +#include "private/bionic_globals.h" #include "android-base/macros.h" #include "android-base/strings.h" #include "android-base/stringprintf.h" @@ -1655,6 +1657,7 @@ bool find_libraries(android_namespace_t* ns, if (!si->is_linked() && !si->prelink_image()) { return false; } + register_soinfo_tls(si); } // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is @@ -1890,6 +1893,7 @@ static void soinfo_unload_impl(soinfo* root) { si->get_realpath(), si); notify_gdb_of_unload(si); + unregister_soinfo_tls(si); get_cfi_shadow()->BeforeUnload(si); soinfo_free(si); } @@ -2669,16 +2673,32 @@ static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) { #else static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) { if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE || - ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) { + ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE || + ELFW(R_TYPE)(rel->r_info) == R_GENERIC_TLS_DTPREL || + ELFW(R_TYPE)(rel->r_info) == R_GENERIC_TLS_TPREL) { return *reinterpret_cast<ElfW(Addr)*>(reloc_addr); } return 0; } #endif +static bool is_tls_reloc(ElfW(Word) type) { + switch (type) { + case R_GENERIC_TLS_DTPMOD: + case R_GENERIC_TLS_DTPREL: + case R_GENERIC_TLS_TPREL: + case R_GENERIC_TLSDESC: + return true; + default: + return false; + } +} + template<typename ElfRelIteratorT> bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group, const soinfo_list_t& local_group) { + const size_t tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer(); + for (size_t idx = 0; rel_iterator.has_next(); ++idx) { const auto rel = rel_iterator.next(); if (rel == nullptr) { @@ -2701,7 +2721,22 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r const ElfW(Sym)* s = nullptr; soinfo* lsi = nullptr; - if (sym != 0) { + if (sym == 0) { + // Do nothing. + } 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 + // STT_TLS type. Bionic doesn't support these relocations, so issue an + // error. References: + // - https://groups.google.com/d/topic/generic-abi/dJ4_Y78aQ2M/discussion + // - https://sourceware.org/bugzilla/show_bug.cgi?id=17699 + s = &symtab_[sym]; + sym_name = get_string(s->st_name); + DL_ERR("unexpected TLS reference to local symbol \"%s\": " + "sym type %d, rel type %u (idx %zu of \"%s\")", + sym_name, ELF_ST_TYPE(s->st_info), type, idx, get_realpath()); + return false; + } else { sym_name = get_string(symtab_[sym].st_name); const version_info* vi = nullptr; @@ -2738,6 +2773,10 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r case R_GENERIC_GLOB_DAT: case R_GENERIC_RELATIVE: case R_GENERIC_IRELATIVE: + case R_GENERIC_TLS_DTPMOD: + case R_GENERIC_TLS_DTPREL: + case R_GENERIC_TLS_TPREL: + case R_GENERIC_TLSDESC: #if defined(__aarch64__) case R_AARCH64_ABS64: case R_AARCH64_ABS32: @@ -2785,12 +2824,21 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r } } #endif - if (ELF_ST_TYPE(s->st_info) == STT_TLS) { - DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"", - sym_name, get_realpath()); - return false; + if (is_tls_reloc(type)) { + if (ELF_ST_TYPE(s->st_info) != STT_TLS) { + DL_ERR("reference to non-TLS symbol \"%s\" from TLS relocation in \"%s\"", + sym_name, get_realpath()); + return false; + } + sym_addr = s->st_value; + } else { + if (ELF_ST_TYPE(s->st_info) == STT_TLS) { + DL_ERR("reference to TLS symbol \"%s\" from non-TLS relocation in \"%s\"", + sym_name, get_realpath()); + return false; + } + sym_addr = lsi->resolve_symbol_address(s); } - sym_addr = lsi->resolve_symbol_address(s); #if !defined(__LP64__) if (protect_segments) { if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { @@ -2863,6 +2911,39 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr; } break; + case R_GENERIC_TLS_TPREL: + count_relocation(kRelocRelative); + 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()) { + if (lsi_tls->module->static_offset != SIZE_MAX) { + tpoff += lsi_tls->module->static_offset - tls_tp_base; + } else { + DL_ERR("TLS symbol \"%s\" in dlopened \"%s\" referenced from \"%s\" using IE access model", + 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", + reinterpret_cast<void*>(reloc), + reinterpret_cast<void*>(tpoff), sym_name); + *reinterpret_cast<ElfW(Addr)*>(reloc) = tpoff; + } + break; #if defined(__aarch64__) case R_AARCH64_ABS64: @@ -2964,14 +3045,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r */ DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath()); return false; - case R_AARCH64_TLS_TPREL64: - TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", - reloc, (sym_addr + addend), rel->r_offset); - break; - case R_AARCH64_TLSDESC: - TRACE_TYPE(RELO, "RELO TLSDESC *** %16llx <- %16llx - %16llx\n", - reloc, (sym_addr + addend), rel->r_offset); - break; #elif defined(__x86_64__) case R_X86_64_32: count_relocation(kRelocRelative); @@ -3076,6 +3149,19 @@ bool soinfo::prelink_image() { &ARM_exidx, &ARM_exidx_count); #endif + TlsSegment tls_segment; + if (__bionic_get_tls_segment(phdr, phnum, load_bias, &tls_segment)) { + if (!__bionic_check_tls_alignment(&tls_segment.alignment)) { + if (!relocating_linker) { + DL_ERR("TLS segment alignment in \"%s\" is not a power of 2: %zu", + get_realpath(), tls_segment.alignment); + } + return false; + } + tls_ = std::make_unique<soinfo_tls>(); + tls_->segment = tls_segment; + } + // Extract useful information from dynamic section. // Note that: "Except for the DT_NULL element at the end of the array, // and the relative order of DT_NEEDED elements, entries may appear in any order." |