summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linker/linker.cpp')
-rw-r--r--linker/linker.cpp123
1 files changed, 96 insertions, 27 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index df7dd4020..0bc312129 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -46,8 +46,8 @@
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
-
#include <async_safe/log.h>
+#include <bionic/pthread_internal.h>
// Private C library headers.
@@ -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;
@@ -85,11 +86,16 @@ static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
+static uint64_t g_module_load_counter = 0;
+static uint64_t g_module_unload_counter = 0;
+
static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_STRING ".txt";
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";
@@ -97,7 +103,7 @@ static const char* const kVendorLibDir = "/vendor/lib64";
static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
static const char* const kAsanOdmLibDir = "/data/asan/odm/lib64";
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
-static const char* const kRuntimeApexLibDir = "/apex/com.android.runtime/lib64";
+static const char* const kArtApexLibDir = "/apex/com.android.art/lib64";
#else
static const char* const kSystemLibDir = "/system/lib";
static const char* const kOdmLibDir = "/odm/lib";
@@ -105,7 +111,7 @@ static const char* const kVendorLibDir = "/vendor/lib";
static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
static const char* const kAsanOdmLibDir = "/data/asan/odm/lib";
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
-static const char* const kRuntimeApexLibDir = "/apex/com.android.runtime/lib";
+static const char* const kArtApexLibDir = "/apex/com.android.art/lib";
#endif
static const char* const kAsanLibDirPrefix = "/data/asan";
@@ -239,7 +245,7 @@ static bool is_greylisted(android_namespace_t* ns, const char* name, const soinf
* return true if translation is needed
*/
static bool translateSystemPathToApexPath(const char* name, std::string* out_name_to_apex) {
- static const char* const kSystemToRuntimeApexLibs[] = {
+ static const char* const kSystemToArtApexLibs[] = {
"libicuuc.so",
"libicui18n.so",
};
@@ -257,9 +263,9 @@ static bool translateSystemPathToApexPath(const char* name, std::string* out_nam
const char* base_name = basename(name);
- for (const char* soname : kSystemToRuntimeApexLibs) {
+ for (const char* soname : kSystemToArtApexLibs) {
if (strcmp(base_name, soname) == 0) {
- *out_name_to_apex = std::string(kRuntimeApexLibDir) + "/" + base_name;
+ *out_name_to_apex = std::string(kArtApexLibDir) + "/" + base_name;
return true;
}
}
@@ -270,8 +276,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];
@@ -423,6 +427,24 @@ static bool realpath_fd(int fd, std::string* realpath) {
return true;
}
+// Returns the address of the current thread's copy of a TLS module. If the current thread doesn't
+// have a copy yet, allocate one on-demand if should_alloc is true, and return nullptr otherwise.
+static inline void* get_tls_block_for_this_thread(const soinfo_tls* si_tls, bool should_alloc) {
+ const TlsModule& tls_mod = get_tls_module(si_tls->module_id);
+ if (tls_mod.static_offset != SIZE_MAX) {
+ const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+ char* static_tls = reinterpret_cast<char*>(__get_bionic_tcb()) - layout.offset_bionic_tcb();
+ return static_tls + tls_mod.static_offset;
+ } else if (should_alloc) {
+ const TlsIndex ti { si_tls->module_id, 0 };
+ return TLS_GET_ADDR(&ti);
+ } else {
+ TlsDtv* dtv = __get_tcb_dtv(__get_bionic_tcb());
+ if (dtv->generation < tls_mod.first_generation) return nullptr;
+ return dtv->modules[__tls_module_id_to_idx(si_tls->module_id)];
+ }
+}
+
#if defined(__arm__)
// For a given PC, find the .so that it belongs to.
@@ -452,6 +474,16 @@ int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), v
dl_info.dlpi_name = si->link_map_head.l_name;
dl_info.dlpi_phdr = si->phdr;
dl_info.dlpi_phnum = si->phnum;
+ dl_info.dlpi_adds = g_module_load_counter;
+ dl_info.dlpi_subs = g_module_unload_counter;
+ if (soinfo_tls* tls_module = si->get_tls()) {
+ dl_info.dlpi_tls_modid = tls_module->module_id;
+ dl_info.dlpi_tls_data = get_tls_block_for_this_thread(tls_module, /*should_alloc=*/false);
+ } else {
+ dl_info.dlpi_tls_modid = 0;
+ dl_info.dlpi_tls_data = nullptr;
+ }
+
rv = cb(&dl_info, sizeof(dl_phdr_info), data);
if (rv != 0) {
break;
@@ -951,7 +983,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;
@@ -1901,6 +1935,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;
@@ -2037,8 +2074,12 @@ static void soinfo_unload_impl(soinfo* root) {
"... dlclose: unloading \"%s\"@%p ...",
si->get_realpath(),
si);
+ ++g_module_unload_counter;
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);
}
@@ -2420,18 +2461,15 @@ bool do_dlsym(void* handle,
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
if (type == STT_TLS) {
// For a TLS symbol, dlsym returns the address of the current thread's
- // copy of the symbol. This function may allocate a DTV and/or storage
- // for the source TLS module. (Allocating a DTV isn't necessary if the
- // symbol is part of static TLS, but it's simpler to reuse
- // __tls_get_addr.)
- soinfo_tls* tls_module = found->get_tls();
+ // copy of the symbol.
+ const soinfo_tls* tls_module = found->get_tls();
if (tls_module == nullptr) {
DL_ERR("TLS symbol \"%s\" in solib \"%s\" with no TLS segment",
sym_name, found->get_realpath());
return false;
}
- const TlsIndex ti { tls_module->module_id, sym->st_value };
- *symbol = TLS_GET_ADDR(&ti);
+ void* tls_block = get_tls_block_for_this_thread(tls_module, /*should_alloc=*/true);
+ *symbol = static_cast<char*>(tls_block) + sym->st_value;
} else {
*symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
}
@@ -2471,14 +2509,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
@@ -2488,21 +2541,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;
}
@@ -2542,6 +2592,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.
@@ -2573,6 +2624,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;
}
@@ -4074,6 +4135,7 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
}
}
+ ++g_module_load_counter;
notify_gdb_of_load(this);
set_image_linked();
return true;
@@ -4142,6 +4204,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())) {