diff options
author | Scott Lobdell <slobdell@google.com> | 2019-08-25 12:20:54 -0700 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2019-08-25 12:20:54 -0700 |
commit | 4f9bfdcaca2414c8959986f0a4d73f16cb15e1c4 (patch) | |
tree | 540bab5498d276cbbfad24c48a7ff989ee8b920a /linker/linker.cpp | |
parent | bfda022dd6fbbcea60e9f52496d90ece514b32da (diff) | |
parent | f77cc9b224c35fa7d1d71e7c374ef19e47b5f6a5 (diff) |
Merge RP1A.190822.001
Change-Id: Iaf90835a99d87f6246798efd2cea6fe9f750ea18
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r-- | linker/linker.cpp | 145 |
1 files changed, 110 insertions, 35 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index 32dce3805..d581dd8ce 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -76,6 +76,7 @@ static std::unordered_map<void*, size_t> g_dso_handle_counters; +static bool g_anonymous_namespace_set = false; static android_namespace_t* g_anonymous_namespace = &g_default_namespace; static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces; @@ -90,6 +91,8 @@ static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_ST static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt"; static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt"; +static const char* const kLdGeneratedConfigFilePath = "/dev/linkerconfig/ld.config.txt"; + #if defined(__LP64__) static const char* const kSystemLibDir = "/system/lib64"; static const char* const kOdmLibDir = "/odm/lib64"; @@ -270,8 +273,6 @@ static bool translateSystemPathToApexPath(const char* name, std::string* out_nam static std::vector<std::string> g_ld_preload_names; -static bool g_anonymous_namespace_initialized; - #if STATS struct linker_stats_t { int count[kRelocMax]; @@ -282,6 +283,16 @@ 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) { } @@ -393,16 +404,23 @@ static void parse_LD_LIBRARY_PATH(const char* path) { } static bool realpath_fd(int fd, std::string* realpath) { - std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX); - async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); - if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) { + // proc_self_fd needs to be large enough to hold "/proc/self/fd/" plus an + // integer, plus the NULL terminator. + char proc_self_fd[32]; + // We want to statically allocate this large buffer so that we don't grow + // the stack by too much. + static char buf[PATH_MAX]; + + async_safe_format_buffer(proc_self_fd, sizeof(proc_self_fd), "/proc/self/fd/%d", fd); + auto length = readlink(proc_self_fd, buf, sizeof(buf)); + if (length == -1) { if (!is_first_stage_init()) { - PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd); + PRINT("readlink(\"%s\") failed: %s [fd=%d]", proc_self_fd, strerror(errno), fd); } return false; } - *realpath = &buf[0]; + realpath->assign(buf, length); return true; } @@ -934,7 +952,9 @@ static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, } soinfo* find_containing_library(const void* p) { - ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); + // Addresses within a library may be tagged if they point to globals. Untag + // them so that the bounds check succeeds. + ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(untag_address(p)); for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) { if (address < si->base || address - si->base >= si->size) { continue; @@ -1215,12 +1235,14 @@ static bool find_loaded_library_by_inode(android_namespace_t* ns, off64_t file_offset, bool search_linked_namespaces, soinfo** candidate) { + if (file_stat.st_dev == 0 || file_stat.st_ino == 0) { + *candidate = nullptr; + return false; + } auto predicate = [&](soinfo* si) { - return si->get_st_dev() != 0 && - si->get_st_ino() != 0 && + return si->get_st_ino() == file_stat.st_ino && si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino && si->get_file_offset() == file_offset; }; @@ -1882,6 +1904,9 @@ bool find_libraries(android_namespace_t* ns, // flag is set. link_extinfo = extinfo; } + 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) || !get_cfi_shadow()->AfterLoad(si, solist_get_head())) { return false; @@ -2020,6 +2045,9 @@ static void soinfo_unload_impl(soinfo* root) { si); notify_gdb_of_unload(si); unregister_soinfo_tls(si); + if (__libc_shared_globals()->unload_hook) { + __libc_shared_globals()->unload_hook(si->load_bias, si->phdr, si->phnum); + } get_cfi_shadow()->BeforeUnload(si); soinfo_free(si); } @@ -2452,14 +2480,29 @@ int do_dlclose(void* handle) { return 0; } -bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) { - if (g_anonymous_namespace_initialized) { - DL_ERR("anonymous namespace has already been initialized."); - return false; +// Make ns as the anonymous namespace that is a namespace used when +// we fail to determine the caller address (e.g., call from mono-jited code) +// Since there can be multiple anonymous namespace in a process, subsequent +// call to this function causes an error. +static bool set_anonymous_namespace(android_namespace_t* ns) { + if (!g_anonymous_namespace_set && ns != nullptr) { + CHECK(ns->is_also_used_as_anonymous()); + g_anonymous_namespace = ns; + g_anonymous_namespace_set = true; + return true; } + return false; +} +// TODO(b/130388701) remove this. Currently, this is used only for testing +// where we don't have classloader namespace. +bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) { ProtectedDataGuard guard; + // Test-only feature: we need to change the anonymous namespace multiple times + // while the test is running. + g_anonymous_namespace_set = false; + // create anonymous namespace // When the caller is nullptr - create_namespace will take global group // from the anonymous namespace, which is fine because anonymous namespace @@ -2469,21 +2512,18 @@ bool init_anonymous_namespace(const char* shared_lib_sonames, const char* librar "(anonymous)", nullptr, library_search_path, - ANDROID_NAMESPACE_TYPE_ISOLATED, + ANDROID_NAMESPACE_TYPE_ISOLATED | + ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS, nullptr, &g_default_namespace); - if (anon_ns == nullptr) { - return false; - } + CHECK(anon_ns != nullptr); if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) { + // TODO: delete anon_ns return false; } - g_anonymous_namespace = anon_ns; - g_anonymous_namespace_initialized = true; - return true; } @@ -2523,6 +2563,7 @@ android_namespace_t* create_namespace(const void* caller_addr, ns->set_name(name); ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0); ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0); + ns->set_also_used_as_anonymous((type & ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS) != 0); if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) { // append parent namespace paths. @@ -2554,6 +2595,16 @@ android_namespace_t* create_namespace(const void* caller_addr, ns->set_default_library_paths(std::move(default_library_paths)); ns->set_permitted_paths(std::move(permitted_paths)); + if (ns->is_also_used_as_anonymous() && !set_anonymous_namespace(ns)) { + DL_ERR("failed to set namespace: [name=\"%s\", ld_library_path=\"%s\", default_library_paths=\"%s\"" + " permitted_paths=\"%s\"] as the anonymous namespace", + ns->get_name(), + android::base::Join(ns->get_ld_library_paths(), ':').c_str(), + android::base::Join(ns->get_default_library_paths(), ':').c_str(), + android::base::Join(ns->get_permitted_paths(), ':').c_str()); + return nullptr; + } + return ns; } @@ -2874,6 +2925,17 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r 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) { @@ -2917,14 +2979,25 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r return false; } else { sym_name = get_string(symtab_[sym].st_name); - const version_info* vi = nullptr; - if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { - return false; - } + 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 (!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; + } + + symbol_lookup_cache.sym = sym; + symbol_lookup_cache.s = s; + symbol_lookup_cache.lsi = lsi; } if (s == nullptr) { @@ -3121,10 +3194,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r *reinterpret_cast<ElfW(Addr)*>(reloc) = tpoff; } 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); @@ -3149,7 +3218,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r reinterpret_cast<void*>(sym_addr + addend), sym_name); *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; break; -#endif // !defined(__aarch64__) #if defined(__aarch64__) // Bionic currently only implements TLSDESC for arm64. This implementation should work with @@ -4073,10 +4141,10 @@ static std::vector<android_namespace_t*> init_default_namespace_no_config(bool i return namespaces; } -// return /apex/<name>/etc/ld.config.txt from /apex/<name>/bin/<exec> +// return /apex/<name>/etc/ld.config.txt from /apex/<name>/bin/* static std::string get_ld_config_file_apex_path(const char* executable_path) { std::vector<std::string> paths = android::base::Split(executable_path, "/"); - if (paths.size() == 5 && paths[1] == "apex" && paths[3] == "bin") { + if (paths.size() >= 5 && paths[1] == "apex" && paths[3] == "bin") { return std::string("/apex/") + paths[2] + "/etc/ld.config.txt"; } return ""; @@ -4106,6 +4174,13 @@ static std::string get_ld_config_file_path(const char* executable_path) { } #endif + // Use generated linker config if flag is set + // TODO(b/138920271) Do not check property once it is confirmed as stable + if (android::base::GetBoolProperty("sys.linker.use_generated_config", false) && + file_exists(kLdGeneratedConfigFilePath)) { + return kLdGeneratedConfigFilePath; + } + std::string path = get_ld_config_file_apex_path(executable_path); if (!path.empty()) { if (file_exists(path.c_str())) { |