Merge "We should use load_bias.  This patch fixes MIPS NDK device exception test failures."
diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c
index a73bb71..ba7f008 100644
--- a/libc/bionic/libc_init_static.c
+++ b/libc/bionic/libc_init_static.c
@@ -48,6 +48,14 @@
 
 #include <bionic_tls.h>
 #include <errno.h>
+#include <sys/mman.h>
+
+// Returns the address of the page containing address 'x'.
+#define PAGE_START(x)  ((x) & PAGE_MASK)
+
+// Returns the address of the next page after address 'x', unless 'x' is
+// itself at the start of a page.
+#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
 
 static void call_array(void(**list)())
 {
@@ -57,6 +65,42 @@
     }
 }
 
+/*
+ * Find the value of the AT_* variable passed to us by the kernel.
+ */
+static unsigned find_aux(unsigned *vecs, unsigned type) {
+    while (vecs[0]) {
+        if (vecs[0] == type) {
+            return vecs[1];
+        }
+        vecs += 2;
+    }
+
+    return 0; // should never happen
+}
+
+static void apply_gnu_relro(unsigned *vecs) {
+    Elf32_Phdr *phdr_start;
+    unsigned phdr_ct;
+    Elf32_Phdr *phdr;
+
+    phdr_start = (Elf32_Phdr *) find_aux(vecs, AT_PHDR);
+    phdr_ct    = find_aux(vecs, AT_PHNUM);
+
+    for (phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) {
+        if (phdr->p_type != PT_GNU_RELRO)
+            continue;
+
+        Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr);
+        Elf32_Addr seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz);
+
+        // Check return value here? What do we do if we fail?
+        mprotect((void *) seg_page_start,
+                 seg_page_end - seg_page_start,
+                 PROT_READ);
+    }
+}
+
 __noreturn void __libc_init(uintptr_t *elfdata,
                        void (*onexit)(void),
                        int (*slingshot)(int, char**, char**),
@@ -64,6 +108,7 @@
 {
     int  argc;
     char **argv, **envp;
+    unsigned *vecs;
 
     __libc_init_tls(NULL);
 
@@ -84,6 +129,14 @@
     argv = (char**)(elfdata + 1);
     envp = argv + argc + 1;
 
+    // The auxiliary vector is at the end of the environment block
+    vecs = (unsigned *) envp;
+    while (vecs[0] != 0) {
+        vecs++;
+    }
+    /* The end of the environment block is marked by two NULL pointers */
+    vecs++;
+
     /* The executable may have its own destructors listed in its .fini_array
      * so we need to ensure that these are called when the program exits
      * normally.
@@ -91,5 +144,6 @@
     if (structors->fini_array)
         __cxa_atexit(__libc_fini,structors->fini_array,NULL);
 
+    apply_gnu_relro(vecs);
     exit(slingshot(argc, argv, envp));
 }
diff --git a/linker/linker_format.cpp b/linker/linker_format.cpp
index 60b759b..65c6264 100644
--- a/linker/linker_format.cpp
+++ b/linker/linker_format.cpp
@@ -26,6 +26,10 @@
  * SUCH DAMAGE.
  */
 
+// Temporarily disable _FORTIFY_SOURCE to get this code to
+// compile under GCC 4.7
+#undef _FORTIFY_SOURCE
+
 #include <assert.h>
 #include <stdarg.h>
 #include <string.h>