Merge changes I72d37b7c,I7d254a10,I2e967acf

* changes:
  versioner: use a virtual filesystem for input files.
  versioner: cache -cc1 flags generated by the clang Driver.
  versioner: refactor to use CompilerInstance directly.
diff --git a/README.md b/README.md
index 0bf6c6d..6f8edf4 100644
--- a/README.md
+++ b/README.md
@@ -268,6 +268,25 @@
 The coverage report is now available at `covreport/index.html`.
 
 
+Running the benchmarks
+----------------------
+
+### Device benchmarks
+
+    $ mma
+    $ adb remount
+    $ adb sync
+    $ adb shell /data/nativetest/bionic-benchmarks/bionic-benchmarks
+    $ adb shell /data/nativetest64/bionic-benchmarks/bionic-benchmarks
+
+You can use `--benchmark_filter=getpid` to just run benchmarks with "getpid"
+in their name.
+
+### Host benchmarks
+
+See the "Host tests" section of "Running the tests" above.
+
+
 Attaching GDB to the tests
 --------------------------
 
diff --git a/libc/Android.bp b/libc/Android.bp
index 62ca943..00932de 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1209,6 +1209,7 @@
         "bionic/arpa_inet.cpp",
         "bionic/assert.cpp",
         "bionic/atof.cpp",
+        "bionic/bionic_arc4random.cpp",
         "bionic/bionic_netlink.cpp",
         "bionic/bionic_systrace.cpp",
         "bionic/bionic_time_conversions.cpp",
diff --git a/libc/NOTICE b/libc/NOTICE
index a2f2b0a..cdf29e3 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -5503,7 +5503,7 @@
 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 Emulation of getentropy(2) as documented at:
