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;