diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 9a8dbc93f..64df7a570 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -248,6 +248,7 @@ soinfo* get_libdl_info() { __libdl_info.ref_count_ = 1; __libdl_info.strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB); __libdl_info.local_group_root_ = &__libdl_info; + __libdl_info.soname_ = "libdl.so"; } return &__libdl_info; diff --git a/linker/linker.cpp b/linker/linker.cpp index 3960f9aa8..44ae4d49d 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -78,19 +78,6 @@ #undef ELF_ST_TYPE #define ELF_ST_TYPE(x) (static_cast(x) & 0xf) -#if defined(__LP64__) -#define SEARCH_NAME(x) x -#else -// Nvidia drivers are relying on the bug: -// http://code.google.com/p/android/issues/detail?id=6670 -// so we continue to use base-name lookup for lp32 -static const char* get_base_name(const char* name) { - const char* bname = strrchr(name, '/'); - return bname ? bname + 1 : name; -} -#define SEARCH_NAME(x) get_base_name(x) -#endif - static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); static LinkerTypeAllocator g_soinfo_allocator; @@ -1029,7 +1016,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, return nullptr; } - soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags); + soinfo* si = soinfo_alloc(name, &file_stat, file_offset, rtld_flags); if (si == nullptr) { return nullptr; } @@ -1051,10 +1038,15 @@ static soinfo* load_library(LoadTaskList& load_tasks, return si; } -static soinfo *find_loaded_library_by_name(const char* name) { - const char* search_name = SEARCH_NAME(name); +static soinfo *find_loaded_library_by_soname(const char* name) { + // Ignore filename with path. + if (strchr(name, '/') != nullptr) { + return nullptr; + } + for (soinfo* si = solist; si != nullptr; si = si->next) { - if (!strcmp(search_name, si->name)) { + const char* soname = si->get_soname(); + if (soname != nullptr && (strcmp(name, soname) == 0)) { return si; } } @@ -1062,13 +1054,12 @@ static soinfo *find_loaded_library_by_name(const char* name) { } static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { - - soinfo* si = find_loaded_library_by_name(name); + soinfo* si = find_loaded_library_by_soname(name); // Library might still be loaded, the accurate detection // of this fact is done by load_library. if (si == nullptr) { - TRACE("[ '%s' has not been found by name. Trying harder...]", name); + TRACE("[ '%s' has not been found by soname. Trying harder...]", name); si = load_library(load_tasks, name, rtld_flags, extinfo); } @@ -1832,6 +1823,7 @@ uint32_t soinfo::get_dt_flags_1() const { return 0; } + void soinfo::set_dt_flags_1(uint32_t dt_flags_1) { if (has_min_version(1)) { if ((dt_flags_1 & DF_1_GLOBAL) != 0) { @@ -1846,6 +1838,14 @@ void soinfo::set_dt_flags_1(uint32_t dt_flags_1) { } } +const char* soinfo::get_soname() { + if (has_min_version(2)) { + return soname_; + } else { + return name; + } +} + // This is a return on get_children()/get_parents() if // 'this->flags' does not have FLAG_NEW_SOINFO set. static soinfo::soinfo_list_t g_empty_list; @@ -2012,14 +2012,17 @@ bool soinfo::prelink_image() { #endif // Extract useful information from dynamic section. + // Note that: "Except for the DT_NULL element at the end of the array, + // and the relative order of DT_NEEDED elements, entries may appear in any order." + // + // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html uint32_t needed_count = 0; for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); switch (d->d_tag) { case DT_SONAME: - // TODO: glibc dynamic linker uses this name for - // initial library lookup; consider doing the same here. + // this is parsed after we have strtab initialized (see below). break; case DT_HASH: @@ -2342,6 +2345,14 @@ bool soinfo::prelink_image() { } } + // second pass - parse entries relying on strtab + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_SONAME) { + soname_ = get_string(d->d_un.d_val); + break; + } + } + DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", reinterpret_cast(base), strtab_, symtab_); diff --git a/linker/linker.h b/linker/linker.h index e4681ebe5..04acda413 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -92,7 +92,7 @@ #define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE) -#define SOINFO_VERSION 1 +#define SOINFO_VERSION 2 #define SOINFO_NAME_LEN 128 @@ -278,6 +278,8 @@ struct soinfo { soinfo* get_local_group_root() const; + const char* get_soname(); + private: ElfW(Sym)* elf_lookup(SymbolName& symbol_name); ElfW(Sym)* elf_addr_lookup(const void* addr); @@ -322,6 +324,8 @@ struct soinfo { uint8_t* android_relocs_; size_t android_relocs_size_; + const char* soname_; + friend soinfo* get_libdl_info(); }; diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index ef4ff20f0..2bd9476fa 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -97,6 +97,32 @@ TEST(dlfcn, dlopen_noload) { ASSERT_EQ(0, dlclose(handle2)); } +TEST(dlfcn, dlopen_by_soname) { + static const char* soname = "libdlext_test_soname.so"; + static const char* filename = "libdlext_test_different_soname.so"; + // 1. Make sure there is no library with soname in default search path + void* handle = dlopen(soname, RTLD_NOW); + ASSERT_TRUE(handle == nullptr); + + // 2. Load a library using filename + handle = dlopen(filename, RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + // 3. Find library by soname + void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle_soname != nullptr) << dlerror(); + ASSERT_EQ(handle, handle_soname); + + // 4. RTLD_NOLOAD should still work with filename + void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle_filename != nullptr) << dlerror(); + ASSERT_EQ(handle, handle_filename); + + dlclose(handle_filename); + dlclose(handle_soname); + dlclose(handle); +} + // ifuncs are only supported on intel and arm64 for now #if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 7ca856cdd..665ce0cb7 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -117,6 +117,17 @@ build_type := target build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk +# ---------------------------------------------------------------------------- +# Library with soname which does not match filename +# ---------------------------------------------------------------------------- +libdlext_test_different_soname_src_files := \ + dlext_test_library.cpp \ + +module := libdlext_test_different_soname +module_tag := optional +libdlext_test_different_soname_ldflags := -Wl,-soname=libdlext_test_soname.so +include $(LOCAL_PATH)/Android.build.testlib.mk + # ----------------------------------------------------------------------------- # Library used by dlext tests - zipped and aligned # -----------------------------------------------------------------------------