am 1506fc17: Expose android_set_abort_message().
* commit '1506fc178e9dcd873eaf95535ac7625ebb59388f':
Expose android_set_abort_message().
diff --git a/libc/arch-arm/bionic/_setjmp.S b/libc/arch-arm/bionic/_setjmp.S
index 64a0a31..7d637fd 100644
--- a/libc/arch-arm/bionic/_setjmp.S
+++ b/libc/arch-arm/bionic/_setjmp.S
@@ -107,7 +107,7 @@
/* validation failed, die die die. */
botch:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(_longjmp)
diff --git a/libc/arch-arm/bionic/abort_arm.S b/libc/arch-arm/bionic/abort_arm.S
index 6b181ef..1039502 100644
--- a/libc/arch-arm/bionic/abort_arm.S
+++ b/libc/arch-arm/bionic/abort_arm.S
@@ -40,5 +40,5 @@
.cfi_def_cfa_offset 8
.cfi_rel_offset r3, 0
.cfi_rel_offset r14, 4
- bl PIC_SYM(__libc_android_abort, PLT)
+ bl __libc_android_abort
END(abort)
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index ed59d07..0c9082c 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -56,7 +56,7 @@
.cfi_rel_offset r14, 4
mov r0, #0x00000000
- bl PIC_SYM(sigblock, PLT)
+ bl sigblock
mov r1, r0
ldmfd sp!, {r0, r14}
@@ -108,7 +108,7 @@
.cfi_adjust_cfa_offset 4
mov r0, r2
- bl PIC_SYM(sigsetmask, PLT)
+ bl sigsetmask
add sp, sp, #4 /* unalign the stack */
.cfi_adjust_cfa_offset -4
@@ -147,7 +147,7 @@
/* validation failed, die die die. */
botch:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(longjmp)
diff --git a/libc/arch-arm/bionic/sigsetjmp.S b/libc/arch-arm/bionic/sigsetjmp.S
index 7016f50..f9e30ee 100644
--- a/libc/arch-arm/bionic/sigsetjmp.S
+++ b/libc/arch-arm/bionic/sigsetjmp.S
@@ -50,8 +50,8 @@
ENTRY(sigsetjmp)
teq r1, #0
- beq PIC_SYM(_setjmp, PLT)
- b PIC_SYM(setjmp, PLT)
+ beq _setjmp
+ b setjmp
END(sigsetjmp)
.L_setjmp_magic:
@@ -61,6 +61,6 @@
ldr r2, .L_setjmp_magic
ldr r3, [r0]
teq r2, r3
- beq PIC_SYM(_longjmp, PLT)
- b PIC_SYM(longjmp, PLT)
+ beq _longjmp
+ b longjmp
END(siglongjmp)
diff --git a/libc/arch-arm/include/machine/asm.h b/libc/arch-arm/include/machine/asm.h
index 7954f05..88d16f9 100644
--- a/libc/arch-arm/include/machine/asm.h
+++ b/libc/arch-arm/include/machine/asm.h
@@ -50,10 +50,4 @@
#undef __bionic_asm_function_type
#define __bionic_asm_function_type #function
-#if defined(__ELF__) && defined(PIC)
-#define PIC_SYM(x,y) x ## ( ## y ## )
-#else
-#define PIC_SYM(x,y) x
-#endif
-
#endif /* !_ARM_ASM_H_ */
diff --git a/libc/arch-arm64/bionic/_setjmp.S b/libc/arch-arm64/bionic/_setjmp.S
index 3836899..e11ef68 100644
--- a/libc/arch-arm64/bionic/_setjmp.S
+++ b/libc/arch-arm64/bionic/_setjmp.S
@@ -105,7 +105,7 @@
/* validation failed, die die die */
.L_fail:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(_longjmp)
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index f9d2266..35815a6 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -45,7 +45,7 @@
stp x0, x30, [sp, #-16]!
mov x0, xzr
- bl PIC_SYM(sigblock, PLT)
+ bl sigblock
mov w1, w0
ldp x0, x30, [sp], #16
@@ -117,7 +117,7 @@
/* validation failed, die die die */
.L_fail:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(longjmp)
diff --git a/libc/arch-arm64/bionic/sigsetjmp.S b/libc/arch-arm64/bionic/sigsetjmp.S
index 4fdb367..be7cecb 100644
--- a/libc/arch-arm64/bionic/sigsetjmp.S
+++ b/libc/arch-arm64/bionic/sigsetjmp.S
@@ -35,8 +35,8 @@
*/
ENTRY(sigsetjmp)
- cbz w1, PIC_SYM(_setjmp, PLT)
- b PIC_SYM(setjmp, PLT)
+ cbz w1, _setjmp
+ b setjmp
END(sigsetjmp)
.L_setjmp_magic:
@@ -46,6 +46,6 @@
ldr w2, .L_setjmp_magic
ldr w3, [x0]
cmp w2, w3
- b.eq PIC_SYM(_longjmp, PLT)
- b PIC_SYM(longjmp, PLT)
+ b.eq _longjmp
+ b longjmp
END(siglongjmp)
diff --git a/libc/arch-arm64/include/machine/asm.h b/libc/arch-arm64/include/machine/asm.h
index 4bfabaf..31b5c63 100644
--- a/libc/arch-arm64/include/machine/asm.h
+++ b/libc/arch-arm64/include/machine/asm.h
@@ -45,10 +45,4 @@
#undef __bionic_asm_function_type
#define __bionic_asm_function_type %function
-#if defined(__ELF__) && defined(PIC)
-#define PIC_SYM(x,y) x ## ( ## y ## )
-#else
-#define PIC_SYM(x,y) x
-#endif
-
#endif /* _AARCH64_ASM_H_ */
diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp
index 0a0fdd5..9b5c9e7 100644
--- a/libc/bionic/clone.cpp
+++ b/libc/bionic/clone.cpp
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-#define __GNU_SOURCE 1
+#define _GNU_SOURCE 1
#include <sched.h>
#include <stdlib.h>
#include <stdarg.h>
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 9e4eecd..ff9940e 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -51,7 +51,7 @@
extern "C" int __set_tls(void* ptr);
extern "C" int __set_tid_address(int* tid_address);
-void __libc_init_vdso();
+__LIBC_HIDDEN__ void __libc_init_vdso();
// Not public, but well-known in the BSDs.
const char* __progname;
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index a564c39..30081a5 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -26,6 +26,7 @@
* SUCH DAMAGE.
*/
#include <new>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -45,7 +46,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
-#include <unistd.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -80,6 +80,16 @@
uint8_t namelen;
uint8_t reserved[3];
+ // TODO: The following fields should be declared as atomic_uint32_t.
+ // They should be assigned to with release semantics, instead of using
+ // explicit fences. Unfortunately, the read accesses are generally
+ // followed by more dependent read accesses, and the dependence
+ // is assumed to enforce memory ordering. Which it does on supported
+ // hardware. This technically should use memory_order_consume, if
+ // that worked as intended.
+ // We should also avoid rereading these fields redundantly, since not
+ // all processor implementations ensure that multiple loads from the
+ // same field are carried out in the right order.
volatile uint32_t prop;
volatile uint32_t left;
@@ -93,7 +103,8 @@
this->namelen = name_length;
memcpy(this->name, name, name_length);
this->name[name_length] = '\0';
- ANDROID_MEMBAR_FULL();
+ ANDROID_MEMBAR_FULL(); // TODO: Instead use a release store
+ // for subsequent pointer assignment.
}
private:
@@ -102,14 +113,15 @@
struct prop_area {
uint32_t bytes_used;
- volatile uint32_t serial;
+ atomic_uint_least32_t serial;
uint32_t magic;
uint32_t version;
uint32_t reserved[28];
char data[0];
prop_area(const uint32_t magic, const uint32_t version) :
- serial(0), magic(magic), version(version) {
+ magic(magic), version(version) {
+ atomic_init(&serial, 0);
memset(reserved, 0, sizeof(reserved));
// Allocate enough space for the root node.
bytes_used = sizeof(prop_bt);
@@ -120,7 +132,7 @@
};
struct prop_info {
- volatile uint32_t serial;
+ atomic_uint_least32_t serial;
char value[PROP_VALUE_MAX];
char name[0];
@@ -128,10 +140,11 @@
const uint8_t valuelen) {
memcpy(this->name, name, namelen);
this->name[namelen] = '\0';
- this->serial = (valuelen << 24);
+ atomic_init(&this->serial, valuelen << 24);
memcpy(this->value, value, valuelen);
this->value[valuelen] = '\0';
- ANDROID_MEMBAR_FULL();
+ ANDROID_MEMBAR_FULL(); // TODO: Instead use a release store
+ // for subsequent point assignment.
}
private:
DISALLOW_COPY_AND_ASSIGN(prop_info);
@@ -605,11 +618,20 @@
}
while (true) {
- uint32_t serial = __system_property_serial(pi);
+ uint32_t serial = __system_property_serial(pi); // acquire semantics
size_t len = SERIAL_VALUE_LEN(serial);
memcpy(value, pi->value, len + 1);
- ANDROID_MEMBAR_FULL();
- if (serial == pi->serial) {
+ // TODO: Fix the synchronization scheme here.
+ // There is no fully supported way to implement this kind
+ // of synchronization in C++11, since the memcpy races with
+ // updates to pi, and the data being accessed is not atomic.
+ // The following fence is unintuitive, but would be the
+ // correct one if memcpy used memory_order_relaxed atomic accesses.
+ // In practice it seems unlikely that the generated code would
+ // would be any different, so this should be OK.
+ atomic_thread_fence(memory_order_acquire);
+ if (serial ==
+ atomic_load_explicit(&(pi->serial), memory_order_relaxed)) {
if (name != 0) {
strcpy(name, pi->name);
}
@@ -658,14 +680,24 @@
if (len >= PROP_VALUE_MAX)
return -1;
- pi->serial = pi->serial | 1;
- ANDROID_MEMBAR_FULL();
+ uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
+ serial |= 1;
+ atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
+ // The memcpy call here also races. Again pretend it
+ // used memory_order_relaxed atomics, and use the analogous
+ // counterintuitive fence.
+ atomic_thread_fence(memory_order_release);
memcpy(pi->value, value, len + 1);
- ANDROID_MEMBAR_FULL();
- pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
+ atomic_store_explicit(
+ &pi->serial,
+ (len << 24) | ((serial + 1) & 0xffffff),
+ memory_order_release);
__futex_wake(&pi->serial, INT32_MAX);
- pa->serial++;
+ atomic_store_explicit(
+ &pa->serial,
+ atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+ memory_order_release);
__futex_wake(&pa->serial, INT32_MAX);
return 0;
@@ -688,17 +720,25 @@
if (!pi)
return -1;
- pa->serial++;
+ // There is only a single mutator, but we want to make sure that
+ // updates are visible to a reader waiting for the update.
+ atomic_store_explicit(
+ &pa->serial,
+ atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+ memory_order_release);
__futex_wake(&pa->serial, INT32_MAX);
return 0;
}
+// Wait for non-locked serial, and retrieve it with acquire semantics.
unsigned int __system_property_serial(const prop_info *pi)
{
- uint32_t serial = pi->serial;
+ uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_acquire);
while (SERIAL_DIRTY(serial)) {
- __futex_wait(const_cast<volatile uint32_t*>(&pi->serial), serial, NULL);
- serial = pi->serial;
+ __futex_wait(const_cast<volatile void *>(
+ reinterpret_cast<const void *>(&pi->serial)),
+ serial, NULL);
+ serial = atomic_load_explicit(&pi->serial, memory_order_acquire);
}
return serial;
}
@@ -706,12 +746,14 @@
unsigned int __system_property_wait_any(unsigned int serial)
{
prop_area *pa = __system_property_area__;
+ uint32_t my_serial;
do {
__futex_wait(&pa->serial, serial, NULL);
- } while (pa->serial == serial);
+ my_serial = atomic_load_explicit(&pa->serial, memory_order_acquire);
+ } while (my_serial == serial);
- return pa->serial;
+ return my_serial;
}
const prop_info *__system_property_find_nth(unsigned n)
diff --git a/libc/dns/resolv/__dn_comp.c b/libc/dns/resolv/__dn_comp.c
deleted file mode 100644
index 93d3f19..0000000
--- a/libc/dns/resolv/__dn_comp.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* $NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#if defined(__indr_reference)
-__indr_reference(__dn_comp,dn_comp)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
-#include <resolv.h>
-#endif
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef dn_comp
-int dn_comp(const char *, u_char *, int, u_char **, u_char **);
-
-int
-dn_comp(const char *exp_dn, u_char *comp_dn, u_char **dnptrs,
- u_char **lastdnptr, int length)
-{
-
- return __dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr);
-}
-
-#endif
diff --git a/libc/dns/resolv/__res_close.c b/libc/dns/resolv/__res_close.c
deleted file mode 100644
index 3af50b0..0000000
--- a/libc/dns/resolv/__res_close.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* $NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#if defined(__indr_reference)
-__indr_reference(__res_close, res_close)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include "resolv_private.h"
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef res_close
-void res_close(void);
-
-void
-res_close(void)
-{
-
- __res_close();
-}
-
-#endif
diff --git a/libc/dns/resolv/__res_send.c b/libc/dns/resolv/__res_send.c
deleted file mode 100644
index 198b05c..0000000
--- a/libc/dns/resolv/__res_send.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif
-
-#if defined(__indr_reference)
-__indr_reference(__res_send, res_send)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
-#include <resolv.h>
-#endif
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef res_send
-int res_send(const u_char *, int, u_char *, int);
-
-int
-res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
-{
-
- return __res_send(buf, buflen, ans, anssiz);
-}
-
-#endif
diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h
index 067be1f..86265bf 100644
--- a/libc/include/arpa/inet.h
+++ b/libc/include/arpa/inet.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _ARPA_INET_H_
#define _ARPA_INET_H_
@@ -34,8 +35,6 @@
__BEGIN_DECLS
-typedef uint32_t in_addr_t;
-
in_addr_t inet_addr(const char*);
int inet_aton(const char*, struct in_addr*);
in_addr_t inet_lnaof(struct in_addr);
diff --git a/libc/include/elf.h b/libc/include/elf.h
index 0975b7a..faae73e 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -69,14 +69,17 @@
#define PT_GNU_RELRO 0x6474e552
-#define STB_LOOS 10
-#define STB_HIOS 12
-#define STB_LOPROC 13
-#define STB_HIPROC 15
+#define STB_LOOS 10
+#define STB_HIOS 12
+#define STB_LOPROC 13
+#define STB_HIPROC 15
-#define STT_LOOS 10
-#define STT_HIOS 12
-#define STT_LOPROC 13
-#define STT_HIPROC 15
+#define STT_GNU_IFUNC 10
+#define STT_LOOS 10
+#define STT_HIOS 12
+#define STT_LOPROC 13
+#define STT_HIPROC 15
+
+#define R_386_IRELATIVE 42
#endif /* _ELF_H */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 4450bb6..32557d9 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -82,9 +82,9 @@
#if defined(__BIONIC_FORTIFY)
extern int __open_2(const char*, int);
-extern int __open_real(const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "open");
+extern int __open_real(const char*, int, ...) __RENAME(open);
extern int __openat_2(int, const char*, int);
-extern int __openat_real(int, const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "openat");
+extern int __openat_real(int, const char*, int, ...) __RENAME(openat);
__errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
__errordecl(__creat_too_many_args, "too many arguments");
diff --git a/libc/include/features.h b/libc/include/features.h
index 343c84d..a279c7f 100644
--- a/libc/include/features.h
+++ b/libc/include/features.h
@@ -25,34 +25,11 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _FEATURES_H_
#define _FEATURES_H_
-/* certain Linux-specific programs expect a <features.h> header file
- * that defines various features macros
- */
-
-/* we do include a number of BSD extensions */
-#define _BSD_SOURCE 1
-
-/* we do include a number of GNU extensions */
-#define _GNU_SOURCE 1
-
-/* C95 support */
-#undef __USE_ISOC95
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L
-# define __USE_ISOC95 1
-#endif
-
-/* C99 support */
-#undef __USE_ISOC99
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
-# define __USE_ISOC99 1
-#endif
-
-/* Posix support */
-#define __USE_POSIX 1
-#define __USE_POSIX2 1
-#define __USE_XPG 1
+/* Our <features.h> macro fun is all in <sys/cdefs.h>. */
+#include <sys/cdefs.h>
#endif /* _FEATURES_H_ */
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index bf3b498..44c7fc1 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _NETINET_IN_H_
#define _NETINET_IN_H_
@@ -43,6 +44,9 @@
#define INET_ADDRSTRLEN 16
+typedef uint16_t in_port_t;
+typedef uint32_t in_addr_t;
+
extern int bindresvport (int sd, struct sockaddr_in *sin);
static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
diff --git a/libc/include/sched.h b/libc/include/sched.h
index e43b6cc..6155ab7 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -52,7 +52,7 @@
extern int sched_getparam(pid_t, struct sched_param*);
extern int sched_rr_get_interval(pid_t, struct timespec*);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int clone(int (*)(void*), void*, int, void*, ...);
extern int unshare(int);
@@ -146,7 +146,7 @@
extern int __sched_cpucount(size_t setsize, cpu_set_t* set);
-#endif /* _GNU_SOURCE */
+#endif /* __USE_GNU */
__END_DECLS
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 9c6bd3f..516f8cb 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -38,6 +38,14 @@
#ifndef _STDIO_H_
#define _STDIO_H_
+/*
+ * This file must contain a reference to __gnuc_va_list so that GCC's
+ * fixincludes knows that that's what's being used for va_list, and so
+ * to leave our <stdio.h> alone. (fixincludes gets in the way of pointing
+ * one toolchain at various different sets of platform headers.)
+ * If you alter this comment, be sure to keep "__gnuc_va_list" in it!
+ */
+
#include <sys/cdefs.h>
#include <sys/types.h>
@@ -400,7 +408,7 @@
#endif
extern char* __fgets_chk(char*, int, FILE*, size_t);
-extern char* __fgets_real(char*, int, FILE*) __asm__(__USER_LABEL_PREFIX__ "fgets");
+extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
diff --git a/libc/include/string.h b/libc/include/string.h
index 8df68e3..643132d 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -180,8 +180,7 @@
return __builtin___memset_chk(s, c, n, __bos0(s));
}
-extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t)
- __asm__(__USER_LABEL_PREFIX__ "strlcpy");
+extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy);
extern size_t __strlcpy_chk(char *, const char *, size_t, size_t);
__BIONIC_FORTIFY_INLINE
@@ -204,8 +203,7 @@
return __strlcpy_chk(dest, src, size, bos);
}
-extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t)
- __asm__(__USER_LABEL_PREFIX__ "strlcat");
+extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat);
extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 0286616..79d8bca 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -267,20 +267,6 @@
#endif /* NO_KERNEL_RCSIDS */
#endif /* _KERNEL */
-#if !defined(_STANDALONE) && !defined(_KERNEL)
-#ifdef __GNUC__
-#define __RENAME(x) ___RENAME(x)
-#else
-#ifdef __lint__
-#define __RENAME(x) __symbolrename(x)
-#else
-#error "No function renaming possible"
-#endif /* __lint__ */
-#endif /* __GNUC__ */
-#else /* _STANDALONE || _KERNEL */
-#define __RENAME(x) no renaming in kernel or standalone environment
-#endif
-
/*
* A barrier to stop the optimizer from moving code or assume live
* register values. This is gcc specific, the version is more or less
@@ -359,64 +345,33 @@
#endif
/*
- * Macros for manipulating "link sets". Link sets are arrays of pointers
- * to objects, which are gathered up by the linker.
- *
- * Object format-specific code has provided us with the following macros:
- *
- * __link_set_add_text(set, sym)
- * Add a reference to the .text symbol `sym' to `set'.
- *
- * __link_set_add_rodata(set, sym)
- * Add a reference to the .rodata symbol `sym' to `set'.
- *
- * __link_set_add_data(set, sym)
- * Add a reference to the .data symbol `sym' to `set'.
- *
- * __link_set_add_bss(set, sym)
- * Add a reference to the .bss symbol `sym' to `set'.
- *
- * __link_set_decl(set, ptype)
- * Provide an extern declaration of the set `set', which
- * contains an array of the pointer type `ptype'. This
- * macro must be used by any code which wishes to reference
- * the elements of a link set.
- *
- * __link_set_start(set)
- * This points to the first slot in the link set.
- *
- * __link_set_end(set)
- * This points to the (non-existent) slot after the last
- * entry in the link set.
- *
- * __link_set_count(set)
- * Count the number of entries in link set `set'.
- *
- * In addition, we provide the following macros for accessing link sets:
- *
- * __link_set_foreach(pvar, set)
- * Iterate over the link set `set'. Because a link set is
- * an array of pointers, pvar must be declared as "type **pvar",
- * and the actual entry accessed as "*pvar".
- *
- * __link_set_entry(set, idx)
- * Access the link set entry at index `idx' from set `set'.
+ * Some BSD source needs these macros.
+ * Originally they embedded the rcs versions of each source file
+ * in the generated binary. We strip strings during build anyway,.
*/
-#define __link_set_foreach(pvar, set) \
- for (pvar = __link_set_start(set); pvar < __link_set_end(set); pvar++)
-
-#define __link_set_entry(set, idx) (__link_set_begin(set)[idx])
+#define __IDSTRING(_prefix,_s) /* nothing */
+#define __COPYRIGHT(_s) /* nothing */
+#define __FBSDID(_s) /* nothing */
+#define __RCSID(_s) /* nothing */
+#define __SCCSID(_s) /* nothing */
/*
- * Some of the FreeBSD sources used in Bionic need this.
- * Originally, this is used to embed the rcs versions of each source file
- * in the generated binary. We certainly don't want this in Bionic.
+ * _BSD_SOURCE and _GNU_SOURCE are expected to be defined by callers before
+ * any standard header file is included. In those header files we test
+ * against __USE_BSD and __USE_GNU. glibc does this in <features.h> but we
+ * do it in <sys/cdefs.h> instead because that's where our existing
+ * _POSIX_C_SOURCE tests were, and we're already confident that <sys/cdefs.h>
+ * is included everywhere it should be.
*/
-#define __FBSDID(s) /* nothing */
+#if defined(_BSD_SOURCE)
+# define __USE_BSD 1
+#endif
+
+#if defined(_GNU_SOURCE)
+# define __USE_GNU 1
+#endif
/*-
- * The following definitions are an extension of the behavior originally
- * implemented in <sys/_posix.h>, but with a different level of granularity.
* POSIX.1 requires that the macros we test be defined before any standard
* header file is included.
*
@@ -570,11 +525,24 @@
#endif
#define __bos0(s) __builtin_object_size((s), 0)
-#define __BIONIC_FORTIFY_INLINE \
- extern __inline__ \
- __attribute__ ((always_inline)) \
- __attribute__ ((gnu_inline))
+#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
#endif
#define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
+/* Used to tag non-static symbols that are private and never exposed by the shared library. */
+#define __LIBC_HIDDEN__ __attribute__((visibility("hidden")))
+
+/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */
+#ifdef __LP64__
+#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__
+#else
+#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__
+#endif
+
+/* Used to tag non-static symbols that are public and exposed by the shared library. */
+#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default")))
+
+/* Used to rename functions so that the compiler emits a call to 'x' rather than the function this was applied to. */
+#define __RENAME(x) __asm__(#x)
+
#endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h
index 4dd7dc3..6bb0a57 100644
--- a/libc/include/sys/cdefs_elf.h
+++ b/libc/include/sys/cdefs_elf.h
@@ -30,27 +30,13 @@
#ifndef _SYS_CDEFS_ELF_H_
#define _SYS_CDEFS_ELF_H_
-#ifdef __LEADING_UNDERSCORE
-#define _C_LABEL(x) __CONCAT(_,x)
-#define _C_LABEL_STRING(x) "_"x
-#else
-#define _C_LABEL(x) x
-#define _C_LABEL_STRING(x) x
-#endif
+#define __strong_alias(alias, sym) \
+ __asm__(".global " #alias "\n" \
+ #alias " = " #sym);
-#define ___RENAME(x) __asm__(___STRING(_C_LABEL(x)))
-
-#define __indr_reference(sym,alias) /* nada, since we do weak refs */
-
-#define __strong_alias(alias,sym) \
- __asm__(".global " _C_LABEL_STRING(#alias) "\n" \
- _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
-
-#define __weak_alias(alias,sym) \
- __asm__(".weak " _C_LABEL_STRING(#alias) "\n" \
- _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
-#define __weak_extern(sym) \
- __asm__(".weak " _C_LABEL_STRING(#sym));
+#define __weak_alias(alias,sym) \
+ __asm__(".weak " #alias "\n" \
+ #alias " = " #sym);
/* We use __warnattr instead of __warn_references.
* TODO: remove this and put an empty definition in one of the upstream-* compatibility headers.
@@ -58,74 +44,4 @@
#define __warn_references(sym,msg) \
/*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/
-#define __SECTIONSTRING(_sec, _str) \
- __asm__(".section " #_sec "\n\t.asciz \"" _str "\"\n\t.previous")
-
-/* Used to tag non-static symbols that are private and never exposed by the shared library. */
-#define __LIBC_HIDDEN__ __attribute__((visibility ("hidden")))
-
-/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */
-#ifdef __LP64__
-#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__
-#else
-#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__
-#endif
-
-/* Used to tag non-static symbols that are public and exposed by the shared library. */
-#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default")))
-
-#define __IDSTRING(_n,_s) __SECTIONSTRING(.ident,_s)
-
-#define __RCSID(_s) __IDSTRING(rcsid,_s)
-#define __SCCSID(_s)
-#define __SCCSID2(_s)
-#if 0 /* XXX userland __COPYRIGHTs have \ns in them */
-#define __COPYRIGHT(_s) __SECTIONSTRING(.copyright,_s)
-#else
-#define __COPYRIGHT(_s) \
- static const char copyright[] \
- __attribute__((__unused__,__section__(".copyright"))) = _s
-#endif
-
-#define __KERNEL_RCSID(_n, _s) __RCSID(_s)
-#define __KERNEL_SCCSID(_n, _s)
-#if 0 /* XXX see above */
-#define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s)
-#else
-#define __KERNEL_COPYRIGHT(_n, _s) __SECTIONSTRING(.copyright, _s)
-#endif
-
-#ifndef __lint__
-#define __link_set_make_entry(set, sym) \
- static void const * const __link_set_##set##_sym_##sym \
- __section("link_set_" #set) __used = &sym
-#define __link_set_make_entry2(set, sym, n) \
- static void const * const __link_set_##set##_sym_##sym##_##n \
- __section("link_set_" #set) __used = &sym[n]
-#else
-#define __link_set_make_entry(set, sym) \
- extern void const * const __link_set_##set##_sym_##sym
-#define __link_set_make_entry2(set, sym, n) \
- extern void const * const __link_set_##set##_sym_##sym##_##n
-#endif /* __lint__ */
-
-#define __link_set_add_text(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_data(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_bss(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_text2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_rodata2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_data2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_bss2(set, sym, n) __link_set_make_entry2(set, sym, n)
-
-#define __link_set_decl(set, ptype) \
- extern ptype * const __start_link_set_##set[]; \
- extern ptype * const __stop_link_set_##set[] \
-
-#define __link_set_start(set) (__start_link_set_##set)
-#define __link_set_end(set) (__stop_link_set_##set)
-
-#define __link_set_count(set) \
- (__link_set_end(set) - __link_set_start(set))
-
#endif /* !_SYS_CDEFS_ELF_H_ */
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index ae2f238..a8840ff 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -294,8 +294,7 @@
#if defined(__BIONIC_FORTIFY)
__errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*);
-extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*)
- __asm__(__USER_LABEL_PREFIX__ "recvfrom");
+extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom);
__BIONIC_FORTIFY_INLINE
ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) {
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index c0c168b..b56ffa4 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
@@ -162,7 +163,7 @@
#if defined(__BIONIC_FORTIFY)
extern mode_t __umask_chk(mode_t);
-extern mode_t __umask_real(mode_t) __asm__(__USER_LABEL_PREFIX__ "umask");
+extern mode_t __umask_real(mode_t) __RENAME(umask);
__errordecl(__umask_invalid_mode, "umask called with invalid mode");
__BIONIC_FORTIFY_INLINE
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 7fbafdf..34ae2bc 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _UNISTD_H_
#define _UNISTD_H_
@@ -112,7 +113,7 @@
extern int fchdir(int);
extern int rmdir(const char *);
extern int pipe(int *);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int pipe2(int *, int);
#endif
extern int chroot(const char *);
@@ -143,7 +144,7 @@
extern int dup(int);
extern int dup2(int, int);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int dup3(int, int, int);
#endif
extern int fcntl(int, int, ...);
@@ -201,8 +202,7 @@
extern ssize_t __read_chk(int, void*, size_t, size_t);
__errordecl(__read_dest_size_error, "read called with size bigger than destination");
__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
-extern ssize_t __read_real(int, void*, size_t)
- __asm__(__USER_LABEL_PREFIX__ "read");
+extern ssize_t __read_real(int, void*, size_t) __RENAME(read);
__BIONIC_FORTIFY_INLINE
ssize_t read(int fd, void* buf, size_t count) {
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 58a10e0..8326730 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -3,12 +3,18 @@
import glob
import os
import re
-import string
import subprocess
import sys
+only_unwanted = False
+if len(sys.argv) > 1:
+ if sys.argv[1] in ('-u', '--unwanted'):
+ only_unwanted = True
+
toolchain = os.environ['ANDROID_TOOLCHAIN']
arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
+if arch == 'aarch64':
+ arch = 'arm64'
def GetSymbolsFromSo(so_file):
# Example readelf output:
@@ -50,6 +56,15 @@
return glibc_to_bionic_names[name]
return name
+def GetNdkIgnored():
+ global arch
+ symbols = set()
+ files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' %
+ (os.getenv('ANDROID_BUILD_TOP'), arch))
+ for f in files:
+ symbols |= set(open(f, 'r').read().splitlines())
+ return symbols
+
glibc_to_bionic_names = {
'__res_init': 'res_init',
'__res_mkquery': 'res_mkquery',
@@ -59,6 +74,7 @@
glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*')
bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so')
+ndk_ignored = GetNdkIgnored()
glibc = map(MangleGlibcNameToBionic, glibc)
@@ -100,6 +116,16 @@
'__errno',
'__fe_dfl_env',
'__get_h_errno',
+ '__fpclassifyd',
+ '__isfinite',
+ '__isfinitef',
+ '__isfinitel',
+ '__isnormal',
+ '__isnormalf',
+ '__isnormall',
+ '__sF',
+ '__pthread_cleanup_pop',
+ '__pthread_cleanup_push',
])
# bionic exposes various Linux features that glibc doesn't.
linux_stuff = set([
@@ -133,21 +159,43 @@
'mknodat',
'stat',
'stat64',
+ 'optreset',
+ 'sigsetjmp',
+])
+# These exist in glibc, but under slightly different names (generally one extra
+# or one fewer _). TODO: check against glibc names.
+libresolv_stuff = set([
+ '__res_send_setqhook',
+ '__res_send_setrhook',
+ '_resolv_flush_cache_for_net',
+ '_resolv_set_nameservers_for_net',
+ 'dn_expand',
+ 'nsdispatch',
+])
+# Implementation details we know we export (and can't get away from).
+known = set([
+ '_ctype_',
+ '__libc_init',
])
-print 'glibc:'
-for symbol in sorted(glibc):
- print symbol
+if not only_unwanted:
+ print 'glibc:'
+ for symbol in sorted(glibc):
+ print symbol
-print
-print 'bionic:'
-for symbol in sorted(bionic):
- print symbol
+ print
+ print 'bionic:'
+ for symbol in sorted(bionic):
+ print symbol
-print
-print 'in bionic but not glibc:'
-allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | std_stuff | weird_stuff)
+ print
+ print 'in bionic but not glibc:'
+
+allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
+ std_stuff | weird_stuff | libresolv_stuff | known)
for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
+ if symbol in ndk_ignored:
+ symbol += '*'
print symbol
sys.exit(0)
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 316e05b..4619ec6 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -4,6 +4,7 @@
# the header files listing all available system calls, and the
# makefiles used to build all the stubs.
+import atexit
import commands
import filecmp
import glob
@@ -12,13 +13,16 @@
import shutil
import stat
import sys
+import tempfile
from bionic_utils import *
-bionic_libc_root = os.environ["ANDROID_BUILD_TOP"] + "/bionic/libc/"
-
# temp directory where we store all intermediate files
-bionic_temp = "/tmp/bionic_gensyscalls/"
+bionic_temp = tempfile.mkdtemp(prefix="bionic_gensyscalls");
+# Make sure the directory is deleted when the script exits.
+atexit.register(shutil.rmtree, bionic_temp)
+
+bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
warning = "Generated by gensyscalls.py. Do not edit."
@@ -34,9 +38,10 @@
def create_file(relpath):
- dir = os.path.dirname(bionic_temp + relpath)
+ full_path = os.path.join(bionic_temp, relpath)
+ dir = os.path.dirname(full_path)
make_dir(dir)
- return open(bionic_temp + relpath, "w")
+ return open(full_path, "w")
syscall_stub_header = "/* " + warning + " */\n" + \
@@ -267,7 +272,7 @@
# This lets us support regular system calls like __NR_write and also weird
# ones like __ARM_NR_cacheflush, where the NR doesn't come at the start.
def make__NR_name(name):
- if name.startswith("__"):
+ if name.startswith("__ARM_NR_"):
return name
else:
return "__NR_%s" % (name)
@@ -446,15 +451,15 @@
glibc_fp.write("#define _BIONIC_GLIBC_SYSCALLS_H_\n")
glibc_fp.write("#if defined(__aarch64__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-generic/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-generic/unistd.h"))
glibc_fp.write("#elif defined(__arm__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-arm/asm/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-arm/asm/unistd.h"))
glibc_fp.write("#elif defined(__mips__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-mips/asm/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-mips/asm/unistd.h"))
glibc_fp.write("#elif defined(__i386__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_32.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-x86/asm/unistd_32.h"))
glibc_fp.write("#elif defined(__x86_64__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_64.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-x86/asm/unistd_64.h"))
glibc_fp.write("#endif\n")
glibc_fp.write("#endif /* _BIONIC_GLIBC_SYSCALLS_H_ */\n")
@@ -478,14 +483,13 @@
def regenerate(self):
D("scanning for existing architecture-specific stub files...")
- bionic_libc_root_len = len(bionic_libc_root)
-
for arch in all_arches:
- arch_path = bionic_libc_root + "arch-" + arch
- D("scanning " + arch_path)
- files = glob.glob(arch_path + "/syscalls/*.S")
- for f in files:
- self.old_stubs.append(f[bionic_libc_root_len:])
+ arch_dir = "arch-" + arch
+ D("scanning " + os.path.join(bionic_libc_root, arch_dir))
+ rel_path = os.path.join(arch_dir, "syscalls")
+ for file in os.listdir(os.path.join(bionic_libc_root, rel_path)):
+ if file.endswith(".S"):
+ self.old_stubs.append(os.path.join(rel_path, file))
D("found %d stub files" % len(self.old_stubs))
@@ -503,13 +507,15 @@
edits = []
for stub in self.new_stubs + self.other_files:
- if not os.path.exists(bionic_libc_root + stub):
+ tmp_file = os.path.join(bionic_temp, stub)
+ libc_file = os.path.join(bionic_libc_root, stub)
+ if not os.path.exists(libc_file):
# new file, git add it
D("new file: " + stub)
- adds.append(bionic_libc_root + stub)
- shutil.copyfile(bionic_temp + stub, bionic_libc_root + stub)
+ adds.append(libc_file)
+ shutil.copyfile(tmp_file, libc_file)
- elif not filecmp.cmp(bionic_temp + stub, bionic_libc_root + stub):
+ elif not filecmp.cmp(tmp_file, libc_file):
D("changed file: " + stub)
edits.append(stub)
@@ -517,7 +523,7 @@
for stub in self.old_stubs:
if not stub in self.new_stubs:
D("deleted file: " + stub)
- deletes.append(bionic_libc_root + stub)
+ deletes.append(os.path.join(bionic_libc_root, stub))
if not DRY_RUN:
if adds:
@@ -526,10 +532,11 @@
commands.getoutput("git rm " + " ".join(deletes))
if edits:
for file in edits:
- shutil.copyfile(bionic_temp + file, bionic_libc_root + file)
- commands.getoutput("git add " + " ".join((bionic_libc_root + file) for file in edits))
+ shutil.copyfile(os.path.join(bionic_temp, file),
+ os.path.join(bionic_libc_root, file))
+ commands.getoutput("git add " + " ".join((os.path.join(bionic_libc_root, file)) for file in edits))
- commands.getoutput("git add %s%s" % (bionic_libc_root,"SYSCALLS.TXT"))
+ commands.getoutput("git add %s" % (os.path.join(bionic_libc_root, "SYSCALLS.TXT")))
if (not adds) and (not deletes) and (not edits):
D("no changes detected!")
@@ -539,5 +546,5 @@
D_setlevel(1)
state = State()
-state.process_file(bionic_libc_root+"SYSCALLS.TXT")
+state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
state.regenerate()
diff --git a/libc/upstream-freebsd/android/include/freebsd-compat.h b/libc/upstream-freebsd/android/include/freebsd-compat.h
index d5f1425..b44b94a 100644
--- a/libc/upstream-freebsd/android/include/freebsd-compat.h
+++ b/libc/upstream-freebsd/android/include/freebsd-compat.h
@@ -17,7 +17,7 @@
#ifndef _BIONIC_FREEBSD_COMPAT_H_included
#define _BIONIC_FREEBSD_COMPAT_H_included
-#define __USE_BSD
+#define _BSD_SOURCE
#define REPLACE_GETOPT
/*
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 84be931..04bc728 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -17,6 +17,9 @@
#ifndef _BIONIC_NETBSD_COMPAT_H_included
#define _BIONIC_NETBSD_COMPAT_H_included
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
// NetBSD uses _DIAGASSERT to null-check arguments and the like.
#include <assert.h>
#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
@@ -24,9 +27,6 @@
// TODO: update our <sys/cdefs.h> to support this properly.
#define __type_fit(t, a) (0 == 0)
-#define _GNU_SOURCE
-#define __USE_BSD
-
// TODO: we don't yet have thread-safe environment variables.
#define __readlockenv() 0
#define __unlockenv() 0
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 34ad2c5..488b5f9 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -17,11 +17,11 @@
#ifndef _BIONIC_OPENBSD_COMPAT_H_included
#define _BIONIC_OPENBSD_COMPAT_H_included
+#define _BSD_SOURCE
+
#include <sys/cdefs.h>
#include <stddef.h> // For size_t.
-#define __USE_BSD
-
/* OpenBSD's <ctype.h> uses these names, which conflicted with stlport.
* Additionally, we changed the numeric/digit type from N to D for libcxx.
*/
diff --git a/libm/include/math.h b/libm/include/math.h
index 4faec33..c51f3af 100644
--- a/libm/include/math.h
+++ b/libm/include/math.h
@@ -462,11 +462,11 @@
#endif /* __ISO_C_VISIBLE >= 1999 */
-#if defined(_GNU_SOURCE)
+#if defined(__USE_GNU)
void sincos(double, double*, double*);
void sincosf(float, float*, float*);
void sincosl(long double, long double*, long double*);
-#endif /* _GNU_SOURCE */
+#endif /* __USE_GNU */
#pragma GCC visibility pop
__END_DECLS
diff --git a/libm/sincos.c b/libm/sincos.c
index ad75549..a5608cf 100644
--- a/libm/sincos.c
+++ b/libm/sincos.c
@@ -22,8 +22,8 @@
* 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.
- *
*/
+
#define _GNU_SOURCE 1
#include <math.h>
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 52eb56a..8a7c073 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -466,6 +466,29 @@
return NULL;
}
+static void resolve_ifunc_symbols(soinfo* si) {
+
+ phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias);
+
+ TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES");
+
+ for (size_t i = 0; i < si->nchain; ++i) {
+ ElfW(Sym)* s = &si->symtab[i];
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+ // The address of the ifunc in the symbol table is the address of the
+ // function that chooses the function to which the ifunc will refer.
+ // In order to return the proper value, we run the choosing function
+ // in the linker and then return its result (minus the base offset).
+ TRACE_TYPE(IFUNC, "FOUND IFUNC");
+ ElfW(Addr) (*ifunc_ptr)();
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
+ s->st_value = (ifunc_ptr() - si->base);
+ TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value);
+ }
+ }
+ phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias);
+}
+
static unsigned elfhash(const char* _name) {
const unsigned char* name = reinterpret_cast<const unsigned char*>(_name);
unsigned h = 0, g;
@@ -786,6 +809,10 @@
return NULL;
}
+ // if the library has any ifuncs, we will need to resolve them so that dlsym
+ // can handle them properly
+ resolve_ifunc_symbols(si);
+
return si;
}
@@ -899,6 +926,53 @@
protect_data(PROT_READ);
}
+// ifuncs are only defined for x86
+#if defined(__i386__)
+static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) {
+ for (size_t idx = 0; idx < count; ++idx, ++rel) {
+ ElfW(Sym)* s;
+ soinfo* lsi;
+ unsigned type = ELFW(R_TYPE)(rel->r_info);
+ unsigned sym = ELFW(R_SYM)(rel->r_info);
+ ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias);
+ ElfW(Addr) sym_addr = 0;
+ const char* sym_name = NULL;
+ sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
+ s = soinfo_do_lookup(si, sym_name, &lsi, needed);
+
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) {
+ TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr));
+ ElfW(Addr) (*ifunc_ptr)();
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_ptr();
+ }
+ }
+}
+#endif
+
+#if defined(__x86_64__)
+static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) {
+ for (size_t idx = 0; idx < count; ++idx, ++rela) {
+ ElfW(Sym)* s;
+ soinfo* lsi;
+ unsigned type = ELFW(R_TYPE)(rela->r_info);
+ unsigned sym = ELFW(R_SYM)(rela->r_info);
+ ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + si->load_bias);
+ ElfW(Addr) sym_addr = 0;
+ const char* sym_name = NULL;
+ sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
+ s = soinfo_do_lookup(si, sym_name, &lsi, needed);
+
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) {
+ TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend));
+ ElfW(Addr) (*ifunc_ptr)();
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_ptr();
+ }
+ }
+}
+#endif
+
#if defined(USE_RELA)
static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) {
ElfW(Sym)* s;
@@ -1110,7 +1184,11 @@
MARK(rela->r_offset);
TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc),
static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
- *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+ si->set_has_ifuncs(true);
+ } else {
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
+ }
break;
case R_X86_64_GLOB_DAT:
count_relocation(kRelocAbsolute);
@@ -1289,7 +1367,11 @@
count_relocation(kRelocAbsolute);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
- *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+ si->set_has_ifuncs(true);
+ } else {
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
+ }
break;
case R_386_GLOB_DAT:
count_relocation(kRelocAbsolute);
@@ -1549,6 +1631,14 @@
st_ino = ino;
}
+void soinfo::set_has_ifuncs(bool ifuncs) {
+ if ((this->flags & FLAG_NEW_SOINFO) == 0) {
+ return;
+ }
+
+ has_ifuncs = ifuncs;
+}
+
dev_t soinfo::get_st_dev() {
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
return 0;
@@ -1565,6 +1655,14 @@
return st_ino;
}
+bool soinfo::get_has_ifuncs() {
+ if ((this->flags & FLAG_NEW_SOINFO) == 0) {
+ return false;
+ }
+
+ return has_ifuncs;
+}
+
// This is a return on get_children() in case
// 'this->flags' does not have FLAG_NEW_SOINFO set.
static soinfo::soinfo_list_t g_empty_list;
@@ -1949,6 +2047,18 @@
}
#endif
+ // if there are ifuncs, we need to do an additional relocation pass.
+ // they cannot be resolved until the rest of the relocations are done
+ // because we need to call the resolution function which may be waiting
+ // on relocations.
+ if(si->get_has_ifuncs()) {
+#if defined(__i386__)
+ soinfo_ifunc_relocate(si, si->plt_rel, si->plt_rel_count, needed);
+#elif defined(__x86_64__)
+ soinfo_ifunc_relocate(si, si->plt_rela, si->plt_rela_count, needed);
+#endif
+ }
+
#if defined(__mips__)
if (!mips_relocate_got(si, needed)) {
return false;
diff --git a/linker/linker.h b/linker/linker.h
index 374652e..d7cf24b 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -204,8 +204,12 @@
void set_st_dev(dev_t st_dev);
void set_st_ino(ino_t st_ino);
+ void set_has_ifuncs(bool ifunc);
ino_t get_st_ino();
dev_t get_st_dev();
+ bool get_has_ifuncs();
+
+
soinfo_list_t& get_children();
@@ -218,6 +222,8 @@
// when FLAG_NEW_SOINFO is set in this->flags.
unsigned int version;
+ bool has_ifuncs;
+
dev_t st_dev;
ino_t st_ino;
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 3faa38e..0c7a784 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -42,6 +42,7 @@
#define TRACE_DEBUG 1
#define DO_TRACE_LOOKUP 1
#define DO_TRACE_RELO 1
+#define DO_TRACE_IFUNC 1
#define TIMING 0
#define STATS 0
#define COUNT_PAGES 0
diff --git a/tests/atexit_test.cpp b/tests/atexit_test.cpp
index e01220e..e92889d 100644
--- a/tests/atexit_test.cpp
+++ b/tests/atexit_test.cpp
@@ -24,20 +24,33 @@
#include <string>
-TEST(atexit, dlclose) {
+TEST(atexit, sofile) {
std::string atexit_call_sequence;
bool valid_this_in_static_dtor = false;
+ bool attr_dtor_called = false;
+
void* handle = dlopen("libtest_atexit.so", RTLD_NOW);
- ASSERT_TRUE(handle != NULL);
+ ASSERT_TRUE(handle != nullptr);
+
+ typedef int (*int_fn)(void);
+ int_fn get_cxx_ctor_called, get_attr_ctor_called;
+ get_cxx_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_cxx_ctor_called"));
+ get_attr_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_attr_ctor_called"));
+ ASSERT_TRUE(get_cxx_ctor_called != nullptr);
+ ASSERT_TRUE(get_attr_ctor_called != nullptr);
+
+ ASSERT_EQ(1, get_cxx_ctor_called());
+ ASSERT_EQ(1, get_attr_ctor_called());
void* sym = dlsym(handle, "register_atexit");
- ASSERT_TRUE(sym != NULL);
- reinterpret_cast<void (*)(std::string*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor);
+ ASSERT_TRUE(sym != nullptr);
+ reinterpret_cast<void (*)(std::string*, bool*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor, &attr_dtor_called);
ASSERT_EQ(0, dlclose(handle));
// this test verifies atexit call from atexit handler. as well as the order of calls
ASSERT_EQ("Humpty Dumpty sat on a wall", atexit_call_sequence);
ASSERT_TRUE(valid_this_in_static_dtor);
+ ASSERT_TRUE(attr_dtor_called);
}
class TestMainStaticDtorClass {
@@ -57,7 +70,7 @@
static const TestMainStaticDtorClass* expected_this;
};
-const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = NULL;
+const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = nullptr;
static void atexit_func5() {
fprintf(stderr, "5");
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index c2c9286..fc788ac 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -87,6 +87,39 @@
ASSERT_EQ(0, dlclose(handle2));
}
+// ifuncs are only supported on intel for now
+#if defined(__i386__) || defined(__x86_64__)
+TEST(dlfcn, ifunc) {
+ const char* (*foo_ptr)();
+ const char* (*foo_library_ptr)();
+
+ // ifunc's choice depends on whether IFUNC_CHOICE has a value
+ // first check the set case
+ setenv("IFUNC_CHOICE", "set", 1);
+ void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+ ASSERT_TRUE(handle != NULL);
+ *(void **)(&foo_ptr) = dlsym(handle, "foo");
+ *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+ ASSERT_TRUE(foo_ptr != NULL);
+ ASSERT_TRUE(foo_library_ptr != NULL);
+ ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0);
+ ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0);
+ dlclose(handle);
+
+ // then check the unset case
+ unsetenv("IFUNC_CHOICE");
+ handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+ ASSERT_TRUE(handle != NULL);
+ *(void **)(&foo_ptr) = dlsym(handle, "foo");
+ *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+ ASSERT_TRUE(foo_ptr != NULL);
+ ASSERT_TRUE(foo_library_ptr != NULL);
+ ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0);
+ ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0);
+ dlclose(handle);
+}
+#endif
+
TEST(dlfcn, dlopen_failure) {
void* self = dlopen("/does/not/exist", RTLD_NOW);
ASSERT_TRUE(self == NULL);
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
index 51c9db8..b331150 100644
--- a/tests/getauxval_test.cpp
+++ b/tests/getauxval_test.cpp
@@ -15,7 +15,6 @@
*/
#include <sys/cdefs.h>
-#include <features.h>
#include <gtest/gtest.h>
// getauxval() was only added as of glibc version 2.16.
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 75df539..b1cc836 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -17,6 +17,7 @@
LOCAL_PATH := $(call my-dir)
TEST_PATH := $(LOCAL_PATH)/..
+common_cppflags += -std=gnu++11
# -----------------------------------------------------------------------------
# Library used by dlfcn tests.
# -----------------------------------------------------------------------------
@@ -115,6 +116,20 @@
include $(TEST_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
+# Library used by ifunc tests
+# -----------------------------------------------------------------------------
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
+ libtest_ifunc_src_files := \
+ dlopen_testlib_ifunc.c
+
+ LOCAL_SDK_VERSION := current
+ module := libtest_ifunc
+ build_type := target
+ build_target := SHARED_LIBRARY
+ include $(TEST_PATH)/Android.build.mk
+endif
+
+# -----------------------------------------------------------------------------
# Library used by atexit tests
# -----------------------------------------------------------------------------
diff --git a/tests/libs/atexit_testlib.cpp b/tests/libs/atexit_testlib.cpp
index d35f57b..314e8de 100644
--- a/tests/libs/atexit_testlib.cpp
+++ b/tests/libs/atexit_testlib.cpp
@@ -19,12 +19,19 @@
#include <string>
// use external control number from main test
-static std::string* atexit_sequence = NULL;
-static bool* atexit_valid_this_in_static_dtor = NULL;
+static std::string* atexit_sequence = nullptr;
+static bool* atexit_valid_this_in_static_dtor = nullptr;
+static bool* atexit_attr_dtor_called = nullptr;
+
+static int cxx_ctor_called = 0;
+static int attr_ctor_called = 0;
static class AtExitStaticClass {
public:
- AtExitStaticClass() { expected_this = this; }
+ AtExitStaticClass() {
+ expected_this = this;
+ cxx_ctor_called = 1;
+ }
~AtExitStaticClass() {
if (atexit_valid_this_in_static_dtor) {
*atexit_valid_this_in_static_dtor = (expected_this == this);
@@ -35,7 +42,7 @@
} static_obj;
-const AtExitStaticClass* AtExitStaticClass::expected_this = NULL;
+const AtExitStaticClass* AtExitStaticClass::expected_this = nullptr;
// 4
static void atexit_handler_from_atexit_from_atexit2() {
@@ -66,10 +73,30 @@
*atexit_sequence += " a wall";
}
-extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor) {
+// attribute c-tor and d-tor
+static void __attribute__((constructor)) atexit_attr_ctor() {
+ attr_ctor_called = 1;
+}
+
+static void __attribute__((destructor)) atexit_attr_dtor() {
+ if (atexit_attr_dtor_called) {
+ *atexit_attr_dtor_called = true;
+ }
+}
+
+extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor, bool* attr_dtor_called) {
atexit_sequence = sequence;
atexit_valid_this_in_static_dtor = valid_this_in_static_dtor;
+ atexit_attr_dtor_called = attr_dtor_called;
atexit(atexit_handler_regular);
atexit(atexit_handler_with_atexit);
}
+extern "C" int get_cxx_ctor_called() {
+ return cxx_ctor_called;
+}
+
+extern "C" int get_attr_ctor_called() {
+ return attr_ctor_called;
+}
+
diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c
new file mode 100644
index 0000000..1c4bafa
--- /dev/null
+++ b/tests/libs/dlopen_testlib_ifunc.c
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+
+const char* f1() {
+ return "unset";
+}
+
+const char* f2() {
+ return "set";
+}
+
+void* foo_ifunc() {
+ char* choice = getenv("IFUNC_CHOICE");
+ return choice == NULL ? f1 : f2;
+}
+
+const char* foo_library() {
+ return foo();
+}
\ No newline at end of file
diff --git a/tests/math_sincos_test.cpp b/tests/math_sincos_test.cpp
index 0fab2c2..f2e30de 100644
--- a/tests/math_sincos_test.cpp
+++ b/tests/math_sincos_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define _GNU_SOURCE 1
+
#include <math.h>
#include <gtest/gtest.h>
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 241c4a0..c9ead8d 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -17,7 +17,6 @@
#include <time.h>
#include <errno.h>
-#include <features.h>
#include <gtest/gtest.h>
#include <pthread.h>
#include <signal.h>
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index eca3c5e..c887f8a 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -19,7 +19,6 @@
#if defined(__BIONIC__)
#define HAVE_UCHAR 1
#elif defined(__GLIBC__)
-#include <features.h>
#define HAVE_UCHAR __GLIBC_PREREQ(2, 16)
#endif