Initialize __libc_sysinfo early on.
__libc_sysinfo is hidden, so accessing it doesn't require a relocated GOT.
It is important not to have a relocatable initializer on __libc_sysinfo,
because if it did have one, and if we initialized it before relocating the
linker, then on 32-bit x86 (which uses REL rather than RELA), the
relocation step would calculate the wrong addend and overwrite
__libc_sysinfo with garbage.
Asides:
* It'd be simpler to keep the __libc_sysinfo initializer for static
executables, but the loader pulls in libc_init_static (even though it
uses almost none of the code in that file, like __libc_init).
* The loader has called __libc_init_sysinfo three times by the time it
has relocated itself. A static executable calls it twice, while libc.so
calls it only once.
Bug: none
Test: lunch aosp_x86-userdebug ; emulator
Test: adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
Test: adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
Change-Id: I5944f57847db7191608f4f83dde22b49e279e6cb
diff --git a/libc/Android.bp b/libc/Android.bp
index 00686ac..42b6cf7 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -102,7 +102,10 @@
srcs: ["arch-arm64/bionic/__set_tls.c"],
},
x86: {
- srcs: ["arch-x86/bionic/__set_tls.cpp"],
+ srcs: [
+ "arch-x86/bionic/__libc_init_sysinfo.cpp",
+ "arch-x86/bionic/__set_tls.cpp",
+ ],
},
x86_64: {
srcs: ["arch-x86_64/bionic/__set_tls.c"],
diff --git a/libc/arch-x86/bionic/__libc_init_sysinfo.cpp b/libc/arch-x86/bionic/__libc_init_sysinfo.cpp
new file mode 100644
index 0000000..f7c8c23
--- /dev/null
+++ b/libc/arch-x86/bionic/__libc_init_sysinfo.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 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 "private/KernelArgumentBlock.h"
+#include "private/bionic_globals.h"
+
+// This file is compiled without stack protection, because it runs before TLS
+// has been set up.
+
+__LIBC_HIDDEN__ __attribute__((__naked__)) void __libc_int0x80() {
+ __asm__ volatile("int $0x80; ret");
+}
+
+__LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args) {
+ // Running under valgrind, AT_SYSINFO won't be set. http://b/77856586.
+ void* at_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
+ __libc_sysinfo = (at_sysinfo != nullptr) ? at_sysinfo :
+ reinterpret_cast<void*>(__libc_int0x80);
+}
+
+// TODO: lose this function and just access __libc_sysinfo directly.
+__LIBC_HIDDEN__ extern "C" void* __kernel_syscall() {
+ return __libc_sysinfo;
+}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2396c36..1ff6603 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -60,25 +60,6 @@
// Not public, but well-known in the BSDs.
const char* __progname;
-#if defined(__i386__)
-__attribute__((__naked__)) static void __libc_int0x80() {
- __asm__ volatile("int $0x80; ret");
-}
-
-__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
-
-__LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args) {
- // Running under valgrind, AT_SYSINFO won't be set.
- void* at_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
- if (at_sysinfo != nullptr) __libc_sysinfo = at_sysinfo;
-}
-
-// TODO: lose this function and just access __libc_sysinfo directly.
-__LIBC_HIDDEN__ extern "C" void* __kernel_syscall() {
- return __libc_sysinfo;
-}
-#endif
-
void __libc_init_globals(KernelArgumentBlock& args) {
#if defined(__i386__)
__libc_init_sysinfo(args);
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index fb086c8..6b8f57f 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -62,6 +62,12 @@
extern int __cxa_atexit(void (*)(void *), void *, void *);
};
+// Use an initializer so __libc_sysinfo will have a fallback implementation
+// while .preinit_array constructors run.
+#if defined(__i386__)
+__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
+#endif
+
// We need a helper function for __libc_preinit because compiling with LTO may
// inline functions requiring a stack protector check, but __stack_chk_guard is
// not initialized at the start of __libc_preinit. __libc_preinit_impl will run
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 4d62efe..038f6a7 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -45,6 +45,13 @@
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
+// Leave the variable uninitialized for the sake of the dynamic loader, which
+// links in this file. The loader will initialize this variable before
+// relocating itself.
+#if defined(__i386__)
+__LIBC_HIDDEN__ void* __libc_sysinfo;
+#endif
+
extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
static void call_array(void(**list)()) {
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 94dd7e8..ad0244c 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -50,6 +50,7 @@
#if defined(__i386__)
__LIBC_HIDDEN__ extern void* __libc_sysinfo;
+__LIBC_HIDDEN__ void __libc_int0x80();
__LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args);
#endif
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index fa4fd4c..331f831 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -510,6 +510,10 @@
extern "C" ElfW(Addr) __linker_init(void* raw_args) {
KernelArgumentBlock args(raw_args);
+#if defined(__i386__)
+ __libc_init_sysinfo(args);
+#endif
+
// AT_BASE is set to 0 in the case when linker is run by iself
// so in order to link the linker it needs to calcuate AT_BASE
// using information at hand. The trick below takes advantage
@@ -552,15 +556,6 @@
// functions at this point.
if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);
-#if defined(__i386__)
- // On x86, we can't make system calls before this point.
- // We can't move this up because this needs to assign to a global.
- // Note that until we call __libc_init_main_thread below we have
- // no TLS, so you shouldn't make a system call that can fail, because
- // it will SEGV when it tries to set errno.
- __libc_init_sysinfo(args);
-#endif
-
// Initialize the main thread (including TLS, so system calls really work).
__libc_init_main_thread(args);