summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
authorRyan Prichard <rprichard@google.com>2020-01-10 22:21:15 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-01-10 22:21:15 +0000
commita04764bd286cf86f28d65487e1b6d6d36c9671e8 (patch)
tree26736176398392ba7e9c584c8a8b7561c71bfa41 /linker/linker.cpp
parent9c5c87ed0575328b004a2512d7ff8ef8495cdcca (diff)
parent551565e87c595aeced1cd1edf50c916378a3623e (diff)
Merge changes I578d36a1,Id17508ab,I385f312b
* changes: Create linker_log[_va_list] functions Validate defined versions in prelink_image Prelink each library only once
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r--linker/linker.cpp72
1 files changed, 32 insertions, 40 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8b0520ae8..10833be9d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -508,10 +508,7 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
*/
if (si_from->has_DT_SYMBOLIC) {
DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
- if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
- return false;
- }
-
+ s = si_from->find_symbol_by_name(symbol_name, vi);
if (s != nullptr) {
*si_found_in = si_from;
}
@@ -519,15 +516,10 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
// 1. Look for it in global_group
if (s == nullptr) {
- bool error = false;
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());
- if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
- error = true;
- return false;
- }
-
+ s = global_si->find_symbol_by_name(symbol_name, vi);
if (s != nullptr) {
*si_found_in = global_si;
return false;
@@ -535,15 +527,10 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
return true;
});
-
- if (error) {
- return false;
- }
}
// 2. Look for it in the local group
if (s == nullptr) {
- bool error = false;
local_group.visit([&](soinfo* local_si) {
if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
// we already did this - skip
@@ -552,11 +539,7 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
DEBUG("%s: looking up %s in %s (from local group)",
si_from->get_realpath(), name, local_si->get_realpath());
- if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
- error = true;
- return false;
- }
-
+ s = local_si->find_symbol_by_name(symbol_name, vi);
if (s != nullptr) {
*si_found_in = local_si;
return false;
@@ -564,10 +547,6 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
return true;
});
-
- if (error) {
- return false;
- }
}
if (s != nullptr) {
@@ -863,11 +842,7 @@ static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
return kWalkSkip;
}
- if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
- result = nullptr;
- return kWalkStop;
- }
-
+ result = current_soinfo->find_symbol_by_name(symbol_name, vi);
if (result != nullptr) {
*found = current_soinfo;
return kWalkStop;
@@ -947,10 +922,7 @@ static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
continue;
}
- if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
- return nullptr;
- }
-
+ s = si->find_symbol_by_name(symbol_name, vi);
if (s != nullptr) {
*found = si;
break;
@@ -2819,25 +2791,38 @@ static bool for_each_verdef(const soinfo* si, F functor) {
return true;
}
-bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
+ElfW(Versym) find_verdef_version_index(const soinfo* si, const version_info* vi) {
if (vi == nullptr) {
- *versym = kVersymNotNeeded;
- return true;
+ return kVersymNotNeeded;
}
- *versym = kVersymGlobal;
+ ElfW(Versym) result = kVersymGlobal;
- return for_each_verdef(si,
+ if (!for_each_verdef(si,
[&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
if (verdef->vd_hash == vi->elf_hash &&
strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
- *versym = verdef->vd_ndx;
+ result = verdef->vd_ndx;
return true;
}
return false;
}
- );
+ )) {
+ // verdef should have already been validated in prelink_image.
+ async_safe_fatal("invalid verdef after prelinking: %s, %s",
+ si->get_realpath(), linker_get_error_buffer());
+ }
+
+ return result;
+}
+
+// Validate the library's verdef section. On error, returns false and invokes DL_ERR.
+bool validate_verdef_section(const soinfo* si) {
+ return for_each_verdef(si,
+ [&](size_t, const ElfW(Verdef)*, const ElfW(Verdaux)*) {
+ return false;
+ });
}
bool VersionTracker::init_verdef(const soinfo* si_from) {
@@ -3346,6 +3331,7 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
static soinfo_list_t g_empty_list;
bool soinfo::prelink_image() {
+ if (flags_ & FLAG_PRELINKED) return true;
/* Extract dynamic section */
ElfW(Word) dynamic_flags = 0;
phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
@@ -3840,6 +3826,12 @@ bool soinfo::prelink_image() {
// Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
}
+
+ // Validate each library's verdef section once, so we don't have to validate
+ // it each time we look up a symbol with a version.
+ if (!validate_verdef_section(this)) return false;
+
+ flags_ |= FLAG_PRELINKED;
return true;
}