Merge "Initialize main thread TLS before the global stack guard."
diff --git a/libc/Android.bp b/libc/Android.bp
index 4fcd83e..f61cc46 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -15,9 +15,12 @@
"bionic/sigsetmask.c",
"bionic/system_properties_compat.c",
"stdio/fread.c",
+ "stdio/parsefloat.c",
"stdio/refill.c",
"stdio/stdio.cpp",
"stdio/stdio_ext.cpp",
+ "stdio/vfscanf.c",
+ "stdio/vfwscanf.c",
"stdlib/atexit.c",
"stdlib/exit.c",
]
@@ -397,11 +400,8 @@
"upstream-openbsd/lib/libc/locale/mbstowcs.c",
"upstream-openbsd/lib/libc/locale/mbtowc.c",
"upstream-openbsd/lib/libc/locale/wcscoll.c",
- "upstream-openbsd/lib/libc/locale/wcstod.c",
- "upstream-openbsd/lib/libc/locale/wcstof.c",
"upstream-openbsd/lib/libc/locale/wcstoimax.c",
"upstream-openbsd/lib/libc/locale/wcstol.c",
- "upstream-openbsd/lib/libc/locale/wcstold.c",
"upstream-openbsd/lib/libc/locale/wcstoll.c",
"upstream-openbsd/lib/libc/locale/wcstombs.c",
"upstream-openbsd/lib/libc/locale/wcstoul.c",
@@ -453,7 +453,6 @@
"upstream-openbsd/lib/libc/stdio/ungetwc.c",
"upstream-openbsd/lib/libc/stdio/vasprintf.c",
"upstream-openbsd/lib/libc/stdio/vdprintf.c",
- "upstream-openbsd/lib/libc/stdio/vfscanf.c",
"upstream-openbsd/lib/libc/stdio/vsscanf.c",
"upstream-openbsd/lib/libc/stdio/vswprintf.c",
"upstream-openbsd/lib/libc/stdio/vswscanf.c",
@@ -520,7 +519,6 @@
srcs: [
"upstream-openbsd/lib/libc/stdio/vfprintf.c",
"upstream-openbsd/lib/libc/stdio/vfwprintf.c",
- "upstream-openbsd/lib/libc/stdio/vfwscanf.c",
],
cflags: [
"-include openbsd-compat.h",
@@ -1365,6 +1363,7 @@
"bionic/unlink.cpp",
"bionic/wait.cpp",
"bionic/wchar.cpp",
+ "bionic/wcstod.cpp",
"bionic/wctype.cpp",
"bionic/wmempcpy.cpp",
],
@@ -1990,4 +1989,125 @@
defaults: ["crt_defaults"],
}
+// The following module lives in prebuilts/ndk because we need to preprocess the
+// headers to include ifdef guards for __ANDROID_API__. Update with
+// bionic/tools/update_headers.sh.
+// ndk_headers {
+// name: "common_libc",
+// from: "include",
+// to: "",
+// srcs: ["include/**/*.h"],
+// }
+
+ndk_headers {
+ name: "libc_linux",
+ from: "kernel/uapi/linux",
+ to: "linux",
+ srcs: ["kernel/uapi/linux/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_android",
+ from: "kernel/android/uapi/linux",
+ to: "linux",
+ srcs: ["kernel/android/uapi/linux/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_generic",
+ from: "kernel/uapi/asm-generic",
+ to: "asm-generic",
+ srcs: ["kernel/uapi/asm-generic/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_arm",
+ from: "kernel/uapi/asm-arm",
+ to: "arm-linux-androideabi",
+ srcs: ["kernel/uapi/asm-arm/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_arm64",
+ from: "kernel/uapi/asm-arm64",
+ to: "aarch64-linux-android",
+ srcs: ["kernel/uapi/asm-arm64/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_mips",
+ from: "kernel/uapi/asm-mips",
+ to: "mipsel-linux-android",
+ srcs: ["kernel/uapi/asm-mips/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_mips64",
+ from: "kernel/uapi/asm-mips",
+ to: "mips64el-linux-android",
+ srcs: ["kernel/uapi/asm-mips/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_x86",
+ from: "kernel/uapi/asm-x86",
+ to: "i686-linux-android",
+ srcs: ["kernel/uapi/asm-x86/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_asm_x86_64",
+ from: "kernel/uapi/asm-x86",
+ to: "x86_64-linux-android",
+ srcs: ["kernel/uapi/asm-x86/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_arm",
+ from: "arch-arm/include",
+ to: "arm-linux-androideabi",
+ srcs: ["arch-arm/include/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_arm64",
+ from: "arch-arm64/include",
+ to: "aarch64-linux-android",
+ srcs: ["arch-arm64/include/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_mips",
+ from: "arch-mips/include",
+ to: "mipsel-linux-android",
+ srcs: ["arch-mips/include/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_mips64",
+ from: "arch-mips/include",
+ to: "mips64el-linux-android",
+ srcs: ["arch-mips/include/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_x86",
+ from: "arch-x86/include",
+ to: "i686-linux-android",
+ srcs: ["arch-x86/include/**/*.h"],
+}
+
+ndk_headers {
+ name: "libc_machine_x86_64",
+ from: "arch-x86_64/include",
+ to: "x86_64-linux-android",
+ srcs: ["arch-x86_64/include/**/*.h"],
+}
+
+ndk_library {
+ name: "libc.ndk",
+ symbol_file: "libc.map.txt",
+ first_version: "9",
+}
+
subdirs = ["malloc_debug"]
diff --git a/libc/arch-arm/bionic/__bionic_clone.S b/libc/arch-arm/bionic/__bionic_clone.S
index a85ea34..8836748 100644
--- a/libc/arch-arm/bionic/__bionic_clone.S
+++ b/libc/arch-arm/bionic/__bionic_clone.S
@@ -51,7 +51,7 @@
# Are we the child?
movs r0, r0
- beq 1f
+ beq .L_bc_child
# In the parent, reload saved registers then either return or set errno.
ldmfd sp!, {r4, r5, r6, r7}
@@ -60,9 +60,9 @@
neg r0, r0
b __set_errno_internal
- # The child.
- # Setting lr to 0 will make the unwinder stop at __start_thread
-1: mov lr, #0
+.L_bc_child:
+ # Setting lr to 0 will make the unwinder stop at __start_thread.
+ mov lr, #0
# Call __start_thread with the 'fn' and 'arg' we stored on the child stack.
pop {r0, r1}
b __start_thread
diff --git a/libc/bionic/sys_msg.cpp b/libc/bionic/sys_msg.cpp
index 462c83b..4880356 100644
--- a/libc/bionic/sys_msg.cpp
+++ b/libc/bionic/sys_msg.cpp
@@ -32,8 +32,9 @@
#include <unistd.h>
int msgctl(int id, int cmd, msqid_ds* buf) {
-#if !defined(__LP64__)
+#if !defined(__LP64__) || defined(__mips__)
// Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit.
+ // Mips64 is an exception to this, it requires the flag.
cmd |= IPC_64;
#endif
#if defined(SYS_msgctl)
diff --git a/libc/bionic/sys_sem.cpp b/libc/bionic/sys_sem.cpp
index 058cfef..5e2a05c 100644
--- a/libc/bionic/sys_sem.cpp
+++ b/libc/bionic/sys_sem.cpp
@@ -33,8 +33,9 @@
#include <unistd.h>
int semctl(int id, int num, int cmd, ...) {
-#if !defined(__LP64__)
+#if !defined(__LP64__) || defined(__mips__)
// Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit.
+ // Mips64 is an exception to this, it requires the flag.
cmd |= IPC_64;
#endif
va_list ap;
diff --git a/libc/bionic/sys_shm.cpp b/libc/bionic/sys_shm.cpp
index f780e04..f3b26e7 100644
--- a/libc/bionic/sys_shm.cpp
+++ b/libc/bionic/sys_shm.cpp
@@ -45,8 +45,9 @@
}
int shmctl(int id, int cmd, struct shmid_ds* buf) {
-#if !defined(__LP64__)
+#if !defined(__LP64__) || defined(__mips__)
// Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit.
+ // Mips64 is an exception to this, it requires the flag.
cmd |= IPC_64;
#endif
#if defined(SYS_shmctl)
diff --git a/libc/bionic/wcstod.cpp b/libc/bionic/wcstod.cpp
new file mode 100644
index 0000000..eb66ba0
--- /dev/null
+++ b/libc/bionic/wcstod.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 <wchar.h>
+
+#include <stdlib.h>
+
+#include "local.h"
+
+template <typename float_type> float_type wcstod(const wchar_t* str, wchar_t** end,
+ float_type strtod_fn(const char*, char**)) {
+ // What's the longest span of the input that might be part of the float?
+ size_t max_len = wcsspn(str, L"-+0123456789.xXeEpP()nNaAiIfFtTyY");
+
+ // We know the only valid characters are ASCII, so convert them by brute force.
+ char* ascii_str = new char[max_len + 1];
+ if (!ascii_str) return float_type();
+ for (size_t i = 0; i < max_len; ++i) {
+ ascii_str[i] = str[i] & 0xff;
+ }
+ ascii_str[max_len] = 0;
+
+ // Set up a fake FILE that points to those ASCII characters, for `parsefloat`.
+ FILE f;
+ __sfileext fext;
+ _FILEEXT_SETUP(&f, &fext);
+ f._flags = __SRD;
+ f._bf._base = f._p = reinterpret_cast<unsigned char*>(ascii_str);
+ f._bf._size = f._r = max_len;
+ f._read = [](void*, char*, int) { return 0; }; // aka `eofread`, aka "no more data".
+ f._lb._base = NULL;
+
+ // Ask `parsefloat` to look at the same data more carefully.
+
+ // We can't just do this straight away because we can't construct a suitable FILE*
+ // in the absence of any `fwmemopen` analogous to `fmemopen`. And we don't want to
+ // duplicate the `parsefloat` logic. We also don't want to actually have to have wchar_t
+ // implementations of the ASCII `strtod` logic (though if you were designing a libc
+ // from scratch, you'd probably want to just make that more generic and lose all the
+ // cruft on top).
+ size_t actual_len = parsefloat(&f, ascii_str, ascii_str + max_len);
+
+ // Finally let the ASCII conversion function do the work.
+ char* ascii_end;
+ float_type result = strtod_fn(ascii_str, &ascii_end);
+ if (ascii_end != ascii_str + actual_len) abort();
+
+ if (end) *end = const_cast<wchar_t*>(str) + actual_len;
+
+ delete[] ascii_str;
+ return result;
+}
+
+float wcstof(const wchar_t* s, wchar_t** end) {
+ return wcstod<float>(s, end, strtof);
+}
+
+double wcstod(const wchar_t* s, wchar_t** end) {
+ return wcstod<double>(s, end, strtod);
+}
+
+long double wcstold(const wchar_t* s, wchar_t** end) {
+ return wcstod<long double>(s, end, strtold);
+}
diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h
index 3686261..196c28e 100644
--- a/libc/include/android/versioning.h
+++ b/libc/include/android/versioning.h
@@ -27,4 +27,6 @@
#define __INTRODUCED_IN_X86(api_level) __attribute__((annotate("introduced_in_x86=" #api_level)))
#define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" #api_level)))
+#define __VERSIONER_NO_GUARD __attribute__((annotate("versioner_no_guard")))
+
#endif /* ANDROID_VERSIONING_H */
diff --git a/libc/include/bits/wctype.h b/libc/include/bits/wctype.h
index b98e500..c968d71 100644
--- a/libc/include/bits/wctype.h
+++ b/libc/include/bits/wctype.h
@@ -58,8 +58,8 @@
int iswctype(wint_t, wctype_t);
typedef const void* wctrans_t;
-wint_t towctrans(wint_t, wctrans_t) __INTRODUCED_IN_FUTURE;
-wctrans_t wctrans(const char*) __INTRODUCED_IN_FUTURE;
+wint_t towctrans(wint_t, wctrans_t) __INTRODUCED_IN_FUTURE __VERSIONER_NO_GUARD;
+wctrans_t wctrans(const char*) __INTRODUCED_IN_FUTURE __VERSIONER_NO_GUARD;
__END_DECLS
diff --git a/libc/include/locale.h b/libc/include/locale.h
index a681a17..c1b6299 100644
--- a/libc/include/locale.h
+++ b/libc/include/locale.h
@@ -96,7 +96,7 @@
char int_n_sign_posn;
};
-struct lconv* localeconv(void) __INTRODUCED_IN(21);
+struct lconv* localeconv(void) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
locale_t duplocale(locale_t) __INTRODUCED_IN(21);
void freelocale(locale_t) __INTRODUCED_IN(21);
diff --git a/libc/include/math.h b/libc/include/math.h
index 37aa2cc..4437b81 100644
--- a/libc/include/math.h
+++ b/libc/include/math.h
@@ -169,7 +169,7 @@
double fmin(double, double) __pure2;
double nearbyint(double);
double round(double);
-double scalbln(double, long) __INTRODUCED_IN_X86(18);
+double scalbln(double, long) __INTRODUCED_IN_X86(18) __VERSIONER_NO_GUARD;
double scalbn(double, int);
double tgamma(double);
double trunc(double);
@@ -230,7 +230,7 @@
float remainderf(float, float);
float remquof(float, float, int *);
float rintf(float);
-float scalblnf(float, long) __INTRODUCED_IN_X86(18);
+float scalblnf(float, long) __INTRODUCED_IN_X86(18) __VERSIONER_NO_GUARD;
float scalbnf(float, int);
float truncf(float);
@@ -259,11 +259,12 @@
long double fabsl(long double) __pure2;
long double fdiml(long double, long double);
long double floorl(long double);
-long double fmal(long double, long double, long double) __INTRODUCED_IN(21);
+long double fmal(long double, long double, long double) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
long double fmaxl(long double, long double) __pure2;
long double fminl(long double, long double) __pure2;
long double fmodl(long double, long double) __INTRODUCED_IN(21);
-long double frexpl(long double value, int*) __INTRODUCED_IN(21); /* fundamentally !__pure2 */
+long double frexpl(long double value, int*)
+ __INTRODUCED_IN(21) __VERSIONER_NO_GUARD; /* fundamentally !__pure2 */
long double hypotl(long double, long double) __INTRODUCED_IN(21);
int ilogbl(long double) __pure2;
long double ldexpl(long double, int);
@@ -280,16 +281,16 @@
long double modfl(long double, long double*) __INTRODUCED_IN(21); /* fundamentally !__pure2 */
long double nanl(const char*) __pure2 __INTRODUCED_IN(13);
long double nearbyintl(long double) __INTRODUCED_IN(21);
-long double nextafterl(long double, long double) __INTRODUCED_IN(21);
-double nexttoward(double, long double) __INTRODUCED_IN(18);
+long double nextafterl(long double, long double) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
+double nexttoward(double, long double) __INTRODUCED_IN(18) __VERSIONER_NO_GUARD;
float nexttowardf(float, long double);
-long double nexttowardl(long double, long double) __INTRODUCED_IN(18);
+long double nexttowardl(long double, long double) __INTRODUCED_IN(18) __VERSIONER_NO_GUARD;
long double powl(long double, long double) __INTRODUCED_IN(21);
long double remainderl(long double, long double) __INTRODUCED_IN(21);
long double remquol(long double, long double, int*) __INTRODUCED_IN(21);
long double rintl(long double) __INTRODUCED_IN(21);
long double roundl(long double);
-long double scalblnl(long double, long) __INTRODUCED_IN_X86(18);
+long double scalblnl(long double, long) __INTRODUCED_IN_X86(18) __VERSIONER_NO_GUARD;
long double scalbnl(long double, int);
long double sinhl(long double) __INTRODUCED_IN(21);
long double sinl(long double) __INTRODUCED_IN(21);
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index 00b5cf9..3574976 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -47,8 +47,13 @@
int bindresvport(int, struct sockaddr_in*);
+#if __ANDROID_API__ >= 24
extern const struct in6_addr in6addr_any __INTRODUCED_IN(24);
extern const struct in6_addr in6addr_loopback __INTRODUCED_IN(24);
+#else
+static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+static const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+#endif /* __ANDROID_API__ >= 24 */
__END_DECLS
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 28cd4a8..6b0ec12 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -147,14 +147,23 @@
const char* getprogname(void) __INTRODUCED_IN(21);
void setprogname(const char*) __INTRODUCED_IN(21);
-int mblen(const char*, size_t) __INTRODUCED_IN_FUTURE;
+int mblen(const char*, size_t) __INTRODUCED_IN_FUTURE __VERSIONER_NO_GUARD;
size_t mbstowcs(wchar_t*, const char*, size_t);
-int mbtowc(wchar_t*, const char*, size_t) __INTRODUCED_IN(21);
-int wctomb(char*, wchar_t) __INTRODUCED_IN(21);
+int mbtowc(wchar_t*, const char*, size_t) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
+int wctomb(char*, wchar_t) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
+
size_t wcstombs(char*, const wchar_t*, size_t);
+#if __ANDROID_API__ >= 21
size_t __ctype_get_mb_cur_max(void) __INTRODUCED_IN(21);
#define MB_CUR_MAX __ctype_get_mb_cur_max()
+#else
+/*
+ * 4 is only true for UTF-8 locales, but that's what we default to. We'll need
+ * the NDK compatibility library to fix this properly.
+ */
+#define MB_CUR_MAX 4
+#endif
#if defined(__BIONIC_FORTIFY)
diff --git a/libc/include/string.h b/libc/include/string.h
index 18b12bd..4a83c4e 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -239,9 +239,7 @@
return __stpncpy_chk2(dst, src, n, bos_dst, bos_src);
}
-#endif /* __ANDROID_API__ >= 21 */
-#if __ANDROID_API__ >= 17
__BIONIC_FORTIFY_INLINE
char* strncpy(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src, size_t n) {
size_t bos_dst = __bos(dst);
@@ -262,7 +260,9 @@
return __strncpy_chk2(dst, src, n, bos_dst, bos_src);
}
+#endif /* __ANDROID_API__ >= 21 */
+#if __ANDROID_API__ >= 17
__BIONIC_FORTIFY_INLINE
char* strcat(char* _Nonnull __restrict dst, const char* _Nonnull __restrict src) {
return __builtin___strcat_chk(dst, src, __bos(dst));
diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h
index 0f454b0..5a8a81d 100644
--- a/libc/include/sys/select.h
+++ b/libc/include/sys/select.h
@@ -61,7 +61,7 @@
void __FD_SET_chk(int, fd_set*, size_t) __INTRODUCED_IN(21);
int __FD_ISSET_chk(int, fd_set*, size_t) __INTRODUCED_IN(21);
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && __ANDROID_API__ >= 21
#define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
#define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
#define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
@@ -69,7 +69,7 @@
#define FD_CLR(fd, set) (__FDS_BITS(set)[__FDELT(fd)] &= ~__FDMASK(fd))
#define FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
#define FD_ISSET(fd, set) ((__FDS_BITS(set)[__FDELT(fd)] & __FDMASK(fd)) != 0)
-#endif /* defined(__BIONIC_FORTIFY) */
+#endif /* defined(__BIONIC_FORTIFY) && __ANDROID_API >= 21 */
int select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
int pselect(int, fd_set*, fd_set*, fd_set*, const struct timespec*, const sigset_t*);
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 910fee1..03dc849 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -114,7 +114,22 @@
? (struct cmsghdr*) (msg)->msg_control : (struct cmsghdr*) NULL)
#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && (cmsg)->cmsg_len <= (unsigned long) ((mhdr)->msg_controllen - ((char*)(cmsg) - (char*)(mhdr)->msg_control)))
+#if __ANDROID_API__ >= 21
struct cmsghdr* __cmsg_nxthdr(struct msghdr*, struct cmsghdr*) __INTRODUCED_IN(21);
+#else
+/* TODO(danalbert): Move this into libandroid_support. */
+static inline struct cmsghdr* __cmsg_nxthdr(struct msghdr* msg, struct cmsghdr* cmsg) {
+ struct cmsghdr* ptr =
+ __BIONIC_CAST(reinterpret_cast, struct cmsghdr*,
+ (__BIONIC_CAST(reinterpret_cast, char*, cmsg) + CMSG_ALIGN(cmsg->cmsg_len)));
+ size_t len = __BIONIC_CAST(reinterpret_cast, char*, ptr + 1) -
+ __BIONIC_CAST(reinterpret_cast, char*, msg->msg_control);
+ if (len > msg->msg_controllen) {
+ return NULL;
+ }
+ return ptr;
+}
+#endif /* __ANDROID_API__ >= 21 */
#define SCM_RIGHTS 0x01
#define SCM_CREDENTIALS 0x02
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index ac7d4c2..4e7d8ba 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -209,7 +209,7 @@
#if __ANDROID_API__ >= 21
int getpagesize(void) __INTRODUCED_IN(21);
#else
-__inline__ int getpagesize(void) {
+static __inline__ int getpagesize(void) {
return sysconf(_SC_PAGESIZE);
}
#endif
@@ -489,6 +489,7 @@
}
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 23
__BIONIC_FORTIFY_INLINE
ssize_t readlink(const char* path, char* buf, size_t size) {
size_t bos = __bos(buf);
@@ -538,6 +539,7 @@
return __readlinkat_chk(dirfd, path, buf, size, bos);
}
+#endif /* __ANDROID_API__ >= 23 */
#endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index b8cf7cf..49edaba 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -122,7 +122,7 @@
"6 malloc_debug recorded. of frames to capture. The default value is 8000000.\n"
"6 malloc_debug If the allocation list fills up, all further allocations are not recorded.\n"
"6 malloc_debug \n"
- "6 malloc_debug record_alloc_file[=FILE]\n"
+ "6 malloc_debug record_allocs_file[=FILE]\n"
"6 malloc_debug This option only has meaning if the record_allocs options has been specified.\n"
"6 malloc_debug This is the name of the file to which recording information will be dumped.\n"
"6 malloc_debug The default is /data/local/tmp/record_allocs.txt.\n"
diff --git a/libc/upstream-openbsd/lib/libc/stdio/floatio.h b/libc/stdio/floatio.h
similarity index 100%
rename from libc/upstream-openbsd/lib/libc/stdio/floatio.h
rename to libc/stdio/floatio.h
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 7be5a7c..575a428 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -147,11 +147,7 @@
#define __SNPT 0
#define __SOPT 0
-#if defined(__cplusplus)
-#define _EXT(fp) reinterpret_cast<__sfileext*>((fp)->_ext._base)
-#else
-#define _EXT(fp) ((struct __sfileext *)((fp)->_ext._base))
-#endif
+#define _EXT(fp) __BIONIC_CAST(reinterpret_cast, struct __sfileext*, (fp)->_ext._base)
#define _UB(fp) _EXT(fp)->_ub
#define _FLOCK(fp) _EXT(fp)->_lock
@@ -171,7 +167,7 @@
#define _FILEEXT_SETUP(f, fext) \
do { \
- (f)->_ext._base = (unsigned char *)(fext); \
+ (f)->_ext._base = __BIONIC_CAST(reinterpret_cast, unsigned char*, fext); \
_FILEEXT_INIT(f); \
} while (0)
@@ -259,6 +255,9 @@
extern void __sinit(void); // Not actually implemented.
#define __sdidinit 1
+size_t parsefloat(FILE*, char*, char*);
+size_t wparsefloat(FILE*, wchar_t*, wchar_t*);
+
__END_DECLS
#endif
diff --git a/libc/stdio/parsefloat.c b/libc/stdio/parsefloat.c
new file mode 100644
index 0000000..e911da4
--- /dev/null
+++ b/libc/stdio/parsefloat.c
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <ctype.h>
+#include <stdlib.h>
+
+#include "local.h"
+#include "floatio.h"
+
+#define BUF 513 /* Maximum length of numeric string. */
+
+size_t parsefloat(FILE *fp, char *buf, char *end) {
+ char *commit, *p;
+ int infnanpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
+ S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ unsigned char c;
+ int gotmantdig = 0, ishex = 0;
+
+ /*
+ * We set commit = p whenever the string we have read so far
+ * constitutes a valid representation of a floating point
+ * number by itself. At some point, the parse will complete
+ * or fail, and we will ungetc() back to the last commit point.
+ * To ensure that the file offset gets updated properly, it is
+ * always necessary to read at least one character that doesn't
+ * match; thus, we can't short-circuit "infinity" or "nan(...)".
+ */
+ commit = buf - 1;
+ for (p = buf; p < end; ) {
+ c = *fp->_p;
+reswitch:
+ switch (state) {
+ case S_START:
+ state = S_GOTSIGN;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_GOTSIGN:
+ switch (c) {
+ case '0':
+ state = S_MAYBEHEX;
+ commit = p;
+ break;
+ case 'I':
+ case 'i':
+ state = S_INF;
+ break;
+ case 'N':
+ case 'n':
+ state = S_NAN;
+ break;
+ default:
+ state = S_DIGITS;
+ goto reswitch;
+ }
+ break;
+ case S_INF:
+ if (infnanpos > 6 ||
+ (c != "nfinity"[infnanpos] &&
+ c != "NFINITY"[infnanpos]))
+ goto parsedone;
+ if (infnanpos == 1 || infnanpos == 6)
+ commit = p; /* inf or infinity */
+ infnanpos++;
+ break;
+ case S_NAN:
+ switch (infnanpos) {
+ case -1: /* XXX kludge to deal with nan(...) */
+ goto parsedone;
+ case 0:
+ if (c != 'A' && c != 'a')
+ goto parsedone;
+ break;
+ case 1:
+ if (c != 'N' && c != 'n')
+ goto parsedone;
+ else
+ commit = p;
+ break;
+ case 2:
+ if (c != '(')
+ goto parsedone;
+ break;
+ default:
+ if (c == ')') {
+ commit = p;
+ infnanpos = -2;
+ } else if (!isalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ case S_MAYBEHEX:
+ state = S_DIGITS;
+ if (c == 'X' || c == 'x') {
+ ishex = 1;
+ break;
+ } else { /* we saw a '0', but no 'x' */
+ gotmantdig = 1;
+ goto reswitch;
+ }
+ case S_DIGITS:
+ if ((ishex && isxdigit(c)) || isdigit(c))
+ gotmantdig = 1;
+ else {
+ state = S_FRAC;
+ if (c != '.')
+ goto reswitch;
+ }
+ if (gotmantdig)
+ commit = p;
+ break;
+ case S_FRAC:
+ if (((c == 'E' || c == 'e') && !ishex) ||
+ ((c == 'P' || c == 'p') && ishex)) {
+ if (!gotmantdig)
+ goto parsedone;
+ else
+ state = S_EXP;
+ } else if ((ishex && isxdigit(c)) || isdigit(c)) {
+ commit = p;
+ gotmantdig = 1;
+ } else
+ goto parsedone;
+ break;
+ case S_EXP:
+ state = S_EXPDIGITS;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_EXPDIGITS:
+ if (isdigit(c))
+ commit = p;
+ else
+ goto parsedone;
+ break;
+ default:
+ abort();
+ }
+ *p++ = c;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ break; /* EOF */
+ }
+
+parsedone:
+ while (commit < --p)
+ (void)ungetc(*(unsigned char *)p, fp);
+ *++commit = '\0';
+ return commit - buf;
+}
+
+size_t wparsefloat(FILE *fp, wchar_t *buf, wchar_t *end) {
+ wchar_t *commit, *p;
+ int infnanpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
+ S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ wint_t c;
+ int gotmantdig = 0, ishex = 0;
+
+ /*
+ * We set commit = p whenever the string we have read so far
+ * constitutes a valid representation of a floating point
+ * number by itself. At some point, the parse will complete
+ * or fail, and we will ungetc() back to the last commit point.
+ * To ensure that the file offset gets updated properly, it is
+ * always necessary to read at least one character that doesn't
+ * match; thus, we can't short-circuit "infinity" or "nan(...)".
+ */
+ commit = buf - 1;
+ c = WEOF;
+ for (p = buf; p < end; ) {
+ if ((c = __fgetwc_unlock(fp)) == WEOF)
+ break;
+reswitch:
+ switch (state) {
+ case S_START:
+ state = S_GOTSIGN;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_GOTSIGN:
+ switch (c) {
+ case '0':
+ state = S_MAYBEHEX;
+ commit = p;
+ break;
+ case 'I':
+ case 'i':
+ state = S_INF;
+ break;
+ case 'N':
+ case 'n':
+ state = S_NAN;
+ break;
+ default:
+ state = S_DIGITS;
+ goto reswitch;
+ }
+ break;
+ case S_INF:
+ if (infnanpos > 6 ||
+ (c != (wint_t)"nfinity"[infnanpos] &&
+ c != (wint_t)"NFINITY"[infnanpos]))
+ goto parsedone;
+ if (infnanpos == 1 || infnanpos == 6)
+ commit = p; /* inf or infinity */
+ infnanpos++;
+ break;
+ case S_NAN:
+ switch (infnanpos) {
+ case -1: /* XXX kludge to deal with nan(...) */
+ goto parsedone;
+ case 0:
+ if (c != 'A' && c != 'a')
+ goto parsedone;
+ break;
+ case 1:
+ if (c != 'N' && c != 'n')
+ goto parsedone;
+ else
+ commit = p;
+ break;
+ case 2:
+ if (c != '(')
+ goto parsedone;
+ break;
+ default:
+ if (c == ')') {
+ commit = p;
+ infnanpos = -2;
+ } else if (!iswalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ case S_MAYBEHEX:
+ state = S_DIGITS;
+ if (c == 'X' || c == 'x') {
+ ishex = 1;
+ break;
+ } else { /* we saw a '0', but no 'x' */
+ gotmantdig = 1;
+ goto reswitch;
+ }
+ case S_DIGITS:
+ if ((ishex && iswxdigit(c)) || iswdigit(c))
+ gotmantdig = 1;
+ else {
+ state = S_FRAC;
+ if (c != L'.')
+ goto reswitch;
+ }
+ if (gotmantdig)
+ commit = p;
+ break;
+ case S_FRAC:
+ if (((c == 'E' || c == 'e') && !ishex) ||
+ ((c == 'P' || c == 'p') && ishex)) {
+ if (!gotmantdig)
+ goto parsedone;
+ else
+ state = S_EXP;
+ } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
+ commit = p;
+ gotmantdig = 1;
+ } else
+ goto parsedone;
+ break;
+ case S_EXP:
+ state = S_EXPDIGITS;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_EXPDIGITS:
+ if (iswdigit(c))
+ commit = p;
+ else
+ goto parsedone;
+ break;
+ default:
+ abort();
+ }
+ *p++ = c;
+ c = WEOF;
+ }
+
+parsedone:
+ if (c != WEOF)
+ ungetwc(c, fp);
+ while (commit < --p)
+ ungetwc(*p, fp);
+ *++commit = '\0';
+ return (int)(commit - buf);
+}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfscanf.c b/libc/stdio/vfscanf.c
similarity index 90%
rename from libc/upstream-openbsd/lib/libc/stdio/vfscanf.c
rename to libc/stdio/vfscanf.c
index abefe32..e47d0df 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfscanf.c
+++ b/libc/stdio/vfscanf.c
@@ -346,14 +346,14 @@
wcp = NULL;
n = 0;
while (width != 0) {
- if (n == MB_CUR_MAX) {
+ if (n == (int)MB_CUR_MAX) {
fp->_flags |= __SERR;
goto input_failure;
}
buf[n++] = *fp->_p;
fp->_p++;
fp->_r--;
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
nconv = mbrtowc(wcp, buf, n, &mbs);
if (nconv == (size_t)-1) {
fp->_flags |= __SERR;
@@ -383,7 +383,7 @@
if (flags & SUPPRESS) {
size_t sum = 0;
for (;;) {
- if ((n = fp->_r) < width) {
+ if ((n = fp->_r) < (int)width) {
sum += n;
width -= n;
fp->_p += n;
@@ -428,14 +428,14 @@
n = 0;
nchars = 0;
while (width != 0) {
- if (n == MB_CUR_MAX) {
+ if (n == (int)MB_CUR_MAX) {
fp->_flags |= __SERR;
goto input_failure;
}
buf[n++] = *fp->_p;
fp->_p++;
fp->_r--;
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
nconv = mbrtowc(wcp, buf, n, &mbs);
if (nconv == (size_t)-1) {
fp->_flags |= __SERR;
@@ -532,14 +532,14 @@
wcp = &twc;
n = 0;
while (!isspace(*fp->_p) && width != 0) {
- if (n == MB_CUR_MAX) {
+ if (n == (int)MB_CUR_MAX) {
fp->_flags |= __SERR;
goto input_failure;
}
buf[n++] = *fp->_p;
fp->_p++;
fp->_r--;
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
nconv = mbrtowc(wcp, buf, n, &mbs);
if (nconv == (size_t)-1) {
fp->_flags |= __SERR;
@@ -760,96 +760,25 @@
#ifdef FLOATING_POINT
case CT_FLOAT:
/* scan a floating point number as if by strtod */
-#ifdef hardway
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
-#else
- /* size_t is unsigned, hence this optimisation */
- if (--width > sizeof(buf) - 2)
- width = sizeof(buf) - 2;
- width++;
-#endif
- flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
- for (p = buf; width; width--) {
- c = *fp->_p;
- /*
- * This code mimicks the integer conversion
- * code, but is much simpler.
- */
- switch (c) {
-
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- flags &= ~(SIGNOK | NDIGITS);
- goto fok;
-
- case '+': case '-':
- if (flags & SIGNOK) {
- flags &= ~SIGNOK;
- goto fok;
- }
- break;
- case '.':
- if (flags & DPTOK) {
- flags &= ~(SIGNOK | DPTOK);
- goto fok;
- }
- break;
- case 'e': case 'E':
- /* no exponent without some digits */
- if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
- flags =
- (flags & ~(EXPOK|DPTOK)) |
- SIGNOK | NDIGITS;
- goto fok;
- }
- break;
- }
- break;
- fok:
- *p++ = c;
- if (--fp->_r > 0)
- fp->_p++;
- else if (__srefill(fp))
- break; /* EOF */
- }
- /*
- * If no digits, might be missing exponent digits
- * (just give back the exponent) or might be missing
- * regular digits, but had sign and/or decimal point.
- */
- if (flags & NDIGITS) {
- if (flags & EXPOK) {
- /* no digits at all */
- while (p > buf)
- ungetc(*(u_char *)--p, fp);
- goto match_failure;
- }
- /* just a bad exponent (e and maybe sign) */
- c = *(u_char *)--p;
- if (c != 'e' && c != 'E') {
- (void) ungetc(c, fp);/* sign */
- c = *(u_char *)--p;
- }
- (void) ungetc(c, fp);
- }
+ if ((width = parsefloat(fp, buf, buf + width)) == 0)
+ goto match_failure;
if ((flags & SUPPRESS) == 0) {
- *p = '\0';
if (flags & LONGDBL) {
- long double res = strtold(buf,
- (char **)NULL);
+ long double res = strtold(buf, &p);
*va_arg(ap, long double *) = res;
} else if (flags & LONG) {
- double res = strtod(buf, (char **)NULL);
+ double res = strtod(buf, &p);
*va_arg(ap, double *) = res;
} else {
- float res = strtof(buf, (char **)NULL);
+ float res = strtof(buf, &p);
*va_arg(ap, float *) = res;
}
+ if ((size_t)(p - buf) != width) abort();
nassigned++;
}
- nread += p - buf;
+ nread += width;
break;
#endif /* FLOATING_POINT */
}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c b/libc/stdio/vfwscanf.c
similarity index 89%
rename from libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c
rename to libc/stdio/vfwscanf.c
index cbb36be..0a7bfa9 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c
+++ b/libc/stdio/vfwscanf.c
@@ -95,6 +95,9 @@
(cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
(wmemchr(ccls, (_c), ccle - ccls) != NULL))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+
/*
* vfwscanf
*/
@@ -120,9 +123,6 @@
size_t nconv; /* number of bytes in mb. conversion */
char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
mbstate_t mbs;
-#ifdef FLOATING_POINT
- wchar_t decimal_point = 0;
-#endif
/* `basefix' is used to avoid `if' tests in the integer scanner */
static short basefix[17] =
@@ -371,7 +371,7 @@
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
n = 0;
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
while (width != 0 &&
(wi = __fgetwc_unlock(fp)) != WEOF) {
if (width >= MB_CUR_MAX &&
@@ -436,7 +436,7 @@
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
n = 0;
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
while ((wi = __fgetwc_unlock(fp)) != WEOF &&
width != 0 && INCCL(wi)) {
if (width >= MB_CUR_MAX &&
@@ -497,7 +497,7 @@
} else {
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
- bzero(&mbs, sizeof(mbs));
+ memset(&mbs, 0, sizeof(mbs));
while ((wi = __fgetwc_unlock(fp)) != WEOF &&
width != 0 &&
!iswspace(wi)) {
@@ -686,95 +686,23 @@
if (width == 0 || width > sizeof(buf) /
sizeof(*buf) - 1)
width = sizeof(buf) / sizeof(*buf) - 1;
- flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
- for (p = buf; width; width--) {
- c = __fgetwc_unlock(fp);
- /*
- * This code mimicks the integer conversion
- * code, but is much simpler.
- */
- switch (c) {
-
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- flags &= ~(SIGNOK | NDIGITS);
- goto fok;
-
- case '+': case '-':
- if (flags & SIGNOK) {
- flags &= ~SIGNOK;
- goto fok;
- }
- break;
- case 'e': case 'E':
- /* no exponent without some digits */
- if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
- flags =
- (flags & ~(EXPOK|DPTOK)) |
- SIGNOK | NDIGITS;
- goto fok;
- }
- break;
- default:
- if (decimal_point == 0) {
- bzero(&mbs, sizeof(mbs));
- nconv = mbrtowc(&decimal_point,
- localeconv()->decimal_point,
- MB_CUR_MAX, &mbs);
- if (nconv == 0 ||
- nconv == (size_t)-1 ||
- nconv == (size_t)-2)
- decimal_point = '.';
- }
- if (c == decimal_point &&
- (flags & DPTOK)) {
- flags &= ~(SIGNOK | DPTOK);
- goto fok;
- }
- break;
- }
- if (c != WEOF)
- __ungetwc(c, fp);
- break;
- fok:
- *p++ = c;
- }
- /*
- * If no digits, might be missing exponent digits
- * (just give back the exponent) or might be missing
- * regular digits, but had sign and/or decimal point.
- */
- if (flags & NDIGITS) {
- if (flags & EXPOK) {
- /* no digits at all */
- while (p > buf)
- __ungetwc(*--p, fp);
- goto match_failure;
- }
- /* just a bad exponent (e and maybe sign) */
- c = *--p;
- if (c != 'e' && c != 'E') {
- __ungetwc(c, fp);/* sign */
- c = *--p;
- }
- __ungetwc(c, fp);
- }
+ if ((width = wparsefloat(fp, buf, buf + width)) == 0)
+ goto match_failure;
if ((flags & SUPPRESS) == 0) {
- *p = 0;
if (flags & LONGDBL) {
- long double res = wcstold(buf, NULL);
+ long double res = wcstold(buf, &p);
*va_arg(ap, long double *) = res;
} else if (flags & LONG) {
- double res = wcstod(buf, NULL);
+ double res = wcstod(buf, &p);
*va_arg(ap, double *) = res;
} else {
- float res = wcstof(buf, NULL);
+ float res = wcstof(buf, &p);
*va_arg(ap, float *) = res;
}
+ if (p - buf != (ptrdiff_t)width) abort();
nassigned++;
}
- nread += p - buf;
+ nread += width;
nconversions++;
break;
#endif /* FLOATING_POINT */
@@ -785,6 +713,7 @@
match_failure:
return (nassigned);
}
+#pragma GCC diagnostic pop
int
vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap)
diff --git a/libc/upstream-openbsd/android/include/gd_qnan.h b/libc/upstream-openbsd/android/include/gd_qnan.h
index e8e907b..e5bf973 100644
--- a/libc/upstream-openbsd/android/include/gd_qnan.h
+++ b/libc/upstream-openbsd/android/include/gd_qnan.h
@@ -14,35 +14,20 @@
* limitations under the License.
*/
-#if __arm__
+//
+// The values in this file came from reading the bits of <math.h>'s NAN back from a union.
+//
-#define f_QNAN 0xffffffff
-
-#define d_QNAN0 0xffffffff
-#define d_QNAN1 0xffffffff
-
-#elif __mips__
-
-#define f_QNAN 0x7fbfffff
-
-#define d_QNAN0 0x7ff7ffff
-#define d_QNAN1 0xffffffff
-
-#else
-
-#define f_QNAN 0xffc00000
+#define f_QNAN 0x7fc00000
#define d_QNAN0 0x00000000
-#define d_QNAN1 0xfff80000
+#define d_QNAN1 0x7ff80000
-#endif
-
-/* long double. */
#if __LP64__
-#define ld_QNAN0 0x7fff8000
+#define ld_QNAN0 0x00000000
#define ld_QNAN1 0x00000000
#define ld_QNAN2 0x00000000
-#define ld_QNAN3 0x00000000
+#define ld_QNAN3 0x7fff8000
#else
-/* sizeof(long double) == sizeof(double), so we shouldn't be trying to use these constants. */
+// LP32 sizeof(long double) == sizeof(double), so LP32 shouldn't try to use these constants.
#endif
diff --git a/libc/upstream-openbsd/lib/libc/locale/_wcstod.h b/libc/upstream-openbsd/lib/libc/locale/_wcstod.h
deleted file mode 100644
index ae993ad..0000000
--- a/libc/upstream-openbsd/lib/libc/locale/_wcstod.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* $OpenBSD: _wcstod.h,v 1.2 2013/06/02 15:22:20 matthew Exp $ */
-/* $NetBSD: wcstod.c,v 1.4 2001/10/28 12:08:43 yamt Exp $ */
-
-/*-
- * Copyright (c)1999, 2000, 2001 Citrus 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:
- * 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.
- *
- * $Citrus: xpg4dl/FreeBSD/lib/libc/locale/wcstod.c,v 1.2 2001/09/27 16:23:57 yamt Exp $
- */
-
-/*
- * function template for wcstof, wcstod and wcstold.
- *
- * parameters:
- * FUNCNAME : function name
- * float_type : return type
- * STRTOD_FUNC : conversion function
- */
-
-float_type
-FUNCNAME(const wchar_t *nptr, wchar_t **endptr)
-{
- const wchar_t *src;
- size_t size;
- const wchar_t *start;
- const wchar_t *aftersign;
-
- /*
- * check length of string and call strtod
- */
- src = nptr;
-
- /* skip space first */
- while (iswspace(*src)) {
- src++;
- }
-
- /* get length of string */
- start = src;
- if (*src && wcschr(L"+-", *src))
- src++;
- aftersign = src;
- if (wcsncasecmp(src, L"inf", 3) == 0) {
- src += 3;
- if (wcsncasecmp(src, L"inity", 5) == 0)
- src += 5;
- goto match;
- }
- if (wcsncasecmp(src, L"nan", 3) == 0) {
- src += 3;
- if (*src == L'(') {
- size = 1;
- while (src[size] != L'\0' && src[size] != L')')
- size++;
- if (src[size] == L')')
- src += size + 1;
- }
- goto match;
- }
- size = wcsspn(src, L"0123456789");
- src += size;
- if (*src == L'.') {/* XXX use localeconv */
- src++;
- size = wcsspn(src, L"0123456789");
- src += size;
- }
- if (*src && wcschr(L"Ee", *src)) {
- src++;
- if (*src && wcschr(L"+-", *src))
- src++;
- size = wcsspn(src, L"0123456789");
- src += size;
- }
-match:
- size = src - start;
-
- /*
- * convert to a char-string and pass it to strtod.
- */
- if (src > aftersign) {
- mbstate_t st;
- char *buf;
- char *end;
- const wchar_t *s;
- size_t size_converted;
- float_type result;
- size_t bufsize;
-
- s = start;
- memset(&st, 0, sizeof(st));
- bufsize = wcsnrtombs(NULL, &s, size, 0, &st);
-
- buf = malloc(bufsize + 1);
- if (!buf) {
- errno = ENOMEM; /* XXX */
- goto fail;
- }
-
- s = start;
- memset(&st, 0, sizeof(st));
- size_converted = wcsnrtombs(buf, &s, size, bufsize, &st);
- if (size_converted != bufsize) {
- /* XXX should not happen */
- free(buf);
- errno = EILSEQ;
- goto fail;
- }
-
- buf[bufsize] = 0;
- result = STRTOD_FUNC(buf, &end);
-
- if (endptr) {
- const char *s = buf;
- memset(&st, 0, sizeof(st));
- size = mbsnrtowcs(NULL, &s, end - buf, 0, &st);
-
- /* LINTED bad interface */
- *endptr = (wchar_t*)start + size;
- }
-
- free(buf);
-
- return result;
- }
-
-fail:
- if (endptr)
- /* LINTED bad interface */
- *endptr = (wchar_t*)nptr;
-
- return 0;
-}
diff --git a/libc/upstream-openbsd/lib/libc/locale/wcstod.c b/libc/upstream-openbsd/lib/libc/locale/wcstod.c
deleted file mode 100644
index 957d0a1..0000000
--- a/libc/upstream-openbsd/lib/libc/locale/wcstod.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* $OpenBSD: wcstod.c,v 1.3 2009/01/13 18:18:31 kettenis Exp $ */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#define FUNCNAME wcstod
-typedef double float_type;
-#define STRTOD_FUNC strtod
-
-#include "_wcstod.h"
diff --git a/libc/upstream-openbsd/lib/libc/locale/wcstof.c b/libc/upstream-openbsd/lib/libc/locale/wcstof.c
deleted file mode 100644
index 40d76c7..0000000
--- a/libc/upstream-openbsd/lib/libc/locale/wcstof.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* $OpenBSD: wcstof.c,v 1.1 2009/01/13 18:18:31 kettenis Exp $ */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#define FUNCNAME wcstof
-typedef float float_type;
-#define STRTOD_FUNC strtof
-
-#include "_wcstod.h"
diff --git a/libc/upstream-openbsd/lib/libc/locale/wcstold.c b/libc/upstream-openbsd/lib/libc/locale/wcstold.c
deleted file mode 100644
index a642542..0000000
--- a/libc/upstream-openbsd/lib/libc/locale/wcstold.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* $OpenBSD: wcstold.c,v 1.1 2009/01/13 18:18:31 kettenis Exp $ */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#define FUNCNAME wcstold
-typedef long double float_type;
-#define STRTOD_FUNC strtold
-
-#include "_wcstod.h"
diff --git a/libm/Android.bp b/libm/Android.bp
index 23b9d5e..64d281f 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -531,3 +531,9 @@
},
stl: "none",
}
+
+ndk_library {
+ name: "libm.ndk",
+ symbol_file: "libm.map.txt",
+ first_version: "9",
+}
diff --git a/libm/libm.arm.map b/libm/libm.arm.map
index a61dc2e..3052f03 100644
--- a/libm/libm.arm.map
+++ b/libm/libm.arm.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.arm64.map b/libm/libm.arm64.map
index 11032ca..3e259dd 100644
--- a/libm/libm.arm64.map
+++ b/libm/libm.arm64.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.map.txt b/libm/libm.map.txt
index 66dfd19..c77e1d1 100644
--- a/libm/libm.map.txt
+++ b/libm/libm.map.txt
@@ -1,6 +1,6 @@
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -8,59 +8,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -68,62 +68,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -131,7 +131,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -140,17 +140,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -166,77 +166,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -244,20 +244,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.mips.map b/libm/libm.mips.map
index 8353627..2f01cfa 100644
--- a/libm/libm.mips.map
+++ b/libm/libm.mips.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.mips64.map b/libm/libm.mips64.map
index 11032ca..3e259dd 100644
--- a/libm/libm.mips64.map
+++ b/libm/libm.mips64.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.x86.map b/libm/libm.x86.map
index 11032ca..3e259dd 100644
--- a/libm/libm.x86.map
+++ b/libm/libm.x86.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/libm/libm.x86_64.map b/libm/libm.x86_64.map
index 11032ca..3e259dd 100644
--- a/libm/libm.x86_64.map
+++ b/libm/libm.x86_64.map
@@ -1,7 +1,7 @@
# Generated by genversion-scripts.py. Do not edit.
LIBC {
global:
- __fe_dfl_env;
+ __fe_dfl_env; # var
__signbit;
__signbitf;
__signbitl;
@@ -9,59 +9,59 @@
acosf;
acosh;
acoshf;
- acoshl;
- acosl;
+ acoshl; # introduced=21
+ acosl; # introduced=21
asin;
asinf;
asinh;
asinhf;
- asinhl;
- asinl;
+ asinhl; # introduced=21
+ asinl; # introduced=21
atan;
atan2;
atan2f;
- atan2l;
+ atan2l; # introduced=21
atanf;
atanh;
atanhf;
- atanhl;
- atanl;
- cabs;
- cabsf;
- cabsl;
- cacos;
- cacosf;
- cacosh;
- cacoshf;
- carg;
- cargf;
- cargl;
- casin;
- casinf;
- casinh;
- casinhf;
- catan;
- catanf;
- catanh;
- catanhf;
+ atanhl; # introduced=21
+ atanl; # introduced=21
+ cabs; # introduced=23
+ cabsf; # introduced=23
+ cabsl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ cacos; # introduced=23
+ cacosf; # introduced=23
+ cacosh; # introduced=23
+ cacoshf; # introduced=23
+ carg; # introduced=23
+ cargf; # introduced=23
+ cargl; # introduced=23
+ casin; # introduced=23
+ casinf; # introduced=23
+ casinh; # introduced=23
+ casinhf; # introduced=23
+ catan; # introduced=23
+ catanf; # introduced=23
+ catanh; # introduced=23
+ catanhf; # introduced=23
cbrt;
cbrtf;
- cbrtl;
- ccos;
- ccosf;
- ccosh;
- ccoshf;
+ cbrtl; # introduced=21
+ ccos; # introduced=23
+ ccosf; # introduced=23
+ ccosh; # introduced=23
+ ccoshf; # introduced=23
ceil;
ceilf;
ceill;
- cexp;
- cexpf;
- cimag;
- cimagf;
- cimagl;
- conj;
- conjf;
- conjl;
+ cexp; # introduced=23
+ cexpf; # introduced=23
+ cimag; # introduced=23
+ cimagf; # introduced=23
+ cimagl; # introduced=23
+ conj; # introduced=23
+ conjf; # introduced=23
+ conjl; # introduced=23
copysign;
copysignf;
copysignl;
@@ -69,62 +69,62 @@
cosf;
cosh;
coshf;
- coshl;
- cosl;
- cproj;
- cprojf;
- cprojl;
- creal;
- crealf;
- creall;
- csin;
- csinf;
- csinh;
- csinhf;
- csqrt;
- csqrtf;
- csqrtl;
- ctan;
- ctanf;
- ctanh;
- ctanhf;
+ coshl; # introduced=21
+ cosl; # introduced=21
+ cproj; # introduced=23
+ cprojf; # introduced=23
+ cprojl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ creal; # introduced=23
+ crealf; # introduced=23
+ creall; # introduced=23
+ csin; # introduced=23
+ csinf; # introduced=23
+ csinh; # introduced=23
+ csinhf; # introduced=23
+ csqrt; # introduced=23
+ csqrtf; # introduced=23
+ csqrtl; # introduced-arm=21 introduced-arm64=23 introduced-mips=21 introduced-mips64=23 introduced-x86=21 introduced-x86_64=23
+ ctan; # introduced=23
+ ctanf; # introduced=23
+ ctanh; # introduced=23
+ ctanhf; # introduced=23
drem;
dremf;
erf;
erfc;
erfcf;
- erfcl;
+ erfcl; # introduced=21
erff;
- erfl;
+ erfl; # introduced=21
exp;
exp2;
exp2f;
- exp2l;
+ exp2l; # introduced=21
expf;
- expl;
+ expl; # introduced=21
expm1;
expm1f;
- expm1l;
+ expm1l; # introduced=21
fabs;
fabsf;
fabsl;
fdim;
fdimf;
fdiml;
- feclearexcept;
- fedisableexcept;
- feenableexcept;
- fegetenv;
- fegetexcept;
- fegetexceptflag;
- fegetround;
- feholdexcept;
- feraiseexcept;
- fesetenv;
- fesetexceptflag;
- fesetround;
- fetestexcept;
- feupdateenv;
+ feclearexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fedisableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feenableexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fegetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feholdexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feraiseexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetexceptflag; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fesetround; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ fetestexcept; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ feupdateenv; # introduced-arm=21 introduced-arm64=21 introduced-mips=21 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
finite;
finitef;
floor;
@@ -132,7 +132,7 @@
floorl;
fma;
fmaf;
- fmal;
+ fmal; # introduced=21
fmax;
fmaxf;
fmaxl;
@@ -141,17 +141,17 @@
fminl;
fmod;
fmodf;
- fmodl;
+ fmodl; # introduced=21
frexp;
frexpf;
- frexpl;
+ frexpl; # introduced=21
gamma;
gamma_r;
gammaf;
gammaf_r;
hypot;
hypotf;
- hypotl;
+ hypotl; # introduced=21
ilogb;
ilogbf;
ilogbl;
@@ -167,77 +167,77 @@
lgamma_r;
lgammaf;
lgammaf_r;
- lgammal;
- lgammal_r;
+ lgammal; # introduced=21
+ lgammal_r; # introduced=23
llrint;
llrintf;
- llrintl;
+ llrintl; # introduced=21
llround;
llroundf;
llroundl;
log;
log10;
log10f;
- log10l;
+ log10l; # introduced=21
log1p;
log1pf;
- log1pl;
- log2;
- log2f;
- log2l;
+ log1pl; # introduced=21
+ log2; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2f; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ log2l; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logb;
logbf;
- logbl;
+ logbl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
logf;
- logl;
+ logl; # introduced=21
lrint;
lrintf;
- lrintl;
+ lrintl; # introduced=21
lround;
lroundf;
lroundl;
modf;
modff;
- modfl;
- nan;
- nanf;
- nanl;
+ modfl; # introduced=21
+ nan; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ nanl; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
nearbyint;
nearbyintf;
- nearbyintl;
+ nearbyintl; # introduced=21
nextafter;
nextafterf;
- nextafterl;
- nexttoward;
+ nextafterl; # introduced=21
+ nexttoward; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
nexttowardf;
- nexttowardl;
+ nexttowardl; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
pow;
powf;
- powl;
+ powl; # introduced=21
remainder;
remainderf;
- remainderl;
+ remainderl; # introduced=21
remquo;
remquof;
- remquol;
+ remquol; # introduced=21
rint;
rintf;
- rintl;
+ rintl; # introduced=21
round;
roundf;
roundl;
scalb;
scalbf;
- scalbln;
- scalblnf;
- scalblnl;
+ scalbln; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnf; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ scalblnl; # introduced-arm=9 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
scalbn;
scalbnf;
scalbnl;
- signgam;
+ signgam; # var
significand;
significandf;
- significandl;
+ significandl; # introduced=21
sin;
sincos;
sincosf;
@@ -245,20 +245,20 @@
sinf;
sinh;
sinhf;
- sinhl;
- sinl;
+ sinhl; # introduced=21
+ sinl; # introduced=21
sqrt;
sqrtf;
- sqrtl;
+ sqrtl; # introduced=21
tan;
tanf;
tanh;
tanhf;
- tanhl;
- tanl;
+ tanhl; # introduced=21
+ tanl; # introduced=21
tgamma;
- tgammaf;
- tgammal;
+ tgammaf; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
+ tgammal; # introduced=21
trunc;
truncf;
truncl;
diff --git a/linker/Android.bp b/linker/Android.bp
index 39f1da9..4d770ac 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -22,6 +22,7 @@
"linker_gdb_support.cpp",
"linker_globals.cpp",
"linker_libc_support.c",
+ "linker_main.cpp",
"linker_namespaces.cpp",
"linker_logger.cpp",
"linker_mapped_file_fragment.cpp",
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 033aa8f..fab64bc 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -44,8 +44,6 @@
#include <vector>
// Private C library headers.
-#include "private/bionic_globals.h"
-#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
#include "private/ScopedPthreadMutexLocker.h"
#include "private/ScopeGuard.h"
@@ -56,6 +54,7 @@
#include "linker_globals.h"
#include "linker_debug.h"
#include "linker_dlwarning.h"
+#include "linker_main.h"
#include "linker_namespaces.h"
#include "linker_sleb128.h"
#include "linker_phdr.h"
@@ -65,7 +64,6 @@
#include "android-base/strings.h"
#include "android-base/stringprintf.h"
-#include "debuggerd/client.h"
#include "ziparchive/zip_archive.h"
extern void __libc_init_globals(KernelArgumentBlock&);
@@ -79,18 +77,12 @@
static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
-static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
-
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
-static soinfo* solist;
-static soinfo* sonext;
-static soinfo* somain; // main process, always the one after libdl_info
-
#if defined(__LP64__)
static const char* const kSystemLibDir = "/system/lib64";
static const char* const kVendorLibDir = "/vendor/lib64";
@@ -193,14 +185,9 @@
static const char* const* g_default_ld_paths;
static std::vector<std::string> g_ld_preload_names;
-static std::vector<soinfo*> g_ld_preloads;
-
static bool g_public_namespace_initialized;
static soinfo_list_t g_public_namespace;
-int g_ld_debug_verbosity;
-abort_msg_t* g_abort_message = nullptr; // For debuggerd.
-
#if STATS
struct linker_stats_t {
int count[kRelocMax];
@@ -259,19 +246,20 @@
g_namespace_list_allocator.free(entry);
}
-static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
- struct stat* file_stat, off64_t file_offset,
- uint32_t rtld_flags) {
+soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
+ struct stat* file_stat, off64_t file_offset,
+ uint32_t rtld_flags) {
if (strlen(name) >= PATH_MAX) {
DL_ERR("library name \"%s\" too long", name);
return nullptr;
}
+ TRACE("name %s: allocating soinfo for ns=%p", name, ns);
+
soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
file_offset, rtld_flags);
- sonext->next = si;
- sonext = si;
+ solist_add_soinfo(si);
si->generate_handle();
ns->add_soinfo(si);
@@ -295,33 +283,17 @@
}
}
- soinfo *prev = nullptr, *trav;
-
TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
- for (trav = solist; trav != nullptr; trav = trav->next) {
- if (trav == si) {
- break;
- }
- prev = trav;
- }
-
- if (trav == nullptr) {
- // si was not in solist
- DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
+ if (!solist_remove_soinfo(si)) {
+ // TODO (dimitry): revisit this - for now preserving the logic
+ // but it does not look right, abort if soinfo is not in the list instead?
return;
}
// clear links to/from si
si->remove_all_links();
- // prev will never be null, because the first entry in solist is
- // always the static libdl_info.
- prev->next = si->next;
- if (si == sonext) {
- sonext = prev;
- }
-
si->~soinfo();
g_soinfo_allocator.free(si);
}
@@ -339,17 +311,6 @@
g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
}
-static void parse_LD_PRELOAD(const char* path) {
- g_ld_preload_names.clear();
- if (path != nullptr) {
- // We have historically supported ':' as well as ' ' in LD_PRELOAD.
- g_ld_preload_names = android::base::Split(path, " :");
- std::remove_if(g_ld_preload_names.begin(),
- g_ld_preload_names.end(),
- [] (const std::string& s) { return s.empty(); });
- }
-}
-
static bool realpath_fd(int fd, std::string* realpath) {
std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
__libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
@@ -375,7 +336,7 @@
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
- for (soinfo* si = solist; si != 0; si = si->next) {
+ for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
if ((addr >= si->base) && (addr < (si->base + si->size))) {
*pcount = si->ARM_exidx_count;
return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
@@ -391,7 +352,7 @@
// loaded libraries. gcc_eh does the rest.
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
int rv = 0;
- for (soinfo* si = solist; si != nullptr; si = si->next) {
+ for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
dl_phdr_info dl_info;
dl_info.dlpi_addr = si->link_map_head.l_addr;
dl_info.dlpi_name = si->link_map_head.l_name;
@@ -499,33 +460,28 @@
return true;
}
-class ProtectedDataGuard {
- public:
- ProtectedDataGuard() {
- if (ref_count_++ == 0) {
- protect_data(PROT_READ | PROT_WRITE);
- }
+ProtectedDataGuard::ProtectedDataGuard() {
+ if (ref_count_++ == 0) {
+ protect_data(PROT_READ | PROT_WRITE);
+ }
+}
+
+ProtectedDataGuard::~ProtectedDataGuard() {
+ if (ref_count_ == 0) { // overflow
+ __libc_fatal("Too many nested calls to dlopen()");
}
- ~ProtectedDataGuard() {
- if (ref_count_ == 0) { // overflow
- __libc_fatal("Too many nested calls to dlopen()");
- }
-
- if (--ref_count_ == 0) {
- protect_data(PROT_READ);
- }
+ if (--ref_count_ == 0) {
+ protect_data(PROT_READ);
}
- private:
- void protect_data(int protection) {
- g_soinfo_allocator.protect_all(protection);
- g_soinfo_links_allocator.protect_all(protection);
- g_namespace_allocator.protect_all(protection);
- g_namespace_list_allocator.protect_all(protection);
- }
+}
- static size_t ref_count_;
-};
+void ProtectedDataGuard::protect_data(int protection) {
+ g_soinfo_allocator.protect_all(protection);
+ g_soinfo_links_allocator.protect_all(protection);
+ g_namespace_allocator.protect_all(protection);
+ g_namespace_list_allocator.protect_all(protection);
+}
size_t ProtectedDataGuard::ref_count_ = 0;
@@ -782,7 +738,7 @@
// Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
// libraries and they are loaded in breath-first (correct) order we can just execute
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
- if (si == somain) {
+ if (si == solist_get_somain()) {
return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
}
@@ -855,7 +811,7 @@
soinfo* find_containing_library(const void* p) {
ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
- for (soinfo* si = solist; si != nullptr; si = si->next) {
+ for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
if (address >= si->base && address - si->base < si->size) {
return si;
}
@@ -1072,7 +1028,7 @@
return fd;
}
-static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
+const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
#if !defined(__LP64__)
// Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
if (get_application_target_sdk_version() <= 22) {
@@ -1089,15 +1045,6 @@
}
template<typename F>
-static void for_each_dt_needed(const soinfo* si, F action) {
- for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
- if (d->d_tag == DT_NEEDED) {
- action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
- }
- }
-}
-
-template<typename F>
static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
@@ -1305,7 +1252,10 @@
// "libdl.so" and global group. There is no point in skipping
// them because relocation process is going to use them
// in any case.
- bool is_libdl = si == solist;
+
+ // TODO (dimitry): remove this once linker stops imposing as libdl.so
+ bool is_libdl = (si == solist_get_head());
+
if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
!si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
ns != &g_default_namespace) {
@@ -1420,14 +1370,16 @@
// not their transitive dependencies) as children of the start_with library.
// This is false when find_libraries is called for dlopen(), when newly loaded
// libraries must form a disjoint tree.
-static bool find_libraries(android_namespace_t* ns,
- soinfo* start_with,
- const char* const library_names[],
- size_t library_names_count, soinfo* soinfos[],
- std::vector<soinfo*>* ld_preloads,
- size_t ld_preloads_count, int rtld_flags,
- const android_dlextinfo* extinfo,
- bool add_as_children) {
+bool find_libraries(android_namespace_t* ns,
+ soinfo* start_with,
+ const char* const library_names[],
+ size_t library_names_count,
+ soinfo* soinfos[],
+ std::vector<soinfo*>* ld_preloads,
+ size_t ld_preloads_count,
+ int rtld_flags,
+ const android_dlextinfo* extinfo,
+ bool add_as_children) {
// Step 0: prepare.
LoadTaskList load_tasks;
std::unordered_map<const soinfo*, ElfReader> readers_map;
@@ -1592,7 +1544,7 @@
soinfo* si;
if (name == nullptr) {
- si = somain;
+ si = solist_get_somain();
} else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
extinfo, /* add_as_children */ false)) {
return nullptr;
@@ -3081,7 +3033,9 @@
// This workaround should keep them working. (applies only
// for apps targeting sdk version <=22). Make an exception for
// the main executable and linker; they do not need to have dt_soname
- if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
+ if (soname_ == nullptr &&
+ this != solist_get_somain() &&
+ (flags_ & FLAG_LINKER) == 0 &&
get_application_target_sdk_version() <= 22) {
soname_ = basename(realpath_.c_str());
DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
@@ -3245,66 +3199,12 @@
return true;
}
-/*
- * This function add vdso to internal dso list.
- * It helps to stack unwinding through signal handlers.
- * Also, it makes bionic more like glibc.
- */
-static void add_vdso(KernelArgumentBlock& args __unused) {
-#if defined(AT_SYSINFO_EHDR)
- ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
- if (ehdr_vdso == nullptr) {
- return;
- }
-
- soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
-
- si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
- si->phnum = ehdr_vdso->e_phnum;
- si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
- si->size = phdr_table_get_load_size(si->phdr, si->phnum);
- si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
-
- si->prelink_image();
- si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr);
-#endif
-}
-
-/* gdb expects the linker to be in the debug shared object list.
- * Without this, gdb has trouble locating the linker's ".text"
- * and ".plt" sections. Gdb could also potentially use this to
- * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
- * Note that the linker shouldn't be on the soinfo list.
- */
-static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
- static link_map linker_link_map_for_gdb;
-#if defined(__LP64__)
- static char kLinkerPath[] = "/system/bin/linker64";
-#else
- static char kLinkerPath[] = "/system/bin/linker";
-#endif
-
- linker_link_map_for_gdb.l_addr = linker_base;
- linker_link_map_for_gdb.l_name = kLinkerPath;
-
- /*
- * Set the dynamic field in the link map otherwise gdb will complain with
- * the following:
- * warning: .dynamic section for "/system/bin/linker" is not at the
- * expected address (wrong library or version mismatch?)
- */
- ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
- ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
- phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
- &linker_link_map_for_gdb.l_ld, nullptr);
-
- insert_link_map_into_debug_map(&linker_link_map_for_gdb);
-}
-
-static void init_default_namespace() {
+void init_default_namespace() {
g_default_namespace.set_name("(default)");
g_default_namespace.set_isolated(false);
+ soinfo* somain = solist_get_somain();
+
const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
somain->load_bias);
const char* bname = basename(interp);
@@ -3323,359 +3223,3 @@
g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
};
-extern "C" int __system_properties_init(void);
-
-static const char* get_executable_path() {
- static std::string executable_path;
- if (executable_path.empty()) {
- char path[PATH_MAX];
- ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
- if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
- __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
- }
- executable_path = std::string(path, path_len);
- }
-
- return executable_path.c_str();
-}
-
-/*
- * This code is called after the linker has linked itself and
- * fixed it's own GOT. It is safe to make references to externs
- * and other non-local data at this point.
- */
-static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
-#if TIMING
- struct timeval t0, t1;
- gettimeofday(&t0, 0);
-#endif
-
- // Sanitize the environment.
- __libc_init_AT_SECURE(args);
-
- // Initialize system properties
- __system_properties_init(); // may use 'environ'
-
- // Register the debuggerd signal handler.
- debuggerd_callbacks_t callbacks = {
- .get_abort_message = []() {
- return g_abort_message;
- },
- .post_dump = ¬ify_gdb_of_libraries,
- };
- debuggerd_init(&callbacks);
-
- g_linker_logger.ResetState();
-
- // Get a few environment variables.
- const char* LD_DEBUG = getenv("LD_DEBUG");
- if (LD_DEBUG != nullptr) {
- g_ld_debug_verbosity = atoi(LD_DEBUG);
- }
-
-#if defined(__LP64__)
- INFO("[ Android dynamic linker (64-bit) ]");
-#else
- INFO("[ Android dynamic linker (32-bit) ]");
-#endif
-
- // These should have been sanitized by __libc_init_AT_SECURE, but the test
- // doesn't cost us anything.
- const char* ldpath_env = nullptr;
- const char* ldpreload_env = nullptr;
- if (!getauxval(AT_SECURE)) {
- ldpath_env = getenv("LD_LIBRARY_PATH");
- if (ldpath_env != nullptr) {
- INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);
- }
- ldpreload_env = getenv("LD_PRELOAD");
- if (ldpreload_env != nullptr) {
- INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
- }
- }
-
- struct stat file_stat;
- // Stat "/proc/self/exe" instead of executable_path because
- // the executable could be unlinked by this point and it should
- // not cause a crash (see http://b/31084669)
- if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
- __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
- }
-
- const char* executable_path = get_executable_path();
- soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
- if (si == nullptr) {
- __libc_fatal("Couldn't allocate soinfo: out of memory?");
- }
-
- /* bootstrap the link map, the main exe always needs to be first */
- si->set_main_executable();
- link_map* map = &(si->link_map_head);
-
- // Register the main executable and the linker upfront to have
- // gdb aware of them before loading the rest of the dependency
- // tree.
- map->l_addr = 0;
- map->l_name = const_cast<char*>(executable_path);
- insert_link_map_into_debug_map(map);
- init_linker_info_for_gdb(linker_base);
-
- // Extract information passed from the kernel.
- si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
- si->phnum = args.getauxval(AT_PHNUM);
-
- /* Compute the value of si->base. We can't rely on the fact that
- * the first entry is the PHDR because this will not be true
- * for certain executables (e.g. some in the NDK unit test suite)
- */
- si->base = 0;
- si->size = phdr_table_get_load_size(si->phdr, si->phnum);
- si->load_bias = 0;
- for (size_t i = 0; i < si->phnum; ++i) {
- if (si->phdr[i].p_type == PT_PHDR) {
- si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
- si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
- break;
- }
- }
- si->dynamic = nullptr;
-
- ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
- if (elf_hdr->e_type != ET_DYN) {
- __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.",
- g_argv[0]);
- }
-
- // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
- parse_LD_LIBRARY_PATH(ldpath_env);
- parse_LD_PRELOAD(ldpreload_env);
-
- somain = si;
-
- init_default_namespace();
-
- if (!si->prelink_image()) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
- }
-
- // add somain to global group
- si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
-
- // Load ld_preloads and dependencies.
- StringLinkedList needed_library_name_list;
- size_t needed_libraries_count = 0;
- size_t ld_preloads_count = 0;
-
- for (const auto& ld_preload_name : g_ld_preload_names) {
- needed_library_name_list.push_back(ld_preload_name.c_str());
- ++needed_libraries_count;
- ++ld_preloads_count;
- }
-
- for_each_dt_needed(si, [&](const char* name) {
- needed_library_name_list.push_back(name);
- ++needed_libraries_count;
- });
-
- const char* needed_library_names[needed_libraries_count];
-
- memset(needed_library_names, 0, sizeof(needed_library_names));
- needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
-
- if (needed_libraries_count > 0 &&
- !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
- nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
- /* add_as_children */ true)) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
- } else if (needed_libraries_count == 0) {
- if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
- }
- si->increment_ref_count();
- }
-
- add_vdso(args);
-
- {
- ProtectedDataGuard guard;
-
- si->call_pre_init_constructors();
-
- /* After the prelink_image, the si->load_bias is initialized.
- * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
- * We need to update this value for so exe here. So Unwind_Backtrace
- * for some arch like x86 could work correctly within so exe.
- */
- map->l_addr = si->load_bias;
- si->call_constructors();
- }
-
-#if TIMING
- gettimeofday(&t1, nullptr);
- PRINT("LINKER TIME: %s: %d microseconds", g_argv[0], (int) (
- (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
- (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
-#endif
-#if STATS
- PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", g_argv[0],
- linker_stats.count[kRelocAbsolute],
- linker_stats.count[kRelocRelative],
- linker_stats.count[kRelocCopy],
- linker_stats.count[kRelocSymbol]);
-#endif
-#if COUNT_PAGES
- {
- unsigned n;
- unsigned i;
- unsigned count = 0;
- for (n = 0; n < 4096; n++) {
- if (bitmask[n]) {
- unsigned x = bitmask[n];
-#if defined(__LP64__)
- for (i = 0; i < 32; i++) {
-#else
- for (i = 0; i < 8; i++) {
-#endif
- if (x & 1) {
- count++;
- }
- x >>= 1;
- }
- }
- }
- PRINT("PAGES MODIFIED: %s: %d (%dKB)", g_argv[0], count, count * 4);
- }
-#endif
-
-#if TIMING || STATS || COUNT_PAGES
- fflush(stdout);
-#endif
-
- ElfW(Addr) entry = args.getauxval(AT_ENTRY);
- TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
- return entry;
-}
-
-/* Compute the load-bias of an existing executable. This shall only
- * be used to compute the load bias of an executable or shared library
- * that was loaded by the kernel itself.
- *
- * Input:
- * elf -> address of ELF header, assumed to be at the start of the file.
- * Return:
- * load bias, i.e. add the value of any p_vaddr in the file to get
- * the corresponding address in memory.
- */
-static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
- ElfW(Addr) offset = elf->e_phoff;
- const ElfW(Phdr)* phdr_table =
- reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
- const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
-
- for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
- if (phdr->p_type == PT_LOAD) {
- return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
- }
- }
- return 0;
-}
-
-static void __linker_cannot_link(const char* argv0) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
-}
-
-/*
- * This is the entry point for the linker, called from begin.S. This
- * method is responsible for fixing the linker's own relocations, and
- * then calling __linker_init_post_relocation().
- *
- * Because this method is called before the linker has fixed it's own
- * relocations, any attempt to reference an extern variable, extern
- * function, or other GOT reference will generate a segfault.
- */
-extern "C" ElfW(Addr) __linker_init(void* raw_args) {
- KernelArgumentBlock args(raw_args);
-
- ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
- ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
- ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
- ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
-
- soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
-
- // If the linker is not acting as PT_INTERP entry_point is equal to
- // _start. Which means that the linker is running as an executable and
- // already linked by PT_INTERP.
- //
- // This happens when user tries to run 'adb shell /system/bin/linker'
- // see also https://code.google.com/p/android/issues/detail?id=63174
- if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
- __libc_format_fd(STDOUT_FILENO,
- "This is %s, the helper program for shared library executables.\n",
- args.argv[0]);
- exit(0);
- }
-
- linker_so.base = linker_addr;
- linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
- linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
- linker_so.dynamic = nullptr;
- linker_so.phdr = phdr;
- linker_so.phnum = elf_hdr->e_phnum;
- linker_so.set_linker_flag();
-
- // Prelink the linker so we can access linker globals.
- if (!linker_so.prelink_image()) __linker_cannot_link(args.argv[0]);
-
- // This might not be obvious... The reasons why we pass g_empty_list
- // in place of local_group here are (1) we do not really need it, because
- // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
- // itself without having to look into local_group and (2) allocators
- // are not yet initialized, and therefore we cannot use linked_list.push_*
- // functions at this point.
- if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);
-
-#if defined(__i386__)
- // On x86, we can't make system calls before this point.
- // We can't move this up because this needs to assign to a global.
- // Note that until we call __libc_init_main_thread below we have
- // no TLS, so you shouldn't make a system call that can fail, because
- // it will SEGV when it tries to set errno.
- __libc_init_sysinfo(args);
-#endif
-
- // Initialize the main thread (including TLS, so system calls really work).
- __libc_init_main_thread(args);
-
- // We didn't protect the linker's RELRO pages in link_image because we
- // couldn't make system calls on x86 at that point, but we can now...
- if (!linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);
-
- // Initialize the linker's static libc's globals
- __libc_init_globals(args);
-
- // store argc/argv/envp to use them for calling constructors
- g_argc = args.argc;
- g_argv = args.argv;
- g_envp = args.envp;
-
- // Initialize the linker's own global variables
- linker_so.call_constructors();
-
- // Initialize static variables. Note that in order to
- // get correct libdl_info we need to call constructors
- // before get_libdl_info().
- solist = get_libdl_info();
- sonext = get_libdl_info();
- g_default_namespace.add_soinfo(get_libdl_info());
-
- // We have successfully fixed our own relocations. It's safe to run
- // the main part of the linker now.
- args.abort_message_ptr = &g_abort_message;
- ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
-
- INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
-
- // Return the address that the calling assembly stub should jump to.
- return start_address;
-}
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
new file mode 100644
index 0000000..2e98bf0
--- /dev/null
+++ b/linker/linker_main.cpp
@@ -0,0 +1,536 @@
+/*
+ * 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 "linker_main.h"
+
+#include "linker_debug.h"
+#include "linker_gdb_support.h"
+#include "linker_globals.h"
+#include "linker_phdr.h"
+#include "linker_utils.h"
+
+#include "private/bionic_globals.h"
+#include "private/bionic_tls.h"
+#include "private/KernelArgumentBlock.h"
+
+#include "android-base/strings.h"
+#include "android-base/stringprintf.h"
+#include "debuggerd/client.h"
+
+#include <vector>
+
+extern void __libc_init_globals(KernelArgumentBlock&);
+extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
+
+extern "C" void _start();
+
+static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
+
+// These should be preserved static to avoid emitting
+// RELATIVE relocations for the part of the code running
+// before linker links itself.
+
+// TODO (dimtiry): remove somain, rename solist to solist_head
+static soinfo* solist;
+static soinfo* sonext;
+static soinfo* somain; // main process, always the one after libdl_info
+
+void solist_add_soinfo(soinfo* si) {
+ sonext->next = si;
+ sonext = si;
+}
+
+bool solist_remove_soinfo(soinfo* si) {
+ soinfo *prev = nullptr, *trav;
+ for (trav = solist; trav != nullptr; trav = trav->next) {
+ if (trav == si) {
+ break;
+ }
+ prev = trav;
+ }
+
+ if (trav == nullptr) {
+ // si was not in solist
+ PRINT("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
+ return false;
+ }
+
+ // prev will never be null, because the first entry in solist is
+ // always the static libdl_info.
+ prev->next = si->next;
+ if (si == sonext) {
+ sonext = prev;
+ }
+
+ return true;
+}
+
+soinfo* solist_get_head() {
+ return solist;
+}
+
+soinfo* solist_get_somain() {
+ return somain;
+}
+
+int g_ld_debug_verbosity;
+abort_msg_t* g_abort_message = nullptr; // For debuggerd.
+
+static std::vector<std::string> g_ld_preload_names;
+
+static std::vector<soinfo*> g_ld_preloads;
+
+static void parse_path(const char* path, const char* delimiters,
+ std::vector<std::string>* resolved_paths) {
+ std::vector<std::string> paths;
+ split_path(path, delimiters, &paths);
+ resolve_paths(paths, resolved_paths);
+}
+
+static void parse_LD_LIBRARY_PATH(const char* path) {
+ std::vector<std::string> ld_libary_paths;
+ parse_path(path, ":", &ld_libary_paths);
+ g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
+}
+
+static void parse_LD_PRELOAD(const char* path) {
+ g_ld_preload_names.clear();
+ if (path != nullptr) {
+ // We have historically supported ':' as well as ' ' in LD_PRELOAD.
+ g_ld_preload_names = android::base::Split(path, " :");
+ std::remove_if(g_ld_preload_names.begin(),
+ g_ld_preload_names.end(),
+ [] (const std::string& s) { return s.empty(); });
+ }
+}
+
+// An empty list of soinfos
+static soinfo_list_t g_empty_list;
+
+static void add_vdso(KernelArgumentBlock& args __unused) {
+#if defined(AT_SYSINFO_EHDR)
+ ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
+ if (ehdr_vdso == nullptr) {
+ return;
+ }
+
+ soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
+
+ si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
+ si->phnum = ehdr_vdso->e_phnum;
+ si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
+ si->size = phdr_table_get_load_size(si->phdr, si->phnum);
+ si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
+
+ si->prelink_image();
+ si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr);
+#endif
+}
+
+/* gdb expects the linker to be in the debug shared object list.
+ * Without this, gdb has trouble locating the linker's ".text"
+ * and ".plt" sections. Gdb could also potentially use this to
+ * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
+ * Note that the linker shouldn't be on the soinfo list.
+ */
+static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
+ static link_map linker_link_map_for_gdb;
+#if defined(__LP64__)
+ static char kLinkerPath[] = "/system/bin/linker64";
+#else
+ static char kLinkerPath[] = "/system/bin/linker";
+#endif
+
+ linker_link_map_for_gdb.l_addr = linker_base;
+ linker_link_map_for_gdb.l_name = kLinkerPath;
+
+ /*
+ * Set the dynamic field in the link map otherwise gdb will complain with
+ * the following:
+ * warning: .dynamic section for "/system/bin/linker" is not at the
+ * expected address (wrong library or version mismatch?)
+ */
+ ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
+ ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
+ phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
+ &linker_link_map_for_gdb.l_ld, nullptr);
+
+ insert_link_map_into_debug_map(&linker_link_map_for_gdb);
+}
+
+extern "C" int __system_properties_init(void);
+
+static const char* get_executable_path() {
+ static std::string executable_path;
+ if (executable_path.empty()) {
+ char path[PATH_MAX];
+ ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
+ if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
+ __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+ }
+ executable_path = std::string(path, path_len);
+ }
+
+ return executable_path.c_str();
+}
+
+/*
+ * This code is called after the linker has linked itself and
+ * fixed it's own GOT. It is safe to make references to externs
+ * and other non-local data at this point.
+ */
+static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
+#if TIMING
+ struct timeval t0, t1;
+ gettimeofday(&t0, 0);
+#endif
+
+ // Sanitize the environment.
+ __libc_init_AT_SECURE(args);
+
+ // Initialize system properties
+ __system_properties_init(); // may use 'environ'
+
+ // Register the debuggerd signal handler.
+ debuggerd_callbacks_t callbacks = {
+ .get_abort_message = []() {
+ return g_abort_message;
+ },
+ .post_dump = ¬ify_gdb_of_libraries,
+ };
+ debuggerd_init(&callbacks);
+
+ g_linker_logger.ResetState();
+
+ // Get a few environment variables.
+ const char* LD_DEBUG = getenv("LD_DEBUG");
+ if (LD_DEBUG != nullptr) {
+ g_ld_debug_verbosity = atoi(LD_DEBUG);
+ }
+
+#if defined(__LP64__)
+ INFO("[ Android dynamic linker (64-bit) ]");
+#else
+ INFO("[ Android dynamic linker (32-bit) ]");
+#endif
+
+ // These should have been sanitized by __libc_init_AT_SECURE, but the test
+ // doesn't cost us anything.
+ const char* ldpath_env = nullptr;
+ const char* ldpreload_env = nullptr;
+ if (!getauxval(AT_SECURE)) {
+ ldpath_env = getenv("LD_LIBRARY_PATH");
+ if (ldpath_env != nullptr) {
+ INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);
+ }
+ ldpreload_env = getenv("LD_PRELOAD");
+ if (ldpreload_env != nullptr) {
+ INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
+ }
+ }
+
+ struct stat file_stat;
+ // Stat "/proc/self/exe" instead of executable_path because
+ // the executable could be unlinked by this point and it should
+ // not cause a crash (see http://b/31084669)
+ if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
+ __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+ }
+
+ const char* executable_path = get_executable_path();
+ soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
+ if (si == nullptr) {
+ __libc_fatal("Couldn't allocate soinfo: out of memory?");
+ }
+
+ /* bootstrap the link map, the main exe always needs to be first */
+ si->set_main_executable();
+ link_map* map = &(si->link_map_head);
+
+ // Register the main executable and the linker upfront to have
+ // gdb aware of them before loading the rest of the dependency
+ // tree.
+ map->l_addr = 0;
+ map->l_name = const_cast<char*>(executable_path);
+ insert_link_map_into_debug_map(map);
+ init_linker_info_for_gdb(linker_base);
+
+ // Extract information passed from the kernel.
+ si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
+ si->phnum = args.getauxval(AT_PHNUM);
+
+ /* Compute the value of si->base. We can't rely on the fact that
+ * the first entry is the PHDR because this will not be true
+ * for certain executables (e.g. some in the NDK unit test suite)
+ */
+ si->base = 0;
+ si->size = phdr_table_get_load_size(si->phdr, si->phnum);
+ si->load_bias = 0;
+ for (size_t i = 0; i < si->phnum; ++i) {
+ if (si->phdr[i].p_type == PT_PHDR) {
+ si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
+ si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
+ break;
+ }
+ }
+ si->dynamic = nullptr;
+
+ ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
+ if (elf_hdr->e_type != ET_DYN) {
+ __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.",
+ g_argv[0]);
+ }
+
+ // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
+ parse_LD_LIBRARY_PATH(ldpath_env);
+ parse_LD_PRELOAD(ldpreload_env);
+
+ somain = si;
+
+ init_default_namespace();
+
+ if (!si->prelink_image()) {
+ __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ }
+
+ // add somain to global group
+ si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+
+ // Load ld_preloads and dependencies.
+ std::vector<const char*> needed_library_name_list;
+ size_t ld_preloads_count = 0;
+
+ for (const auto& ld_preload_name : g_ld_preload_names) {
+ needed_library_name_list.push_back(ld_preload_name.c_str());
+ ++ld_preloads_count;
+ }
+
+ for_each_dt_needed(si, [&](const char* name) {
+ needed_library_name_list.push_back(name);
+ });
+
+ const char** needed_library_names = &needed_library_name_list[0];
+ size_t needed_libraries_count = needed_library_name_list.size();
+
+ if (needed_libraries_count > 0 &&
+ !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
+ nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
+ /* add_as_children */ true)) {
+ __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ } else if (needed_libraries_count == 0) {
+ if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
+ __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ }
+ si->increment_ref_count();
+ }
+
+ add_vdso(args);
+
+ {
+ ProtectedDataGuard guard;
+
+ si->call_pre_init_constructors();
+
+ /* After the prelink_image, the si->load_bias is initialized.
+ * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
+ * We need to update this value for so exe here. So Unwind_Backtrace
+ * for some arch like x86 could work correctly within so exe.
+ */
+ map->l_addr = si->load_bias;
+ si->call_constructors();
+ }
+
+#if TIMING
+ gettimeofday(&t1, nullptr);
+ PRINT("LINKER TIME: %s: %d microseconds", g_argv[0], (int) (
+ (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
+ (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
+#endif
+#if STATS
+ PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", g_argv[0],
+ linker_stats.count[kRelocAbsolute],
+ linker_stats.count[kRelocRelative],
+ linker_stats.count[kRelocCopy],
+ linker_stats.count[kRelocSymbol]);
+#endif
+#if COUNT_PAGES
+ {
+ unsigned n;
+ unsigned i;
+ unsigned count = 0;
+ for (n = 0; n < 4096; n++) {
+ if (bitmask[n]) {
+ unsigned x = bitmask[n];
+#if defined(__LP64__)
+ for (i = 0; i < 32; i++) {
+#else
+ for (i = 0; i < 8; i++) {
+#endif
+ if (x & 1) {
+ count++;
+ }
+ x >>= 1;
+ }
+ }
+ }
+ PRINT("PAGES MODIFIED: %s: %d (%dKB)", g_argv[0], count, count * 4);
+ }
+#endif
+
+#if TIMING || STATS || COUNT_PAGES
+ fflush(stdout);
+#endif
+
+ ElfW(Addr) entry = args.getauxval(AT_ENTRY);
+ TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
+ return entry;
+}
+
+/* Compute the load-bias of an existing executable. This shall only
+ * be used to compute the load bias of an executable or shared library
+ * that was loaded by the kernel itself.
+ *
+ * Input:
+ * elf -> address of ELF header, assumed to be at the start of the file.
+ * Return:
+ * load bias, i.e. add the value of any p_vaddr in the file to get
+ * the corresponding address in memory.
+ */
+static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
+ ElfW(Addr) offset = elf->e_phoff;
+ const ElfW(Phdr)* phdr_table =
+ reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
+ const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
+
+ for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
+ if (phdr->p_type == PT_LOAD) {
+ return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
+ }
+ }
+ return 0;
+}
+
+static void __linker_cannot_link(const char* argv0) {
+ __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
+}
+
+/*
+ * This is the entry point for the linker, called from begin.S. This
+ * method is responsible for fixing the linker's own relocations, and
+ * then calling __linker_init_post_relocation().
+ *
+ * Because this method is called before the linker has fixed it's own
+ * relocations, any attempt to reference an extern variable, extern
+ * function, or other GOT reference will generate a segfault.
+ */
+extern "C" ElfW(Addr) __linker_init(void* raw_args) {
+ KernelArgumentBlock args(raw_args);
+
+ ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
+ ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
+ ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
+ ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
+
+ soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
+
+ // If the linker is not acting as PT_INTERP entry_point is equal to
+ // _start. Which means that the linker is running as an executable and
+ // already linked by PT_INTERP.
+ //
+ // This happens when user tries to run 'adb shell /system/bin/linker'
+ // see also https://code.google.com/p/android/issues/detail?id=63174
+ if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
+ __libc_format_fd(STDOUT_FILENO,
+ "This is %s, the helper program for shared library executables.\n",
+ args.argv[0]);
+ exit(0);
+ }
+
+ linker_so.base = linker_addr;
+ linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
+ linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
+ linker_so.dynamic = nullptr;
+ linker_so.phdr = phdr;
+ linker_so.phnum = elf_hdr->e_phnum;
+ linker_so.set_linker_flag();
+
+ // Prelink the linker so we can access linker globals.
+ if (!linker_so.prelink_image()) __linker_cannot_link(args.argv[0]);
+
+ // This might not be obvious... The reasons why we pass g_empty_list
+ // in place of local_group here are (1) we do not really need it, because
+ // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
+ // itself without having to look into local_group and (2) allocators
+ // are not yet initialized, and therefore we cannot use linked_list.push_*
+ // functions at this point.
+ if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);
+
+#if defined(__i386__)
+ // On x86, we can't make system calls before this point.
+ // We can't move this up because this needs to assign to a global.
+ // Note that until we call __libc_init_main_thread below we have
+ // no TLS, so you shouldn't make a system call that can fail, because
+ // it will SEGV when it tries to set errno.
+ __libc_init_sysinfo(args);
+#endif
+
+ // Initialize the main thread (including TLS, so system calls really work).
+ __libc_init_main_thread(args);
+
+ // We didn't protect the linker's RELRO pages in link_image because we
+ // couldn't make system calls on x86 at that point, but we can now...
+ if (!linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);
+
+ // Initialize the linker's static libc's globals
+ __libc_init_globals(args);
+
+ // store argc/argv/envp to use them for calling constructors
+ g_argc = args.argc;
+ g_argv = args.argv;
+ g_envp = args.envp;
+
+ // Initialize the linker's own global variables
+ linker_so.call_constructors();
+
+ // Initialize static variables. Note that in order to
+ // get correct libdl_info we need to call constructors
+ // before get_libdl_info().
+ solist = get_libdl_info();
+ sonext = get_libdl_info();
+ g_default_namespace.add_soinfo(get_libdl_info());
+
+ // We have successfully fixed our own relocations. It's safe to run
+ // the main part of the linker now.
+ args.abort_message_ptr = &g_abort_message;
+ ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
+
+ INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
+
+ // Return the address that the calling assembly stub should jump to.
+ return start_address;
+}
diff --git a/linker/linker_main.h b/linker/linker_main.h
new file mode 100644
index 0000000..0030f49
--- /dev/null
+++ b/linker/linker_main.h
@@ -0,0 +1,68 @@
+/*
+ * 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 __LINKER_MAIN_H
+#define __LINKER_MAIN_H
+
+#include <android/dlext.h>
+
+#include "linker_namespaces.h"
+#include "linker_soinfo.h"
+
+class ProtectedDataGuard {
+ public:
+ ProtectedDataGuard();
+ ~ProtectedDataGuard();
+
+ private:
+ void protect_data(int protection);
+ static size_t ref_count_;
+};
+
+void init_default_namespace();
+soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
+ struct stat* file_stat, off64_t file_offset,
+ uint32_t rtld_flags);
+
+bool find_libraries(android_namespace_t* ns,
+ soinfo* start_with,
+ const char* const library_names[],
+ size_t library_names_count,
+ soinfo* soinfos[],
+ std::vector<soinfo*>* ld_preloads,
+ size_t ld_preloads_count,
+ int rtld_flags,
+ const android_dlextinfo* extinfo,
+ bool add_as_children);
+
+void solist_add_soinfo(soinfo* si);
+bool solist_remove_soinfo(soinfo* si);
+soinfo* solist_get_head();
+soinfo* solist_get_somain();
+
+#endif
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index d7b584e..a0fe9e2 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -342,4 +342,15 @@
// This function is used by dlvsym() to calculate hash of sym_ver
uint32_t calculate_elf_hash(const char* name);
+const char* fix_dt_needed(const char* dt_needed, const char* sopath);
+
+template<typename F>
+void for_each_dt_needed(const soinfo* si, F action) {
+ for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+ if (d->d_tag == DT_NEEDED) {
+ action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
+ }
+ }
+}
+
#endif /* __LINKER_SOINFO_H */
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index e7447e4..05ac687 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -164,6 +164,11 @@
std::vector<std::string>* resolved_paths) {
resolved_paths->clear();
for (const auto& path : paths) {
+ // skip empty paths
+ if (path.empty()) {
+ continue;
+ }
+
char resolved_path[PATH_MAX];
const char* original_path = path.c_str();
if (realpath(original_path, resolved_path) != nullptr) {
diff --git a/tests/Android.bp b/tests/Android.bp
index 0bbe4e3..ed42bde 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -151,6 +151,9 @@
"libbase",
],
host_ldlibs: ["-lrt"],
+ shared: {
+ enabled: false,
+ },
}
// -----------------------------------------------------------------------------
@@ -179,6 +182,9 @@
"-D_FORTIFY_SOURCE=1",
"-DTEST_NAME=Fortify1_gcc"
],
+ shared: {
+ enabled: false,
+ },
}
cc_test_library {
@@ -189,6 +195,9 @@
"-D_FORTIFY_SOURCE=2",
"-DTEST_NAME=Fortify2_gcc"
],
+ shared: {
+ enabled: false,
+ },
}
cc_test_library {
@@ -199,6 +208,9 @@
"-D_FORTIFY_SOURCE=1",
"-DTEST_NAME=Fortify1_clang"
],
+ shared: {
+ enabled: false,
+ },
}
cc_test_library {
@@ -209,6 +221,9 @@
"-D_FORTIFY_SOURCE=2",
"-DTEST_NAME=Fortify2_clang"
],
+ shared: {
+ enabled: false,
+ },
}
// -----------------------------------------------------------------------------
@@ -226,7 +241,7 @@
],
shared: {
enabled: false,
- }
+ },
}
// -----------------------------------------------------------------------------
@@ -241,6 +256,9 @@
enabled: true,
},
},
+ shared: {
+ enabled: false,
+ },
}
// -----------------------------------------------------------------------------
@@ -252,6 +270,9 @@
defaults: ["bionic_tests_defaults"],
srcs: ["gtest_main.cpp"],
cppflags: ["-DUSING_GTEST_OUTPUT_FORMAT"],
+ shared: {
+ enabled: false,
+ },
}
// -----------------------------------------------------------------------------
@@ -313,6 +334,10 @@
"libz",
"libutils",
],
+ ldflags: [
+ "-Wl,--rpath,\\$${ORIGIN}/../bionic-loader-test-libs",
+ "-Wl,--enable-new-dtags",
+ ],
},
}
}
diff --git a/tests/Android.build.prebuilt.mk b/tests/Android.build.prebuilt.mk
index db2dfe4..c98aee2 100644
--- a/tests/Android.build.prebuilt.mk
+++ b/tests/Android.build.prebuilt.mk
@@ -17,8 +17,8 @@
include $(CLEAR_VARS)
LOCAL_MULTILIB := both
LOCAL_MODULE := $(bionic_tests_module)
-LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/prebuilt-elf-files
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/prebuilt-elf-files
+LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/prebuilt-elf-files
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/prebuilt-elf-files
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES_arm := prebuilt-elf-files/arm/$(bionic_tests_module)
@@ -28,3 +28,4 @@
LOCAL_SRC_FILES_mips := prebuilt-elf-files/mips/$(bionic_tests_module)
LOCAL_SRC_FILES_mips64 := prebuilt-elf-files/mips64/$(bionic_tests_module)
include $(BUILD_PREBUILT)
+bionic-loader-test-libs-target: $(LOCAL_MODULE)
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index c3230e7..f597e61 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -55,9 +55,9 @@
constexpr auto LIBSIZE = 1024 * 1024; // how much address space to reserve for it
#if defined(__LP64__)
-#define NATIVE_TESTS_PATH "/nativetest64"
+#define NATIVE_TESTS_PATH "/nativetest64/bionic-loader-test-libs"
#else
-#define NATIVE_TESTS_PATH "/nativetest"
+#define NATIVE_TESTS_PATH "/nativetest/bionic-loader-test-libs"
#endif
#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so"
@@ -150,11 +150,9 @@
}
TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
// lib_path is relative when $ANDROID_DATA is relative
- char lib_realpath_buf[PATH_MAX];
- ASSERT_TRUE(realpath(lib_path.c_str(), lib_realpath_buf) == lib_realpath_buf);
- const std::string lib_realpath = std::string(lib_realpath_buf);
+ std::string lib_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")) + LIBZIPPATH, &lib_path)) << strerror(errno);
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -179,7 +177,7 @@
extinfo.library_fd_offset = 0;
handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
ASSERT_TRUE(handle_ == nullptr);
- ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
+ ASSERT_EQ("dlopen failed: \"" + lib_path + "\" has bad ELF magic", dlerror());
// Check if dlsym works after unsuccessful dlopen().
// Supply non-exiting one to make linker visit every soinfo.
@@ -235,7 +233,8 @@
}
TEST(dlfcn, dlopen_from_zip_absolute_path) {
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
+ std::string lib_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")) + LIBZIPPATH, &lib_path)) << strerror(errno);
void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
@@ -248,7 +247,9 @@
}
TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string lib_path = data_path + LIBZIPPATH_WITH_RUNPATH;
void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
@@ -266,7 +267,9 @@
}
TEST(dlfcn, dlopen_from_zip_ld_library_path) {
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string lib_path = data_path + LIBZIPPATH + "!/libdir";
typedef void (*fn_t)(const char*);
fn_t android_update_LD_LIBRARY_PATH =
@@ -1110,7 +1113,9 @@
static const char* root_lib = "libnstest_root.so";
std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string lib_path = data_path + NATIVE_TESTS_PATH;
const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index f474ed9..34c4108 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1129,8 +1129,20 @@
dlclose(handle);
}
+// Bionic specific tests
+#if defined(__BIONIC__)
+
+#if defined(__LP64__)
+#define NATIVE_TESTS_PATH "/nativetest64/bionic-loader-test-libs"
+#else
+#define NATIVE_TESTS_PATH "/nativetest/bionic-loader-test-libs"
+#endif
+
+#define PREBUILT_ELF_PATH NATIVE_TESTS_PATH "/prebuilt-elf-files"
+
TEST(dlfcn, dt_runpath_absolute_path) {
- void* handle = dlopen(PATH_TO_SYSTEM_LIB "libtest_dt_runpath_d.so", RTLD_NOW);
+ std::string libpath = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH + "/libtest_dt_runpath_d.so";
+ void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef void *(* dlopen_b_fn)();
@@ -1143,19 +1155,10 @@
dlclose(handle);
}
-// Bionic specific tests
-#if defined(__BIONIC__)
-
-#if defined(__LP64__)
-#define NATIVE_TESTS_PATH "/nativetest64"
-#else
-#define NATIVE_TESTS_PATH "/nativetest"
-#endif
-
-#define PREBUILT_ELF_PATH NATIVE_TESTS_PATH "/prebuilt-elf-files"
-
TEST(dlfcn, dlopen_invalid_rw_load_segment) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-rw_load_segment.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-rw_load_segment.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W + E load segments are not allowed";
@@ -1163,7 +1166,9 @@
}
TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-unaligned_shdr_offset.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-unaligned_shdr_offset.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: ";
@@ -1171,7 +1176,9 @@
}
TEST(dlfcn, dlopen_invalid_zero_shentsize) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shentsize.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shentsize.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has unsupported e_shentsize: 0x0 (expected 0x";
@@ -1179,7 +1186,9 @@
}
TEST(dlfcn, dlopen_invalid_zero_shstrndx) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shstrndx.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shstrndx.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid e_shstrndx";
@@ -1187,7 +1196,9 @@
}
TEST(dlfcn, dlopen_invalid_empty_shdr_table) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-empty_shdr_table.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-empty_shdr_table.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has no section headers";
@@ -1195,7 +1206,9 @@
}
TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shdr_table_offset.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shdr_table_offset.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: 0/";
@@ -1203,7 +1216,9 @@
}
TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
- std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shdr_table_content.so";
+ std::string data_path;
+ ASSERT_TRUE(get_realpath(std::string(getenv("ANDROID_DATA")), &data_path)) << strerror(errno);
+ const std::string libpath = data_path + PREBUILT_ELF_PATH + "/libtest_invalid-zero_shdr_table_content.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" .dynamic section header was not found";
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 4abd37e..f2b7edd 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -55,6 +55,16 @@
return g_executable_path;
}
+bool get_realpath(const std::string& path, std::string* real_path) {
+ char realpath_buf[PATH_MAX];
+ if (realpath(path.c_str(), realpath_buf) != realpath_buf) {
+ return false;
+ }
+
+ *real_path = realpath_buf;
+ return true;
+}
+
int get_argc() {
return g_argc;
}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 0303138..8283633 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -17,6 +17,12 @@
cc_defaults {
name: "bionic_testlib_defaults",
host_supported: true,
+ ldflags: [
+ "-Wl,--rpath,\\$${ORIGIN}",
+ "-Wl,--enable-new-dtags",
+ ],
+ relative_install_path: "bionic-loader-test-libs",
+ gtest: false,
sanitize: {
never: true,
},
@@ -30,7 +36,7 @@
// -----------------------------------------------------------------------------
// Library to test gnu-styled hash
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libgnu-hash-table-library",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlext_test_library.cpp"],
@@ -48,7 +54,7 @@
// -----------------------------------------------------------------------------
// Library to test sysv-styled hash
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libsysv-hash-table-library",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlext_test_library.cpp"],
@@ -63,8 +69,9 @@
// -----------------------------------------------------------------------------
// Library used by dlext tests - without GNU RELRO program header
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libdlext_test_norelro",
+ defaults: ["bionic_testlib_defaults"],
srcs: ["dlext_test_library.cpp"],
ldflags: ["-Wl,-z,norelro"],
shared_libs = ["libtest_simple"],
@@ -93,7 +100,7 @@
// -----------------------------------------------------------------------------
// Library used by dlfcn tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_simple",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_simple.cpp"],
@@ -102,7 +109,7 @@
// -----------------------------------------------------------------------------
// Library used by dlfcn nodelete tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_nodelete_1",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_nodelete_1.cpp"],
@@ -111,7 +118,7 @@
// -----------------------------------------------------------------------------
// Library used by dlfcn nodelete tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_nodelete_2",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_nodelete_2.cpp"],
@@ -120,7 +127,7 @@
// -----------------------------------------------------------------------------
// Library used by dlfcn nodelete tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_nodelete_dt_flags_1",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_nodelete_dt_flags_1.cpp"],
@@ -172,7 +179,7 @@
//
// libtest_with_dependency_loop -> a -> b -> c -> a
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_with_dependency_loop",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_loopy_root.cpp"],
@@ -182,7 +189,7 @@
// -----------------------------------------------------------------------------
// libtest_with_dependency_loop_a.so
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_with_dependency_loop_a",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_loopy_a.cpp"],
@@ -194,7 +201,7 @@
//
// this is temporary placeholder - will be removed
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_with_dependency_loop_b_tmp",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_loopy_invalid.cpp"],
@@ -204,7 +211,7 @@
// -----------------------------------------------------------------------------
// libtest_with_dependency_loop_b.so
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_with_dependency_loop_b",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_loopy_b.cpp"],
@@ -214,7 +221,7 @@
// -----------------------------------------------------------------------------
// libtest_with_dependency_loop_c.so
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_with_dependency_loop_c",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_loopy_c.cpp"],
@@ -230,7 +237,7 @@
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_relo_check_dt_needed_order",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_relo_check_dt_needed_order.cpp"],
@@ -240,13 +247,13 @@
],
}
-cc_library {
+cc_test_library {
name: "libtest_relo_check_dt_needed_order_1",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_relo_check_dt_needed_order_1.cpp"],
}
-cc_library {
+cc_test_library {
name: "libtest_relo_check_dt_needed_order_2",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_relo_check_dt_needed_order_2.cpp"],
@@ -260,7 +267,7 @@
// -----------------------------------------------------------------------------
// Library used by ifunc tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_ifunc",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_ifunc.c"],
@@ -281,7 +288,7 @@
// Library used by atexit tests
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_atexit",
defaults: ["bionic_testlib_defaults"],
srcs: ["atexit_testlib.cpp"],
@@ -291,7 +298,7 @@
// This library is used by dl_load test to check symbol preempting
// by main executable
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libdl_preempt_test_1",
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_preempt_library_1.cpp"],
@@ -301,7 +308,7 @@
// This library is used by dl_load test to check symbol preempting
// by libdl_preempt_test_1.so
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libdl_preempt_test_2",
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_preempt_library_2.cpp"],
@@ -310,7 +317,7 @@
// -----------------------------------------------------------------------------
// Library with DF_1_GLOBAL
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libdl_test_df_1_global",
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_df_1_global.cpp"],
@@ -328,7 +335,7 @@
// -----------------------------------------------------------------------------
// Library using symbol from libdl_test_df_1_global
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlsym_df_1_global",
defaults: ["bionic_testlib_defaults"],
srcs: ["dl_df_1_use_global.cpp"],
@@ -337,7 +344,7 @@
// -----------------------------------------------------------------------------
// Library with weak function
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlsym_weak_func",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlsym_weak_function.cpp"],
@@ -346,7 +353,7 @@
// -----------------------------------------------------------------------------
// Library to check RTLD_LOCAL with dlsym in 'this'
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlsym_from_this",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlsym_from_this_symbol.cpp"],
@@ -360,7 +367,7 @@
}
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlsym_from_this_child",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlsym_from_this_functions.cpp"],
@@ -368,7 +375,7 @@
}
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlsym_from_this_grandchild",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlsym_from_this_symbol2.cpp"],
@@ -377,7 +384,7 @@
// -----------------------------------------------------------------------------
// Empty library
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_empty",
defaults: ["bionic_testlib_defaults"],
srcs: ["empty.cpp"],
@@ -386,7 +393,7 @@
// -----------------------------------------------------------------------------
// Library with weak undefined function
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlopen_weak_undefined_func",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_weak_undefined.cpp"],
@@ -395,7 +402,7 @@
// -----------------------------------------------------------------------------
// Library with constructor that calls dlopen() b/7941716
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlopen_from_ctor",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_testlib_dlopen_from_ctor.cpp"],
@@ -409,7 +416,7 @@
// -----------------------------------------------------------------------------
// Library that depends on the library with constructor that calls dlopen() b/7941716
// -----------------------------------------------------------------------------
-cc_library {
+cc_test_library {
name: "libtest_dlopen_from_ctor_main",
defaults: ["bionic_testlib_defaults"],
srcs: ["empty.cpp"],
@@ -434,10 +441,4 @@
"libz",
"libutils",
],
-
- target: {
- windows: {
- enabled: true,
- },
- },
}
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 56be1e2..37499ba 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -26,7 +26,7 @@
LOCAL_MODULE := libdlext_test_zip_zipaligned
LOCAL_MODULE_SUFFIX := .zip
LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_zip
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test_zip
LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
include $(BUILD_SYSTEM)/base_rules.mk
@@ -48,7 +48,7 @@
LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned
LOCAL_MODULE_SUFFIX := .zip
LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_runpath_zip
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test_runpath_zip
LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
include $(BUILD_SYSTEM)/base_rules.mk
diff --git a/tests/libs/Android.build.linker_namespaces.mk b/tests/libs/Android.build.linker_namespaces.mk
index f913780..df6428c 100644
--- a/tests/libs/Android.build.linker_namespaces.mk
+++ b/tests/libs/Android.build.linker_namespaces.mk
@@ -35,24 +35,24 @@
# -----------------------------------------------------------------------------
libnstest_root_src_files := namespaces_root.cpp
libnstest_root_shared_libraries := libnstest_public libnstest_private
-libnstest_root_install_to_out_data_dir := private_namespace_libs
+libnstest_root_relative_install_path := private_namespace_libs
module := libnstest_root
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
libnstest_public_src_files := namespaces_public.cpp
module := libnstest_public
-libnstest_public_install_to_out_data_dir := public_namespace_libs
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+libnstest_public_relative_install_path := public_namespace_libs
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
libnstest_private_src_files := namespaces_private.cpp
-libnstest_private_install_to_out_data_dir := private_namespace_libs
+libnstest_private_relative_install_path := private_namespace_libs
module := libnstest_private
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
libnstest_dlopened_src_files := namespaces_dlopened.cpp
-libnstest_dlopened_install_to_out_data_dir := private_namespace_libs
+libnstest_dlopened_relative_install_path := private_namespace_libs
module := libnstest_dlopened
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
# -----------------------------------------------------------------------------
# This set of libraries is to test isolated namespaces
@@ -71,14 +71,14 @@
# -----------------------------------------------------------------------------
libnstest_root_not_isolated_src_files := namespaces_root.cpp
libnstest_root_not_isolated_shared_libraries := libnstest_public libnstest_private_external
-libnstest_root_not_isolated_install_to_out_data_dir := private_namespace_libs
+libnstest_root_not_isolated_relative_install_path := private_namespace_libs
libnstest_root_not_isolated_ldflags := -Wl,--rpath,\$$ORIGIN/../private_namespace_libs_external \
-Wl,--enable-new-dtags
module := libnstest_root_not_isolated
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
libnstest_private_external_src_files := namespaces_private.cpp
-libnstest_private_external_install_to_out_data_dir := private_namespace_libs_external
+libnstest_private_external_relative_install_path := private_namespace_libs_external
module := libnstest_private_external
-include $(LOCAL_PATH)/Android.build.target.testlib.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
diff --git a/tests/libs/Android.build.testlib.mk b/tests/libs/Android.build.testlib.mk
index 5b688e4..407a389 100644
--- a/tests/libs/Android.build.testlib.mk
+++ b/tests/libs/Android.build.testlib.mk
@@ -17,6 +17,7 @@
build_target := SHARED_LIBRARY
build_type := host
include $(TEST_PATH)/Android.build.mk
-build_type := target
-include $(TEST_PATH)/Android.build.mk
+bionic-loader-test-libs-host: $(LOCAL_MODULE)
+
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
diff --git a/tests/libs/Android.build.testlib.target.mk b/tests/libs/Android.build.testlib.target.mk
new file mode 100644
index 0000000..143be5b
--- /dev/null
+++ b/tests/libs/Android.build.testlib.target.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+build_type := target
+# 1. Install test libraries to /data/nativetests../bionic-loader-test-libs/
+# by default.
+ifeq ($($(module)_relative_install_path),)
+ $(module)_install_to_out_data_dir := bionic-loader-test-libs
+else
+ $(module)_install_to_out_data_dir := bionic-loader-test-libs/$($(module)_relative_install_path)
+endif
+# 2. Set dt_runpath to origin to resolve dependencies
+$(module)_ldflags += -Wl,--rpath,\$${ORIGIN} -Wl,--enable-new-dtags
+include $(TEST_PATH)/Android.build.mk
+
+bionic-loader-test-libs-target: $(LOCAL_MODULE)
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 3c3d78b..94cc516 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -29,6 +29,7 @@
$(LOCAL_PATH)/Android.build.linker_namespaces.mk \
$(LOCAL_PATH)/Android.build.pthread_atfork.mk \
$(LOCAL_PATH)/Android.build.testlib.mk \
+ $(LOCAL_PATH)/Android.build.testlib.target.mk \
$(LOCAL_PATH)/Android.build.versioned_lib.mk \
$(TEST_PATH)/Android.build.mk
@@ -51,12 +52,12 @@
# create symlink to libdlext_test.so for symlink test
# -----------------------------------------------------------------------------
# Use = instead of := to defer the evaluation of $@
-$(TARGET_OUT)/lib/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \
+$(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \
$(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so
ifneq ($(TARGET_2ND_ARCH),)
# link 64 bit .so
-$(TARGET_OUT)/lib64/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \
+$($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \
$(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so
endif
@@ -77,11 +78,12 @@
libdlext_test_fd_shared_libraries := libtest_simple
-libdlext_test_fd_install_to_out_data_dir := $(module)
+libdlext_test_fd_relative_install_path := $(module)
+
+libdlext_test_fd_ldflags := -Wl,--rpath,\$${ORIGIN}/.. -Wl,--enable-new-dtags
+
module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(TEST_PATH)/Android.build.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
# -----------------------------------------------------------------------------
@@ -94,22 +96,18 @@
libdlext_test_zip_shared_libraries := libatest_simple_zip
-libdlext_test_zip_install_to_out_data_dir := $(module)
+libdlext_test_zip_relative_install_path := $(module)
module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(TEST_PATH)/Android.build.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
module := libatest_simple_zip
libatest_simple_zip_src_files := \
dlopen_testlib_simple.cpp
-libatest_simple_zip_install_to_out_data_dir := $(module)
+libatest_simple_zip_relative_install_path := $(module)
module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(TEST_PATH)/Android.build.mk
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
# ----------------------------------------------------------------------------
# Library with soname which does not match filename
diff --git a/tests/libs/bionic_tests_zipalign.cpp b/tests/libs/bionic_tests_zipalign.cpp
index a72820f..8e31474 100644
--- a/tests/libs/bionic_tests_zipalign.cpp
+++ b/tests/libs/bionic_tests_zipalign.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <algorithm>
+#include <memory>
#include <string>
#include <vector>
@@ -36,7 +37,7 @@
fprintf(stderr, " The output zip file that will be created from the input file.\n");
}
-typedef std::pair<ZipEntry*, ZipString*> ZipData;
+using ZipData = std::pair<std::unique_ptr<ZipEntry>, std::unique_ptr<ZipString>>;
static bool GetEntries(ZipArchiveHandle handle, std::vector<ZipData>* entries) {
void* cookie;
@@ -49,14 +50,15 @@
ZipEntry entry;
ZipString name;
while ((return_value = Next(cookie, &entry, &name)) == 0) {
- entries->push_back(std::make_pair(new ZipEntry(entry), new ZipString(name)));
+ entries->emplace_back(std::make_pair(std::make_unique<ZipEntry>(entry),
+ std::make_unique<ZipString>(name)));
}
if (return_value != -1) {
fprintf(stderr, "Error while iterating over zip entries: %s\n", ErrorCodeString(return_value));
} else {
// Sort by offset.
std::sort(entries->begin(), entries->end(),
- [](ZipData a, ZipData b) { return a.first->offset < b.first->offset; });
+ [](ZipData& a, ZipData& b) { return a.first->offset < b.first->offset; });
}
EndIteration(cookie);
@@ -75,8 +77,8 @@
int32_t error;
for (auto& entry : entries) {
- ZipEntry* zip_entry = entry.first;
- ZipString* zip_str = entry.second;
+ ZipEntry* zip_entry = entry.first.get();
+ ZipString* zip_str = entry.second.get();
size_t flags = 0;
if ((zip_entry->method & kCompressDeflated) != 0) {
diff --git a/tests/math_data_test.h b/tests/math_data_test.h
index 0aba701..42dc42c 100644
--- a/tests/math_data_test.h
+++ b/tests/math_data_test.h
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <math.h>
#include <fenv.h>
template <typename RT, typename T1>
@@ -102,7 +103,28 @@
uint64_t sign_magnitude;
};
-// TODO: long double.
+template <> union fp_u<long double> {
+ long double value;
+#if defined(__LP64__)
+ struct {
+ unsigned fracl;
+ unsigned fraclm;
+ unsigned frachm;
+ unsigned frach:16;
+ unsigned exp:15;
+ unsigned sign:1;
+ } bits;
+ __int128_t sign_magnitude;
+#else
+ struct {
+ unsigned fracl;
+ unsigned frach:20;
+ unsigned exp:11;
+ unsigned sign:1;
+ } bits;
+ uint64_t sign_magnitude;
+#endif
+};
template <typename T>
static inline auto SignAndMagnitudeToBiased(const T& value) -> decltype(fp_u<T>::sign_magnitude) {
@@ -134,14 +156,8 @@
return ::testing::AssertionSuccess();
}
- // Output the actual and expected values as hex floating point.
- char expected_str[64];
- char actual_str[64];
- snprintf(expected_str, sizeof(expected_str), "%a", expected);
- snprintf(actual_str, sizeof(actual_str), "%a", actual);
-
return ::testing::AssertionFailure()
- << "expected (" << expected_str << ") != actual (" << actual_str << ")";
+ << "expected (" << std::hexfloat << expected << ") != actual (" << actual << ")";
}
};
@@ -282,4 +298,3 @@
data[i].expected, f(data[i].input1, data[i].input2, data[i].input3)) << "Failed on element " << i;
}
}
-
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index ecba4ad..79c5e92 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -402,51 +402,135 @@
}
template <typename T>
-void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
- const T* fmt, const T* fmt_plus,
- const T* minus_inf, const T* inf_, const T* plus_inf,
- const T* minus_nan, const T* nan_, const T* plus_nan) {
+static void CheckInfNan(int snprintf_fn(T*, size_t, const T*, ...),
+ int sscanf_fn(const T*, const T*, ...),
+ const T* fmt_string, const T* fmt, const T* fmt_plus,
+ const T* minus_inf, const T* inf_, const T* plus_inf,
+ const T* minus_nan, const T* nan_, const T* plus_nan) {
T buf[BUFSIZ];
+ float f;
- snprintf_fn(buf, sizeof(buf), fmt, nan(""));
+ // NaN.
+
+ snprintf_fn(buf, sizeof(buf), fmt, nanf(""));
EXPECT_STREQ(nan_, buf) << fmt;
- snprintf_fn(buf, sizeof(buf), fmt, -nan(""));
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_TRUE(isnan(f));
+
+ snprintf_fn(buf, sizeof(buf), fmt, -nanf(""));
EXPECT_STREQ(minus_nan, buf) << fmt;
- snprintf_fn(buf, sizeof(buf), fmt_plus, nan(""));
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_TRUE(isnan(f));
+
+ snprintf_fn(buf, sizeof(buf), fmt_plus, nanf(""));
EXPECT_STREQ(plus_nan, buf) << fmt_plus;
- snprintf_fn(buf, sizeof(buf), fmt_plus, -nan(""));
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_TRUE(isnan(f));
+
+ snprintf_fn(buf, sizeof(buf), fmt_plus, -nanf(""));
EXPECT_STREQ(minus_nan, buf) << fmt_plus;
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_TRUE(isnan(f));
- snprintf_fn(buf, sizeof(buf), fmt, HUGE_VAL);
+ // Inf.
+
+ snprintf_fn(buf, sizeof(buf), fmt, HUGE_VALF);
EXPECT_STREQ(inf_, buf) << fmt;
- snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VAL);
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_EQ(HUGE_VALF, f);
+
+ snprintf_fn(buf, sizeof(buf), fmt, -HUGE_VALF);
EXPECT_STREQ(minus_inf, buf) << fmt;
- snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VAL);
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_EQ(-HUGE_VALF, f);
+
+ snprintf_fn(buf, sizeof(buf), fmt_plus, HUGE_VALF);
EXPECT_STREQ(plus_inf, buf) << fmt_plus;
- snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VAL);
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_EQ(HUGE_VALF, f);
+
+ snprintf_fn(buf, sizeof(buf), fmt_plus, -HUGE_VALF);
EXPECT_STREQ(minus_inf, buf) << fmt_plus;
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f));
+ EXPECT_EQ(-HUGE_VALF, f);
+
+ // Check case-insensitivity.
+ snprintf_fn(buf, sizeof(buf), fmt_string, "[InFiNiTy]");
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f)) << buf;
+ EXPECT_EQ(HUGE_VALF, f);
+ snprintf_fn(buf, sizeof(buf), fmt_string, "[NaN]");
+ EXPECT_EQ(1, sscanf_fn(buf, fmt, &f)) << buf;
+ EXPECT_TRUE(isnan(f));
}
-TEST(STDIO_TEST, snprintf_inf_nan) {
- CheckInfNan(snprintf, "%a", "%+a", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
- CheckInfNan(snprintf, "%A", "%+A", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
- CheckInfNan(snprintf, "%e", "%+e", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
- CheckInfNan(snprintf, "%E", "%+E", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
- CheckInfNan(snprintf, "%f", "%+f", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
- CheckInfNan(snprintf, "%F", "%+F", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
- CheckInfNan(snprintf, "%g", "%+g", "-inf", "inf", "+inf", "-nan", "nan", "+nan");
- CheckInfNan(snprintf, "%G", "%+G", "-INF", "INF", "+INF", "-NAN", "NAN", "+NAN");
+TEST(STDIO_TEST, snprintf_sscanf_inf_nan) {
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%a]", "[%+a]",
+ "[-inf]", "[inf]", "[+inf]",
+ "[-nan]", "[nan]", "[+nan]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%A]", "[%+A]",
+ "[-INF]", "[INF]", "[+INF]",
+ "[-NAN]", "[NAN]", "[+NAN]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%e]", "[%+e]",
+ "[-inf]", "[inf]", "[+inf]",
+ "[-nan]", "[nan]", "[+nan]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%E]", "[%+E]",
+ "[-INF]", "[INF]", "[+INF]",
+ "[-NAN]", "[NAN]", "[+NAN]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%f]", "[%+f]",
+ "[-inf]", "[inf]", "[+inf]",
+ "[-nan]", "[nan]", "[+nan]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%F]", "[%+F]",
+ "[-INF]", "[INF]", "[+INF]",
+ "[-NAN]", "[NAN]", "[+NAN]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%g]", "[%+g]",
+ "[-inf]", "[inf]", "[+inf]",
+ "[-nan]", "[nan]", "[+nan]");
+ CheckInfNan(snprintf, sscanf, "%s",
+ "[%G]", "[%+G]",
+ "[-INF]", "[INF]", "[+INF]",
+ "[-NAN]", "[NAN]", "[+NAN]");
}
-TEST(STDIO_TEST, wsprintf_inf_nan) {
- CheckInfNan(swprintf, L"%a", L"%+a", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
- CheckInfNan(swprintf, L"%A", L"%+A", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
- CheckInfNan(swprintf, L"%e", L"%+e", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
- CheckInfNan(swprintf, L"%E", L"%+E", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
- CheckInfNan(swprintf, L"%f", L"%+f", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
- CheckInfNan(swprintf, L"%F", L"%+F", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
- CheckInfNan(swprintf, L"%g", L"%+g", L"-inf", L"inf", L"+inf", L"-nan", L"nan", L"+nan");
- CheckInfNan(swprintf, L"%G", L"%+G", L"-INF", L"INF", L"+INF", L"-NAN", L"NAN", L"+NAN");
+TEST(STDIO_TEST, swprintf_swscanf_inf_nan) {
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%a]", L"[%+a]",
+ L"[-inf]", L"[inf]", L"[+inf]",
+ L"[-nan]", L"[nan]", L"[+nan]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%A]", L"[%+A]",
+ L"[-INF]", L"[INF]", L"[+INF]",
+ L"[-NAN]", L"[NAN]", L"[+NAN]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%e]", L"[%+e]",
+ L"[-inf]", L"[inf]", L"[+inf]",
+ L"[-nan]", L"[nan]", L"[+nan]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%E]", L"[%+E]",
+ L"[-INF]", L"[INF]", L"[+INF]",
+ L"[-NAN]", L"[NAN]", L"[+NAN]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%f]", L"[%+f]",
+ L"[-inf]", L"[inf]", L"[+inf]",
+ L"[-nan]", L"[nan]", L"[+nan]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%F]", L"[%+F]",
+ L"[-INF]", L"[INF]", L"[+INF]",
+ L"[-NAN]", L"[NAN]", L"[+NAN]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%g]", L"[%+g]",
+ L"[-inf]", L"[inf]", L"[+inf]",
+ L"[-nan]", L"[nan]", L"[+nan]");
+ CheckInfNan(swprintf, swscanf, L"%s",
+ L"[%G]", L"[%+G]",
+ L"[-INF]", L"[INF]", L"[+INF]",
+ L"[-NAN]", L"[NAN]", L"[+NAN]");
}
TEST(STDIO_TEST, snprintf_d_INT_MAX) {
@@ -646,15 +730,34 @@
fclose(fp);
}
-TEST(STDIO_TEST, sscanf) {
- char s1[123];
- int i1;
- double d1;
- char s2[123];
- ASSERT_EQ(3, sscanf(" hello 123 1.23 ", "%s %i %lf %s", s1, &i1, &d1, s2));
- ASSERT_STREQ("hello", s1);
- ASSERT_EQ(123, i1);
- ASSERT_DOUBLE_EQ(1.23, d1);
+TEST(STDIO_TEST, sscanf_swscanf) {
+ struct stuff {
+ char s1[123];
+ int i1;
+ double d1;
+ float f1;
+ char s2[123];
+
+ void Check() {
+ ASSERT_STREQ("hello", s1);
+ ASSERT_EQ(123, i1);
+ ASSERT_DOUBLE_EQ(1.23, d1);
+ ASSERT_FLOAT_EQ(9.0f, f1);
+ ASSERT_STREQ("world", s2);
+ }
+ } s;
+
+ memset(&s, 0, sizeof(s));
+ ASSERT_EQ(5, sscanf(" hello 123 1.23 0x1.2p3 world",
+ "%s %i %lf %f %s",
+ s.s1, &s.i1, &s.d1, &s.f1, s.s2));
+ s.Check();
+
+ memset(&s, 0, sizeof(s));
+ ASSERT_EQ(5, swscanf(L" hello 123 1.23 0x1.2p3 world",
+ L"%s %i %lf %f %s",
+ s.s1, &s.i1, &s.d1, &s.f1, s.s2));
+ s.Check();
}
TEST(STDIO_TEST, cantwrite_EBADF) {
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 773230f..5b9442f 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -17,16 +17,18 @@
#include <gtest/gtest.h>
#include "BionicDeathTest.h"
+#include "math_data_test.h"
#include "TemporaryFile.h"
#include "utils.h"
#include <errno.h>
+#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
+#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -288,16 +290,65 @@
ASSERT_DOUBLE_EQ(1.23, atof("1.23"));
}
+template <typename T>
+static void CheckStrToFloat(T fn(const char* s, char** end)) {
+ FpUlpEq<0, T> pred;
+
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn("9.0", nullptr));
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn("0.9e1", nullptr));
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn("0x1.2p3", nullptr));
+
+ EXPECT_TRUE(isnan(fn("+nan", nullptr)));
+ EXPECT_TRUE(isnan(fn("nan", nullptr)));
+ EXPECT_TRUE(isnan(fn("-nan", nullptr)));
+
+ EXPECT_TRUE(isnan(fn("+nan(0xff)", nullptr)));
+ EXPECT_TRUE(isnan(fn("nan(0xff)", nullptr)));
+ EXPECT_TRUE(isnan(fn("-nan(0xff)", nullptr)));
+
+ char* p;
+ EXPECT_TRUE(isnan(fn("+nanny", &p)));
+ EXPECT_STREQ("ny", p);
+ EXPECT_TRUE(isnan(fn("nanny", &p)));
+ EXPECT_STREQ("ny", p);
+ EXPECT_TRUE(isnan(fn("-nanny", &p)));
+ EXPECT_STREQ("ny", p);
+
+ EXPECT_EQ(0, fn("muppet", &p));
+ EXPECT_STREQ("muppet", p);
+ EXPECT_EQ(0, fn(" muppet", &p));
+ EXPECT_STREQ(" muppet", p);
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+inf", nullptr));
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("inf", nullptr));
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-inf", nullptr));
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+infinity", nullptr));
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("infinity", nullptr));
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-infinity", nullptr));
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("+infinitude", &p));
+ EXPECT_STREQ("initude", p);
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("infinitude", &p));
+ EXPECT_STREQ("initude", p);
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn("-infinitude", &p));
+ EXPECT_STREQ("initude", p);
+
+ // Check case-insensitivity.
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn("InFiNiTy", nullptr));
+ EXPECT_TRUE(isnan(fn("NaN", nullptr)));
+}
+
TEST(stdlib, strtod) {
- ASSERT_DOUBLE_EQ(1.23, strtod("1.23", NULL));
+ CheckStrToFloat(strtod);
}
TEST(stdlib, strtof) {
- ASSERT_FLOAT_EQ(1.23, strtof("1.23", NULL));
+ CheckStrToFloat(strtof);
}
TEST(stdlib, strtold) {
- ASSERT_DOUBLE_EQ(1.23, strtold("1.23", NULL));
+ CheckStrToFloat(strtold);
}
TEST(stdlib, strtof_2206701) {
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 48c299a..2a46d8b 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -124,7 +124,10 @@
TEST(time, mktime_EOVERFLOW) {
struct tm t;
memset(&t, 0, sizeof(tm));
- t.tm_year = 0;
+
+ // LP32 year range is 1901-2038, so this year is guaranteed not to overflow.
+ t.tm_year = 2016 - 1900;
+
t.tm_mon = 2;
t.tm_mday = 10;
@@ -132,7 +135,10 @@
ASSERT_NE(static_cast<time_t>(-1), mktime(&t));
ASSERT_EQ(0, errno);
+ // This will overflow for LP32 or LP64.
t.tm_year = INT_MAX;
+
+ errno = 0;
ASSERT_EQ(static_cast<time_t>(-1), mktime(&t));
ASSERT_EQ(EOVERFLOW, errno);
}
diff --git a/tests/utils.h b/tests/utils.h
index 08e8cea..4391f41 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -122,6 +122,9 @@
// The absolute path to the executable
const std::string& get_executable_path();
+// Get realpath
+bool get_realpath(const std::string& path, std::string* realpath);
+
// Access to argc/argv/envp
int get_argc();
char** get_argv();
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 000dc98..db51c08 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -22,6 +22,8 @@
#include <stdint.h>
#include <wchar.h>
+#include "math_data_test.h"
+
#define NUM_WCHARS(num_bytes) ((num_bytes)/sizeof(wchar_t))
TEST(wchar, sizeof_wchar_t) {
@@ -389,14 +391,6 @@
ASSERT_EQ('\x20', *invalid);
}
-TEST(wchar, wcstod) {
- ASSERT_DOUBLE_EQ(1.23, wcstod(L"1.23", NULL));
-}
-
-TEST(wchar, wcstof) {
- ASSERT_FLOAT_EQ(1.23f, wcstof(L"1.23", NULL));
-}
-
TEST(wchar, wcstol) {
ASSERT_EQ(123L, wcstol(L"123", NULL, 0));
}
@@ -405,10 +399,6 @@
ASSERT_EQ(123LL, wcstol(L"123", NULL, 0));
}
-TEST(wchar, wcstold) {
- ASSERT_DOUBLE_EQ(1.23L, wcstold(L"1.23", NULL));
-}
-
TEST(wchar, wcstoul) {
ASSERT_EQ(123UL, wcstoul(L"123", NULL, 0));
}
@@ -672,3 +662,64 @@
wchar_t dst[6];
ASSERT_EQ(&dst[4], wmempcpy(dst, L"hello", 4));
}
+
+template <typename T>
+static void CheckWcsToFloat(T fn(const wchar_t* s, wchar_t** end)) {
+ FpUlpEq<0, T> pred;
+
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"9.0", nullptr));
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0.9e1", nullptr));
+ EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0x1.2p3", nullptr));
+
+ EXPECT_TRUE(isnan(fn(L"+nan", nullptr)));
+ EXPECT_TRUE(isnan(fn(L"nan", nullptr)));
+ EXPECT_TRUE(isnan(fn(L"-nan", nullptr)));
+
+ EXPECT_TRUE(isnan(fn(L"+nan(0xff)", nullptr)));
+ EXPECT_TRUE(isnan(fn(L"nan(0xff)", nullptr)));
+ EXPECT_TRUE(isnan(fn(L"-nan(0xff)", nullptr)));
+
+ wchar_t* p;
+ EXPECT_TRUE(isnan(fn(L"+nanny", &p)));
+ EXPECT_STREQ(L"ny", p);
+ EXPECT_TRUE(isnan(fn(L"nanny", &p)));
+ EXPECT_STREQ(L"ny", p);
+ EXPECT_TRUE(isnan(fn(L"-nanny", &p)));
+ EXPECT_STREQ(L"ny", p);
+
+ EXPECT_EQ(0, fn(L"muppet", &p));
+ EXPECT_STREQ(L"muppet", p);
+ EXPECT_EQ(0, fn(L" muppet", &p));
+ EXPECT_STREQ(L" muppet", p);
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+inf", nullptr));
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"inf", nullptr));
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-inf", nullptr));
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinity", nullptr));
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinity", nullptr));
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinity", nullptr));
+
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinitude", &p));
+ EXPECT_STREQ(L"initude", p);
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinitude", &p));
+ EXPECT_STREQ(L"initude", p);
+ EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinitude", &p));
+ EXPECT_STREQ(L"initude", p);
+
+ // Check case-insensitivity.
+ EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"InFiNiTy", nullptr));
+ EXPECT_TRUE(isnan(fn(L"NaN", nullptr)));
+}
+
+TEST(wchar, wcstod) {
+ CheckWcsToFloat(wcstod);
+}
+
+TEST(wchar, wcstof) {
+ CheckWcsToFloat(wcstof);
+}
+
+TEST(wchar, wcstold) {
+ CheckWcsToFloat(wcstold);
+}
diff --git a/tools/versioner/src/DeclarationDatabase.cpp b/tools/versioner/src/DeclarationDatabase.cpp
index 88f7b55..02383bb 100644
--- a/tools/versioner/src/DeclarationDatabase.cpp
+++ b/tools/versioner/src/DeclarationDatabase.cpp
@@ -84,6 +84,7 @@
std::string declaration_name = getDeclName(named_decl);
bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
bool is_definition = false;
+ bool no_guard = false;
if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
declaration_type = DeclarationType::function;
@@ -140,7 +141,9 @@
// Find and parse __ANDROID_AVAILABILITY_DUMP__ annotations.
for (const AnnotateAttr* attr : decl->specific_attrs<AnnotateAttr>()) {
llvm::StringRef annotation = attr->getAnnotation();
- if (annotation == "introduced_in_future") {
+ if (annotation == "versioner_no_guard") {
+ no_guard = true;
+ } else if (annotation == "introduced_in_future") {
// Tag the compiled-for arch, since this can vary across archs.
availability.arch_availability[type.arch].future = true;
} else {
@@ -200,11 +203,13 @@
declaration.location = location;
declaration.is_extern = is_extern;
declaration.is_definition = is_definition;
+ declaration.no_guard = no_guard;
declaration.availability.insert(std::make_pair(type, availability));
symbol_it->second.declarations.insert(std::make_pair(location, declaration));
} else {
if (declaration_it->second.is_extern != is_extern ||
- declaration_it->second.is_definition != is_definition) {
+ declaration_it->second.is_definition != is_definition ||
+ declaration_it->second.no_guard != no_guard) {
errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
location.filename.c_str(), location.start.line, location.start.column);
}
diff --git a/tools/versioner/src/DeclarationDatabase.h b/tools/versioner/src/DeclarationDatabase.h
index b130ca9..8f43d79 100644
--- a/tools/versioner/src/DeclarationDatabase.h
+++ b/tools/versioner/src/DeclarationDatabase.h
@@ -148,6 +148,7 @@
bool is_extern;
bool is_definition;
+ bool no_guard;
std::map<CompilationType, DeclarationAvailability> availability;
bool calculateAvailability(DeclarationAvailability* output) const;
@@ -161,6 +162,9 @@
fprintf(out, "%s ", is_extern ? "extern" : "static");
fprintf(out, "%s ", is_definition ? "definition" : "declaration");
+ if (no_guard) {
+ fprintf(out, "no_guard ");
+ }
fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(),
location.start.line, location.start.column);
diff --git a/tools/versioner/src/Preprocessor.cpp b/tools/versioner/src/Preprocessor.cpp
index 8d0b943..3c86486 100644
--- a/tools/versioner/src/Preprocessor.cpp
+++ b/tools/versioner/src/Preprocessor.cpp
@@ -452,6 +452,11 @@
const Location& location = decl_it.first;
const Declaration& decl = decl_it.second;
+ if (decl.no_guard) {
+ // No guard required.
+ continue;
+ }
+
DeclarationAvailability macro_guard = calculateRequiredGuard(decl);
if (!macro_guard.empty()) {
guards[location.filename][location] = macro_guard;
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index 432fd66..daf6f0b 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -77,6 +77,12 @@
command.push_back("-D__ANDROID_API__="s + std::to_string(type.api_level));
command.push_back("-D_FORTIFY_SOURCE=2");
command.push_back("-D_GNU_SOURCE");
+ command.push_back("-Wall");
+ command.push_back("-Wextra");
+ command.push_back("-Werror");
+ command.push_back("-Wno-unused-macros");
+ command.push_back("-Wno-unused-function");
+ command.push_back("-Wno-unused-variable");
command.push_back("-Wno-unknown-attributes");
command.push_back("-Wno-pragma-once-outside-header");
command.push_back("-target");
diff --git a/tools/versioner/tests/preprocessor_no_guard/expected/foo.h b/tools/versioner/tests/preprocessor_no_guard/expected/foo.h
new file mode 100644
index 0000000..2bf1dbf
--- /dev/null
+++ b/tools/versioner/tests/preprocessor_no_guard/expected/foo.h
@@ -0,0 +1 @@
+int foo() __VERSIONER_NO_GUARD __INTRODUCED_IN(14);
diff --git a/tools/versioner/tests/preprocessor_no_guard/headers/foo.h b/tools/versioner/tests/preprocessor_no_guard/headers/foo.h
new file mode 100644
index 0000000..2bf1dbf
--- /dev/null
+++ b/tools/versioner/tests/preprocessor_no_guard/headers/foo.h
@@ -0,0 +1 @@
+int foo() __VERSIONER_NO_GUARD __INTRODUCED_IN(14);
diff --git a/tools/versioner/tests/preprocessor_no_guard/run.sh b/tools/versioner/tests/preprocessor_no_guard/run.sh
new file mode 100644
index 0000000..1b0aae2
--- /dev/null
+++ b/tools/versioner/tests/preprocessor_no_guard/run.sh
@@ -0,0 +1,4 @@
+rm -rf out
+set -e
+versioner headers -i -o out
+diff -q -w -B out expected