diff --git a/linker/linker.cpp b/linker/linker.cpp index ceee3a57b..94672a87a 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1728,6 +1728,27 @@ bool VersionTracker::init(const soinfo* si_from) { return init_verneed(si_from) && init_verdef(si_from); } +bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym, + const char* sym_name, const version_info** vi) { + const ElfW(Versym)* sym_ver_ptr = get_versym(sym); + ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr; + + if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) { + *vi = version_tracker.get_version_info(sym_ver); + + if (*vi == nullptr) { + DL_ERR("cannot find verneed/verdef for version index=%d " + "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname()); + return false; + } + } else { + // there is no version info + *vi = nullptr; + } + + return true; +} + #if !defined(__mips__) #if defined(USE_RELA) static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) { @@ -1776,27 +1797,16 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa if (sym != 0) { sym_name = get_string(symtab_[sym].st_name); - const ElfW(Versym)* sym_ver_ptr = get_versym(sym); - ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr; + const version_info* vi = nullptr; - if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) { - // there is no version info for this one - if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) { - return false; - } - } else { - const version_info* vi = version_tracker.get_version_info(sym_ver); - - if (vi == nullptr) { - DL_ERR("cannot find verneed/verdef for version index=%d " - "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname()); - return false; - } - - if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { - return false; - } + 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; + } + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... s = &symtab_[sym]; diff --git a/linker/linker.h b/linker/linker.h index dae3972c0..06e1f53a6 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -338,6 +338,9 @@ struct soinfo { bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const; ElfW(Sym)* gnu_addr_lookup(const void* addr); + bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym, + const char* sym_name, const version_info** vi); + void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void call_function(const char* function_name, linker_function_t function); template diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp index 87b811f00..aaf8b5e51 100644 --- a/linker/linker_mips.cpp +++ b/linker/linker_mips.cpp @@ -75,26 +75,14 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, if (sym != 0) { sym_name = get_string(symtab_[sym].st_name); - const ElfW(Versym)* sym_ver_ptr = get_versym(sym); - ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr; + const version_info* vi = nullptr; - if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) { - // there is no version info for this one - if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) { - return false; - } - } else { - const version_info* vi = version_tracker.get_version_info(sym_ver); + if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { + return false; + } - if (vi == nullptr) { - DL_ERR("cannot find verneed/verdef for version index=%d " - "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname()); - return false; - } - - if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { - return false; - } + if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { + return false; } if (s == nullptr) {