Optimize GNU hash linking for large inputs
Symbol lookup is O(L) where L is the number of libraries to search (e.g.
in the global and local lookup groups). Factor out the per-DSO work into
soinfo_do_lookup_impl, and optimize for the situation where all the DSOs
are using DT_GNU_HASH (rather than SysV hashes).
To load a set of libraries, the loader first constructs an auxiliary list
of libraries (SymbolLookupList, containing SymbolLookupLib objects). The
SymbolLookupList is reused for each DSO in a load group. (-Bsymbolic is
accommodated by modifying the SymbolLookupLib at the front of the list.)
To search for a symbol, soinfo_do_lookup_impl has a small loop that first
scans a vector of GNU bloom filters looking for a possible match.
There was a slight improvement from templatizing soinfo_do_lookup_impl
and skipping the does-this-DSO-lack-GNU-hash check.
Rewrite the relocation processing loop to be faster. There are specialized
functions that handle the expected relocation types in normal relocation
sections and in PLT relocation sections.
This CL can reduce the initial link time of large programs by around
40-50% (e.g. audioserver, cameraserver, etc). On the linker relocation
benchmark (64-bit walleye), it reduces the time from 131.6ms to 71.9ms.
Bug: http://b/143577578 (incidentally fixed by this CL)
Test: bionic-unit-tests
Change-Id: If40a42fb6ff566570f7280b71d58f7fa290b9343
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 10833be..57554fb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -63,8 +63,7 @@
#include "linker_namespaces.h"
#include "linker_sleb128.h"
#include "linker_phdr.h"
-#include "linker_relocs.h"
-#include "linker_reloc_iterators.h"
+#include "linker_relocate.h"
#include "linker_tls.h"
#include "linker_utils.h"
@@ -276,31 +275,6 @@
static std::vector<std::string> g_ld_preload_names;
-#if STATS
-struct linker_stats_t {
- int count[kRelocMax];
-};
-
-static linker_stats_t linker_stats;
-
-void count_relocation(RelocationKind kind) {
- ++linker_stats.count[kind];
-}
-
-void print_linker_stats() {
- PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol (%d cached)",
- g_argv[0],
- linker_stats.count[kRelocAbsolute],
- linker_stats.count[kRelocRelative],
- linker_stats.count[kRelocCopy],
- linker_stats.count[kRelocSymbol],
- linker_stats.count[kRelocSymbolCached]);
-}
-#else
-void count_relocation(RelocationKind) {
-}
-#endif
-
static void notify_gdb_of_load(soinfo* info) {
if (info->is_linker() || info->is_main_executable()) {
// gdb already knows about the linker and the main executable.
@@ -488,79 +462,6 @@
return rv;
}
-
-bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
- soinfo** si_found_in, const soinfo_list_t& global_group,
- const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
- SymbolName symbol_name(name);
- const ElfW(Sym)* s = nullptr;
-
- /* "This element's presence in a shared object library alters the dynamic linker's
- * symbol resolution algorithm for references within the library. Instead of starting
- * a symbol search with the executable file, the dynamic linker starts from the shared
- * object itself. If the shared object fails to supply the referenced symbol, the
- * dynamic linker then searches the executable file and other shared objects as usual."
- *
- * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
- *
- * Note that this is unlikely since static linker avoids generating
- * relocations for -Bsymbolic linked dynamic executables.
- */
- if (si_from->has_DT_SYMBOLIC) {
- DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
- s = si_from->find_symbol_by_name(symbol_name, vi);
- if (s != nullptr) {
- *si_found_in = si_from;
- }
- }
-
- // 1. Look for it in global_group
- if (s == nullptr) {
- global_group.visit([&](soinfo* global_si) {
- DEBUG("%s: looking up %s in %s (from global group)",
- si_from->get_realpath(), name, global_si->get_realpath());
- s = global_si->find_symbol_by_name(symbol_name, vi);
- if (s != nullptr) {
- *si_found_in = global_si;
- return false;
- }
-
- return true;
- });
- }
-
- // 2. Look for it in the local group
- if (s == nullptr) {
- local_group.visit([&](soinfo* local_si) {
- if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
- // we already did this - skip
- return true;
- }
-
- DEBUG("%s: looking up %s in %s (from local group)",
- si_from->get_realpath(), name, local_si->get_realpath());
- s = local_si->find_symbol_by_name(symbol_name, vi);
- if (s != nullptr) {
- *si_found_in = local_si;
- return false;
- }
-
- return true;
- });
- }
-
- if (s != nullptr) {
- TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
- "found in %s, base = %p, load bias = %p",
- si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
- (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
- reinterpret_cast<void*>((*si_found_in)->load_bias));
- }
-
- *symbol = s;
- return true;
-}
-
ProtectedDataGuard::ProtectedDataGuard() {
if (ref_count_++ == 0) {
protect_data(PROT_READ | PROT_WRITE);
@@ -1906,6 +1807,9 @@
});
soinfo_list_t global_group = local_group_ns->get_global_group();
+ SymbolLookupList lookup_list(global_group, local_group);
+ soinfo* local_group_root = local_group.front();
+
bool linked = local_group.visit([&](soinfo* si) {
// Even though local group may contain accessible soinfos from other namespaces
// we should avoid linking them (because if they are not linked -> they
@@ -1920,7 +1824,8 @@
if (__libc_shared_globals()->load_hook) {
__libc_shared_globals()->load_hook(si->load_bias, si->phdr, si->phnum);
}
- if (!si->link_image(global_group, local_group, link_extinfo, &relro_fd_offset) ||
+ lookup_list.set_dt_symbolic_lib(si->has_DT_SYMBOLIC ? si : nullptr);
+ if (!si->link_image(lookup_list, local_group_root, link_extinfo, &relro_fd_offset) ||
!get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
return false;
}
@@ -2912,421 +2817,6 @@
return true;
}
-#if !defined(__mips__)
-#if defined(USE_RELA)
-static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
- return rela->r_addend;
-}
-#else
-static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
- // The i386 psABI specifies that R_386_GLOB_DAT doesn't have an addend. The ARM ELF ABI document
- // (IHI0044F) specifies that R_ARM_GLOB_DAT has an addend, but Bionic isn't adding it.
- 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_ABSOLUTE ||
- 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();
- std::vector<std::pair<TlsDescriptor*, size_t>> deferred_tlsdesc_relocs;
-
- struct {
- // Cache key
- ElfW(Word) sym;
-
- // Cache value
- const ElfW(Sym)* s;
- soinfo* lsi;
- } symbol_lookup_cache;
-
- symbol_lookup_cache.sym = 0;
-
- for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
- const auto rel = rel_iterator.next();
- if (rel == nullptr) {
- return false;
- }
-
- ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
- ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
-
- ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
- ElfW(Addr) sym_addr = 0;
- const char* sym_name = nullptr;
- ElfW(Addr) addend = get_addend(rel, reloc);
-
- DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
- if (type == R_GENERIC_NONE) {
- continue;
- }
-
- const ElfW(Sym)* s = nullptr;
- soinfo* lsi = nullptr;
-
- if (sym == 0) {
- // 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
- // 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);
-
- if (sym == symbol_lookup_cache.sym) {
- s = symbol_lookup_cache.s;
- lsi = symbol_lookup_cache.lsi;
- count_relocation(kRelocSymbolCached);
- } else {
- const version_info* vi = nullptr;
-
- if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
- return false;
- }
-
- if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
- return false;
- }
-
- symbol_lookup_cache.sym = sym;
- symbol_lookup_cache.s = s;
- symbol_lookup_cache.lsi = lsi;
- }
-
- if (s == nullptr) {
- // We only allow an undefined symbol if this is a weak reference...
- s = &symtab_[sym];
- if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
- DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
- return false;
- }
-
- /* IHI0044C AAELF 4.5.1.1:
-
- Libraries are not searched to resolve weak references.
- It is not an error for a weak reference to remain unsatisfied.
-
- During linking, the value of an undefined weak reference is:
- - Zero if the relocation type is absolute
- - The address of the place if the relocation is pc-relative
- - The address of nominal base address if the relocation
- type is base-relative.
- */
-
- switch (type) {
- case R_GENERIC_JUMP_SLOT:
- case R_GENERIC_ABSOLUTE:
- 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(__x86_64__)
- case R_X86_64_32:
-#endif
- /*
- * The sym_addr was initialized to be zero above, or the relocation
- * code below does not care about value of sym_addr.
- * No need to do anything.
- */
- break;
-#if defined(__x86_64__)
- case R_X86_64_PC32:
- sym_addr = reloc;
- break;
-#elif defined(__i386__)
- case R_386_PC32:
- sym_addr = reloc;
- break;
-#endif
- default:
- DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
- return false;
- }
- } else { // We got a definition.
-#if !defined(__LP64__)
- // When relocating dso with text_relocation .text segment is
- // not executable. We need to restore elf flags before resolving
- // STT_GNU_IFUNC symbol.
- bool protect_segments = has_text_relocations &&
- lsi == this &&
- ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
- if (protect_segments) {
- if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't protect segments for \"%s\": %s",
- get_realpath(), strerror(errno));
- return false;
- }
- }
-#endif
- 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;
- }
- 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) {
- 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);
- }
-#if !defined(__LP64__)
- if (protect_segments) {
- if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- get_realpath(), strerror(errno));
- return false;
- }
- }
-#endif
- }
- count_relocation(kRelocSymbol);
- }
-
- switch (type) {
- case R_GENERIC_JUMP_SLOT:
- count_relocation(kRelocAbsolute);
- TRACE_TYPE(RELO, "RELO JMP_SLOT %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;
- case R_GENERIC_ABSOLUTE:
- case R_GENERIC_GLOB_DAT:
- count_relocation(kRelocAbsolute);
- TRACE_TYPE(RELO, "RELO ABSOLUTE/GLOB_DAT %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;
- case R_GENERIC_RELATIVE:
- count_relocation(kRelocRelative);
- TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
- reinterpret_cast<void*>(reloc),
- reinterpret_cast<void*>(load_bias + addend));
- *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
- break;
- case R_GENERIC_IRELATIVE:
- count_relocation(kRelocRelative);
- TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
- reinterpret_cast<void*>(reloc),
- reinterpret_cast<void*>(load_bias + addend));
- // In the linker, ifuncs are called as soon as possible so that string functions work.
- // We must not call them again. (e.g. On arm32, resolving an ifunc changes the meaning of
- // the addend from a resolver function to the implementation.)
- if (!is_linker()) {
-#if !defined(__LP64__)
- // When relocating dso with text_relocation .text segment is
- // not executable. We need to restore elf flags for this
- // particular call.
- if (has_text_relocations) {
- if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't protect segments for \"%s\": %s",
- get_realpath(), strerror(errno));
- return false;
- }
- }
-#endif
- ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
-#if !defined(__LP64__)
- // Unprotect it afterwards...
- if (has_text_relocations) {
- if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- get_realpath(), strerror(errno));
- return false;
- }
- }
-#endif
- *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
- }
- break;
- case R_GENERIC_COPY:
- // Copy relocations allow read-only data or code in a non-PIE executable to access a
- // variable from a DSO. The executable reserves extra space in its .bss section, and the
- // linker copies the variable into the extra space. The executable then exports its copy
- // to interpose the copy in the DSO.
- //
- // Bionic only supports PIE executables, so copy relocations aren't supported. The ARM and
- // AArch64 ABI documents only allow them for ET_EXEC (non-PIE) objects. See IHI0056B and
- // IHI0044F.
- DL_ERR("%s COPY relocations are not supported", get_realpath());
- return false;
- case R_GENERIC_TLS_TPREL:
- count_relocation(kRelocRelative);
- {
- ElfW(Addr) tpoff = 0;
- if (lsi == nullptr) {
- // Unresolved weak relocation. Leave tpoff at 0 to resolve
- // &weak_tls_symbol to __get_tls().
- } 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 {
- DL_ERR("TLS symbol \"%s\" in dlopened \"%s\" referenced from \"%s\" using IE access model",
- sym_name, lsi->get_realpath(), 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;
- case R_GENERIC_TLS_DTPMOD:
- count_relocation(kRelocRelative);
- {
- 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);
- 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;
-
-#if defined(__aarch64__)
- // Bionic currently only implements TLSDESC for arm64. This implementation should work with
- // other architectures, as long as the resolver functions are implemented.
- case R_GENERIC_TLSDESC:
- count_relocation(kRelocRelative);
- {
- TlsDescriptor* desc = reinterpret_cast<TlsDescriptor*>(reloc);
- if (lsi == nullptr) {
- // Unresolved weak relocation.
- desc->func = tlsdesc_resolver_unresolved_weak;
- desc->arg = addend;
- TRACE_TYPE(RELO, "RELO TLSDESC %16p <- unresolved weak 0x%zx %s\n",
- reinterpret_cast<void*>(reloc), static_cast<size_t>(addend), sym_name);
- } else {
- CHECK(lsi->get_tls() != nullptr); // We rejected a missing TLS segment above.
- size_t module_id = lsi->get_tls()->module_id;
- const TlsModule& mod = get_tls_module(module_id);
- if (mod.static_offset != SIZE_MAX) {
- desc->func = tlsdesc_resolver_static;
- desc->arg = mod.static_offset - tls_tp_base + sym_addr + addend;
- TRACE_TYPE(RELO, "RELO TLSDESC %16p <- static (0x%zx - 0x%zx + 0x%zx + 0x%zx) %s\n",
- reinterpret_cast<void*>(reloc), mod.static_offset, tls_tp_base,
- static_cast<size_t>(sym_addr), static_cast<size_t>(addend), sym_name);
- } else {
- tlsdesc_args_.push_back({
- .generation = mod.first_generation,
- .index.module_id = module_id,
- .index.offset = sym_addr + addend,
- });
- // Defer the TLSDESC relocation until the address of the TlsDynamicResolverArg object
- // is finalized.
- deferred_tlsdesc_relocs.push_back({ desc, tlsdesc_args_.size() - 1 });
- const TlsDynamicResolverArg& desc_arg = tlsdesc_args_.back();
- TRACE_TYPE(RELO, "RELO TLSDESC %16p <- dynamic (gen %zu, mod %zu, off %zu) %s",
- reinterpret_cast<void*>(reloc), desc_arg.generation,
- desc_arg.index.module_id, desc_arg.index.offset, sym_name);
- }
- }
- }
- break;
-#endif // defined(__aarch64__)
-
-#if defined(__x86_64__)
- case R_X86_64_32:
- count_relocation(kRelocAbsolute);
- TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
- static_cast<size_t>(sym_addr), sym_name);
- *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
- break;
- case R_X86_64_PC32:
- count_relocation(kRelocRelative);
- TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
- static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
- static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
- *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
- break;
-#elif defined(__i386__)
- case R_386_PC32:
- count_relocation(kRelocRelative);
- TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
- reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
- *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
- break;
-#endif
- default:
- DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
- return false;
- }
- }
-
-#if defined(__aarch64__)
- // Bionic currently only implements TLSDESC for arm64.
- for (const std::pair<TlsDescriptor*, size_t>& pair : deferred_tlsdesc_relocs) {
- TlsDescriptor* desc = pair.first;
- desc->func = tlsdesc_resolver_dynamic;
- desc->arg = reinterpret_cast<size_t>(&tlsdesc_args_[pair.second]);
- }
-#endif
-
- return true;
-}
-#endif // !defined(__mips__)
-
// An empty list of soinfos
static soinfo_list_t g_empty_list;
@@ -3835,7 +3325,7 @@
return true;
}
-bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
+bool soinfo::link_image(const SymbolLookupList& lookup_list, soinfo* local_group_root,
const android_dlextinfo* extinfo, size_t* relro_fd_offset) {
if (is_image_linked()) {
// already linked.
@@ -3847,7 +3337,7 @@
get_realpath(), reinterpret_cast<void*>(base));
}
- local_group_root_ = local_group.front();
+ local_group_root_ = local_group_root;
if (local_group_root_ == nullptr) {
local_group_root_ = this;
}
@@ -3856,12 +3346,6 @@
target_sdk_version_ = get_application_target_sdk_version();
}
- VersionTracker version_tracker;
-
- if (!version_tracker.init(this)) {
- return false;
- }
-
#if !defined(__LP64__)
if (has_text_relocations) {
// Fail if app is targeting M or above.
@@ -3886,78 +3370,9 @@
}
#endif
- if (android_relocs_ != nullptr) {
- // check signature
- if (android_relocs_size_ > 3 &&
- android_relocs_[0] == 'A' &&
- android_relocs_[1] == 'P' &&
- android_relocs_[2] == 'S' &&
- android_relocs_[3] == '2') {
- DEBUG("[ android relocating %s ]", get_realpath());
-
- bool relocated = false;
- const uint8_t* packed_relocs = android_relocs_ + 4;
- const size_t packed_relocs_size = android_relocs_size_ - 4;
-
- relocated = relocate(
- version_tracker,
- packed_reloc_iterator<sleb128_decoder>(
- sleb128_decoder(packed_relocs, packed_relocs_size)),
- global_group, local_group);
-
- if (!relocated) {
- return false;
- }
- } else {
- DL_ERR("bad android relocation header.");
- return false;
- }
- }
-
- if (relr_ != nullptr) {
- DEBUG("[ relocating %s relr ]", get_realpath());
- if (!relocate_relr()) {
- return false;
- }
- }
-
-#if defined(USE_RELA)
- if (rela_ != nullptr) {
- 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 rela ]", get_realpath());
- if (!relocate(version_tracker,
- plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
- return false;
- }
- }
-#else
- if (rel_ != nullptr) {
- 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 rel ]", get_realpath());
- if (!relocate(version_tracker,
- plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
- return false;
- }
- }
-#endif
-
-#if defined(__mips__)
- if (!mips_relocate_got(version_tracker, global_group, local_group)) {
+ if (!relocate(lookup_list)) {
return false;
}
-#endif
DEBUG("[ finished linking %s ]", get_realpath());