Add tests for static ELF TLS
Bug: http://b/78026329
Test: bionic unit tests
Merged-In: I806f2bd193998dfe352372476104876edb27aebf
Change-Id: I806f2bd193998dfe352372476104876edb27aebf
diff --git a/tests/Android.bp b/tests/Android.bp
index beed07a..8ac0531 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -218,6 +218,44 @@
generated_headers: ["generated_android_ids"],
}
+cc_test_library {
+ name: "libBionicElfTlsTests",
+ defaults: ["bionic_tests_defaults"],
+ srcs: [
+ "elftls_test.cpp",
+ ],
+ include_dirs: [
+ "bionic/libc",
+ ],
+ shared: {
+ enabled: false,
+ },
+ cflags: [
+ "-fno-emulated-tls",
+ ],
+}
+
+cc_test_library {
+ name: "libBionicElfTlsLoaderTests",
+ defaults: ["bionic_tests_defaults"],
+ srcs: [
+ "elftls_dl_test.cpp",
+ ],
+ include_dirs: [
+ "bionic/libc",
+ ],
+ static_libs: [
+ "liblog",
+ "libbase",
+ ],
+ shared: {
+ enabled: false,
+ },
+ cflags: [
+ "-fno-emulated-tls",
+ ],
+}
+
// -----------------------------------------------------------------------------
// Fortify tests.
// -----------------------------------------------------------------------------
@@ -306,6 +344,7 @@
defaults: ["bionic_tests_defaults"],
whole_static_libs: [
"libBionicStandardTests",
+ "libBionicElfTlsTests",
"libfortify1-tests-clang",
"libfortify2-tests-clang",
],
@@ -389,6 +428,7 @@
whole_static_libs: [
"libBionicTests",
"libBionicLoaderTests",
+ "libBionicElfTlsLoaderTests",
],
static_libs: [
@@ -423,6 +463,8 @@
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
+ "libtest_elftls_shared_var",
+ "libtest_elftls_tprel",
],
static_libs: [
// The order of these libraries matters, do not shuffle them.
@@ -471,6 +513,7 @@
required: [
"cfi_test_helper",
"cfi_test_helper2",
+ "elftls_dlopen_ie_error_helper",
"exec_linker_helper",
"exec_linker_helper_lib",
"libtest_dt_runpath_a",
@@ -528,6 +571,9 @@
"libtest_dlsym_from_this",
"libtest_dlsym_weak_func",
"libtest_dt_runpath_d",
+ "libtest_elftls_shared_var",
+ "libtest_elftls_shared_var_ie",
+ "libtest_elftls_tprel",
"libtest_empty",
"libtest_ifunc_variable_impl",
"libtest_ifunc_variable",
@@ -629,6 +675,8 @@
"libbase",
"libdebuggerd_handler",
"libgtest_isolated",
+ "libtest_elftls_shared_var",
+ "libtest_elftls_tprel",
],
static_executable: true,
@@ -662,12 +710,15 @@
shared_libs: [
"libdl_preempt_test_1",
"libdl_preempt_test_2",
-
"libdl_test_df_1_global",
+ "libtest_elftls_shared_var",
+ "libtest_elftls_tprel",
],
whole_static_libs: [
"libBionicStandardTests",
+ "libBionicElfTlsTests",
+ "libBionicElfTlsLoaderTests",
"libfortify1-tests-clang",
"libfortify2-tests-clang",
],
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
new file mode 100644
index 0000000..0a97c28
--- /dev/null
+++ b/tests/elftls_dl_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dlfcn.h>
+#include <gtest/gtest.h>
+
+#include <thread>
+
+#include "gtest_globals.h"
+#include "utils.h"
+
+// Access libtest_elftls_shared_var.so's TLS variable using an IE access.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+TEST(elftls_dl, dlopen_shared_var_ie) {
+ // libtest_elftls_shared_var_ie.so can be dlopen'ed, even though it contains a
+ // TLS IE access, because its IE access references a TLS variable from
+ // libtest_elftls_shared_var.so, which is DT_NEEDED by the executable. This
+ // pattern appears in sanitizers, which use TLS IE instrumentation in shared
+ // objects to access special variables exported from the executable or from a
+ // preloaded solib.
+ void* lib = dlopen("libtest_elftls_shared_var_ie.so", RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, lib);
+
+ auto bump_shared_var = reinterpret_cast<int(*)()>(dlsym(lib, "bump_shared_var"));
+ ASSERT_NE(nullptr, bump_shared_var);
+
+ ASSERT_EQ(21, ++elftls_shared_var);
+ ASSERT_EQ(22, bump_shared_var());
+
+ std::thread([bump_shared_var] {
+ ASSERT_EQ(21, ++elftls_shared_var);
+ ASSERT_EQ(22, bump_shared_var());
+ }).join();
+}
+
+TEST(elftls_dl, dlopen_ie_error) {
+ std::string helper = GetTestlibRoot() +
+ "/elftls_dlopen_ie_error_helper/elftls_dlopen_ie_error_helper";
+ std::string src_path = GetTestlibRoot() + "/libtest_elftls_shared_var_ie.so";
+ std::string dst_path = GetTestlibRoot() + "/libtest_elftls_shared_var.so";
+#if defined(__BIONIC__)
+ std::string error =
+ "dlerror: dlopen failed: TLS symbol \"elftls_shared_var\" in dlopened \"" + dst_path + "\" " +
+ "referenced from \"" + src_path + "\" using IE access model\n";
+#else
+ // glibc will reserve some surplus static TLS memory, allowing this test to pass.
+ std::string error = "success\n";
+#endif
+
+ chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, error.c_str());
+}
diff --git a/tests/elftls_test.cpp b/tests/elftls_test.cpp
new file mode 100644
index 0000000..11d41ce
--- /dev/null
+++ b/tests/elftls_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <thread>
+
+#include "private/__get_tls.h"
+
+// Specify the LE access model explicitly. This file is compiled into the
+// bionic-unit-tests executable, but the compiler sees an -fpic object file
+// output into a static library, so it defaults to dynamic TLS accesses.
+
+// This variable will be zero-initialized (.tbss)
+__attribute__((tls_model("local-exec"))) static __thread int tlsvar_le_zero;
+
+// This variable will have an initializer (.tdata)
+__attribute__((tls_model("local-exec"))) static __thread int tlsvar_le_init = 10;
+
+// Access libtest_elftls_shared_var's TLS variable using an IE access.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+TEST(elftls, basic_le) {
+ // Check the variables on the main thread.
+ ASSERT_EQ(11, ++tlsvar_le_init);
+ ASSERT_EQ(1, ++tlsvar_le_zero);
+
+ // Check variables on a new thread.
+ std::thread([] {
+ ASSERT_EQ(11, ++tlsvar_le_init);
+ ASSERT_EQ(1, ++tlsvar_le_zero);
+ }).join();
+}
+
+TEST(elftls, shared_ie) {
+ ASSERT_EQ(21, ++elftls_shared_var);
+ std::thread([] {
+ ASSERT_EQ(21, ++elftls_shared_var);
+ }).join();
+}
+
+extern "C" int* missing_weak_tls_addr();
+extern "C" int bump_static_tls_var_1();
+extern "C" int bump_static_tls_var_2();
+
+TEST(elftls, tprel_missing_weak) {
+ ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
+ std::thread([] {
+ ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
+ }).join();
+}
+
+TEST(elftls, tprel_addend) {
+ ASSERT_EQ(4, bump_static_tls_var_1());
+ ASSERT_EQ(8, bump_static_tls_var_2());
+ std::thread([] {
+ ASSERT_EQ(4, bump_static_tls_var_1());
+ ASSERT_EQ(8, bump_static_tls_var_2());
+ }).join();
+}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index c06cb12..05d1ed2 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -40,7 +40,7 @@
}
// -----------------------------------------------------------------------------
-// Library to test ELF TLS
+// Libraries and helper binaries for ELF TLS
// -----------------------------------------------------------------------------
cc_test_library {
name: "libelf-tls-library",
@@ -50,6 +50,35 @@
allow_undefined_symbols: true, // __tls_get_addr is undefined.
}
+cc_test_library {
+ name: "libtest_elftls_shared_var",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_shared_var.cpp"],
+ cflags: ["-fno-emulated-tls"],
+}
+
+cc_test_library {
+ name: "libtest_elftls_shared_var_ie",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_shared_var_ie.cpp"],
+ cflags: ["-fno-emulated-tls"],
+ shared_libs: ["libtest_elftls_shared_var"],
+}
+
+cc_test_library {
+ name: "libtest_elftls_tprel",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_tprel.cpp"],
+ cflags: ["-fno-emulated-tls"],
+}
+
+cc_test {
+ name: "elftls_dlopen_ie_error_helper",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elftls_dlopen_ie_error_helper.cpp"],
+ ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
// -----------------------------------------------------------------------------
// Library to test gnu-styled hash
// -----------------------------------------------------------------------------
diff --git a/tests/libs/elftls_dlopen_ie_error_helper.cpp b/tests/libs/elftls_dlopen_ie_error_helper.cpp
new file mode 100644
index 0000000..5902e07
--- /dev/null
+++ b/tests/libs/elftls_dlopen_ie_error_helper.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+// This helper executable attempts to load libtest_elftls_shared_var_ie.so,
+// then reports success or failure. With Bionic, it is expected to fail, because
+// libtest_elftls_shared_var_ie.so tries to access a dynamically-allocated TLS
+// variable using the IE access model intended for static TLS.
+
+int main() {
+ void* lib = dlopen("libtest_elftls_shared_var_ie.so", RTLD_LOCAL | RTLD_NOW);
+ if (lib) {
+ printf("success\n");
+ } else {
+ printf("dlerror: %s\n", dlerror());
+ }
+ return 0;
+}
diff --git a/tests/libs/elftls_shared_var.cpp b/tests/libs/elftls_shared_var.cpp
new file mode 100644
index 0000000..27a15f0
--- /dev/null
+++ b/tests/libs/elftls_shared_var.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This shared object merely declares a global TLS variable without accessing
+// it.
+
+extern "C" __thread int elftls_shared_var = 20;
diff --git a/tests/libs/elftls_shared_var_ie.cpp b/tests/libs/elftls_shared_var_ie.cpp
new file mode 100644
index 0000000..14e2ab0
--- /dev/null
+++ b/tests/libs/elftls_shared_var_ie.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Accessing a symbol in libtest_elftls_shared_var.so using an IE access should
+// work iff the solib is part of static TLS.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+extern "C" int bump_shared_var() {
+ return ++elftls_shared_var;
+}
diff --git a/tests/libs/elftls_tprel.cpp b/tests/libs/elftls_tprel.cpp
new file mode 100644
index 0000000..eb2fd93
--- /dev/null
+++ b/tests/libs/elftls_tprel.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This shared object tests TPREL relocations in the dynamic linker. It's always
+// part of static TLS.
+
+// For accesses to these variables, the bfd and lld linkers generate a TPREL
+// relocation with no symbol but a non-zero addend.
+__attribute__((tls_model("initial-exec"))) static __thread int tls_var_1 = 3;
+__attribute__((tls_model("initial-exec"))) static __thread int tls_var_2 = 7;
+
+extern "C" int bump_static_tls_var_1() {
+ return ++tls_var_1;
+}
+
+extern "C" int bump_static_tls_var_2() {
+ return ++tls_var_2;
+}
+
+__attribute__((tls_model("initial-exec"), weak)) extern "C" __thread int missing_weak_tls;
+
+extern "C" int* missing_weak_tls_addr() {
+ // The dynamic linker should resolve a TPREL relocation to this symbol to 0,
+ // which this function adds to the thread pointer.
+ return &missing_weak_tls;
+}