diff --git a/linker/linker_relocate.cpp b/linker/linker_relocate.cpp index 72be5f74c..c7c7bfbb3 100644 --- a/linker/linker_relocate.cpp +++ b/linker/linker_relocate.cpp @@ -229,6 +229,12 @@ static bool process_relocation_impl(Relocator& relocator, const rel_t& reloc) { auto get_addend_norel = [&]() -> ElfW(Addr) { return 0; }; #endif + if (!IsGeneral && __predict_false(is_tls_reloc(r_type))) { + // Always process TLS relocations using the slow code path, so that STB_LOCAL symbols are + // diagnosed, and ifunc processing is skipped. + return process_relocation_general(relocator, reloc); + } + if (IsGeneral && is_tls_reloc(r_type)) { if (r_sym == 0) { // By convention in ld.bfd and lld, an omitted symbol on a TLS relocation @@ -242,8 +248,15 @@ static bool process_relocation_impl(Relocator& relocator, const rel_t& reloc) { // - https://groups.google.com/d/topic/generic-abi/dJ4_Y78aQ2M/discussion // - https://sourceware.org/bugzilla/show_bug.cgi?id=17699 sym = &relocator.si_symtab[r_sym]; - DL_ERR("unexpected TLS reference to local symbol \"%s\" in \"%s\": sym type %d, rel type %u", - sym_name, relocator.si->get_realpath(), ELF_ST_TYPE(sym->st_info), r_type); + auto sym_type = ELF_ST_TYPE(sym->st_info); + if (sym_type == STT_SECTION) { + DL_ERR("unexpected TLS reference to local section in \"%s\": sym type %d, rel type %u", + relocator.si->get_realpath(), sym_type, r_type); + } else { + DL_ERR( + "unexpected TLS reference to local symbol \"%s\" in \"%s\": sym type %d, rel type %u", + sym_name, relocator.si->get_realpath(), sym_type, r_type); + } return false; } else if (!lookup_symbol(relocator, r_sym, sym_name, &found_in, &sym)) { return false; diff --git a/tests/Android.bp b/tests/Android.bp index 3061142e0..48149c7aa 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -295,6 +295,29 @@ cc_prebuilt_test_library_shared { }, } +cc_prebuilt_test_library_shared { + name: "libtest_invalid-local-tls", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-local-tls.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-local-tls.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-local-tls.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-local-tls.so"], + }, + }, +} + // ----------------------------------------------------------------------------- // All standard tests. // ----------------------------------------------------------------------------- @@ -994,6 +1017,7 @@ cc_defaults { "libtest_init_fini_order_root", "libtest_init_fini_order_root2", "libtest_invalid-empty_shdr_table", + "libtest_invalid-local-tls", "libtest_invalid-rw_load_segment", "libtest_invalid-textrels", "libtest_invalid-textrels2", diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index e3664fd97..940e7268c 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -1654,6 +1654,21 @@ TEST(dlfcn, dlopen_invalid_textrels2) { ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror()); } +TEST(dlfcn, dlopen_invalid_local_tls) { + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-local-tls.so"; + + void* handle = dlopen(libpath.c_str(), RTLD_NOW); + ASSERT_TRUE(handle == nullptr); +#if defined(__arm__) + const char* referent = "local section"; +#else + const char* referent = "local symbol \"tls_var_2\""; +#endif + std::string expected_dlerror = std::string("dlopen failed: unexpected TLS reference to ") + + referent + " in \"" + libpath + "\""; + ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror()); +} + TEST(dlfcn, dlopen_df_1_global) { void* handle = dlopen("libtest_dlopen_df_1_global.so", RTLD_NOW); ASSERT_TRUE(handle != nullptr) << dlerror(); diff --git a/tests/prebuilt-elf-files/arm/libtest_invalid-local-tls.so b/tests/prebuilt-elf-files/arm/libtest_invalid-local-tls.so new file mode 100755 index 000000000..a42848de2 Binary files /dev/null and b/tests/prebuilt-elf-files/arm/libtest_invalid-local-tls.so differ diff --git a/tests/prebuilt-elf-files/arm64/libtest_invalid-local-tls.so b/tests/prebuilt-elf-files/arm64/libtest_invalid-local-tls.so new file mode 100755 index 000000000..20c576525 Binary files /dev/null and b/tests/prebuilt-elf-files/arm64/libtest_invalid-local-tls.so differ diff --git a/tests/prebuilt-elf-files/gen-libtest_invalid-local-tls.sh b/tests/prebuilt-elf-files/gen-libtest_invalid-local-tls.sh new file mode 100755 index 000000000..0f3e73628 --- /dev/null +++ b/tests/prebuilt-elf-files/gen-libtest_invalid-local-tls.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Bionic doesn't support the references to STB_LOCAL symbols of type STT_TLS +# and STT_SECTION that ld.gold generates. Set NDK21E to the path to a copy of +# NDK r21e, which still has ld.gold (unlike the platform build or newer NDKs). + +set -e + +cat >test.c <test2.c <