-http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+http://man.openbsd.org/getentropy.2
 
 -------------------------------------------------------------------
 
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
index 3692f04..da40f6c 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,174 @@
  * SUCH DAMAGE.
  */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "__strcat_chk_common.S"
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of src string, then get the source of the dst string.
+// Check that the two lengths together don't exceed the threshold, then
+// do a memcpy of the data.
+ENTRY(__strcat_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+    push    {r4, r5}
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+
+    mov     lr, r2
+
+    // Save the dst register to r5
+    mov     r5, r0
+
+    // Zero out r4
+    eor     r4, r4, r4
+
+    // r1 contains the address of the string to count.
+.L_strlen_start:
+    mov     r0, r1
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r1], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r1], #8
+
+    pld     [r1, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r1, r0
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_zero_in_first_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_finish
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_finish
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_finish
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_finish
+
+.L_zero_in_second_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_finish
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_finish
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_finish:
+    cmp     r4, #0
+    bne     .L_strlen_done
+
+    // Time to get the dst string length.
+    mov     r1, r5
+
+    // Save the original source address to r5.
+    mov     r5, r0
+
+    // Save the current length (adding 1 for the terminator).
+    add     r4, r3, #1
+    b       .L_strlen_start
+
+    // r0 holds the pointer to the dst string.
+    // r3 holds the dst string length.
+    // r4 holds the src string length + 1.
+.L_strlen_done:
+    add     r2, r3, r4
+    cmp     r2, lr
+    itt     hi
+    movhi   r0, lr
+    bhi     __strcat_chk_fail
+
+    // Set up the registers for the memcpy code.
+    mov     r1, r5
+    pld     [r1, #64]
+    mov     r2, r4
+    add     r0, r0, r3
+    pop     {r4, r5}
+    .cfi_adjust_cfa_offset -8
+    .cfi_restore r4
+    .cfi_restore r5
+
+#include "memcpy_base.S"
+
+    // Undo the above cfi directives
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+END(__strcat_chk)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S
deleted file mode 100644
index a610dd5..0000000
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2013 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/bionic_asm.h>
-
-    .syntax unified
-
-    .thumb
-    .thumb_func
-
-// Get the length of src string, then get the source of the dst string.
-// Check that the two lengths together don't exceed the threshold, then
-// do a memcpy of the data.
-ENTRY(__strcat_chk)
-    pld     [r0, #0]
-    push    {r0, lr}
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-    push    {r4, r5}
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r4, 0
-    .cfi_rel_offset r5, 4
-
-    mov     lr, r2
-
-    // Save the dst register to r5
-    mov     r5, r0
-
-    // Zero out r4
-    eor     r4, r4, r4
-
-    // r1 contains the address of the string to count.
-.L_strlen_start:
-    mov     r0, r1
-    ands    r3, r1, #7
-    beq     .L_mainloop
-
-    // Align to a double word (64 bits).
-    rsb     r3, r3, #8
-    lsls    ip, r3, #31
-    beq     .L_align_to_32
-
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_32:
-    bcc     .L_align_to_64
-    ands    ip, r3, #2
-    beq     .L_align_to_64
-
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_64:
-    tst     r3, #4
-    beq     .L_mainloop
-    ldr     r3, [r1], #4
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-
-    .p2align 2
-.L_mainloop:
-    ldrd    r2, r3, [r1], #8
-
-    pld     [r1, #64]
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_first_register
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-    b       .L_mainloop
-
-.L_update_count_and_finish:
-    sub     r3, r1, r0
-    sub     r3, r3, #1
-    b       .L_finish
-
-.L_zero_in_first_register:
-    sub     r3, r1, r0
-    lsls    r2, ip, #17
-    bne     .L_sub8_and_finish
-    bcs     .L_sub7_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub6_and_finish
-
-    sub     r3, r3, #5
-    b       .L_finish
-
-.L_sub8_and_finish:
-    sub     r3, r3, #8
-    b       .L_finish
-
-.L_sub7_and_finish:
-    sub     r3, r3, #7
-    b       .L_finish
-
-.L_sub6_and_finish:
-    sub     r3, r3, #6
-    b       .L_finish
-
-.L_zero_in_second_register:
-    sub     r3, r1, r0
-    lsls    r2, ip, #17
-    bne     .L_sub4_and_finish
-    bcs     .L_sub3_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub2_and_finish
-
-    sub     r3, r3, #1
-    b       .L_finish
-
-.L_sub4_and_finish:
-    sub     r3, r3, #4
-    b       .L_finish
-
-.L_sub3_and_finish:
-    sub     r3, r3, #3
-    b       .L_finish
-
-.L_sub2_and_finish:
-    sub     r3, r3, #2
-
-.L_finish:
-    cmp     r4, #0
-    bne     .L_strlen_done
-
-    // Time to get the dst string length.
-    mov     r1, r5
-
-    // Save the original source address to r5.
-    mov     r5, r0
-
-    // Save the current length (adding 1 for the terminator).
-    add     r4, r3, #1
-    b       .L_strlen_start
-
-    // r0 holds the pointer to the dst string.
-    // r3 holds the dst string length.
-    // r4 holds the src string length + 1.
-.L_strlen_done:
-    add     r2, r3, r4
-    cmp     r2, lr
-    itt     hi
-    movhi   r0, lr
-    bhi     __strcat_chk_fail
-
-    // Set up the registers for the memcpy code.
-    mov     r1, r5
-    pld     [r1, #64]
-    mov     r2, r4
-    add     r0, r0, r3
-    pop     {r4, r5}
-    .cfi_adjust_cfa_offset -8
-    .cfi_restore r4
-    .cfi_restore r5
-
-#include MEMCPY_BASE
-
-    // Undo the above cfi directives
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r4, 0
-    .cfi_rel_offset r5, 4
-END(__strcat_chk)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
index d8cb3d9..026adcc 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,136 @@
  * SUCH DAMAGE.
  */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "__strcpy_chk_common.S"
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of the source string first, then do a memcpy of the data
+// instead of a strcpy.
+ENTRY(__strcpy_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
+    mov     lr, r2
+    mov     r0, r1
+
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r0], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r0], #8
+
+    pld     [r0, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r0, r1
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_zero_in_first_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_check_size
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_check_size
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_check_size
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_check_size
+
+.L_zero_in_second_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_check_size
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_check_size
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_check_size:
+    pld     [r1, #0]
+    pld     [r1, #64]
+    ldr     r0, [sp]
+
+    // Add 1 for copy length to get the string terminator.
+    add     r2, r3, #1
+
+    cmp     r2, lr
+    itt     hi
+    movhi   r0, r2
+    bhi     __strcpy_chk_fail
+
+#include "memcpy_base.S"
+
+END(__strcpy_chk)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S
deleted file mode 100644
index 377e720..0000000
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2013 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/bionic_asm.h>
-
-    .syntax unified
-
-    .thumb
-    .thumb_func
-
-// Get the length of the source string first, then do a memcpy of the data
-// instead of a strcpy.
-ENTRY(__strcpy_chk)
-    pld     [r0, #0]
-    push    {r0, lr}
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-
-    mov     lr, r2
-    mov     r0, r1
-
-    ands    r3, r1, #7
-    beq     .L_mainloop
-
-    // Align to a double word (64 bits).
-    rsb     r3, r3, #8
-    lsls    ip, r3, #31
-    beq     .L_align_to_32
-
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_32:
-    bcc     .L_align_to_64
-    ands    ip, r3, #2
-    beq     .L_align_to_64
-
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_64:
-    tst     r3, #4
-    beq     .L_mainloop
-    ldr     r3, [r0], #4
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-
-    .p2align 2
-.L_mainloop:
-    ldrd    r2, r3, [r0], #8
-
-    pld     [r0, #64]
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_first_register
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-    b       .L_mainloop
-
-.L_update_count_and_finish:
-    sub     r3, r0, r1
-    sub     r3, r3, #1
-    b       .L_check_size
-
-.L_zero_in_first_register:
-    sub     r3, r0, r1
-    lsls    r2, ip, #17
-    bne     .L_sub8_and_finish
-    bcs     .L_sub7_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub6_and_finish
-
-    sub     r3, r3, #5
-    b       .L_check_size
-
-.L_sub8_and_finish:
-    sub     r3, r3, #8
-    b       .L_check_size
-
-.L_sub7_and_finish:
-    sub     r3, r3, #7
-    b       .L_check_size
-
-.L_sub6_and_finish:
-    sub     r3, r3, #6
-    b       .L_check_size
-
-.L_zero_in_second_register:
-    sub     r3, r0, r1
-    lsls    r2, ip, #17
-    bne     .L_sub4_and_finish
-    bcs     .L_sub3_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub2_and_finish
-
-    sub     r3, r3, #1
-    b       .L_check_size
-
-.L_sub4_and_finish:
-    sub     r3, r3, #4
-    b       .L_check_size
-
-.L_sub3_and_finish:
-    sub     r3, r3, #3
-    b       .L_check_size
-
-.L_sub2_and_finish:
-    sub     r3, r3, #2
-
-.L_check_size:
-    pld     [r1, #0]
-    pld     [r1, #64]
-    ldr     r0, [sp]
-
-    // Add 1 for copy length to get the string terminator.
-    add     r2, r3, #1
-
-    cmp     r2, lr
-    itt     hi
-    movhi   r0, r2
-    bhi     __strcpy_chk_fail
-
-#include MEMCPY_BASE
-
-END(__strcpy_chk)
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 537f3de..9407a08 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,8 +25,58 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*
+ * Copyright (c) 2013 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+ */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "memcpy_common.S"
+        .text
+        .syntax unified
+        .fpu    neon
+
+ENTRY(__memcpy_chk)
+        cmp r2, r3
+        bls memcpy
+
+        // Preserve lr for backtrace.
+        push        {lr}
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
+        bl          __memcpy_chk_fail
+END(__memcpy_chk)
+
+// Prototype: void *memcpy (void *dst, const void *src, size_t count).
+ENTRY(memcpy)
+        pld     [r1, #64]
+        push    {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
+#include "memcpy_base.S"
+END(memcpy)
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
index aac737d..1d152bb 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
@@ -68,11 +68,6 @@
         cmp     r2, #16
         blo     .L_copy_less_than_16_unknown_align
 
-        // TODO: The aligned copy code is extremely slow copying some large
-        //       buffers so always go through the unaligned path for now.
-        //cmp     r2, #832
-        //bge     .L_check_alignment
-
 .L_copy_unknown_alignment:
         // Unknown alignment of src and dst.
         // Assumes that the first few bytes have already been prefetched.
@@ -157,178 +152,3 @@
         strbcs      lr, [r0]
 
         pop         {r0, pc}
-
-.L_check_alignment:
-        // If src and dst cannot both be aligned to a word boundary,
-        // use the unaligned copy version.
-        eor     r3, r0, r1
-        ands    r3, r3, #0x3
-        bne     .L_copy_unknown_alignment
-
-        // To try and improve performance, stack layout changed,
-        // i.e., not keeping the stack looking like users expect
-        // (highest numbered register at highest address).
-        strd    r4, r5, [sp, #-8]!
-        .cfi_adjust_cfa_offset 8
-        .cfi_rel_offset r4, 0
-        .cfi_rel_offset r5, 4
-        strd    r6, r7, [sp, #-8]!
-        .cfi_adjust_cfa_offset 8
-        .cfi_rel_offset r6, 0
-        .cfi_rel_offset r7, 4
-        strd    r8, r9, [sp, #-8]!
-        .cfi_adjust_cfa_offset 8
-        .cfi_rel_offset r8, 0
-        .cfi_rel_offset r9, 4
-
-        // Optimized for already aligned dst code.
-        ands    ip, r0, #3
-        bne     .L_dst_not_word_aligned
-
-.L_word_aligned:
-        // Align the destination buffer to 8 bytes, to make sure double
-        // loads and stores don't cross a cache line boundary,
-        // as they are then more expensive even if the data is in the cache
-        // (require two load/store issue cycles instead of one).
-        // If only one of the buffers is not 8 bytes aligned,
-        // then it's more important to align dst than src,
-        // because there is more penalty for stores
-        // than loads that cross a cacheline boundary.
-        // This check and realignment are only done if there is >= 832
-        // bytes to copy.
-
-        // Dst is word aligned, but check if it is already double word aligned.
-        ands    r3, r0, #4
-        beq     1f
-        ldr     r3, [r1], #4
-        str     r3, [r0], #4
-        sub     r2, #4
-
-1:      // Can only get here if > 64 bytes to copy, so don't do check r2.
-        sub     r2, #64
-
-2:      // Every loop iteration copies 64 bytes.
-        .irp    offset, #0, #8, #16, #24, #32
-        ldrd    r4, r5, [r1, \offset]
-        strd    r4, r5, [r0, \offset]
-        .endr
-
-        ldrd    r4, r5, [r1, #40]
-        ldrd    r6, r7, [r1, #48]
-        ldrd    r8, r9, [r1, #56]
-
-        // Keep the pld as far from the next load as possible.
-        // The amount to prefetch was determined experimentally using
-        // large sizes, and verifying the prefetch size does not affect
-        // the smaller copies too much.
-        // WARNING: If the ldrd and strd instructions get too far away
-        //          from each other, performance suffers. Three loads
-        //          in a row is the best tradeoff.
-        pld     [r1, #(64*16)]
-        strd    r4, r5, [r0, #40]
-        strd    r6, r7, [r0, #48]
-        strd    r8, r9, [r0, #56]
-
-        add     r0, r0, #64
-        add     r1, r1, #64
-        subs    r2, r2, #64
-        bge     2b
-
-        // Fix-up the remaining count and make sure we have >= 32 bytes left.
-        adds    r2, r2, #32
-        blo     4f
-
-        // Copy 32 bytes. These cache lines were already preloaded.
-        .irp    offset, #0, #8, #16, #24
-        ldrd    r4, r5, [r1, \offset]
-        strd    r4, r5, [r0, \offset]
-        .endr
-        add     r1, r1, #32
-        add     r0, r0, #32
-        sub     r2, r2, #32
-4:      // Less than 32 left.
-        add     r2, r2, #32
-        tst     r2, #0x10
-        beq     5f
-        // Copy 16 bytes.
-        .irp    offset, #0, #8
-        ldrd    r4, r5, [r1, \offset]
-        strd    r4, r5, [r0, \offset]
-        .endr
-        add     r1, r1, #16
-        add     r0, r0, #16
-
-5:      // Copy up to 15 bytes (count in r2).
-        movs    ip, r2, lsl #29
-        bcc     1f
-        // Copy 8 bytes.
-        ldrd    r4, r5, [r1], #8
-        strd    r4, r5, [r0], #8
-1:      bge         2f
-        // Copy 4 bytes.
-        ldr     r4, [r1], #4
-        str     r4, [r0], #4
-2:      // Copy 0 to 4 bytes.
-        lsls    r2, r2, #31
-        itt     ne
-        ldrbne  lr, [r1], #1
-        strbne  lr, [r0], #1
-        itttt   cs
-        ldrbcs  ip, [r1], #1
-        ldrbcs  lr, [r1]
-        strbcs  ip, [r0], #1
-        strbcs  lr, [r0]
-
-        // Restore registers: optimized pop {r0, pc}
-        ldrd    r8, r9, [sp], #8
-        .cfi_adjust_cfa_offset -8
-        .cfi_restore r8
-        .cfi_restore r9
-        ldrd    r6, r7, [sp], #8
-        .cfi_adjust_cfa_offset -8
-        .cfi_restore r6
-        .cfi_restore r7
-        ldrd    r4, r5, [sp], #8
-        .cfi_adjust_cfa_offset -8
-        .cfi_restore r4
-        .cfi_restore r5
-        pop     {r0, pc}
-
-        // Put the cfi directives back for the below instructions.
-        .cfi_adjust_cfa_offset 24
-        .cfi_rel_offset r4, 0
-        .cfi_rel_offset r5, 4
-        .cfi_rel_offset r6, 8
-        .cfi_rel_offset r7, 12
-        .cfi_rel_offset r8, 16
-        .cfi_rel_offset r9, 20
-
-.L_dst_not_word_aligned:
-        // Align dst to word.
-        rsb     ip, ip, #4
-        cmp     ip, #2
-
-        itt     gt
-        ldrbgt  lr, [r1], #1
-        strbgt  lr, [r0], #1
-
-        itt     ge
-        ldrbge  lr, [r1], #1
-        strbge  lr, [r0], #1
-
-        ldrb    lr, [r1], #1
-        strb    lr, [r0], #1
-
-        sub     r2, r2, ip
-
-        // Src is guaranteed to be at least word aligned by this point.
-        b       .L_word_aligned
-
-        // Undo any cfi directives from above.
-        .cfi_adjust_cfa_offset -24
-        .cfi_restore r4
-        .cfi_restore r5
-        .cfi_restore r6
-        .cfi_restore r7
-        .cfi_restore r8
-        .cfi_restore r9
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_common.S b/libc/arch-arm/cortex-a15/bionic/memcpy_common.S
deleted file mode 100644
index 4d1167f..0000000
--- a/libc/arch-arm/cortex-a15/bionic/memcpy_common.S
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.
- */
-/*
- * Copyright (c) 2013 ARM Ltd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. The name of the company may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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/bionic_asm.h>
-
-        .text
-        .syntax unified
-        .fpu    neon
-
-ENTRY(__memcpy_chk)
-        cmp r2, r3
-        bls memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
-// Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(memcpy)
-        pld     [r1, #64]
-        push    {r0, lr}
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
-
-#include MEMCPY_BASE
-END(memcpy)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
index c5bc98a..da40f6c 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,174 @@
  * SUCH DAMAGE.
  */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "arch-arm/cortex-a15/bionic/__strcat_chk_common.S"
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of src string, then get the source of the dst string.
+// Check that the two lengths together don't exceed the threshold, then
+// do a memcpy of the data.
+ENTRY(__strcat_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+    push    {r4, r5}
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+
+    mov     lr, r2
+
+    // Save the dst register to r5
+    mov     r5, r0
+
+    // Zero out r4
+    eor     r4, r4, r4
+
+    // r1 contains the address of the string to count.
+.L_strlen_start:
+    mov     r0, r1
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r1], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r1], #8
+
+    pld     [r1, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r1, r0
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_zero_in_first_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_finish
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_finish
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_finish
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_finish
+
+.L_zero_in_second_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_finish
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_finish
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_finish:
+    cmp     r4, #0
+    bne     .L_strlen_done
+
+    // Time to get the dst string length.
+    mov     r1, r5
+
+    // Save the original source address to r5.
+    mov     r5, r0
+
+    // Save the current length (adding 1 for the terminator).
+    add     r4, r3, #1
+    b       .L_strlen_start
+
+    // r0 holds the pointer to the dst string.
+    // r3 holds the dst string length.
+    // r4 holds the src string length + 1.
+.L_strlen_done:
+    add     r2, r3, r4
+    cmp     r2, lr
+    itt     hi
+    movhi   r0, lr
+    bhi     __strcat_chk_fail
+
+    // Set up the registers for the memcpy code.
+    mov     r1, r5
+    pld     [r1, #64]
+    mov     r2, r4
+    add     r0, r0, r3
+    pop     {r4, r5}
+    .cfi_adjust_cfa_offset -8
+    .cfi_restore r4
+    .cfi_restore r5
+
+#include "memcpy_base.S"
+
+    // Undo the above cfi directives
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+END(__strcat_chk)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
index 1f8945d..026adcc 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,136 @@
  * SUCH DAMAGE.
  */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "arch-arm/cortex-a15/bionic/__strcpy_chk_common.S"
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of the source string first, then do a memcpy of the data
+// instead of a strcpy.
+ENTRY(__strcpy_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
+    mov     lr, r2
+    mov     r0, r1
+
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r0], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r0], #8
+
+    pld     [r0, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r0, r1
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_zero_in_first_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_check_size
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_check_size
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_check_size
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_check_size
+
+.L_zero_in_second_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_check_size
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_check_size
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_check_size:
+    pld     [r1, #0]
+    pld     [r1, #64]
+    ldr     r0, [sp]
+
+    // Add 1 for copy length to get the string terminator.
+    add     r2, r3, #1
+
+    cmp     r2, lr
+    itt     hi
+    movhi   r0, r2
+    bhi     __strcpy_chk_fail
+
+#include "memcpy_base.S"
+
+END(__strcpy_chk)
diff --git a/libc/arch-arm/cortex-a53/bionic/memcpy.S b/libc/arch-arm/cortex-a53/bionic/memcpy.S
index 664f574..9407a08 100644
--- a/libc/arch-arm/cortex-a53/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,8 +25,58 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*
+ * Copyright (c) 2013 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+ */
 
-// Indicate which memcpy base file to include.
-#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
+#include <private/bionic_asm.h>
 
-#include "arch-arm/cortex-a15/bionic/memcpy_common.S"
+        .text
+        .syntax unified
+        .fpu    neon
+
+ENTRY(__memcpy_chk)
+        cmp r2, r3
+        bls memcpy
+
+        // Preserve lr for backtrace.
+        push        {lr}
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
+        bl          __memcpy_chk_fail
+END(__memcpy_chk)
+
+// Prototype: void *memcpy (void *dst, const void *src, size_t count).
+ENTRY(memcpy)
+        pld     [r1, #64]
+        push    {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
+#include "memcpy_base.S"
+END(memcpy)
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index b5a83f4..f3dbfa5 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -29,6 +29,7 @@
 #include "libc_init_common.h"
 
 #include "private/KernelArgumentBlock.h"
+#include "private/bionic_arc4random.h"
 #include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_ssp.h"
@@ -41,9 +42,7 @@
 uintptr_t __stack_chk_guard = 0;
 
 void __libc_init_global_stack_chk_guard(KernelArgumentBlock& args) {
-  // AT_RANDOM is a pointer to 16 bytes of randomness on the stack.
-  // Take the first 4/8 for the -fstack-protector implementation.
-  __stack_chk_guard = *reinterpret_cast<uintptr_t*>(args.getauxval(AT_RANDOM));
+  __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard), args);
 }
 
 // Setup for the main thread. For dynamic executables, this is called by the
diff --git a/libc/bionic/bionic_arc4random.cpp b/libc/bionic/bionic_arc4random.cpp
new file mode 100644
index 0000000..d20cb68
--- /dev/null
+++ b/libc/bionic/bionic_arc4random.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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/bionic_arc4random.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+#include <syscall.h>
+#include <unistd.h>
+
+#include "private/KernelArgumentBlock.h"
+#include "private/libc_logging.h"
+
+void __libc_safe_arc4random_buf(void* buf, size_t n, KernelArgumentBlock& args) {
+  static bool have_getrandom = syscall(SYS_getrandom, nullptr, 0, 0) == -1 && errno != ENOSYS;
+  static bool have_urandom = access("/dev/urandom", R_OK) == 0;
+  static size_t at_random_bytes_consumed = 0;
+
+  if (have_getrandom || have_urandom) {
+    arc4random_buf(buf, n);
+    return;
+  }
+
+  if (at_random_bytes_consumed + n > 16) {
+    __libc_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
+                 16 - at_random_bytes_consumed, n);
+  }
+
+  memcpy(buf, reinterpret_cast<char*>(args.getauxval(AT_RANDOM)) + at_random_bytes_consumed, n);
+  at_random_bytes_consumed += n;
+  return;
+}
diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp
index b50a96d..3a20aa9 100644
--- a/libc/bionic/clone.cpp
+++ b/libc/bionic/clone.cpp
@@ -38,6 +38,11 @@
 
 // Called from the __bionic_clone assembler to call the thread function then exit.
 extern "C" __LIBC_HIDDEN__ void __start_thread(int (*fn)(void*), void* arg) {
+  pthread_internal_t* self = __get_thread();
+  if (self && self->tid == -1) {
+    self->tid = syscall(__NR_gettid);
+  }
+
   int status = (*fn)(arg);
   __exit(status);
 }
@@ -105,6 +110,9 @@
     // If any other cases become important, we could use a double trampoline like __pthread_start.
     self->set_cached_pid(parent_pid);
     self->tid = caller_tid;
+  } else if (self->tid == -1) {
+    self->tid = syscall(__NR_gettid);
+    self->set_cached_pid(self->tid);
   }
 
   return clone_result;
diff --git a/libc/bionic/fork.cpp b/libc/bionic/fork.cpp
index ffe94f4..32ea255 100644
--- a/libc/bionic/fork.cpp
+++ b/libc/bionic/fork.cpp
@@ -36,9 +36,6 @@
 
   pthread_internal_t* self = __get_thread();
 
-  // Remember the parent pid and invalidate the cached value while we fork.
-  pid_t parent_pid = self->invalidate_cached_pid();
-
   int result = clone(nullptr,
                      nullptr,
                      (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD),
@@ -47,10 +44,11 @@
                      nullptr,
                      &(self->tid));
   if (result == 0) {
+    // Update the cached pid, since clone() will not set it directly (as
+    // self->tid is updated by the kernel).
     self->set_cached_pid(gettid());
     __bionic_atfork_run_child();
   } else {
-    self->set_cached_pid(parent_pid);
     __bionic_atfork_run_parent();
   }
   return result;
diff --git a/libc/bionic/getentropy_linux.c b/libc/bionic/getentropy_linux.c
index 409bd7d..98fb6fb 100644
--- a/libc/bionic/getentropy_linux.c
+++ b/libc/bionic/getentropy_linux.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: getentropy_linux.c,v 1.28 2014/07/20 03:24:10 deraadt Exp $	*/
+/*	$OpenBSD: getentropy_linux.c,v 1.42 2016/04/19 20:20:24 tj Exp $	*/
 
 /*
  * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
@@ -17,7 +17,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
  * Emulation of getentropy(2) as documented at:
- * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ * http://man.openbsd.org/getentropy.2
  */
 
 #define	_POSIX_C_SOURCE	199309L
@@ -27,8 +27,8 @@
 #include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/syscall.h>
-#ifdef HAVE_SYS_SYSCTL_H
-#include <sys/sysctl.h>
+#ifdef SYS__sysctl
+#include <linux/sysctl.h>
 #endif
 #include <sys/statvfs.h>
 #include <sys/socket.h>
@@ -51,8 +51,8 @@
 #include <openssl/sha.h>
 #endif
 
+#include <linux/types.h>
 #include <linux/random.h>
-#include <linux/sysctl.h>
 #ifdef HAVE_GETAUXVAL
 #include <sys/auxv.h>
 #endif
@@ -76,9 +76,7 @@
 int	getentropy(void *buf, size_t len);
 
 static int gotdata(char *buf, size_t len);
-#ifdef SYS__getrandom
 static int getentropy_getrandom(void *buf, size_t len);
-#endif
 static int getentropy_urandom(void *buf, size_t len);
 #ifdef SYS__sysctl
 static int getentropy_sysctl(void *buf, size_t len);
@@ -95,17 +93,17 @@
 
 	if (len > 256) {
 		errno = EIO;
-		return -1;
+		return (-1);
 	}
 
-#ifdef SYS__getrandom
 	/*
 	 * Try descriptor-less getrandom()
 	 */
 	ret = getentropy_getrandom(buf, len);
 	if (ret != -1)
 		return (ret);
-#endif
+	if (errno != ENOSYS)
+		return (-1);
 
 	/*
 	 * Try to get entropy with /dev/urandom
@@ -122,7 +120,7 @@
 	 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
 	 * sysctl is a failsafe API, so it guarantees a result.  This
 	 * should work inside a chroot, or when file descriptors are
-	 * exhuasted.
+	 * exhausted.
 	 *
 	 * However this can fail if the Linux kernel removes support
 	 * for sysctl.  Starting in 2007, there have been efforts to
@@ -190,39 +188,26 @@
 	for (i = 0; i < len; ++i)
 		any_set |= buf[i];
 	if (any_set == 0)
-		return -1;
-	return 0;
+		return (-1);
+	return (0);
 }
 
-#ifdef SYS__getrandom
 static int
 getentropy_getrandom(void *buf, size_t len)
 {
-#if 0
-
-/* Hand-definitions until the API becomes commonplace */
-#ifndef SYS__getrandom
-#ifdef __LP64__
-#define SYS__getrandom 317
-#else
-#define SYS__getrandom 354
-#endif
-#endif
-	struct __getrandom_args args = {
-		.buf = buf;
-		.len = len;
-		.flags = 0;
-	};
-
+	int pre_errno = errno;
+	int ret;
 	if (len > 256)
 		return (-1);
-	ret = syscall(SYS__getrandom, &args);
-	if (ret == len)
-		return (0);
-#endif
-	return -1;
+	do {
+		ret = syscall(SYS_getrandom, buf, len, 0);
+	} while (ret == -1 && errno == EINTR);
+
+	if ((size_t)ret != len)
+		return (-1);
+	errno = pre_errno;
+	return (0);
 }
-#endif
 
 static int
 getentropy_urandom(void *buf, size_t len)
@@ -275,11 +260,11 @@
 	close(fd);
 	if (gotdata(buf, len) == 0) {
 		errno = save_errno;
-		return 0;		/* satisfied */
+		return (0);		/* satisfied */
 	}
 nodevrandom:
 	errno = EIO;
-	return -1;
+	return (-1);
 }
 
 #ifdef SYS__sysctl
@@ -297,7 +282,7 @@
 		struct __sysctl_args args = {
 			.name = mib,
 			.nlen = 3,
-			.oldval = (char*) buf + i,
+			.oldval = (char *)buf + i,
 			.oldlenp = &chunk,
 		};
 		if (syscall(SYS__sysctl, &args) != 0)
@@ -310,13 +295,12 @@
 	}
 sysctlfailed:
 	errno = EIO;
-	return -1;
+	return (-1);
 }
 #endif /* SYS__sysctl */
 
 #ifdef HAVE_OPENSSL
-
-static int cl[] = {
+static const int cl[] = {
 	CLOCK_REALTIME,
 #ifdef CLOCK_MONOTONIC
 	CLOCK_MONOTONIC,
@@ -347,7 +331,7 @@
 	SHA512_CTX *ctx = data;
 
 	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
-	return 0;
+	return (0);
 }
 
 static int
@@ -556,10 +540,9 @@
 	memset(results, 0, sizeof results);
 	if (gotdata(buf, len) == 0) {
 		errno = save_errno;
-		return 0;		/* satisfied */
+		return (0);		/* satisfied */
 	}
 	errno = EIO;
-	return -1;
+	return (-1);
 }
-
 #endif /* HAVE_OPENSSL */
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 2200a6c..84e511c 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -130,13 +130,15 @@
 }
 
 void __bionic_atfork_run_child() {
+  g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+  pthread_mutex_lock(&g_atfork_list_mutex);
   g_atfork_list.walk_forward([](atfork_t* it) {
     if (it->child != nullptr) {
       it->child();
     }
   });
-
-  g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+  pthread_mutex_unlock(&g_atfork_list_mutex);
 }
 
 void __bionic_atfork_run_parent() {
diff --git a/libc/bionic/setjmp_cookie.cpp b/libc/bionic/setjmp_cookie.cpp
index 3be675a..4fa68c2 100644
--- a/libc/bionic/setjmp_cookie.cpp
+++ b/libc/bionic/setjmp_cookie.cpp
@@ -34,14 +34,14 @@
 #include <sys/auxv.h>
 #include <sys/cdefs.h>
 
+#include "private/bionic_arc4random.h"
 #include "private/bionic_globals.h"
 #include "private/libc_logging.h"
 #include "private/KernelArgumentBlock.h"
 
-void __libc_init_setjmp_cookie(libc_globals* globals,
-                               KernelArgumentBlock& args) {
-  char* random_data = reinterpret_cast<char*>(args.getauxval(AT_RANDOM));
-  long value = *reinterpret_cast<long*>(random_data + 8);
+void __libc_init_setjmp_cookie(libc_globals* globals, KernelArgumentBlock& args) {
+  long value;
+  __libc_safe_arc4random_buf(&value, sizeof(value), args);
 
   // Mask off the last bit to store the signal flag.
   globals->setjmp_cookie = value & ~1;
diff --git a/libc/include/android/legacy_fenv_inlines_arm.h b/libc/include/android/legacy_fenv_inlines_arm.h
new file mode 100644
index 0000000..a5bb26b
--- /dev/null
+++ b/libc/include/android/legacy_fenv_inlines_arm.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.1 2004/06/06 10:03:59 das Exp $
+ */
+
+#ifndef ANDROID_LEGACY_FENV_INLINES_ARM_H
+#define ANDROID_LEGACY_FENV_INLINES_ARM_H
+
+#include <fenv.h>
+
+#if __ANDROID_API__ < 21 && defined(__arm__)
+
+__BEGIN_DECLS
+
+#define FPSCR_ENABLE_SHIFT 8
+#define FPSCR_ENABLE_MASK  (FE_ALL_EXCEPT << FPSCR_ENABLE_SHIFT)
+
+#define FPSCR_RMODE_SHIFT 22
+
+static __inline int fegetenv(fenv_t* __envp) {
+  fenv_t _fpscr;
+  __asm__ __volatile__("vmrs %0,fpscr" : "=r" (_fpscr));
+  *__envp = _fpscr;
+  return 0;
+}
+
+static __inline int fesetenv(const fenv_t* __envp) {
+  fenv_t _fpscr = *__envp;
+  __asm__ __volatile__("vmsr fpscr,%0" : :"ri" (_fpscr));
+  return 0;
+}
+
+static __inline int feclearexcept(int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  __fpscr &= ~__excepts;
+  fesetenv(&__fpscr);
+  return 0;
+}
+
+static __inline int fegetexceptflag(fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  *__flagp = __fpscr & __excepts;
+  return 0;
+}
+
+static __inline int fesetexceptflag(const fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  __fpscr &= ~__excepts;
+  __fpscr |= *__flagp & __excepts;
+  fesetenv(&__fpscr);
+  return 0;
+}
+
+static __inline int feraiseexcept(int __excepts) {
+  fexcept_t __ex = __excepts;
+  fesetexceptflag(&__ex, __excepts);
+  return 0;
+}
+
+static __inline int fetestexcept(int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  return (__fpscr & __excepts);
+}
+
+static __inline int fegetround(void) {
+  fenv_t _fpscr;
+  fegetenv(&_fpscr);
+  return ((_fpscr >> FPSCR_RMODE_SHIFT) & 0x3);
+}
+
+static __inline int fesetround(int __round) {
+  fenv_t _fpscr;
+  fegetenv(&_fpscr);
+  _fpscr &= ~(0x3 << FPSCR_RMODE_SHIFT);
+  _fpscr |= (__round << FPSCR_RMODE_SHIFT);
+  fesetenv(&_fpscr);
+  return 0;
+}
+
+static __inline int feholdexcept(fenv_t* __envp) {
+  fenv_t __env;
+  fegetenv(&__env);
+  *__envp = __env;
+  __env &= ~(FE_ALL_EXCEPT | FPSCR_ENABLE_MASK);
+  fesetenv(&__env);
+  return 0;
+}
+
+static __inline int feupdateenv(const fenv_t* __envp) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  fesetenv(__envp);
+  feraiseexcept(__fpscr & FE_ALL_EXCEPT);
+  return 0;
+}
+
+static __inline int feenableexcept(int __mask) {
+  fenv_t __old_fpscr, __new_fpscr;
+  fegetenv(&__old_fpscr);
+  __new_fpscr = __old_fpscr | (__mask & FE_ALL_EXCEPT) << FPSCR_ENABLE_SHIFT;
+  fesetenv(&__new_fpscr);
+  return ((__old_fpscr >> FPSCR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fedisableexcept(int __mask) {
+  fenv_t __old_fpscr, __new_fpscr;
+  fegetenv(&__old_fpscr);
+  __new_fpscr = __old_fpscr & ~((__mask & FE_ALL_EXCEPT) << FPSCR_ENABLE_SHIFT);
+  fesetenv(&__new_fpscr);
+  return ((__old_fpscr >> FPSCR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetexcept(void) {
+  fenv_t __fpscr;
+  fegetenv(&__fpscr);
+  return ((__fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT);
+}
+
+#undef FPSCR_ENABLE_SHIFT
+#undef FPSCR_ENABLE_MASK
+#undef FPSCR_RMODE_SHIFT
+
+__END_DECLS
+
+#endif /* __ANDROID_API__ < 21 && defined(__arm__) */
+
+#endif /* ANDROID_LEGACY_FENV_INLINES_ARM_H */
diff --git a/libc/include/android/legacy_fenv_inlines_mips.h b/libc/include/android/legacy_fenv_inlines_mips.h
new file mode 100644
index 0000000..ead697c
--- /dev/null
+++ b/libc/include/android/legacy_fenv_inlines_mips.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/msun/mips/fenv.c,v 1.1 2008/04/26 12:20:29 imp Exp $
+ */
+
+#ifndef ANDROID_LEGACY_FENV_INLINES_MIPS_H
+#define ANDROID_LEGACY_FENV_INLINES_MIPS_H
+
+#include <fenv.h>
+
+#if __ANDROID_API__ < 21 && (defined(__mips__) && !defined(__LP64__))
+
+__BEGIN_DECLS
+
+#define FCSR_CAUSE_SHIFT 10
+#define FCSR_ENABLE_SHIFT 5
+#define FCSR_ENABLE_MASK (FE_ALL_EXCEPT << FCSR_ENABLE_SHIFT)
+
+#define FCSR_RMASK       0x3
+
+static __inline int fegetenv(fenv_t* __envp) {
+  fenv_t _fcsr = 0;
+#ifdef  __mips_hard_float
+  __asm__ __volatile__("cfc1 %0,$31" : "=r" (_fcsr));
+#endif
+  *__envp = _fcsr;
+  return 0;
+}
+
+static __inline int fesetenv(const fenv_t* __envp) {
+  fenv_t _fcsr = *__envp;
+#ifdef  __mips_hard_float
+  __asm__ __volatile__("ctc1 %0,$31" : : "r" (_fcsr));
+#endif
+  return 0;
+}
+
+static __inline int feclearexcept(int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  __excepts &= FE_ALL_EXCEPT;
+  __fcsr &= ~(__excepts | (__excepts << FCSR_CAUSE_SHIFT));
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int fegetexceptflag(fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  *__flagp = __fcsr & __excepts & FE_ALL_EXCEPT;
+  return 0;
+}
+
+static __inline int fesetexceptflag(const fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  /* Ensure that flags are all legal */
+  __excepts &= FE_ALL_EXCEPT;
+  __fcsr &= ~__excepts;
+  __fcsr |= *__flagp & __excepts;
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int feraiseexcept(int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  /* Ensure that flags are all legal */
+  __excepts &= FE_ALL_EXCEPT;
+  /* Cause bit needs to be set as well for generating the exception*/
+  __fcsr |= __excepts | (__excepts << FCSR_CAUSE_SHIFT);
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int fetestexcept(int __excepts) {
+  fexcept_t __FCSR;
+  fegetenv(&__FCSR);
+  return (__FCSR & __excepts & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetround(void) {
+  fenv_t _fcsr;
+  fegetenv(&_fcsr);
+  return (_fcsr & FCSR_RMASK);
+}
+
+static __inline int fesetround(int __round) {
+  fenv_t _fcsr;
+  fegetenv(&_fcsr);
+  _fcsr &= ~FCSR_RMASK;
+  _fcsr |= (__round & FCSR_RMASK);
+  fesetenv(&_fcsr);
+  return 0;
+}
+
+static __inline int feholdexcept(fenv_t* __envp) {
+  fenv_t __env;
+  fegetenv(&__env);
+  *__envp = __env;
+  __env &= ~(FE_ALL_EXCEPT | FCSR_ENABLE_MASK);
+  fesetenv(&__env);
+  return 0;
+}
+
+static __inline int feupdateenv(const fenv_t* __envp) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  fesetenv(__envp);
+  feraiseexcept(__fcsr & FE_ALL_EXCEPT);
+  return 0;
+}
+
+static __inline int feenableexcept(int __mask) {
+  fenv_t __old_fcsr, __new_fcsr;
+  fegetenv(&__old_fcsr);
+  __new_fcsr = __old_fcsr | (__mask & FE_ALL_EXCEPT) << FCSR_ENABLE_SHIFT;
+  fesetenv(&__new_fcsr);
+  return ((__old_fcsr >> FCSR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fedisableexcept(int __mask) {
+  fenv_t __old_fcsr, __new_fcsr;
+  fegetenv(&__old_fcsr);
+  __new_fcsr = __old_fcsr & ~((__mask & FE_ALL_EXCEPT) << FCSR_ENABLE_SHIFT);
+  fesetenv(&__new_fcsr);
+  return ((__old_fcsr >> FCSR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetexcept(void) {
+  fenv_t __fcsr;
+  fegetenv(&__fcsr);
+  return ((__fcsr & FCSR_ENABLE_MASK) >> FCSR_ENABLE_SHIFT);
+}
+
+#undef FCSR_CAUSE_SHIFT
+#undef FCSR_ENABLE_SHIFT
+#undef FCSR_ENABLE_MASK
+#undef FCSR_RMASK
+
+__END_DECLS
+
+#endif /* __ANDROID_API__ < 21 && (defined(__mips__) && !defined(__LP64__)) */
+
+#endif /* ANDROID_LEGACY_FENV_INLINES_MIPS_H */
diff --git a/libc/include/fenv.h b/libc/include/fenv.h
index f1b2b25..241e845 100644
--- a/libc/include/fenv.h
+++ b/libc/include/fenv.h
@@ -36,6 +36,7 @@
 __BEGIN_DECLS
 
 // fenv was always available on x86.
+#if __ANDROID_API__ >= 21 || defined(__i386__)
 int feclearexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fegetexceptflag(fexcept_t*, int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21)
     __INTRODUCED_IN_X86(9);
@@ -56,6 +57,9 @@
 int feenableexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fedisableexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fegetexcept(void) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
+#else
+/* Defined as inlines for pre-21 ARM and MIPS. */
+#endif
 
 /*
  * The following constant represents the default floating-point environment
@@ -70,4 +74,7 @@
 
 __END_DECLS
 
+#include <android/legacy_fenv_inlines_arm.h>
+#include <android/legacy_fenv_inlines_mips.h>
+
 #endif  /* ! _FENV_H_ */
diff --git a/libc/include/inttypes.h b/libc/include/inttypes.h
index 2c268e6..f74afa3 100644
--- a/libc/include/inttypes.h
+++ b/libc/include/inttypes.h
@@ -29,6 +29,7 @@
 #define __PRI_64_prefix "ll"
 #define __PRI_PTR_prefix
 #endif
+#define __PRI_FAST_prefix __PRI_PTR_prefix
 
 /*
  * 7.8.1 Macros for format specifiers
@@ -58,8 +59,8 @@
 #define	PRIdLEAST64		__PRI_64_prefix"d"		/* int_least64_t */
 
 #define	PRIdFAST8		"d"		/* int_fast8_t */
-#define	PRIdFAST16		"d"		/* int_fast16_t */
-#define	PRIdFAST32		"d"		/* int_fast32_t */
+#define	PRIdFAST16		__PRI_FAST_prefix"d"	/* int_fast16_t */
+#define	PRIdFAST32		__PRI_FAST_prefix"d"	/* int_fast32_t */
 #define	PRIdFAST64		__PRI_64_prefix"d"		/* int_fast64_t */
 
 #define	PRIdMAX			"jd"		/* intmax_t */
@@ -76,8 +77,8 @@
 #define	PRIiLEAST64		__PRI_64_prefix"i"		/* int_least64_t */
 
 #define	PRIiFAST8		"i"		/* int_fast8_t */
-#define	PRIiFAST16		"i"		/* int_fast16_t */
-#define	PRIiFAST32		"i"		/* int_fast32_t */
+#define	PRIiFAST16		__PRI_FAST_prefix"i"	/* int_fast16_t */
+#define	PRIiFAST32		__PRI_FAST_prefix"i"	/* int_fast32_t */
 #define	PRIiFAST64		__PRI_64_prefix"i"		/* int_fast64_t */
 
 #define	PRIiMAX			"ji"		/* intmax_t */
@@ -95,8 +96,8 @@
 #define	PRIoLEAST64		__PRI_64_prefix"o"		/* int_least64_t */
 
 #define	PRIoFAST8		"o"		/* int_fast8_t */
-#define	PRIoFAST16		"o"		/* int_fast16_t */
-#define	PRIoFAST32		"o"		/* int_fast32_t */
+#define	PRIoFAST16		__PRI_FAST_prefix"o"	/* int_fast16_t */
+#define	PRIoFAST32		__PRI_FAST_prefix"o"	/* int_fast32_t */
 #define	PRIoFAST64		__PRI_64_prefix"o"		/* int_fast64_t */
 
 #define	PRIoMAX			"jo"		/* intmax_t */
@@ -113,8 +114,8 @@
 #define	PRIuLEAST64		__PRI_64_prefix"u"		/* uint_least64_t */
 
 #define	PRIuFAST8		"u"		/* uint_fast8_t */
-#define	PRIuFAST16		"u"		/* uint_fast16_t */
-#define	PRIuFAST32		"u"		/* uint_fast32_t */
+#define	PRIuFAST16		__PRI_FAST_prefix"u"	/* uint_fast16_t */
+#define	PRIuFAST32		__PRI_FAST_prefix"u"	/* uint_fast32_t */
 #define	PRIuFAST64		__PRI_64_prefix"u"		/* uint_fast64_t */
 
 #define	PRIuMAX			"ju"		/* uintmax_t */
@@ -131,8 +132,8 @@
 #define	PRIxLEAST64		__PRI_64_prefix"x"		/* uint_least64_t */
 
 #define	PRIxFAST8		"x"		/* uint_fast8_t */
-#define	PRIxFAST16		"x"		/* uint_fast16_t */
-#define	PRIxFAST32		"x"		/* uint_fast32_t */
+#define	PRIxFAST16		__PRI_FAST_prefix"x"	/* uint_fast16_t */
+#define	PRIxFAST32		__PRI_FAST_prefix"x"	/* uint_fast32_t */
 #define	PRIxFAST64		__PRI_64_prefix"x"		/* uint_fast64_t */
 
 #define	PRIxMAX			"jx"		/* uintmax_t */
@@ -149,8 +150,8 @@
 #define	PRIXLEAST64		__PRI_64_prefix"X"		/* uint_least64_t */
 
 #define	PRIXFAST8		"X"		/* uint_fast8_t */
-#define	PRIXFAST16		"X"		/* uint_fast16_t */
-#define	PRIXFAST32		"X"		/* uint_fast32_t */
+#define	PRIXFAST16		__PRI_FAST_prefix"X"	/* uint_fast16_t */
+#define	PRIXFAST32		__PRI_FAST_prefix"X"	/* uint_fast32_t */
 #define	PRIXFAST64		__PRI_64_prefix"X"		/* uint_fast64_t */
 
 #define	PRIXMAX			"jX"		/* uintmax_t */
@@ -168,8 +169,8 @@
 #define	SCNdLEAST64		__PRI_64_prefix"d"		/* int_least64_t */
 
 #define	SCNdFAST8		"hhd"		/* int_fast8_t */
-#define	SCNdFAST16		"hd"		/* int_fast16_t */
-#define	SCNdFAST32		"d"		/* int_fast32_t */
+#define	SCNdFAST16		__PRI_FAST_prefix"d"	/* int_fast16_t */
+#define	SCNdFAST32		__PRI_FAST_prefix"d"	/* int_fast32_t */
 #define	SCNdFAST64		__PRI_64_prefix"d"		/* int_fast64_t */
 
 #define	SCNdMAX			"jd"		/* intmax_t */
@@ -186,8 +187,8 @@
 #define	SCNiLEAST64		__PRI_64_prefix"i"		/* int_least64_t */
 
 #define	SCNiFAST8		"hhi"		/* int_fast8_t */
-#define	SCNiFAST16		"hi"		/* int_fast16_t */
-#define	SCNiFAST32		"i"		/* int_fast32_t */
+#define	SCNiFAST16		__PRI_FAST_prefix"i"	/* int_fast16_t */
+#define	SCNiFAST32		__PRI_FAST_prefix"i"	/* int_fast32_t */
 #define	SCNiFAST64		__PRI_64_prefix"i"		/* int_fast64_t */
 
 #define	SCNiMAX			"ji"		/* intmax_t */
@@ -205,8 +206,8 @@
 #define	SCNoLEAST64		__PRI_64_prefix"o"		/* uint_least64_t */
 
 #define	SCNoFAST8		"hho"		/* uint_fast8_t */
-#define	SCNoFAST16		"ho"		/* uint_fast16_t */
-#define	SCNoFAST32		"o"		/* uint_fast32_t */
+#define	SCNoFAST16		__PRI_FAST_prefix"o"	/* uint_fast16_t */
+#define	SCNoFAST32		__PRI_FAST_prefix"o"	/* uint_fast32_t */
 #define	SCNoFAST64		__PRI_64_prefix"o"		/* uint_fast64_t */
 
 #define	SCNoMAX			"jo"		/* uintmax_t */
@@ -223,8 +224,8 @@
 #define	SCNuLEAST64		__PRI_64_prefix"u"		/* uint_least64_t */
 
 #define	SCNuFAST8		"hhu"		/* uint_fast8_t */
-#define	SCNuFAST16		"hu"		/* uint_fast16_t */
-#define	SCNuFAST32		"u"		/* uint_fast32_t */
+#define	SCNuFAST16		__PRI_FAST_prefix"u"	/* uint_fast16_t */
+#define	SCNuFAST32		__PRI_FAST_prefix"u"		/* uint_fast32_t */
 #define	SCNuFAST64		__PRI_64_prefix"u"		/* uint_fast64_t */
 
 #define	SCNuMAX			"ju"		/* uintmax_t */
@@ -241,8 +242,8 @@
 #define	SCNxLEAST64		__PRI_64_prefix"x"		/* uint_least64_t */
 
 #define	SCNxFAST8		"hhx"		/* uint_fast8_t */
-#define	SCNxFAST16		"hx"		/* uint_fast16_t */
-#define	SCNxFAST32		"x"		/* uint_fast32_t */
+#define	SCNxFAST16		__PRI_FAST_prefix"x"	/* uint_fast16_t */
+#define	SCNxFAST32		__PRI_FAST_prefix"x"	/* uint_fast32_t */
 #define	SCNxFAST64		__PRI_64_prefix"x"		/* uint_fast64_t */
 
 #define	SCNxMAX			"jx"		/* uintmax_t */
diff --git a/libc/include/sys/limits.h b/libc/include/sys/limits.h
index 5aa3d80..60cc7f7 100644
--- a/libc/include/sys/limits.h
+++ b/libc/include/sys/limits.h
@@ -106,18 +106,12 @@
 #  endif
 # endif
 
-/* Bionic: the following has been optimized out from our processed kernel headers */
-
-#define  CHILD_MAX   999
-#define  OPEN_MAX    256
-
 /* Bionic-specific definitions */
 
 #define  _POSIX_VERSION             200809L   /* Posix C language bindings version */
 #define  _POSIX2_VERSION            -1        /* we don't support Posix command-line tools */
 #define  _XOPEN_VERSION             700       /* by Posix definition */
 
-
 /* >= _POSIX_THREAD_DESTRUCTOR_ITERATIONS */
 #define PTHREAD_DESTRUCTOR_ITERATIONS 4
 /* >= _POSIX_THREAD_KEYS_MAX */
diff --git a/libc/libstdc++.arm.map b/libc/libstdc++.arm.map
index 63fd8a0..b6b269d 100644
--- a/libc/libstdc++.arm.map
+++ b/libc/libstdc++.arm.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnajRKSt9nothrow_t; # arm x86 mips
     _Znwj; # arm x86 mips
     _ZnwjRKSt9nothrow_t; # arm x86 mips
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/libstdc++.arm64.map b/libc/libstdc++.arm64.map
index 60fe9ab..d0433c9 100644
--- a/libc/libstdc++.arm64.map
+++ b/libc/libstdc++.arm64.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnamRKSt9nothrow_t; # arm64 x86_64 mips64
     _Znwm; # arm64 x86_64 mips64
     _ZnwmRKSt9nothrow_t; # arm64 x86_64 mips64
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/libstdc++.map.txt b/libc/libstdc++.map.txt
index 6b8d092..32d5d49 100644
--- a/libc/libstdc++.map.txt
+++ b/libc/libstdc++.map.txt
@@ -1,7 +1,6 @@
 LIBC_O {
   global:
     _ZSt7nothrow; # var
-    _ZTV9type_info; # var introduced-arm=9 introduced-mips=9
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
diff --git a/libc/libstdc++.mips.map b/libc/libstdc++.mips.map
index 63fd8a0..b6b269d 100644
--- a/libc/libstdc++.mips.map
+++ b/libc/libstdc++.mips.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnajRKSt9nothrow_t; # arm x86 mips
     _Znwj; # arm x86 mips
     _ZnwjRKSt9nothrow_t; # arm x86 mips
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/libstdc++.mips64.map b/libc/libstdc++.mips64.map
index 60fe9ab..d0433c9 100644
--- a/libc/libstdc++.mips64.map
+++ b/libc/libstdc++.mips64.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnamRKSt9nothrow_t; # arm64 x86_64 mips64
     _Znwm; # arm64 x86_64 mips64
     _ZnwmRKSt9nothrow_t; # arm64 x86_64 mips64
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/libstdc++.x86.map b/libc/libstdc++.x86.map
index 63fd8a0..b6b269d 100644
--- a/libc/libstdc++.x86.map
+++ b/libc/libstdc++.x86.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnajRKSt9nothrow_t; # arm x86 mips
     _Znwj; # arm x86 mips
     _ZnwjRKSt9nothrow_t; # arm x86 mips
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/libstdc++.x86_64.map b/libc/libstdc++.x86_64.map
index 60fe9ab..d0433c9 100644
--- a/libc/libstdc++.x86_64.map
+++ b/libc/libstdc++.x86_64.map
@@ -1,6 +1,7 @@
 # Generated by genversion-scripts.py. Do not edit.
 LIBC_O {
   global:
+    _ZSt7nothrow; # var
     _ZdaPv;
     _ZdaPvRKSt9nothrow_t;
     _ZdlPv;
@@ -9,7 +10,6 @@
     _ZnamRKSt9nothrow_t; # arm64 x86_64 mips64
     _Znwm; # arm64 x86_64 mips64
     _ZnwmRKSt9nothrow_t; # arm64 x86_64 mips64
-    _ZSt7nothrow;
     __cxa_guard_abort;
     __cxa_guard_acquire;
     __cxa_guard_release;
diff --git a/libc/private/bionic_arc4random.h b/libc/private/bionic_arc4random.h
new file mode 100644
index 0000000..d26a4e7
--- /dev/null
+++ b/libc/private/bionic_arc4random.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _PRIVATE_BIONIC_ARC4RANDOM_H_
+#define _PRIVATE_BIONIC_ARC4RANDOM_H_
+
+#include <stddef.h>
+
+#include "private/KernelArgumentBlock.h"
+
+/*
+ * arc4random aborts if it's unable to fetch entropy, which is always the case
+ * for init on devices without getrandom(2), since /dev/random hasn't been
+ * created yet. Provide a wrapper function that falls back to AT_RANDOM if
+ * we don't have getrandom and /dev/urandom is missing.
+ */
+
+void __libc_safe_arc4random_buf(void* buf, size_t n, KernelArgumentBlock& args);
+
+#endif
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index abfe234..ce00600 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libm/libm.arm.map b/libm/libm.arm.map
index 3052f03..7e3175d 100644
--- a/libm/libm.arm.map
+++ b/libm/libm.arm.map
@@ -295,7 +295,7 @@
     ctanl;
 } LIBC;
 
-LIBC_DEPRECATED { # arm mips
+LIBC_DEPRECATED { # arm mips platform-only
   global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
diff --git a/libm/libm.map.txt b/libm/libm.map.txt
index c77e1d1..1fb16b7 100644
--- a/libm/libm.map.txt
+++ b/libm/libm.map.txt
@@ -294,7 +294,7 @@
     ctanl;
 } LIBC;
 
-LIBC_DEPRECATED { # arm mips
+LIBC_DEPRECATED { # arm mips platform-only
   global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
diff --git a/libm/libm.mips.map b/libm/libm.mips.map
index 2f01cfa..b368d41 100644
--- a/libm/libm.mips.map
+++ b/libm/libm.mips.map
@@ -295,7 +295,7 @@
     ctanl;
 } LIBC;
 
-LIBC_DEPRECATED { # arm mips
+LIBC_DEPRECATED { # arm mips platform-only
   global: # arm mips
     __fixdfdi; # arm mips
     __fixsfdi; # arm mips
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index f2b7edd..aacf9ae 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -316,7 +316,7 @@
 // PrettyUnitTestResultPrinter. The reason for copy is that PrettyUnitTestResultPrinter
 // is defined and used in gtest.cc, which is hard to reuse.
 static void OnTestIterationStartPrint(const std::vector<TestCase>& testcase_list, size_t iteration,
-                                      int iteration_count) {
+                                      int iteration_count, size_t job_count) {
   if (iteration_count != 1) {
     printf("\nRepeating all tests (iteration %zu) . . .\n\n", iteration);
   }
@@ -328,9 +328,10 @@
     test_count += testcase.TestCount();
   }
 
-  printf("Running %zu %s from %zu %s.\n",
+  printf("Running %zu %s from %zu %s (%zu %s).\n",
          test_count, (test_count == 1) ? "test" : "tests",
-         testcase_count, (testcase_count == 1) ? "test case" : "test cases");
+         testcase_count, (testcase_count == 1) ? "test case" : "test cases",
+         job_count, (job_count == 1) ? "job" : "jobs");
   fflush(stdout);
 }
 
@@ -870,7 +871,7 @@
   for (size_t iteration = 1;
        iteration_count < 0 || iteration <= static_cast<size_t>(iteration_count);
        ++iteration) {
-    OnTestIterationStartPrint(testcase_list, iteration, iteration_count);
+    OnTestIterationStartPrint(testcase_list, iteration, iteration_count, job_count);
     int64_t iteration_start_time_ns = NanoTime();
     time_t epoch_iteration_start_time = time(NULL);
 
diff --git a/tests/inttypes_test.cpp b/tests/inttypes_test.cpp
index dbbb6d4..80580a4 100644
--- a/tests/inttypes_test.cpp
+++ b/tests/inttypes_test.cpp
@@ -20,24 +20,81 @@
 #include <gtest/gtest.h>
 #include <stdio.h>
 
-TEST(inttypes, misc) {
-  char buf[512];
+#define PRINTF_TYPED(FMT_SUFFIX, TYPE_SUFFIX) \
+  do { \
+    char buf[512]; \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRId##FMT_SUFFIX, int##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("123", buf); \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRIi##FMT_SUFFIX, int##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("123", buf); \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRIo##FMT_SUFFIX, int##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("173", buf); \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRIu##FMT_SUFFIX, uint##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("123", buf); \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRIx##FMT_SUFFIX, uint##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("7b", buf); \
+    memset(buf, 0, sizeof(buf)); \
+    snprintf(buf, sizeof(buf), "%" PRIX##FMT_SUFFIX, uint##TYPE_SUFFIX(123)); \
+    EXPECT_STREQ("7B", buf); \
+  } while (false) \
 
-  intptr_t i = 0;
-  uintptr_t u = 0;
+#define PRINTF_SIZED(WIDTH) \
+  PRINTF_TYPED(WIDTH, WIDTH##_t); \
+  PRINTF_TYPED(FAST##WIDTH, _fast##WIDTH##_t); \
+  PRINTF_TYPED(LEAST##WIDTH, _least##WIDTH##_t) \
 
-  snprintf(buf, sizeof(buf), "%08" PRIdPTR, i);
-  snprintf(buf, sizeof(buf), "%08" PRIiPTR, i);
-  snprintf(buf, sizeof(buf), "%08" PRIoPTR, i);
-  snprintf(buf, sizeof(buf), "%08" PRIuPTR, u);
-  snprintf(buf, sizeof(buf), "%08" PRIxPTR, u);
-  snprintf(buf, sizeof(buf), "%08" PRIXPTR, u);
 
-  sscanf(buf, "%08" SCNdPTR, &i);
-  sscanf(buf, "%08" SCNiPTR, &i);
-  sscanf(buf, "%08" SCNoPTR, &u);
-  sscanf(buf, "%08" SCNuPTR, &u);
-  sscanf(buf, "%08" SCNxPTR, &u);
+#define SCANF_TYPED(FMT_SUFFIX, TYPE_SUFFIX) \
+  do { \
+    int##TYPE_SUFFIX dst_int##TYPE_SUFFIX = 0; \
+    uint##TYPE_SUFFIX dst_uint##TYPE_SUFFIX = 0u; \
+    \
+    sscanf("123", "%" SCNd##FMT_SUFFIX, &dst_int##TYPE_SUFFIX); \
+    EXPECT_EQ(123, dst_int##TYPE_SUFFIX); \
+    dst_int##TYPE_SUFFIX = 0; \
+    sscanf("123", "%" SCNi##FMT_SUFFIX, &dst_int##TYPE_SUFFIX); \
+    EXPECT_EQ(123, dst_int##TYPE_SUFFIX); \
+    dst_int##TYPE_SUFFIX = 0; \
+    sscanf("173", "%" SCNo##FMT_SUFFIX, &dst_int##TYPE_SUFFIX); \
+    EXPECT_EQ(123, dst_int##TYPE_SUFFIX); \
+    dst_int##TYPE_SUFFIX = 0; \
+    sscanf("123", "%" SCNu##FMT_SUFFIX, &dst_uint##TYPE_SUFFIX); \
+    EXPECT_EQ(123u, dst_uint##TYPE_SUFFIX); \
+    dst_uint##TYPE_SUFFIX = 0; \
+    sscanf("7B", "%" SCNx##FMT_SUFFIX, &dst_uint##TYPE_SUFFIX); \
+    EXPECT_EQ(123u, dst_uint##TYPE_SUFFIX); \
+    dst_uint##TYPE_SUFFIX = 0; \
+  } while (false) \
+
+#define SCANF_SIZED(SIZE) \
+  SCANF_TYPED(SIZE, SIZE##_t); \
+  SCANF_TYPED(FAST##SIZE, _fast##SIZE##_t); \
+  SCANF_TYPED(LEAST##SIZE, _least##SIZE##_t) \
+
+
+TEST(inttypes, printf_macros) {
+  PRINTF_SIZED(8);
+  PRINTF_SIZED(16);
+  PRINTF_SIZED(32);
+  PRINTF_SIZED(64);
+
+  PRINTF_TYPED(MAX, max_t);
+  PRINTF_TYPED(PTR, ptr_t);
+}
+
+TEST(inttypes, scanf_macros) {
+  SCANF_SIZED(8);
+  SCANF_SIZED(16);
+  SCANF_SIZED(32);
+  SCANF_SIZED(64);
+
+  SCANF_TYPED(MAX, max_t);
+  SCANF_TYPED(PTR, ptr_t);
 }
 
 TEST(inttypes, wcstoimax) {
diff --git a/tests/pthread_dlfcn_test.cpp b/tests/pthread_dlfcn_test.cpp
index 64423da..1c733fe 100644
--- a/tests/pthread_dlfcn_test.cpp
+++ b/tests/pthread_dlfcn_test.cpp
@@ -37,6 +37,11 @@
 static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
 static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
 
+static void* g_atfork_test_handle = nullptr;
+static void AtForkPrepare() {}
+static void AtForkParent() {}
+static void AtForkChild() { dlclose(g_atfork_test_handle); g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL); }
+
 TEST(pthread, pthread_atfork_with_dlclose) {
   ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
 
@@ -82,3 +87,28 @@
 
   AssertChildExited(pid, 0);
 }
+
+TEST(pthread, pthread_atfork_child_with_dlclose) {
+
+  g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(g_atfork_test_handle != nullptr) << dlerror();
+  typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(g_atfork_test_handle, "proxy_pthread_atfork"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  // the library registers 2 additional atfork handlers in a constructor
+
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild));
+
+  pid_t pid = fork();
+
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  if (pid == 0) {
+    _exit(0);
+  }
+
+  AssertChildExited(pid, 0);
+
+  EXPECT_EQ(0, dlclose(g_atfork_test_handle));
+  g_atfork_test_handle = nullptr;
+}
diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
index f1b08c1..205db86 100644
--- a/tests/sys_prctl_test.cpp
+++ b/tests/sys_prctl_test.cpp
@@ -14,11 +14,19 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
+#include <inttypes.h>
+#include <stdio.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "android-base/file.h"
+#include "android-base/strings.h"
 #include "private/bionic_prctl.h"
 
 // http://b/20017123.
@@ -29,9 +37,28 @@
   ASSERT_NE(MAP_FAILED, p);
   ASSERT_EQ(0, mprotect(p, page_size, PROT_NONE));
   ASSERT_NE(-1, prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, page_size * 3, "anonymous map space"));
-  volatile char* vp = reinterpret_cast<volatile char*>(p);
-  // Below memory access causes SEGV if the memory map is screwed up.
-  *(vp + page_size) = 0;
+  // Now read the maps and verify that there are no overlapped maps.
+  std::string file_data;
+  ASSERT_TRUE(android::base::ReadFileToString("/proc/self/maps", &file_data));
+
+  uintptr_t last_start = 0;
+  uintptr_t last_end = 0;
+  std::vector<std::string> lines = android::base::Split(file_data, "\n");
+  for (size_t i = 0; i < lines.size(); i++) {
+    if (lines[i].empty()) {
+      continue;
+    }
+    uintptr_t start;
+    uintptr_t end;
+    ASSERT_EQ(2, sscanf(lines[i].c_str(), "%" SCNxPTR "-%" SCNxPTR " ", &start, &end))
+        << "Failed to parse line: " << lines[i];
+    // This will never fail on the first line, so no need to do any special checking.
+    ASSERT_GE(start, last_end)
+        << "Overlapping map detected:\n" << lines[i -1] << '\n' << lines[i] << '\n';
+    last_start = start;
+    last_end = end;
+  }
+
   ASSERT_EQ(0, munmap(p, page_size * 3));
 #else
   GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 660679f..b488e82 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -426,7 +426,7 @@
   }
 }
 
-static void TestGetPidCachingWithFork(int (*fork_fn)()) {
+static void TestGetPidCachingWithFork(int (*fork_fn)(), void (*exit_fn)(int)) {
   pid_t parent_pid = getpid();
   ASSERT_EQ(syscall(__NR_getpid), parent_pid);
 
@@ -436,7 +436,7 @@
     // We're the child.
     ASSERT_NO_FATAL_FAILURE(AssertGetPidCorrect());
     ASSERT_EQ(parent_pid, getppid());
-    _exit(123);
+    exit_fn(123);
   } else {
     // We're the parent.
     ASSERT_EQ(parent_pid, getpid());
@@ -460,7 +460,7 @@
   }
 }
 
-static void TestGetTidCachingWithFork(int (*fork_fn)()) {
+static void TestGetTidCachingWithFork(int (*fork_fn)(), void (*exit_fn)(int)) {
   pid_t parent_tid = GetTidForTest();
   ASSERT_EQ(syscall(__NR_gettid), parent_tid);
 
@@ -472,7 +472,7 @@
     EXPECT_EQ(getpid(), GetTidForTest()) << "real tid is " << syscall(__NR_gettid)
                                          << ", pid is " << syscall(__NR_getpid);
     ASSERT_NO_FATAL_FAILURE(AssertGetTidCorrect());
-    _exit(123);
+    exit_fn(123);
   } else {
     // We're the parent.
     ASSERT_EQ(parent_tid, GetTidForTest());
@@ -481,15 +481,15 @@
 }
 
 TEST(UNISTD_TEST, getpid_caching_and_fork) {
-  TestGetPidCachingWithFork(fork);
+  TestGetPidCachingWithFork(fork, exit);
 }
 
 TEST(UNISTD_TEST, gettid_caching_and_fork) {
-  TestGetTidCachingWithFork(fork);
+  TestGetTidCachingWithFork(fork, exit);
 }
 
 TEST(UNISTD_TEST, getpid_caching_and_vfork) {
-  TestGetPidCachingWithFork(vfork);
+  TestGetPidCachingWithFork(vfork, _exit);
 }
 
 static int CloneLikeFork() {
@@ -497,11 +497,11 @@
 }
 
 TEST(UNISTD_TEST, getpid_caching_and_clone_process) {
-  TestGetPidCachingWithFork(CloneLikeFork);
+  TestGetPidCachingWithFork(CloneLikeFork, exit);
 }
 
 TEST(UNISTD_TEST, gettid_caching_and_clone_process) {
-  TestGetTidCachingWithFork(CloneLikeFork);
+  TestGetTidCachingWithFork(CloneLikeFork, exit);
 }
 
 static int CloneAndSetTid() {
@@ -525,7 +525,7 @@
 }
 
 TEST(UNISTD_TEST, gettid_caching_and_clone_process_settid) {
-  TestGetTidCachingWithFork(CloneAndSetTid);
+  TestGetTidCachingWithFork(CloneAndSetTid, exit);
 }
 
 static int CloneStartRoutine(int (*start_routine)(void*)) {
@@ -572,6 +572,22 @@
   AssertChildExited(clone_result, 123);
 }
 
+static int CloneChildExit(void*) {
+  AssertGetPidCorrect();
+  AssertGetTidCorrect();
+  exit(33);
+}
+
+TEST(UNISTD_TEST, clone_fn_and_exit) {
+  int clone_result = CloneStartRoutine(CloneChildExit);
+  ASSERT_NE(-1, clone_result);
+
+  AssertGetPidCorrect();
+  AssertGetTidCorrect();
+
+  AssertChildExited(clone_result, 33);
+}
+
 static void* GetPidCachingPthreadStartRoutine(void*) {
   AssertGetPidCorrect();
   return NULL;
diff --git a/tools/update_headers.sh b/tools/update_headers.sh
index e5b87f1..0095d50 100755
--- a/tools/update_headers.sh
+++ b/tools/update_headers.sh
@@ -35,11 +35,17 @@
 HEADERS_INSTALL=$PREBUILTS_DIR/headers
 if [ -d "$HEADERS_INSTALL" ]; then
   git -C $PREBUILTS_DIR rm -r --ignore-unmatch $HEADERS_INSTALL
-  rm -r $HEADERS_INSTALL
+  if [ -d $HEADERS_INSTALL ]; then
+    rm -r $HEADERS_INSTALL
+  fi
 fi
 
 versioner -p versioner/platforms versioner/current versioner/dependencies \
   -o $HEADERS_INSTALL
+if [ $? -ne 0 ]; then
+  >&2 echo "Header preprocessing failed"
+  exit 1
+fi
 
 cp ../libc/NOTICE $PREBUILTS_DIR
 
diff --git a/tools/versioner/src/DeclarationDatabase.h b/tools/versioner/src/DeclarationDatabase.h
index 6f577a5..0daa2cd 100644
--- a/tools/versioner/src/DeclarationDatabase.h
+++ b/tools/versioner/src/DeclarationDatabase.h
@@ -152,9 +152,9 @@
 
       fprintf(out, "\n%s  ", indent_str.c_str());
       if (!calculateAvailability(&avail)) {
-        fprintf(out, "invalid availability");
+        fprintf(out, "invalid availability\n");
       } else {
-        fprintf(out, "%s", to_string(avail).c_str());
+        fprintf(out, "%s\n", to_string(avail).c_str());
       }
     }
   }
@@ -188,7 +188,6 @@
 
     for (auto& it : declarations) {
       it.second.dump(base_path, out, 4);
-      fprintf(out, "\n");
     }
   }
 };
diff --git a/tools/versioner/src/Preprocessor.cpp b/tools/versioner/src/Preprocessor.cpp
index ff3ff83..c863e6c 100644
--- a/tools/versioner/src/Preprocessor.cpp
+++ b/tools/versioner/src/Preprocessor.cpp
@@ -194,7 +194,7 @@
     bool future = avail.arch_availability[*it.second.begin()].future;
 
     if (future) {
-      return "0";
+      return "__ANDROID_API__ >= __ANDROID_API_FUTURE__";
     }
 
     // The maximum min_version of the set.
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index 5aaf47a..86349e1 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -194,6 +194,21 @@
   return result;
 }
 
+static std::set<CompilationType> getCompilationTypes(const Declaration* decl) {
+  std::set<CompilationType> result;
+  for (const auto& it : decl->availability) {
+    result.insert(it.first);
+  }
+  return result;
+}
+
+template<typename T>
+static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
+  std::vector<T> intersection;
+  std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(intersection));
+  return intersection;
+}
+
 // Perform a sanity check on a symbol's declarations, enforcing the following invariants:
 //   1. At most one inline definition of the function exists.
 //   2. All of the availability declarations for a symbol are compatible.
@@ -205,18 +220,23 @@
 static bool checkSymbol(const Symbol& symbol) {
   std::string cwd = getWorkingDir() + "/";
 
-  const Declaration* inline_definition = nullptr;
+  std::unordered_map<const Declaration*, std::set<CompilationType>> inline_definitions;
   for (const auto& decl_it : symbol.declarations) {
     const Declaration* decl = &decl_it.second;
     if (decl->is_definition) {
-      if (inline_definition) {
-        fprintf(stderr, "versioner: multiple definitions of symbol %s\n", symbol.name.c_str());
-        symbol.dump(cwd);
-        inline_definition->dump(cwd);
-        return false;
+      std::set<CompilationType> compilation_types = getCompilationTypes(decl);
+      for (const auto& inline_def_it : inline_definitions) {
+        auto intersection = Intersection(compilation_types, inline_def_it.second);
+        if (!intersection.empty()) {
+          fprintf(stderr, "versioner: conflicting inline definitions:\n");
+          fprintf(stderr, "  declarations visible in: %s\n", Join(intersection, ", ").c_str());
+          decl->dump(cwd, stderr, 4);
+          inline_def_it.first->dump(cwd, stderr, 4);
+          return false;
+        }
       }
 
-      inline_definition = decl;
+      inline_definitions[decl] = std::move(compilation_types);
     }
 
     DeclarationAvailability availability;
diff --git a/tools/versioner/tests/multiple_definition/expected_fail b/tools/versioner/tests/multiple_definition/expected_fail
new file mode 100644
index 0000000..6c531bd
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition/expected_fail
@@ -0,0 +1,7 @@
+versioner: conflicting inline definitions:
+  declarations visible in: arm-9 [fob = 32], arm-9 [fob = 64], arm-12 [fob = 32], arm-12 [fob = 64]
+    static definition @ headers/foo.h:1:1
+      no availability
+    static definition @ headers/bar.h:1:1
+      no availability
+versioner: sanity check failed
diff --git a/tools/versioner/tests/multiple_definition/headers/bar.h b/tools/versioner/tests/multiple_definition/headers/bar.h
new file mode 100644
index 0000000..a9d0197
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition/headers/bar.h
@@ -0,0 +1,3 @@
+static int foo() {
+  return 0;
+}
diff --git a/tools/versioner/tests/multiple_definition/headers/foo.h b/tools/versioner/tests/multiple_definition/headers/foo.h
new file mode 100644
index 0000000..a9d0197
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition/headers/foo.h
@@ -0,0 +1,3 @@
+static int foo() {
+  return 0;
+}
diff --git a/tools/versioner/tests/multiple_definition/platforms/android-9/arch-arm/symbols/libc.so.functions.txt b/tools/versioner/tests/multiple_definition/platforms/android-9/arch-arm/symbols/libc.so.functions.txt
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition/platforms/android-9/arch-arm/symbols/libc.so.functions.txt
@@ -0,0 +1 @@
+foo
diff --git a/tools/versioner/tests/multiple_definition/run.sh b/tools/versioner/tests/multiple_definition/run.sh
new file mode 100644
index 0000000..e4abbe7
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition/run.sh
@@ -0,0 +1 @@
+versioner headers -p platforms -r arm -a 9 -a 12 -i
diff --git a/tools/versioner/tests/multiple_definition_ok/headers/bar.h b/tools/versioner/tests/multiple_definition_ok/headers/bar.h
new file mode 100644
index 0000000..c3c87bb
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition_ok/headers/bar.h
@@ -0,0 +1,5 @@
+#if __ANDROID_API__ == 12
+static int foo() {
+  return 0;
+}
+#endif
diff --git a/tools/versioner/tests/multiple_definition_ok/headers/foo.h b/tools/versioner/tests/multiple_definition_ok/headers/foo.h
new file mode 100644
index 0000000..9da9b2a
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition_ok/headers/foo.h
@@ -0,0 +1,5 @@
+#if __ANDROID_API__ == 9
+static int foo() {
+  return 0;
+}
+#endif
diff --git a/tools/versioner/tests/multiple_definition_ok/platforms/android-9/arch-arm/symbols/libc.so.functions.txt b/tools/versioner/tests/multiple_definition_ok/platforms/android-9/arch-arm/symbols/libc.so.functions.txt
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition_ok/platforms/android-9/arch-arm/symbols/libc.so.functions.txt
@@ -0,0 +1 @@
+foo
diff --git a/tools/versioner/tests/multiple_definition_ok/run.sh b/tools/versioner/tests/multiple_definition_ok/run.sh
new file mode 100644
index 0000000..e4abbe7
--- /dev/null
+++ b/tools/versioner/tests/multiple_definition_ok/run.sh
@@ -0,0 +1 @@
+versioner headers -p platforms -r arm -a 9 -a 12 -i
diff --git a/tools/versioner/tests/preprocessor/expected/foo.h b/tools/versioner/tests/preprocessor/expected/foo.h
index b83dd07..73947b2 100644
--- a/tools/versioner/tests/preprocessor/expected/foo.h
+++ b/tools/versioner/tests/preprocessor/expected/foo.h
@@ -68,3 +68,9 @@
 int group_lp32() __INTRODUCED_IN_ARM(12) __INTRODUCED_IN_X86(12) __INTRODUCED_IN_MIPS(12);
 #endif /* (!defined(__LP64__) && __ANDROID_API__ >= 12) || (defined(__LP64__)) */
 
+
+
+#if __ANDROID_API__ >= __ANDROID_API_FUTURE__
+int future() __INTRODUCED_IN_FUTURE;
+#endif /* __ANDROID_API__ >= __ANDROID_API_FUTURE__ */
+
diff --git a/tools/versioner/tests/preprocessor/headers/foo.h b/tools/versioner/tests/preprocessor/headers/foo.h
index 7eba47f..81c8b4b 100644
--- a/tools/versioner/tests/preprocessor/headers/foo.h
+++ b/tools/versioner/tests/preprocessor/headers/foo.h
@@ -40,3 +40,5 @@
     __INTRODUCED_IN_64(22);
 
 int group_lp32() __INTRODUCED_IN_ARM(12) __INTRODUCED_IN_X86(12) __INTRODUCED_IN_MIPS(12);
+
+int future() __INTRODUCED_IN_FUTURE;