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);