libc: implement kernel vdso syscalls for i386

This patch uses __kernel_vsyscall instead of "int 0x80"
as the syscall entry point. AT_SYSINFO points to
an adapter to mask the arch specific difference and gives a
performance boost on i386 architecture.

Change-ID: Ib340c604d02c6c25714a95793737e3cfdc3fc5d7
Signed-off-by: Mingwei Shi <mingwei.shi@intel.com>
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 724b6a1..2cdfd2c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -44,6 +44,7 @@
 #include <vector>
 
 // Private C library headers.
+#include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 #include "private/ScopedPthreadMutexLocker.h"
@@ -65,6 +66,8 @@
 extern void __libc_init_globals(KernelArgumentBlock&);
 extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
 
+extern "C" void _start();
+
 // Override macros to use C++ style casts.
 #undef ELF_ST_TYPE
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
@@ -3789,10 +3792,9 @@
   }
 #endif
 
-  /* We can also turn on GNU RELRO protection */
-  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
-    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
-           get_realpath(), strerror(errno));
+  // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
+  // itself --- it can't make system calls yet, and will have to call protect_relro later.
+  if (!is_linker() && !protect_relro()) {
     return false;
   }
 
@@ -3817,6 +3819,15 @@
   return true;
 }
 
+bool soinfo::protect_relro() {
+  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
+    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
+           get_realpath(), strerror(errno));
+    return false;
+  }
+  return true;
+}
+
 /*
  * This function add vdso to internal dso list.
  * It helps to stack unwinding through signal handlers.
@@ -4119,8 +4130,9 @@
   return 0;
 }
 
-extern "C" int __set_tls(void*);
-extern "C" void _start();
+static void __linker_cannot_link(KernelArgumentBlock& args) {
+  __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer());
+}
 
 /*
  * This is the entry point for the linker, called from begin.S. This
@@ -4134,9 +4146,6 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   KernelArgumentBlock args(raw_args);
 
-  void* tls[BIONIC_TLS_SLOTS];
-  __set_tls(tls);
-
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
   ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
@@ -4165,18 +4174,33 @@
   linker_so.phnum = elf_hdr->e_phnum;
   linker_so.set_linker_flag();
 
+  // Prelink the linker so we can access linker globals.
+  if (!linker_so.prelink_image()) __linker_cannot_link(args);
+
   // This might not be obvious... The reasons why we pass g_empty_list
   // in place of local_group here are (1) we do not really need it, because
   // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
   // itself without having to look into local_group and (2) allocators
   // are not yet initialized, and therefore we cannot use linked_list.push_*
   // functions at this point.
-  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer());
-  }
+  if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args);
 
+#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);
 
+  // We didn't protect the linker's RELRO pages in link_image because we
+  // couldn't make system calls on x86 at that point, but we can now...
+  if (!linker_so.protect_relro()) __linker_cannot_link(args);
+
   // Initialize the linker's static libc's globals
   __libc_init_globals(args);
 
diff --git a/linker/linker.h b/linker/linker.h
index d364021..9145454 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -275,6 +275,7 @@
   bool prelink_image();
   bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
                   const android_dlextinfo* extinfo);
+  bool protect_relro();
 
   void add_child(soinfo* child);
   void remove_all_links();