resolved conflicts for merge of c8f6b82f to lmp-dev-plus-aosp

Change-Id: I03a4645eb5fbb54e41da25018729b270ba0ed48e
diff --git a/libc/Android.mk b/libc/Android.mk
index 5098171..c495e43 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -38,8 +38,6 @@
 # =========================================================
 libc_common_src_files := \
     bionic/bindresvport.c \
-    bionic/daemon.c \
-    bionic/err.c \
     bionic/ether_aton.c \
     bionic/ether_ntoa.c \
     bionic/fts.c \
@@ -62,6 +60,7 @@
     bionic/system_properties_compat.c \
     stdio/snprintf.c\
     stdio/sprintf.c \
+    stdio/stdio_ext.cpp \
 
 # Fortify implementations of libc functions.
 libc_common_src_files += \
@@ -121,6 +120,7 @@
     bionic/getpgrp.cpp \
     bionic/getpid.cpp \
     bionic/gettid.cpp \
+    bionic/__gnu_basename.cpp \
     bionic/inotify_init.cpp \
     bionic/lchown.cpp \
     bionic/lfs64_support.cpp \
@@ -132,6 +132,7 @@
     bionic/link.cpp \
     bionic/locale.cpp \
     bionic/lstat.cpp \
+    bionic/malloc_info.cpp \
     bionic/mbrtoc16.cpp \
     bionic/mbrtoc32.cpp \
     bionic/mbstate.cpp \
@@ -334,6 +335,9 @@
     upstream-openbsd/lib/libc/crypt/arc4random_uniform.c \
     upstream-openbsd/lib/libc/gen/alarm.c \
     upstream-openbsd/lib/libc/gen/ctype_.c \
+    upstream-openbsd/lib/libc/gen/daemon.c \
+    upstream-openbsd/lib/libc/gen/err.c \
+    upstream-openbsd/lib/libc/gen/errx.c \
     upstream-openbsd/lib/libc/gen/exec.c \
     upstream-openbsd/lib/libc/gen/fnmatch.c \
     upstream-openbsd/lib/libc/gen/ftok.c \
@@ -343,6 +347,12 @@
     upstream-openbsd/lib/libc/gen/time.c \
     upstream-openbsd/lib/libc/gen/tolower_.c \
     upstream-openbsd/lib/libc/gen/toupper_.c \
+    upstream-openbsd/lib/libc/gen/verr.c \
+    upstream-openbsd/lib/libc/gen/verrx.c \
+    upstream-openbsd/lib/libc/gen/vwarn.c \
+    upstream-openbsd/lib/libc/gen/vwarnx.c \
+    upstream-openbsd/lib/libc/gen/warn.c \
+    upstream-openbsd/lib/libc/gen/warnx.c \
     upstream-openbsd/lib/libc/locale/btowc.c \
     upstream-openbsd/lib/libc/locale/mbrlen.c \
     upstream-openbsd/lib/libc/locale/mbstowcs.c \
@@ -388,6 +398,7 @@
     upstream-openbsd/lib/libc/stdio/fgetws.c \
     upstream-openbsd/lib/libc/stdio/fileno.c \
     upstream-openbsd/lib/libc/stdio/findfp.c \
+    upstream-openbsd/lib/libc/stdio/fmemopen.c \
     upstream-openbsd/lib/libc/stdio/fprintf.c \
     upstream-openbsd/lib/libc/stdio/fpurge.c \
     upstream-openbsd/lib/libc/stdio/fputc.c \
@@ -416,6 +427,8 @@
     upstream-openbsd/lib/libc/stdio/getwchar.c \
     upstream-openbsd/lib/libc/stdio/makebuf.c \
     upstream-openbsd/lib/libc/stdio/mktemp.c \
+    upstream-openbsd/lib/libc/stdio/open_memstream.c \
+    upstream-openbsd/lib/libc/stdio/open_wmemstream.c \
     upstream-openbsd/lib/libc/stdio/perror.c \
     upstream-openbsd/lib/libc/stdio/printf.c \
     upstream-openbsd/lib/libc/stdio/putc.c \
@@ -501,7 +514,10 @@
 libc_common_cflags += -DTARGET_USES_LOGD
 endif
 
-use_clang := false
+use_clang := $(USE_CLANG_PLATFORM_BUILD)
+ifeq ($(use_clang),)
+  use_clang := false
+endif
 
 # Try to catch typical 32-bit assumptions that break with 64-bit pointers.
 libc_common_cflags += \
@@ -637,7 +653,13 @@
     upstream-netbsd/lib/libc/isc/ev_timers.c \
     upstream-netbsd/lib/libc/resolv/mtctxres.c \
 
-LOCAL_CFLAGS := \
+# We use the OpenBSD res_random.
+LOCAL_CFLAGS += \
+    -Dres_randomid=__res_randomid
+LOCAL_SRC_FILES += \
+    upstream-openbsd/lib/libc/net/res_random.c \
+
+LOCAL_CFLAGS += \
     $(libc_common_cflags) \
     -DANDROID_CHANGES \
     -DINET6 \
@@ -731,6 +753,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(libc_upstream_openbsd_src_files)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+  # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
+  LOCAL_CLANG := false
+else
+  LOCAL_CLANG := $(use_clang)
+endif
+
 LOCAL_CFLAGS := \
     $(libc_common_cflags) \
     -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter \
@@ -744,7 +773,6 @@
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_MODULE := libc_openbsd
-LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
@@ -763,6 +791,13 @@
 
 LOCAL_SRC_FILES_32 := $(libc_upstream_openbsd_gdtoa_src_files_32)
 LOCAL_SRC_FILES_64 := $(libc_upstream_openbsd_gdtoa_src_files_64)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+  # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
+  LOCAL_CLANG := false
+else
+  LOCAL_CLANG := $(use_clang)
+endif
+
 LOCAL_CFLAGS := \
     $(libc_common_cflags) \
     -Wno-sign-compare -Wno-uninitialized \
@@ -776,7 +811,6 @@
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_MODULE := libc_gdtoa
-LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
@@ -794,6 +828,11 @@
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -Wframe-larger-than=2048 \
 
+ifeq ($(TARGET_ARCH),x86_64)
+  # Clang assembler has problem with ssse3-strcmp-slm.S, http://b/17302991
+  LOCAL_CLANG_ASFLAGS += -no-integrated-as
+endif
+
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 38ae831..bfa13b7 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -315,7 +315,7 @@
 int     cacheflush:__ARM_NR_cacheflush(long start, long end, long flags)  arm
 
 # MIPS-specific
-int     _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
+int     _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
 int     __set_tls:set_thread_area(void*) mips,mips64
 
 # x86-specific
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..6a25a12 100644
--- a/libc/arch-arm/bionic/sigsetjmp.S
+++ b/libc/arch-arm/bionic/sigsetjmp.S
@@ -33,8 +33,6 @@
  * SUCH DAMAGE.
  */
 
-#define _ALIGN_TEXT .align 0
-
 #include <private/bionic_asm.h>
 #include <machine/setjmp.h>
 
@@ -50,8 +48,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 +59,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..70dbe67 100644
--- a/libc/arch-arm/include/machine/asm.h
+++ b/libc/arch-arm/include/machine/asm.h
@@ -38,9 +38,7 @@
 #ifndef _ARM32_ASM_H_
 #define _ARM32_ASM_H_
 
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 0
-#endif
+#define __bionic_asm_align 0
 
 #undef __bionic_asm_custom_entry
 #undef __bionic_asm_custom_end
@@ -50,10 +48,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..2bea043 100644
--- a/libc/arch-arm64/include/machine/asm.h
+++ b/libc/arch-arm64/include/machine/asm.h
@@ -38,17 +38,9 @@
 #ifndef _AARCH64_ASM_H_
 #define _AARCH64_ASM_H_
 
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 0
-#endif
+#define __bionic_asm_align 0
 
 #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/arch-mips/include/machine/asm.h b/libc/arch-mips/include/machine/asm.h
index 5eacde3..cdc7914 100644
--- a/libc/arch-mips/include/machine/asm.h
+++ b/libc/arch-mips/include/machine/asm.h
@@ -28,9 +28,7 @@
 #ifndef _MIPS64_ASM_H
 #define _MIPS64_ASM_H
 
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 4
-#endif
+#define __bionic_asm_align 4
 
 #undef __bionic_asm_custom_entry
 #undef __bionic_asm_custom_end
diff --git a/libc/arch-mips/string/mips_strlen.c b/libc/arch-mips/string/mips_strlen.c
index 9fb7e6a..45fc4b4 100644
--- a/libc/arch-mips/string/mips_strlen.c
+++ b/libc/arch-mips/string/mips_strlen.c
@@ -30,6 +30,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <string.h>
 #include "mips-string-ops.h"
 
 #define do_strlen_word(__av) {\
@@ -47,8 +48,8 @@
 #define strlen my_strlen
 #endif
 
-int
-strlen (const void *_a)
+size_t
+strlen (const char *_a)
 {
   int cnt = 0;
   unsigned x;
diff --git a/libc/arch-mips64/bionic/syscall.S b/libc/arch-mips64/bionic/syscall.S
index c4fd009..e3710f8 100644
--- a/libc/arch-mips64/bionic/syscall.S
+++ b/libc/arch-mips64/bionic/syscall.S
@@ -52,7 +52,7 @@
 #else
 	move	a3, a4
 	move	a4, a5
-	REG_L	a5, FRAMESZ(sp)
+	move	a5, a6
 #endif
 	syscall
 	move	a0, v0
diff --git a/libc/arch-mips64/include/machine/asm.h b/libc/arch-mips64/include/machine/asm.h
index 5eacde3..cdc7914 100644
--- a/libc/arch-mips64/include/machine/asm.h
+++ b/libc/arch-mips64/include/machine/asm.h
@@ -28,9 +28,7 @@
 #ifndef _MIPS64_ASM_H
 #define _MIPS64_ASM_H
 
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 4
-#endif
+#define __bionic_asm_align 4
 
 #undef __bionic_asm_custom_entry
 #undef __bionic_asm_custom_end
diff --git a/libc/arch-mips64/syscalls/_flush_cache.S b/libc/arch-mips64/syscalls/_flush_cache.S
deleted file mode 100644
index 997ccec..0000000
--- a/libc/arch-mips64/syscalls/_flush_cache.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-    .hidden __set_errno
-
-ENTRY(_flush_cache)
-    .set push
-    .set noreorder
-    li v0, __NR_cacheflush
-    syscall
-    bnez a3, 1f
-    move a0, v0
-    j ra
-    nop
-1:
-    move t0, ra
-    bal     2f
-    nop
-2:
-    .cpsetup ra, t1, 2b
-    LA t9,__set_errno
-    .cpreturn
-    j t9
-    move ra, t0
-    .set pop
-END(_flush_cache)
diff --git a/libc/arch-x86/atom/string/sse2-wcslen-atom.S b/libc/arch-x86/atom/string/sse2-wcslen-atom.S
index 6a6ad51..2f10db4 100644
--- a/libc/arch-x86/atom/string/sse2-wcslen-atom.S
+++ b/libc/arch-x86/atom/string/sse2-wcslen-atom.S
@@ -65,21 +65,21 @@
 ENTRY (wcslen)
 	mov	STR(%esp), %edx
 #endif
-	cmp	$0, (%edx)
+	cmpl	$0, (%edx)
 	jz	L(exit_tail0)
-	cmp	$0, 4(%edx)
+	cmpl	$0, 4(%edx)
 	jz	L(exit_tail1)
-	cmp	$0, 8(%edx)
+	cmpl	$0, 8(%edx)
 	jz	L(exit_tail2)
-	cmp	$0, 12(%edx)
+	cmpl	$0, 12(%edx)
 	jz	L(exit_tail3)
-	cmp	$0, 16(%edx)
+	cmpl	$0, 16(%edx)
 	jz	L(exit_tail4)
-	cmp	$0, 20(%edx)
+	cmpl	$0, 20(%edx)
 	jz	L(exit_tail5)
-	cmp	$0, 24(%edx)
+	cmpl	$0, 24(%edx)
 	jz	L(exit_tail6)
-	cmp	$0, 28(%edx)
+	cmpl	$0, 28(%edx)
 	jz	L(exit_tail7)
 
 	pxor	%xmm0, %xmm0
diff --git a/libc/arch-x86/include/machine/asm.h b/libc/arch-x86/include/machine/asm.h
index 672493d..943f9dd 100644
--- a/libc/arch-x86/include/machine/asm.h
+++ b/libc/arch-x86/include/machine/asm.h
@@ -49,15 +49,6 @@
 #define PIC_GOT(x)	x@GOT(%ebx)
 #define PIC_GOTOFF(x)	x@GOTOFF(%ebx)
 
-/* let kernels and others override entrypoint alignment */
-#if !defined(_ALIGN_TEXT) && !defined(_KERNEL)
-# ifdef _STANDALONE
-#  define _ALIGN_TEXT .align 1
-# elif defined __ELF__
-#  define _ALIGN_TEXT .align 16
-# else
-#  define _ALIGN_TEXT .align 4
-# endif
-#endif
+#define __bionic_asm_align 16
 
 #endif /* !_I386_ASM_H_ */
diff --git a/libc/arch-x86_64/include/machine/asm.h b/libc/arch-x86_64/include/machine/asm.h
index 06da39a..28cd08f 100644
--- a/libc/arch-x86_64/include/machine/asm.h
+++ b/libc/arch-x86_64/include/machine/asm.h
@@ -40,13 +40,6 @@
 #define PIC_PLT(x)	x@PLT
 #define PIC_GOT(x)	x@GOTPCREL(%rip)
 
-/* let kernels and others override entrypoint alignment */
-#ifndef _ALIGN_TEXT
-# ifdef _STANDALONE
-#  define _ALIGN_TEXT .align 4
-# else
-#  define _ALIGN_TEXT .align 16
-# endif
-#endif
+#define __bionic_asm_align 16
 
 #endif /* !_AMD64_ASM_H_ */
diff --git a/libc/bionic/daemon.c b/libc/bionic/__gnu_basename.cpp
similarity index 68%
rename from libc/bionic/daemon.c
rename to libc/bionic/__gnu_basename.cpp
index 8181d16..1eb3f65 100644
--- a/libc/bionic/daemon.c
+++ b/libc/bionic/__gnu_basename.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,11 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 
-int  daemon( int  nochdir, int  noclose )
-{
-   pid_t  pid;
+#define _GNU_SOURCE 1
+#include <string.h>
 
-   if ( !nochdir && chdir("/") != 0 )
-       return -1;
-   
-   if ( !noclose )
-   {
-     int  fd = open("/dev/null", O_RDWR);
-
-     if ( fd < 0 )
-      return -1;
-
-     if ( dup2( fd, 0 ) < 0 ||
-	  dup2( fd, 1 ) < 0 ||
-          dup2( fd, 2 ) < 0 ) 
-     {
-       close(fd);
-      return -1;
-     }
-     close(fd);
-  }
-  
-   pid = fork();
-   if (pid < 0)
-    return -1;
-
-   if (pid > 0)
-    _exit(0);
-
-   if ( setsid() < 0 )
-     return -1;
-
-   return 0;
+extern "C" const char* __gnu_basename(const char* path) {
+  const char* last_slash = strrchr(path, '/');
+  return (last_slash != NULL) ? last_slash + 1 : path;
 }
-
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/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index d83799a..698ab6b 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -71,7 +71,7 @@
   struct mapinfo_t* milist = NULL;
   char data[1024]; // Used to read lines as well as to construct the filename.
   snprintf(data, sizeof(data), "/proc/%d/maps", pid);
-  FILE* fp = fopen(data, "r");
+  FILE* fp = fopen(data, "re");
   if (fp != NULL) {
     while (fgets(data, sizeof(data), fp) != NULL) {
       mapinfo_t* mi = parse_maps_line(data);
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index e89c5d1..5853e7c 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -16,6 +16,7 @@
 
 #include "dlmalloc.h"
 
+#include "malloc.h"
 #include "private/bionic_prctl.h"
 #include "private/libc_logging.h"
 
@@ -54,3 +55,25 @@
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, length, "libc_malloc");
   return map;
 }
+
+// Since dlmalloc isn't the default, we'll leave this unimplemented for now. If
+// we decide we need it later, we can fill it in.
+size_t __mallinfo_narenas() {
+  return 0;
+}
+
+size_t __mallinfo_nbins() {
+  return 0;
+}
+
+struct mallinfo __mallinfo_arena_info(size_t aidx __unused) {
+  struct mallinfo mi;
+  memset(&mi, 0, sizeof(mi));
+  return mi;
+}
+
+struct mallinfo __mallinfo_bin_info(size_t aidx __unused, size_t bidx __unused) {
+  struct mallinfo mi;
+  memset(&mi, 0, sizeof(mi));
+  return mi;
+}
diff --git a/libc/bionic/err.c b/libc/bionic/err.c
deleted file mode 100644
index 84a3d85..0000000
--- a/libc/bionic/err.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*-
- * Copyright (c) 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. 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 <sys/cdefs.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-
-extern const char* __progname;
-
-__noreturn void
-err(int eval, const char *fmt, ...)
-{
-        va_list ap;
-
-        va_start(ap, fmt);
-        verr(eval, fmt, ap);
-        va_end(ap);
-}
-
-__noreturn void
-errx(int eval, const char *fmt, ...)
-{
-        va_list ap;
-
-        va_start(ap, fmt);
-        verrx(eval, fmt, ap);
-        va_end(ap);
-}
-
-__noreturn void
-verr(int eval, const char *fmt, va_list ap)
-{
-        int sverrno;
-
-        sverrno = errno;
-        (void)fprintf(stderr, "%s: ", __progname);
-        if (fmt != NULL) {
-                (void)vfprintf(stderr, fmt, ap);
-                (void)fprintf(stderr, ": ");
-        }
-        (void)fprintf(stderr, "%s\n", strerror(sverrno));
-        exit(eval);
-}
-
-
-__noreturn void
-verrx(int eval, const char *fmt, va_list ap)
-{
-        (void)fprintf(stderr, "%s: ", __progname);
-        if (fmt != NULL)
-                (void)vfprintf(stderr, fmt, ap);
-        (void)fprintf(stderr, "\n");
-        exit(eval);
-}
-
-void
-warn(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarn(fmt, ap);
-	va_end(ap);
-}
-
-void
-warnx(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnx(fmt, ap);
-	va_end(ap);
-}
-
-void
-vwarn(const char *fmt, va_list ap)
-{
-	int sverrno;
-
-	sverrno = errno;
-	(void)fprintf(stderr, "%s: ", __progname);
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-	(void)fprintf(stderr, "%s\n", strerror(sverrno));
-}
-
-void
-vwarnx(const char *fmt, va_list ap)
-{
-	(void)fprintf(stderr, "%s: ", __progname);
-	if (fmt != NULL)
-		(void)vfprintf(stderr, fmt, ap);
-	(void)fprintf(stderr, "\n");
-}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 950073a..2a6a03b 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -49,7 +49,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/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 5655526..49a3762 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -75,10 +75,12 @@
       len = strlen(data);
     }
 
+    total += len;
+
     while (len > 0) {
       int avail = end_ - pos_;
       if (avail == 0) {
-        break;
+        return;
       }
       if (avail > len) {
         avail = len;
@@ -87,11 +89,10 @@
       pos_ += avail;
       pos_[0] = '\0';
       len -= avail;
-      total += avail;
     }
   }
 
-  int total;
+  size_t total;
 
  private:
   char* buffer_;
@@ -109,18 +110,19 @@
       len = strlen(data);
     }
 
+    total += len;
+
     while (len > 0) {
       int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
       if (rc == -1) {
-        break;
+        return;
       }
       data += rc;
       len -= rc;
-      total += rc;
     }
   }
 
-  int total;
+  size_t total;
 
  private:
   int fd_;
diff --git a/libc/bionic/malloc_info.cpp b/libc/bionic/malloc_info.cpp
new file mode 100644
index 0000000..99caedb
--- /dev/null
+++ b/libc/bionic/malloc_info.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "malloc_info.h"
+
+#include <errno.h>
+#include "private/bionic_macros.h"
+
+class __LIBC_HIDDEN__ Elem {
+public:
+  // name must be valid throughout lifetime of the object.
+  explicit Elem(FILE* fp, const char* name,
+                const char* attr_fmt = nullptr, ...) {
+    this->fp = fp;
+    this->name = name;
+
+    fprintf(fp, "<%s", name);
+    if (attr_fmt != nullptr) {
+      va_list args;
+      va_start(args, attr_fmt);
+      fputc(' ', fp);
+      vfprintf(fp, attr_fmt, args);
+      va_end(args);
+    }
+    fputc('>', fp);
+  }
+
+  ~Elem() noexcept {
+    fprintf(fp, "</%s>", name);
+  }
+
+  void contents(const char* fmt, ...) {
+      va_list args;
+      va_start(args, fmt);
+      vfprintf(fp, fmt, args);
+      va_end(args);
+  }
+
+private:
+  FILE* fp;
+  const char* name;
+
+  DISALLOW_COPY_AND_ASSIGN(Elem);
+};
+
+int malloc_info(int options, FILE* fp) {
+  if (options != 0) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  Elem root(fp, "malloc", "version=\"jemalloc-1\"");
+
+  // Dump all of the large allocations in the arenas.
+  for (size_t i = 0; i < __mallinfo_narenas(); i++) {
+    struct mallinfo mi = __mallinfo_arena_info(i);
+    if (mi.hblkhd != 0) {
+      Elem arena_elem(fp, "heap", "nr=\"%d\"", i);
+      {
+        Elem(fp, "allocated-large").contents("%zu", mi.ordblks);
+        Elem(fp, "allocated-huge").contents("%zu", mi.uordblks);
+        Elem(fp, "allocated-bins").contents("%zu", mi.fsmblks);
+
+        size_t total = 0;
+        for (size_t j = 0; j < __mallinfo_nbins(); j++) {
+          struct mallinfo mi = __mallinfo_bin_info(i, j);
+          if (mi.ordblks != 0) {
+            Elem bin_elem(fp, "bin", "nr=\"%d\"", j);
+            Elem(fp, "allocated").contents("%zu", mi.ordblks);
+            Elem(fp, "nmalloc").contents("%zu", mi.uordblks);
+            Elem(fp, "ndalloc").contents("%zu", mi.fordblks);
+            total += mi.ordblks;
+          }
+        }
+        Elem(fp, "bins-total").contents("%zu", total);
+      }
+    }
+  }
+
+  return 0;
+}
diff --git a/libc/bionic/malloc_info.h b/libc/bionic/malloc_info.h
new file mode 100644
index 0000000..5fffae9
--- /dev/null
+++ b/libc/bionic/malloc_info.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBC_BIONIC_MALLOC_INFO_H_
+#define LIBC_BIONIC_MALLOC_INFO_H_
+
+#include <malloc.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+__LIBC_HIDDEN__ size_t __mallinfo_narenas();
+__LIBC_HIDDEN__ size_t __mallinfo_nbins();
+__LIBC_HIDDEN__ struct mallinfo __mallinfo_arena_info(size_t);
+__LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t);
+
+__END_DECLS
+
+#endif // LIBC_BIONIC_MALLOC_INFO_H_
diff --git a/libc/bionic/new.cpp b/libc/bionic/new.cpp
index fcfd1bd..cd84c2e 100644
--- a/libc/bionic/new.cpp
+++ b/libc/bionic/new.cpp
@@ -38,11 +38,11 @@
     return p;
 }
 
-void  operator delete(void* ptr) {
+void  operator delete(void* ptr) throw() {
     free(ptr);
 }
 
-void  operator delete[](void* ptr) {
+void  operator delete[](void* ptr) throw() {
     free(ptr);
 }
 
@@ -54,10 +54,10 @@
     return malloc(size);
 }
 
-void  operator delete(void* ptr, const std::nothrow_t&) {
+void  operator delete(void* ptr, const std::nothrow_t&) throw() {
     free(ptr);
 }
 
-void  operator delete[](void* ptr, const std::nothrow_t&) {
+void  operator delete[](void* ptr, const std::nothrow_t&) throw() {
     free(ptr);
 }
diff --git a/libc/bionic/pututline.c b/libc/bionic/pututline.c
index c8427f7..8cbf470 100644
--- a/libc/bionic/pututline.c
+++ b/libc/bionic/pututline.c
@@ -36,7 +36,7 @@
     struct utmp u;
     long i;
 
-    if (!(f = fopen(_PATH_UTMP, "w+")))
+    if (!(f = fopen(_PATH_UTMP, "w+e")))
         return;
 
     while (fread(&u, sizeof(struct utmp), 1, f) == 1)
@@ -55,7 +55,7 @@
 
     fclose(f);
 
-    if (!(f = fopen(_PATH_UTMP, "w+")))
+    if (!(f = fopen(_PATH_UTMP, "w+e")))
         return;
     fwrite(utmp, sizeof(struct utmp), 1, f);
 
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index 225a823..e1a031f 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -64,10 +64,6 @@
     bionic_old_action->sa_mask = kernel_old_action.sa_mask;
 #ifdef SA_RESTORER
     bionic_old_action->sa_restorer = kernel_old_action.sa_restorer;
-
-    if (bionic_old_action->sa_restorer == &__rt_sigreturn) {
-      bionic_old_action->sa_flags &= ~SA_RESTORER;
-    }
 #endif
   }
 
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 1e57cc0..d419fb1 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -1,11 +1,16 @@
 /* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
 /* Public Domain <marc@snafu.org> */
 
+// G++ automatically defines _GNU_SOURCE, which then means that <string.h>
+// gives us the GNU variant.
+#undef _GNU_SOURCE
+
+#include <string.h>
+
 #include <errno.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdio.h>
-#include <string.h>
 
 #include "private/ErrnoRestorer.h"
 #include "private/libc_logging.h"
@@ -62,6 +67,12 @@
   return 0;
 }
 
+extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) {
+  ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates...
+  strerror_r(error_number, buf, buf_len);
+  return buf; // ...and just returns whatever fit.
+}
+
 extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
   const char* signal_name = __strsignal_lookup(signal_number);
   if (signal_name != NULL) {
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 8309f08..d8aac4f 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -95,7 +95,7 @@
 }
 
 static int __sysconf_nprocessors_onln() {
-  FILE* fp = fopen("/proc/stat", "r");
+  FILE* fp = fopen("/proc/stat", "re");
   if (fp == NULL) {
     return 1;
   }
@@ -118,7 +118,7 @@
 }
 
 static int __get_meminfo(const char* pattern) {
-  FILE* fp = fopen("/proc/meminfo", "r");
+  FILE* fp = fopen("/proc/meminfo", "re");
   if (fp == NULL) {
     return -1;
   }
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index a564c39..ad69cf5 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);
@@ -598,6 +611,14 @@
     return find_property(root_node(), name, strlen(name), NULL, 0, false);
 }
 
+// The C11 standard doesn't allow atomic loads from const fields,
+// though C++11 does.  Fudge it until standards get straightened out.
+static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s,
+                                               memory_order mo) {
+    atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s);
+    return atomic_load_explicit(non_const_s, mo);
+}
+
 int __system_property_read(const prop_info *pi, char *name, char *value)
 {
     if (__predict_false(compat_mode)) {
@@ -605,11 +626,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 ==
+                load_const_atomic(&(pi->serial), memory_order_relaxed)) {
             if (name != 0) {
                 strcpy(name, pi->name);
             }
@@ -658,14 +688,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 +728,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 = load_const_atomic(&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 = load_const_atomic(&pi->serial, memory_order_acquire);
     }
     return serial;
 }
@@ -706,12 +754,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/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 1d847b8..0bd838e 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -899,7 +899,7 @@
     res_static  rs = __res_get_static();
     if (rs == NULL) return;
 	if (!rs->hostf)
-		rs->hostf = fopen(_PATH_HOSTS, "r" );
+		rs->hostf = fopen(_PATH_HOSTS, "re" );
 	else
 		rewind(rs->hostf);
 	rs->stayopen = f;
@@ -925,7 +925,7 @@
 	int af, len;
 	res_static  rs = __res_get_static();
 
-	if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
+	if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) {
 		h_errno = NETDB_INTERNAL;
 		return NULL;
 	}
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index 2612d6a..5443999 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -2017,7 +2017,7 @@
 {
 
 	if (!*hostf)
-		*hostf = fopen(_PATH_HOSTS, "r" );
+		*hostf = fopen(_PATH_HOSTS, "re");
 	else
 		rewind(*hostf);
 }
@@ -2046,7 +2046,7 @@
 	assert(name != NULL);
 	assert(pai != NULL);
 
-	if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
+	if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
 		return (NULL);
  again:
 	if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
diff --git a/libc/dns/net/services.h b/libc/dns/net/services.h
index fa199d0..7f748f7 100644
--- a/libc/dns/net/services.h
+++ b/libc/dns/net/services.h
@@ -30,8 +30,8 @@
 \6tacacs\0\61u\0\
 \12re-mail-ck\0\62t\0\
 \12re-mail-ck\0\62u\0\
-\6domain\0\65t\1\12nameserver\
-\6domain\0\65u\1\12nameserver\
+\6domain\0\65t\0\
+\6domain\0\65u\0\
 \3mtp\0\71t\0\
 \11tacacs-ds\0\101t\0\
 \11tacacs-ds\0\101u\0\
@@ -44,8 +44,8 @@
 \6gopher\0\106u\0\
 \3rje\0\115t\1\6netrjs\
 \6finger\0\117t\0\
-\3www\0\120t\1\4http\
-\3www\0\120u\0\
+\4http\0\120t\1\3www\
+\4http\0\120u\0\
 \4link\0\127t\1\7ttylink\
 \10kerberos\0\130t\3\11kerberos5\4krb5\14kerberos-sec\
 \10kerberos\0\130u\3\11kerberos5\4krb5\14kerberos-sec\
@@ -138,12 +138,16 @@
 \4ldap\1\205u\0\
 \4imsp\1\226t\0\
 \4imsp\1\226u\0\
+\6svrloc\1\253t\0\
+\6svrloc\1\253u\0\
 \5https\1\273t\0\
 \5https\1\273u\0\
 \4snpp\1\274t\0\
 \4snpp\1\274u\0\
 \14microsoft-ds\1\275t\0\
 \14microsoft-ds\1\275u\0\
+\7kpasswd\1\320t\0\
+\7kpasswd\1\320u\0\
 \4saft\1\347t\0\
 \4saft\1\347u\0\
 \6isakmp\1\364t\0\
@@ -158,6 +162,8 @@
 \10npmp-gui\2\143u\1\14dqs313_execd\
 \10hmmp-ind\2\144t\1\20dqs313_intercell\
 \10hmmp-ind\2\144u\1\20dqs313_intercell\
+\4qmqp\2\164t\0\
+\4qmqp\2\164u\0\
 \3ipp\2\167t\0\
 \3ipp\2\167u\0\
 \4exec\2\0t\0\
@@ -181,8 +187,14 @@
 \4uucp\2\34t\1\5uucpd\
 \6klogin\2\37t\0\
 \6kshell\2\40t\1\5krcmd\
+\15dhcpv6-client\2\42t\0\
+\15dhcpv6-client\2\42u\0\
+\15dhcpv6-server\2\43t\0\
+\15dhcpv6-server\2\43u\0\
 \12afpovertcp\2\44t\0\
 \12afpovertcp\2\44u\0\
+\4idfp\2\45t\0\
+\4idfp\2\45u\0\
 \10remotefs\2\54t\2\12rfs_server\3rfs\
 \5nntps\2\63t\1\5snntp\
 \5nntps\2\63u\1\5snntp\
@@ -239,19 +251,33 @@
 \13sa-msg-port\6\156u\1\13old-radacct\
 \6kermit\6\161t\0\
 \6kermit\6\161u\0\
+\11groupwise\6\215t\0\
+\11groupwise\6\215u\0\
 \3l2f\6\245t\1\4l2tp\
 \3l2f\6\245u\1\4l2tp\
 \6radius\7\24t\0\
 \6radius\7\24u\0\
 \13radius-acct\7\25t\1\7radacct\
 \13radius-acct\7\25u\1\7radacct\
+\4msnp\7\107t\0\
+\4msnp\7\107u\0\
 \13unix-status\7\245t\0\
 \12log-server\7\246t\0\
 \12remoteping\7\247t\0\
+\12cisco-sccp\7\320t\0\
+\12cisco-sccp\7\320u\0\
+\6search\7\332t\1\4ndtp\
+\13pipe-server\7\332t\1\13pipe_server\
 \3nfs\10\1t\0\
 \3nfs\10\1u\0\
+\6gnunet\10\46t\0\
+\6gnunet\10\46u\0\
 \12rtcm-sc104\10\65t\0\
 \12rtcm-sc104\10\65u\0\
+\15gsigatekeeper\10\107t\0\
+\15gsigatekeeper\10\107u\0\
+\4gris\10\127t\0\
+\4gris\10\127u\0\
 \12cvspserver\11\141t\0\
 \12cvspserver\11\141u\0\
 \5venus\11\176t\0\
@@ -266,10 +292,14 @@
 \3mon\12\27u\0\
 \4dict\12\104t\0\
 \4dict\12\104u\0\
+\15f5-globalsite\12\350t\0\
+\15f5-globalsite\12\350u\0\
+\6gsiftp\12\373t\0\
+\6gsiftp\12\373u\0\
 \4gpsd\13\203t\0\
 \4gpsd\13\203u\0\
-\6gds_db\13\352t\0\
-\6gds_db\13\352u\0\
+\6gds-db\13\352t\1\6gds_db\
+\6gds-db\13\352u\1\6gds_db\
 \5icpv2\14\72t\1\3icp\
 \5icpv2\14\72u\1\3icp\
 \5mysql\14\352t\0\
@@ -282,24 +312,49 @@
 \4daap\16\151u\0\
 \3svn\16\152t\1\12subversion\
 \3svn\16\152u\1\12subversion\
+\5suucp\17\277t\0\
+\5suucp\17\277u\0\
+\6sysrqd\17\376t\0\
+\6sysrqd\17\376u\0\
+\5sieve\20\136t\0\
+\4epmd\21\21t\0\
+\4epmd\21\21u\0\
+\6remctl\21\25t\0\
+\6remctl\21\25u\0\
+\11f5-iquery\21\1t\0\
+\11f5-iquery\21\1u\0\
 \3iax\21\331t\0\
 \3iax\21\331u\0\
+\3mtn\22\123t\0\
+\3mtn\22\123u\0\
 \13radmin-port\23\43t\0\
 \13radmin-port\23\43u\0\
 \3rfe\23\212u\0\
 \3rfe\23\212t\0\
+\4mmcc\23\272t\0\
+\4mmcc\23\272u\0\
 \3sip\23\304t\0\
 \3sip\23\304u\0\
 \7sip-tls\23\305t\0\
 \7sip-tls\23\305u\0\
+\3aol\24\106t\0\
+\3aol\24\106u\0\
 \13xmpp-client\24\146t\1\15jabber-client\
 \13xmpp-client\24\146u\1\15jabber-client\
 \13xmpp-server\24\225t\1\15jabber-server\
 \13xmpp-server\24\225u\1\15jabber-server\
 \10cfengine\24\274t\0\
 \10cfengine\24\274u\0\
+\4mdns\24\351t\0\
+\4mdns\24\351u\0\
 \12postgresql\25\70t\1\10postgres\
 \12postgresql\25\70u\1\10postgres\
+\7freeciv\25\264t\1\4rptp\
+\7freeciv\25\264u\0\
+\4amqp\26\50t\0\
+\4amqp\26\50u\0\
+\3ggz\26\70t\0\
+\3ggz\26\70u\0\
 \3x11\27\160t\1\5x11-0\
 \3x11\27\160u\1\5x11-0\
 \5x11-1\27\161t\0\
@@ -320,6 +375,12 @@
 \14gnutella-svc\30\312u\0\
 \14gnutella-rtr\30\313t\0\
 \14gnutella-rtr\30\313u\0\
+\13sge-qmaster\31\54t\1\13sge_qmaster\
+\13sge-qmaster\31\54u\1\13sge_qmaster\
+\11sge-execd\31\55t\1\11sge_execd\
+\11sge-execd\31\55u\1\11sge_execd\
+\13mysql-proxy\31\56t\0\
+\13mysql-proxy\31\56u\0\
 \17afs3-fileserver\33\130t\1\3bbs\
 \17afs3-fileserver\33\130u\1\3bbs\
 \15afs3-callback\33\131t\0\
@@ -342,12 +403,21 @@
 \13afs3-rmtsys\33\141u\0\
 \14font-service\33\274t\1\3xfs\
 \14font-service\33\274u\1\3xfs\
+\10http-alt\37\220t\1\10webcache\
+\10http-alt\37\220u\0\
 \12bacula-dir\43\215t\0\
 \12bacula-dir\43\215u\0\
 \11bacula-fd\43\216t\0\
 \11bacula-fd\43\216u\0\
 \11bacula-sd\43\217t\0\
 \11bacula-sd\43\217u\0\
+\5xmms2\45\303t\0\
+\5xmms2\45\303u\0\
+\3nbd\52\71t\0\
+\14zabbix-agent\47\102t\0\
+\14zabbix-agent\47\102u\0\
+\16zabbix-trapper\47\103t\0\
+\16zabbix-trapper\47\103u\0\
 \6amanda\47\140t\0\
 \6amanda\47\140u\0\
 \3hkp\54\153t\0\
@@ -364,16 +434,17 @@
 \4bpcd\65\326u\0\
 \6vopied\65\327t\0\
 \6vopied\65\327u\0\
+\4dcap\126\155t\0\
+\7gsidcap\126\160t\0\
 \4wnn6\127\1t\0\
 \4wnn6\127\1u\0\
 \11kerberos4\2\356u\2\13kerberos-iv\3kdc\
 \11kerberos4\2\356t\2\13kerberos-iv\3kdc\
-\17kerberos_master\2\357u\0\
-\17kerberos_master\2\357t\0\
-\15passwd_server\2\360u\0\
-\10krb_prop\2\362t\2\11krb5_prop\5hprop\
+\17kerberos-master\2\357u\1\17kerberos_master\
+\17kerberos-master\2\357t\0\
+\15passwd-server\2\360u\1\15passwd_server\
+\10krb-prop\2\362t\3\10krb_prop\11krb5_prop\5hprop\
 \11krbupdate\2\370t\1\4kreg\
-\7kpasswd\2\371t\1\4kpwd\
 \4swat\3\205t\0\
 \4kpop\4\125t\0\
 \5knetd\10\5t\0\
@@ -389,9 +460,9 @@
 \10poppassd\0\152t\0\
 \10poppassd\0\152u\0\
 \5ssmtp\1\321t\1\5smtps\
-\10moira_db\3\7t\0\
-\14moira_update\3\11t\0\
-\12moira_ureg\3\13u\0\
+\10moira-db\3\7t\1\10moira_db\
+\14moira-update\3\11t\1\14moira_update\
+\12moira-ureg\3\13u\1\12moira_ureg\
 \5spamd\3\17t\0\
 \5omirr\3\50t\1\6omirrd\
 \5omirr\3\50u\1\6omirrd\
@@ -404,9 +475,7 @@
 \4xtel\5\41t\0\
 \5xtelw\5\42t\0\
 \7support\5\371t\0\
-\5sieve\7\320t\0\
 \7cfinger\7\323t\0\
-\4ndtp\7\332t\0\
 \4frox\10\111t\0\
 \10ninstall\10\146t\0\
 \10ninstall\10\146u\0\
@@ -436,9 +505,7 @@
 \7hostmon\24\353t\0\
 \7hostmon\24\353u\0\
 \5rplay\25\263u\0\
-\5rplay\25\263t\0\
-\4rptp\25\264u\0\
-\4rptp\25\264t\0\
+\4nrpe\26\42t\0\
 \4nsca\26\43t\0\
 \4mrtd\26\52t\0\
 \6bgpsim\26\53t\0\
@@ -446,14 +513,15 @@
 \11sane-port\31\246t\2\4sane\5saned\
 \4ircd\32\13t\0\
 \10zope-ftp\37\125t\0\
-\10webcache\37\220t\0\
 \6tproxy\37\221t\0\
 \7omniorb\37\230t\0\
 \7omniorb\37\230u\0\
 \20clc-build-daemon\43\36t\0\
 \6xinetd\43\212t\0\
 \13mandelspawn\44\217u\1\12mandelbrot\
+\3git\44\312t\0\
 \4zope\45\311t\0\
+\6webmin\47\20t\0\
 \7kamanda\47\141t\0\
 \7kamanda\47\141u\0\
 \11amandaidx\47\142t\0\
@@ -473,6 +541,7 @@
 \5binkp\137\352t\0\
 \3asp\152\356t\0\
 \3asp\152\356u\0\
+\6csync2\170\221t\0\
 \11dircproxy\336\250t\0\
 \5tfido\353\21t\0\
 \4fido\353\23t\0\
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/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 419b748..057ba14 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1453,7 +1453,7 @@
     char* buf;
     int fileLen;
 
-    fp = fopen("/data/reslog.txt", "w+");
+    fp = fopen("/data/reslog.txt", "w+e");
     if (fp != NULL) {
         statep = __res_get_state();
 
diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c
index f1cbed8..713b6e0 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -289,7 +289,7 @@
 	 line[sizeof(name) - 1] == '\t'))
 
 	nserv = 0;
-	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+	if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
 	    /* read the config file */
 	    while (fgets(buf, sizeof(buf), fp) != NULL) {
 		/* skip comments */
@@ -616,47 +616,6 @@
 }
 #endif
 
-#ifdef ANDROID_CHANGES
-static int
-real_randomid(u_int *random_value) {
-	/* open the nonblocking random device, returning -1 on failure */
-	int random_device = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
-	if (random_device < 0) {
-		return -1;
-	}
-
-	/* read from the random device, returning -1 on failure (or too many retries)*/
-	for (u_int retry = 5; retry > 0; retry--) {
-		int retval = read(random_device, random_value, sizeof(u_int));
-		if (retval == sizeof(u_int)) {
-			*random_value &= 0xffff;
-			close(random_device);
-			return 0;
-		} else if ((retval < 0) && (errno != EINTR)) {
-			break;
-		}
-	}
-
-	close(random_device);
-	return -1;
-}
-#endif /* ANDROID_CHANGES */
-
-u_int
-res_randomid(void) {
-#ifdef ANDROID_CHANGES
-	int status = 0;
-	u_int output = 0;
-	status = real_randomid(&output);
-	if (status != -1) {
-		return output;
-	}
-#endif /* ANDROID_CHANGES */
-	struct timeval now;
-	gettimeofday(&now, NULL);
-	return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
-}
-
 /*%
  * This routine is for closing the socket if a virtual circuit is used and
  * the program wants to close it.  This provides support for endhostent()
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..7a9485a 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -69,14 +69,15 @@
 
 #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
 
 #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/libgen.h b/libc/include/libgen.h
index 9dcec75..e89328e 100644
--- a/libc/include/libgen.h
+++ b/libc/include/libgen.h
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _LIBGEN_H
 #define _LIBGEN_H
 
@@ -33,8 +34,18 @@
 
 __BEGIN_DECLS
 
-/* On Android these don't modify their input, and use thread-local storage for their results. */
+#if !defined(__bionic_using_gnu_basename)
+/*
+ * <string.h> gets you the GNU basename.
+ * <libgen.h> the POSIX one.
+ * Note that our "POSIX" one has the wrong argument cv-qualifiers, but doesn't
+ * modify its input and uses thread-local storage for the result if necessary.
+ */
 extern char* basename(const char*);
+#define __bionic_using_posix_basename
+#endif
+
+/* This has the wrong argument cv-qualifiers, but doesn't modify its input and uses thread-local storage for the result if necessary. */
 extern char* dirname(const char*);
 
 #if !defined(__LP64__)
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index e6ea276..cb1dd3b 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -24,6 +24,7 @@
  */
 #include <sys/cdefs.h>
 #include <stddef.h>
+#include <stdio.h>
 
 __BEGIN_DECLS
 
@@ -53,6 +54,27 @@
 
 extern struct mallinfo mallinfo(void);
 
+/*
+ * XML structure for malloc_info(3) is in the following format:
+ *
+ * <malloc version="jemalloc-1">
+ *   <heap nr="INT">
+ *     <allocated-large>INT</allocated-large>
+ *     <allocated-huge>INT</allocated-huge>
+ *     <allocated-bins>INT</allocated-bins>
+ *     <bins-total>INT</bins-total>
+ *     <bin nr="INT">
+ *       <allocated>INT</allocated>
+ *       <nmalloc>INT</nmalloc>
+ *       <ndalloc>INT</ndalloc>
+ *     </bin>
+ *     <!-- more bins -->
+ *   </heap>
+ *   <!-- more heaps -->
+ * </malloc>
+ */
+extern int malloc_info(int, FILE *);
+
 __END_DECLS
 
 #endif  /* LIBC_INCLUDE_MALLOC_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 43b0fbf..594d231 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>
 
@@ -329,6 +337,11 @@
 int	 putchar_unlocked(int);
 #endif /* __POSIX_VISIBLE >= 199506 */
 
+#if __POSIX_VISIBLE >= 200809
+FILE* fmemopen(void*, size_t, const char*);
+FILE* open_memstream(char**, size_t*);
+#endif /* __POSIX_VISIBLE >= 200809 */
+
 __END_DECLS
 
 #endif /* __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE */
@@ -347,6 +360,11 @@
 int	 vasprintf(char ** __restrict, const char * __restrict,
     __va_list)
 		__printflike(2, 0);
+
+void clearerr_unlocked(FILE*);
+int feof_unlocked(FILE*);
+int ferror_unlocked(FILE*);
+
 __END_DECLS
 
 /*
@@ -412,7 +430,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/bionic/daemon.c b/libc/include/stdio_ext.h
similarity index 67%
copy from libc/bionic/daemon.c
copy to libc/include/stdio_ext.h
index 8181d16..f299e54 100644
--- a/libc/bionic/daemon.c
+++ b/libc/include/stdio_ext.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,30 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 
-int  daemon( int  nochdir, int  noclose )
-{
-   pid_t  pid;
+#ifndef _STDIO_EXT_H
+#define _STDIO_EXT_H
 
-   if ( !nochdir && chdir("/") != 0 )
-       return -1;
-   
-   if ( !noclose )
-   {
-     int  fd = open("/dev/null", O_RDWR);
+#include <sys/cdefs.h>
+#include <stdio.h>
 
-     if ( fd < 0 )
-      return -1;
+#define FSETLOCKING_QUERY 0
+#define FSETLOCKING_INTERNAL 1
+#define FSETLOCKING_BYCALLER 2
 
-     if ( dup2( fd, 0 ) < 0 ||
-	  dup2( fd, 1 ) < 0 ||
-          dup2( fd, 2 ) < 0 ) 
-     {
-       close(fd);
-      return -1;
-     }
-     close(fd);
-  }
-  
-   pid = fork();
-   if (pid < 0)
-    return -1;
+__BEGIN_DECLS
 
-   if (pid > 0)
-    _exit(0);
+size_t __fbufsize(FILE*);
+int __freading(FILE*);
+int __fwriting(FILE*);
+int __freadable(FILE*);
+int __fwritable(FILE*);
+int __flbf(FILE*);
+void __fpurge(FILE*);
+size_t __fpending(FILE*);
+void _flushlbf(void);
+int __fsetlocking(FILE*, int);
 
-   if ( setsid() < 0 )
-     return -1;
+__END_DECLS
 
-   return 0;
-}
-
+#endif /* _STDIO_EXT_H */
diff --git a/libc/include/string.h b/libc/include/string.h
index 8df68e3..b0643af 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -25,8 +25,9 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _STRING_H_
-#define _STRING_H_
+
+#ifndef _STRING_H
+#define _STRING_H
 
 #include <sys/cdefs.h>
 #include <stddef.h>
@@ -66,8 +67,12 @@
 extern char*  strtok(char* __restrict, const char* __restrict);
 extern char*  strtok_r(char* __restrict, const char* __restrict, char** __restrict);
 
-extern char*  strerror(int);
-extern int    strerror_r(int errnum, char *buf, size_t n);
+extern char* strerror(int);
+#if defined(__USE_GNU)
+extern char* strerror_r(int, char*, size_t) __RENAME(__gnu_strerror_r);
+#else /* POSIX */
+extern int strerror_r(int, char*, size_t);
+#endif
 
 extern size_t strnlen(const char *, size_t) __purefunc;
 extern char*  strncat(char* __restrict, const char* __restrict, size_t);
@@ -92,6 +97,20 @@
 extern int    strcoll_l(const char *, const char *, locale_t) __purefunc;
 extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t);
 
+#if defined(__USE_GNU) && !defined(__bionic_using_posix_basename)
+/*
+ * glibc has a basename in <string.h> that's different to the POSIX one in <libgen.h>.
+ * It doesn't modify its argument, and in C++ it's const-correct.
+ */
+#if defined(__cplusplus)
+extern "C++" char* basename(char*) __RENAME(__gnu_basename) __nonnull((1));
+extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
+#else
+extern char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
+#endif
+#define __bionic_using_gnu_basename
+#endif
+
 #if defined(__BIONIC_FORTIFY)
 
 __BIONIC_FORTIFY_INLINE
@@ -180,8 +199,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 +222,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);
 
 
@@ -291,4 +308,4 @@
 
 __END_DECLS
 
-#endif /* _STRING_H_ */
+#endif /* _STRING_H */
diff --git a/libc/include/sys/cachectl.h b/libc/include/sys/cachectl.h
index 57e6ae7..a302ff8 100644
--- a/libc/include/sys/cachectl.h
+++ b/libc/include/sys/cachectl.h
@@ -31,6 +31,5 @@
 #ifdef __mips__
 #include <asm/cachectl.h>
 extern int __cachectl (void *addr, __const int nbytes, __const int op);
-extern int _flush_cache (char *addr, __const int nbytes, __const int op);
 #endif
 #endif /* sys/cachectl.h */
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 9a8dfdd..5082327 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,42 @@
 #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.
+ *
+ * The _GNU_SOURCE test needs to come before any _BSD_SOURCE or _POSIX* tests
+ * because _GNU_SOURCE implies everything else.
  */
-#define __FBSDID(s) /* nothing */
+#if defined(_GNU_SOURCE)
+# define __USE_GNU 1
+# undef _POSIX_SOURCE
+# define _POSIX_SOURCE 1
+# undef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200809L
+# undef _BSD_SOURCE
+# define _BSD_SOURCE 1
+#endif
+
+#if defined(_BSD_SOURCE)
+# define __USE_BSD 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 +534,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..a40a867 100644
--- a/libc/include/sys/cdefs_elf.h
+++ b/libc/include/sys/cdefs_elf.h
@@ -30,27 +30,9 @@
 #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	___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 __strong_alias(alias, sym) \
+    __asm__(".global " #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 +40,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/include/wchar.h b/libc/include/wchar.h
index 1898c7e..ae10d93 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -166,6 +166,7 @@
 extern wctrans_t wctrans(const char*);
 
 #if __POSIX_VISIBLE >= 200809
+FILE* open_wmemstream(wchar_t**, size_t*);
 wchar_t* wcsdup(const wchar_t*);
 size_t wcsnlen(const wchar_t*, size_t);
 #endif
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 6601817..ebebe80 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -199,8 +199,7 @@
         if opt == '-u':
             noUpdate = 0
         elif opt == '-v':
-            verbose = 1
-            D_setlevel(1)
+            logging.basicConfig(level=logging.DEBUG)
         elif opt == '-k':
             kernel_original_path = arg
         elif opt == '-d':
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 2be9532..0c098de 100644
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1711,7 +1711,7 @@
         while j < n and not blocks[j].isIf():
             j += 1
         if j > i:
-            D2("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno))
+            logging.debug("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno))
             result += blocks[i:j]
         if j >= n:
             break
@@ -1730,17 +1730,17 @@
                 break
             dir = blocks[j].directive
             if dir == "endif":
-                D2("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno))
+                logging.debug("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno))
                 i = j + 1
             elif dir == "else":
                 # convert 'else' into 'if 1'
-                D2("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno))
+                logging.debug("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno))
                 blocks[j].directive = "if"
                 blocks[j].expr      = CppExpr( CppLineTokenizer("1").toTokenList() )
                 i = j
             elif dir == "elif":
                 # convert 'elif' into 'if'
-                D2("convert 'if 0' .. 'elif' into 'if'")
+                logging.debug("convert 'if 0' .. 'elif' into 'if'")
                 blocks[j].directive = "if"
                 i = j
             continue
@@ -1749,25 +1749,25 @@
         k = find_matching_endif( blocks, j+1 )
         if k >= n:
             # unterminated #if 1, finish here
-            D2("unterminated 'if 1'")
+            logging.debug("unterminated 'if 1'")
             result += blocks[j+1:k]
             break
 
         dir = blocks[k].directive
         if dir == "endif":
-            D2("convert 'if 1' .. 'endif' (lines %d to %d)"  % (blocks[j].lineno, blocks[k].lineno))
+            logging.debug("convert 'if 1' .. 'endif' (lines %d to %d)"  % (blocks[j].lineno, blocks[k].lineno))
             result += optimize_if01(blocks[j+1:k])
             i       = k+1
         elif dir == "else":
             # convert 'else' into 'if 0'
-            D2("convert 'if 1' .. 'else' (lines %d to %d)"  % (blocks[j].lineno, blocks[k].lineno))
+            logging.debug("convert 'if 1' .. 'else' (lines %d to %d)"  % (blocks[j].lineno, blocks[k].lineno))
             result += optimize_if01(blocks[j+1:k])
             blocks[k].directive = "if"
             blocks[k].expr      = CppExpr( CppLineTokenizer("0").toTokenList() )
             i = k
         elif dir == "elif":
             # convert 'elif' into 'if 0'
-            D2("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
+            logging.debug("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
             result += optimize_if01(blocks[j+1:k])
             blocks[k].expr      = CppExpr( CppLineTokenizer("0").toTokenList() )
             i = k
@@ -1835,7 +1835,6 @@
     out = StringOutput()
     lines = string.split(text, '\n')
     list = BlockParser().parse( CppLinesTokenizer(lines) )
-    #D_setlevel(2)
     list.replaceTokens( kernel_token_replacements )
     list.optimizeAll( {"__KERNEL__":kCppUndefinedMacro} )
     list.write(out)
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
index 0478e93..e5a310e 100644
--- a/libc/kernel/tools/utils.py
+++ b/libc/kernel/tools/utils.py
@@ -1,59 +1,29 @@
 # common python utility routines for the Bionic tool scripts
 
-import sys, os, commands, string, commands
+import commands
+import logging
+import os
+import string
+import sys
 
-# basic debugging trace support
-# call D_setlevel to set the verbosity level
-# and D(), D2(), D3(), D4() to add traces
-#
-verbose = 0
 
 def panic(msg):
-    sys.stderr.write( find_program_name() + ": error: " )
-    sys.stderr.write( msg )
+    sys.stderr.write(os.path.basename(sys.argv[0]) + ": error: ")
+    sys.stderr.write(msg)
     sys.exit(1)
 
-def D(msg):
-    global verbose
-    if verbose > 0:
-        print msg
-
-def D2(msg):
-    global verbose
-    if verbose >= 2:
-        print msg
-
-def D3(msg):
-    global verbose
-    if verbose >= 3:
-        print msg
-
-def D4(msg):
-    global verbose
-    if verbose >= 4:
-        print msg
-
-def D_setlevel(level):
-    global verbose
-    verbose = level
-
-
-#  other stuff
-#
-#
-def find_program_name():
-    return os.path.basename(sys.argv[0])
 
 def find_program_dir():
     return os.path.dirname(sys.argv[0])
 
+
 class StringOutput:
     def __init__(self):
         self.line = ""
 
     def write(self,msg):
         self.line += msg
-        D2("write '%s'" % msg)
+        logging.debug("write '%s'" % msg)
 
     def get(self):
         return self.line
@@ -76,47 +46,6 @@
             continue
         os.mkdir(dir)
 
-def walk_source_files(paths,callback,args,excludes=[]):
-    """recursively walk a list of paths and files, only keeping the source files in directories"""
-    for path in paths:
-        if len(path) > 0 and path[0] == '@':
-            # this is the name of another file, include it and parse it
-            path = path[1:]
-            if os.path.exists(path):
-                for line in open(path):
-                    if len(line) > 0 and line[-1] == '\n':
-                        line = line[:-1]
-                    walk_source_files([line],callback,args,excludes)
-            continue
-        if not os.path.isdir(path):
-            callback(path,args)
-        else:
-            for root, dirs, files in os.walk(path):
-                #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
-                if len(excludes):
-                    for d in dirs[:]:
-                        if os.path.join(root,d) in excludes:
-                            dirs.remove(d)
-                for f in files:
-                    r, ext = os.path.splitext(f)
-                    if ext in [ ".h", ".c", ".cpp", ".S" ]:
-                        callback( "%s/%s" % (root,f), args )
-
-def cleanup_dir(path):
-    """create a directory if needed, and ensure that it is totally empty
-       by removing any existing content in it"""
-    if not os.path.exists(path):
-        os.mkdir(path)
-    else:
-        for root, dirs, files in os.walk(path, topdown=False):
-            if root.endswith("kernel_headers/"):
-                # skip 'kernel_headers'
-                continue
-            for name in files:
-                os.remove(os.path.join(root, name))
-            for name in dirs:
-                os.rmdir(os.path.join(root, name))
-
 
 class BatchFileUpdater:
     """a class used to edit several files at once"""
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 7c2686f..d53ebba 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -41,7 +41,7 @@
 #define ENTRY(f) \
     .text; \
     .globl f; \
-    _ALIGN_TEXT; \
+    .align __bionic_asm_align; \
     .type f, __bionic_asm_function_type; \
     f: \
     __bionic_asm_custom_entry(f); \
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
new file mode 100644
index 0000000..bfdecb8
--- /dev/null
+++ b/libc/stdio/stdio_ext.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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 <stdio_ext.h>
+
+#include <stdio.h>
+#include "local.h"
+
+#define FSETLOCKING_QUERY 0
+#define FSETLOCKING_INTERNAL 1
+#define FSETLOCKING_BYCALLER 2
+
+size_t __fbufsize(FILE* fp) {
+  return fp->_bf._size;
+}
+
+/* For a _SRW stream, we don't know whether we last read or wrote.
+int __freading(FILE* fp) {
+  return (fp->_flags & _SRD) != 0 || ...;
+}
+*/
+
+/* For a _SRW stream, we don't know whether we last read or wrote.
+int __fwriting(FILE*) {
+  return (fp->_flags & _SWR) != 0 || ...;
+}
+*/
+
+int __freadable(FILE* fp) {
+  return (fp->_flags & (__SRD|__SRW)) != 0;
+}
+
+int __fwritable(FILE* fp) {
+  return (fp->_flags & (__SWR|__SRW)) != 0;
+}
+
+int __flbf(FILE* fp) {
+  return (fp->_flags & __SLBF) != 0;
+}
+
+void __fpurge(FILE* fp) {
+  fpurge(fp);
+}
+
+size_t __fpending(FILE* fp) {
+  return fp->_p - fp->_bf._base;
+}
+
+void _flushlbf() {
+  // If we flush all streams, we know we've flushed all the line-buffered streams.
+  fflush(NULL);
+}
+
+int __fsetlocking(FILE*, int) {
+  // We don't currently have an implementation that would obey this,
+  // so make setting the state a no-op and always return "we handle locking for you".
+  // http://b/17154740 suggests ways we could fix this.
+  return FSETLOCKING_INTERNAL;
+}
+
+void clearerr_unlocked(FILE* fp) {
+  return __sclearerr(fp);
+}
+
+int feof_unlocked(FILE* fp) {
+  return __sfeof(fp);
+}
+
+int ferror_unlocked(FILE* fp) {
+  return __sferror(fp);
+}
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
deleted file mode 100644
index c38efb5..0000000
--- a/libc/tools/bionic_utils.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# common python utility routines for the Bionic tool scripts
-
-import sys, os, commands, string
-
-all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ]
-
-# basic debugging trace support
-# call D_setlevel to set the verbosity level
-# and D(), D2(), D3(), D4() to add traces
-#
-verbose = 0
-
-def D(msg):
-    global verbose
-    if verbose > 0:
-        print msg
-
-def D2(msg):
-    global verbose
-    if verbose >= 2:
-        print msg
-
-def D3(msg):
-    global verbose
-    if verbose >= 3:
-        print msg
-
-def D4(msg):
-    global verbose
-    if verbose >= 4:
-        print msg
-
-def D_setlevel(level):
-    global verbose
-    verbose = level
-
-
-# parser for the SYSCALLS.TXT file
-#
-class SysCallsTxtParser:
-    def __init__(self):
-        self.syscalls = []
-        self.lineno   = 0
-
-    def E(self, msg):
-        print "%d: %s" % (self.lineno, msg)
-
-    def parse_line(self, line):
-        """ parse a syscall spec line.
-
-        line processing, format is
-           return type    func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list
-        """
-        pos_lparen = line.find('(')
-        E          = self.E
-        if pos_lparen < 0:
-            E("missing left parenthesis in '%s'" % line)
-            return
-
-        pos_rparen = line.rfind(')')
-        if pos_rparen < 0 or pos_rparen <= pos_lparen:
-            E("missing or misplaced right parenthesis in '%s'" % line)
-            return
-
-        return_type = line[:pos_lparen].strip().split()
-        if len(return_type) < 2:
-            E("missing return type in '%s'" % line)
-            return
-
-        syscall_func = return_type[-1]
-        return_type  = string.join(return_type[:-1],' ')
-        socketcall_id = -1
-
-        pos_colon = syscall_func.find(':')
-        if pos_colon < 0:
-            syscall_name = syscall_func
-        else:
-            if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
-                E("misplaced colon in '%s'" % line)
-                return
-
-            # now find if there is a socketcall_id for a dispatch-type syscall
-            # after the optional 2nd colon
-            pos_colon2 = syscall_func.find(':', pos_colon + 1)
-            if pos_colon2 < 0:
-                syscall_name = syscall_func[pos_colon+1:]
-                syscall_func = syscall_func[:pos_colon]
-            else:
-                if pos_colon2+1 >= len(syscall_func):
-                    E("misplaced colon2 in '%s'" % line)
-                    return
-                syscall_name = syscall_func[(pos_colon+1):pos_colon2]
-                socketcall_id = int(syscall_func[pos_colon2+1:])
-                syscall_func = syscall_func[:pos_colon]
-
-        alias_delim = syscall_func.find('|')
-        if alias_delim > 0:
-            alias_list = syscall_func[alias_delim+1:].strip()
-            syscall_func = syscall_func[:alias_delim]
-            alias_delim = syscall_name.find('|')
-            if alias_delim > 0:
-                syscall_name = syscall_name[:alias_delim]
-            syscall_aliases = string.split(alias_list, ',')
-        else:
-            syscall_aliases = []
-
-        if pos_rparen > pos_lparen+1:
-            syscall_params = line[pos_lparen+1:pos_rparen].split(',')
-            params         = string.join(syscall_params,',')
-        else:
-            syscall_params = []
-            params         = "void"
-
-        t = {
-              "name"    : syscall_name,
-              "func"    : syscall_func,
-              "aliases" : syscall_aliases,
-              "params"  : syscall_params,
-              "decl"    : "%-15s  %s (%s);" % (return_type, syscall_func, params),
-              "socketcall_id" : socketcall_id
-        }
-
-        # Parse the architecture list.
-        arch_list = line[pos_rparen+1:].strip()
-        if arch_list == "all":
-            for arch in all_arches:
-                t[arch] = True
-        else:
-            for arch in string.split(arch_list, ','):
-                if arch in all_arches:
-                    t[arch] = True
-                else:
-                    E("invalid syscall architecture '%s' in '%s'" % (arch, line))
-                    return
-
-        self.syscalls.append(t)
-
-        global verbose
-        if verbose >= 2:
-            print t
-
-
-    def parse_file(self, file_path):
-        D2("parse_file: %s" % file_path)
-        fp = open(file_path)
-        for line in fp.xreadlines():
-            self.lineno += 1
-            line = line.strip()
-            if not line: continue
-            if line[0] == '#': continue
-            self.parse_line(line)
-
-        fp.close()
-
-
-class StringOutput:
-    def __init__(self):
-        self.line = ""
-
-    def write(self,msg):
-        self.line += msg
-        D2("write '%s'" % msg)
-
-    def get(self):
-        return self.line
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 58a10e0..8bcf7fc 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,15 +56,26 @@
     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',
   '__res_query': 'res_query',
   '__res_search': 'res_search',
+  '__xpg_basename': '__gnu_basename',
 }
 
 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 +117,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 +160,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..929bec4 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -4,21 +4,29 @@
 # 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
+import logging
 import os.path
 import re
 import shutil
 import stat
+import string
 import sys
+import tempfile
 
-from bionic_utils import *
 
-bionic_libc_root = os.environ["ANDROID_BUILD_TOP"] + "/bionic/libc/"
+all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ]
+
 
 # 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 +42,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 +276,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)
@@ -382,6 +391,120 @@
     return result
 
 
+class SysCallsTxtParser:
+    def __init__(self):
+        self.syscalls = []
+        self.lineno   = 0
+
+    def E(self, msg):
+        print "%d: %s" % (self.lineno, msg)
+
+    def parse_line(self, line):
+        """ parse a syscall spec line.
+
+        line processing, format is
+           return type    func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list
+        """
+        pos_lparen = line.find('(')
+        E          = self.E
+        if pos_lparen < 0:
+            E("missing left parenthesis in '%s'" % line)
+            return
+
+        pos_rparen = line.rfind(')')
+        if pos_rparen < 0 or pos_rparen <= pos_lparen:
+            E("missing or misplaced right parenthesis in '%s'" % line)
+            return
+
+        return_type = line[:pos_lparen].strip().split()
+        if len(return_type) < 2:
+            E("missing return type in '%s'" % line)
+            return
+
+        syscall_func = return_type[-1]
+        return_type  = string.join(return_type[:-1],' ')
+        socketcall_id = -1
+
+        pos_colon = syscall_func.find(':')
+        if pos_colon < 0:
+            syscall_name = syscall_func
+        else:
+            if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
+                E("misplaced colon in '%s'" % line)
+                return
+
+            # now find if there is a socketcall_id for a dispatch-type syscall
+            # after the optional 2nd colon
+            pos_colon2 = syscall_func.find(':', pos_colon + 1)
+            if pos_colon2 < 0:
+                syscall_name = syscall_func[pos_colon+1:]
+                syscall_func = syscall_func[:pos_colon]
+            else:
+                if pos_colon2+1 >= len(syscall_func):
+                    E("misplaced colon2 in '%s'" % line)
+                    return
+                syscall_name = syscall_func[(pos_colon+1):pos_colon2]
+                socketcall_id = int(syscall_func[pos_colon2+1:])
+                syscall_func = syscall_func[:pos_colon]
+
+        alias_delim = syscall_func.find('|')
+        if alias_delim > 0:
+            alias_list = syscall_func[alias_delim+1:].strip()
+            syscall_func = syscall_func[:alias_delim]
+            alias_delim = syscall_name.find('|')
+            if alias_delim > 0:
+                syscall_name = syscall_name[:alias_delim]
+            syscall_aliases = string.split(alias_list, ',')
+        else:
+            syscall_aliases = []
+
+        if pos_rparen > pos_lparen+1:
+            syscall_params = line[pos_lparen+1:pos_rparen].split(',')
+            params         = string.join(syscall_params,',')
+        else:
+            syscall_params = []
+            params         = "void"
+
+        t = {
+              "name"    : syscall_name,
+              "func"    : syscall_func,
+              "aliases" : syscall_aliases,
+              "params"  : syscall_params,
+              "decl"    : "%-15s  %s (%s);" % (return_type, syscall_func, params),
+              "socketcall_id" : socketcall_id
+        }
+
+        # Parse the architecture list.
+        arch_list = line[pos_rparen+1:].strip()
+        if arch_list == "all":
+            for arch in all_arches:
+                t[arch] = True
+        else:
+            for arch in string.split(arch_list, ','):
+                if arch in all_arches:
+                    t[arch] = True
+                else:
+                    E("invalid syscall architecture '%s' in '%s'" % (arch, line))
+                    return
+
+        self.syscalls.append(t)
+
+        logging.debug(t)
+
+
+    def parse_file(self, file_path):
+        logging.debug("parse_file: %s" % file_path)
+        fp = open(file_path)
+        for line in fp.xreadlines():
+            self.lineno += 1
+            line = line.strip()
+            if not line: continue
+            if line[0] == '#': continue
+            self.parse_line(line)
+
+        fp.close()
+
+
 class State:
     def __init__(self):
         self.old_stubs = []
@@ -439,22 +562,22 @@
     def gen_glibc_syscalls_h(self):
         # TODO: generate a separate file for each architecture, like glibc's bits/syscall.h.
         glibc_syscalls_h_path = "include/sys/glibc-syscalls.h"
-        D("generating " + glibc_syscalls_h_path)
+        logging.info("generating " + glibc_syscalls_h_path)
         glibc_fp = create_file(glibc_syscalls_h_path)
         glibc_fp.write("/* %s */\n" % warning)
         glibc_fp.write("#ifndef _BIONIC_GLIBC_SYSCALLS_H_\n")
         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")
@@ -468,7 +591,7 @@
             for arch in all_arches:
                 if syscall.has_key("asm-%s" % arch):
                     filename = "arch-%s/syscalls/%s.S" % (arch, syscall["func"])
-                    D2(">>> generating " + filename)
+                    logging.info(">>> generating " + filename)
                     fp = create_file(filename)
                     fp.write(syscall["asm-%s" % arch])
                     fp.close()
@@ -476,48 +599,49 @@
 
 
     def regenerate(self):
-        D("scanning for existing architecture-specific stub files...")
-
-        bionic_libc_root_len = len(bionic_libc_root)
+        logging.info("scanning for existing architecture-specific stub files...")
 
         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
+            logging.info("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))
+        logging.info("found %d stub files" % len(self.old_stubs))
 
         if not os.path.exists(bionic_temp):
-            D("creating %s..." % bionic_temp)
+            logging.info("creating %s..." % bionic_temp)
             make_dir(bionic_temp)
 
-        D("re-generating stubs and support files...")
+        logging.info("re-generating stubs and support files...")
 
         self.gen_glibc_syscalls_h()
         self.gen_syscall_stubs()
 
-        D("comparing files...")
+        logging.info("comparing files...")
         adds    = []
         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)
+                logging.info("new file:     " + stub)
+                adds.append(libc_file)
+                shutil.copyfile(tmp_file, libc_file)
 
-            elif not filecmp.cmp(bionic_temp + stub, bionic_libc_root + stub):
-                D("changed file: " + stub)
+            elif not filecmp.cmp(tmp_file, libc_file):
+                logging.info("changed file: " + stub)
                 edits.append(stub)
 
         deletes = []
         for stub in self.old_stubs:
             if not stub in self.new_stubs:
-                D("deleted file: " + stub)
-                deletes.append(bionic_libc_root + stub)
+                logging.info("deleted file: " + stub)
+                deletes.append(os.path.join(bionic_libc_root, stub))
 
         if not DRY_RUN:
             if adds:
@@ -526,18 +650,19 @@
                 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!")
+            logging.info("no changes detected!")
         else:
-            D("ready to go!!")
+            logging.info("ready to go!!")
 
-D_setlevel(1)
+logging.basicConfig(level=logging.INFO)
 
 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/namespace.h b/libc/upstream-netbsd/android/include/namespace.h
index 5df543c..630ea9b 100644
--- a/libc/upstream-netbsd/android/include/namespace.h
+++ b/libc/upstream-netbsd/android/include/namespace.h
@@ -17,11 +17,6 @@
 #ifndef _BIONIC_NETBSD_NAMESPACE_H_included
 #define _BIONIC_NETBSD_NAMESPACE_H_included
 
-// NetBSD uses __weak_alias on a lot of functions. We don't want that.
-#if defined(__weak_alias)
-#undef __weak_alias
-#endif
-
 __LIBC_HIDDEN__ int __res_enable_mt(void);
 __LIBC_HIDDEN__ int __res_disable_mt(void);
 
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..630094d 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -17,10 +17,23 @@
 #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
+/* Redirect internal C library calls to the public function. */
+#define _err err
+#define _errx errx
+#define _verr verr
+#define _verrx verrx
+#define _vwarn vwarn
+#define _vwarnx vwarnx
+#define _warn warn
+#define _warnx warnx
+
+/* Ignore all __weak_alias in OpenBSD. */
+#define __weak_alias(alias,sym)
 
 /* 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/libc/upstream-openbsd/lib/libc/gen/daemon.c b/libc/upstream-openbsd/lib/libc/gen/daemon.c
new file mode 100644
index 0000000..79f4264
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/daemon.c
@@ -0,0 +1,64 @@
+/*	$OpenBSD: daemon.c,v 1.7 2010/07/27 22:29:09 marco Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int
+daemon(int nochdir, int noclose)
+{
+	int fd;
+
+	switch (fork()) {
+	case -1:
+		return (-1);
+	case 0:
+		break;
+	default:
+		_exit(0);
+	}
+
+	if (setsid() == -1)
+		return (-1);
+
+	if (!nochdir)
+		(void)chdir("/");
+
+	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+		(void)dup2(fd, STDIN_FILENO);
+		(void)dup2(fd, STDOUT_FILENO);
+		(void)dup2(fd, STDERR_FILENO);
+		if (fd > 2)
+			(void)close(fd);
+	}
+	return (0);
+}
diff --git a/libc/upstream-openbsd/lib/libc/gen/err.c b/libc/upstream-openbsd/lib/libc/gen/err.c
new file mode 100644
index 0000000..e7ec29d
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/err.c
@@ -0,0 +1,47 @@
+/*	$OpenBSD: err.c,v 1.11 2012/12/05 23:19:59 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE2 */
+__dead void
+_err(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_verr(eval, fmt, ap);
+	va_end(ap);
+}
+
+/* PRINTFLIKE2 */
+__weak_alias(err, _err);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/errx.c b/libc/upstream-openbsd/lib/libc/gen/errx.c
new file mode 100644
index 0000000..d213435
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/errx.c
@@ -0,0 +1,47 @@
+/*	$OpenBSD: errx.c,v 1.10 2012/12/05 23:19:59 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE2 */
+__dead void
+_errx(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_verrx(eval, fmt, ap);
+	va_end(ap);
+}
+
+/* PRINTFLIKE2 */
+__weak_alias(errx, _errx);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/verr.c b/libc/upstream-openbsd/lib/libc/gen/verr.c
new file mode 100644
index 0000000..dcd8edc
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/verr.c
@@ -0,0 +1,56 @@
+/*	$OpenBSD: verr.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern char *__progname;		/* Program name, from crt0. */
+
+__dead void
+_verr(int eval, const char *fmt, va_list ap)
+{
+	int sverrno;
+
+	sverrno = errno;
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL) {
+		(void)vfprintf(stderr, fmt, ap);
+		(void)fprintf(stderr, ": ");
+	}
+	(void)fprintf(stderr, "%s\n", strerror(sverrno));
+	exit(eval);
+}
+
+__weak_alias(verr, _verr);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/verrx.c b/libc/upstream-openbsd/lib/libc/gen/verrx.c
new file mode 100644
index 0000000..60da062
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/verrx.c
@@ -0,0 +1,49 @@
+/*	$OpenBSD: verrx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+extern char *__progname;		/* Program name, from crt0. */
+
+__dead void
+_verrx(int eval, const char *fmt, va_list ap)
+{
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL)
+		(void)vfprintf(stderr, fmt, ap);
+	(void)fprintf(stderr, "\n");
+	exit(eval);
+}
+
+__weak_alias(verrx, _verrx);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarn.c b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
new file mode 100644
index 0000000..26b60f3
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
@@ -0,0 +1,54 @@
+/*	$OpenBSD: vwarn.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern char *__progname;		/* Program name, from crt0. */
+
+void
+_vwarn(const char *fmt, va_list ap)
+{
+	int sverrno;
+
+	sverrno = errno;
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL) {
+		(void)vfprintf(stderr, fmt, ap);
+		(void)fprintf(stderr, ": ");
+	}
+	(void)fprintf(stderr, "%s\n", strerror(sverrno));
+}
+
+__weak_alias(vwarn, _vwarn);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarnx.c b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
new file mode 100644
index 0000000..e6b1957
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
@@ -0,0 +1,47 @@
+/*	$OpenBSD: vwarnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+extern char *__progname;		/* Program name, from crt0. */
+
+void
+_vwarnx(const char *fmt, va_list ap)
+{
+	(void)fprintf(stderr, "%s: ", __progname);
+	if (fmt != NULL)
+		(void)vfprintf(stderr, fmt, ap);
+	(void)fprintf(stderr, "\n");
+}
+
+__weak_alias(vwarnx, _vwarnx);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/warn.c b/libc/upstream-openbsd/lib/libc/gen/warn.c
new file mode 100644
index 0000000..c1b47a6
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/warn.c
@@ -0,0 +1,47 @@
+/*	$OpenBSD: warn.c,v 1.10 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE1 */
+void
+_warn(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_vwarn(fmt, ap);
+	va_end(ap);
+}
+
+/* PRINTFLIKE1 */
+__weak_alias(warn, _warn);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/warnx.c b/libc/upstream-openbsd/lib/libc/gen/warnx.c
new file mode 100644
index 0000000..af2ab66
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/warnx.c
@@ -0,0 +1,47 @@
+/*	$OpenBSD: warnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE1 */
+void
+_warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_vwarnx(fmt, ap);
+	va_end(ap);
+}
+
+/* PRINTFLIKE1 */
+__weak_alias(warnx, _warnx);
+
diff --git a/libc/upstream-openbsd/lib/libc/net/res_random.c b/libc/upstream-openbsd/lib/libc/net/res_random.c
new file mode 100644
index 0000000..f28692f
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/net/res_random.c
@@ -0,0 +1,275 @@
+/* $OpenBSD: res_random.c,v 1.21 2014/07/20 04:22:34 guenther Exp $ */
+
+/*
+ * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+ * Copyright 2008 Damien Miller <djm@openbsd.org>
+ * All rights reserved.
+ *
+ * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
+ * such a mathematical system to generate more random (yet non-repeating)
+ * ids to solve the resolver/named problem.  But Niels designed the
+ * actual system based on the constraints.
+ *
+ * Later modified by Damien Miller to wrap the LCG output in a 15-bit
+ * permutation generator based on a Luby-Rackoff block cipher. This
+ * ensures the output is non-repeating and preserves the MSB twiddle
+ * trick, but makes it more resistant to LCG prediction.
+ *
+ * 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 ``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 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.
+ */
+
+/* 
+ * seed = random 15bit
+ * n = prime, g0 = generator to n,
+ * j = random so that gcd(j,n-1) == 1
+ * g = g0^j mod n will be a generator again.
+ *
+ * X[0] = random seed.
+ * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
+ * with a = 7^(even random) mod m, 
+ *      b = random with gcd(b,m) == 1
+ *      m = 31104 and a maximal period of m-1.
+ *
+ * The transaction id is determined by:
+ * id[n] = seed xor (g^X[n] mod n)
+ *
+ * Effectivly the id is restricted to the lower 15 bits, thus
+ * yielding two different cycles by toggling the msb on and off.
+ * This avoids reuse issues caused by reseeding.
+ *
+ * The output of this generator is then randomly permuted though a
+ * custom 15 bit Luby-Rackoff block cipher.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <resolv.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "thread_private.h"
+
+#define RU_OUT  	180	/* Time after wich will be reseeded */
+#define RU_MAX		30000	/* Uniq cycle, avoid blackjack prediction */
+#define RU_GEN		2	/* Starting generator */
+#define RU_N		32749	/* RU_N-1 = 2*2*3*2729 */
+#define RU_AGEN		7	/* determine ru_a as RU_AGEN^(2*rand) */
+#define RU_M		31104	/* RU_M = 2^7*3^5 - don't change */
+#define RU_ROUNDS	11	/* Number of rounds for permute (odd) */
+
+struct prf_ctx {
+	/* PRF lookup table for odd rounds (7 bits input to 8 bits output) */
+	u_char prf7[(RU_ROUNDS / 2) * (1 << 7)];
+
+	/* PRF lookup table for even rounds (8 bits input to 7 bits output) */
+	u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)];
+};
+
+#define PFAC_N 3
+static const u_int16_t pfacts[PFAC_N] = {
+	2, 
+	3,
+	2729
+};
+
+static u_int16_t ru_x;
+static u_int16_t ru_seed, ru_seed2;
+static u_int16_t ru_a, ru_b;
+static u_int16_t ru_g;
+static u_int16_t ru_counter = 0;
+static u_int16_t ru_msb = 0;
+static struct prf_ctx *ru_prf = NULL;
+static time_t ru_reseed;
+
+static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t);
+static void res_initid(void);
+
+/*
+ * Do a fast modular exponation, returned value will be in the range
+ * of 0 - (mod-1)
+ */
+static u_int16_t
+pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod)
+{
+	u_int16_t s, t, u;
+
+	s = 1;
+	t = gen;
+	u = exp;
+
+	while (u) {
+		if (u & 1)
+			s = (s * t) % mod;
+		u >>= 1;
+		t = (t * t) % mod;
+	}
+	return (s);
+}
+
+/*
+ * 15-bit permutation based on Luby-Rackoff block cipher
+ */
+static u_int
+permute15(u_int in)
+{
+	int i;
+	u_int left, right, tmp;
+
+	if (ru_prf == NULL)
+		return in;
+
+	left = (in >> 8) & 0x7f;
+	right = in & 0xff;
+
+	/*
+	 * Each round swaps the width of left and right. Even rounds have
+	 * a 7-bit left, odd rounds have an 8-bit left.	Since this uses an
+	 * odd number of rounds, left is always 8 bits wide at the end.
+	 */
+	for (i = 0; i < RU_ROUNDS; i++) {
+		if ((i & 1) == 0)
+			tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f;
+		else
+			tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right];
+		tmp ^= left;
+		left = right;
+		right = tmp;
+	}
+
+	return (right << 8) | left;
+}
+
+/* 
+ * Initializes the seed and chooses a suitable generator. Also toggles 
+ * the msb flag. The msb flag is used to generate two distinct
+ * cycles of random numbers and thus avoiding reuse of ids.
+ *
+ * This function is called from res_randomid() when needed, an 
+ * application does not have to worry about it.
+ */
+static void 
+res_initid(void)
+{
+	u_int16_t j, i;
+	u_int32_t tmp;
+	int noprime = 1;
+	struct timespec ts;
+
+	ru_x = arc4random_uniform(RU_M);
+
+	/* 15 bits of random seed */
+	tmp = arc4random();
+	ru_seed = (tmp >> 16) & 0x7FFF;
+	ru_seed2 = tmp & 0x7FFF;
+
+	/* Determine the LCG we use */
+	tmp = arc4random();
+	ru_b = (tmp & 0xfffe) | 1;
+	ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M);
+	while (ru_b % 3 == 0)
+		ru_b += 2;
+	
+	j = arc4random_uniform(RU_N);
+
+	/* 
+	 * Do a fast gcd(j,RU_N-1), so we can find a j with
+	 * gcd(j, RU_N-1) == 1, giving a new generator for
+	 * RU_GEN^j mod RU_N
+	 */
+
+	while (noprime) {
+		for (i = 0; i < PFAC_N; i++)
+			if (j % pfacts[i] == 0)
+				break;
+
+		if (i >= PFAC_N)
+			noprime = 0;
+		else 
+			j = (j + 1) % RU_N;
+	}
+
+	ru_g = pmod(RU_GEN, j, RU_N);
+	ru_counter = 0;
+
+	/* Initialise PRF for Luby-Rackoff permutation */
+	if (ru_prf == NULL)
+		ru_prf = malloc(sizeof(*ru_prf));
+	if (ru_prf != NULL)
+		arc4random_buf(ru_prf, sizeof(*ru_prf));
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	ru_reseed = ts.tv_sec + RU_OUT;
+	ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; 
+}
+
+u_int
+res_randomid(void)
+{
+	struct timespec ts;
+	u_int r;
+	_THREAD_PRIVATE_MUTEX(random);
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	_THREAD_PRIVATE_MUTEX_LOCK(random);
+
+	if (ru_counter >= RU_MAX || ts.tv_sec > ru_reseed)
+		res_initid();
+
+	/* Linear Congruential Generator */
+	ru_x = (ru_a * ru_x + ru_b) % RU_M;
+	ru_counter++;
+
+	r = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb;
+
+	_THREAD_PRIVATE_MUTEX_UNLOCK(random);
+
+	return (r);
+}
+
+#if 0
+int
+main(int argc, char **argv)
+{
+	int i, n;
+	u_int16_t wert;
+
+	res_initid();
+
+	printf("Generator: %u\n", ru_g);
+	printf("Seed: %u\n", ru_seed);
+	printf("Reseed at %ld\n", ru_reseed);
+	printf("Ru_X: %u\n", ru_x);
+	printf("Ru_A: %u\n", ru_a);
+	printf("Ru_B: %u\n", ru_b);
+
+	n = argc > 1 ? atoi(argv[1]) : 60001;
+	for (i=0;i<n;i++) {
+		wert = res_randomid();
+		printf("%u\n", wert);
+	}
+	return 0;
+}
+#endif
+
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
new file mode 100644
index 0000000..8cda047
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
@@ -0,0 +1,183 @@
+/*	$OpenBSD: fmemopen.c,v 1.2 2013/03/27 15:06:25 mpi Exp $	*/
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2009 Ted Unangst
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+struct state {
+	char		*string;	/* actual stream */
+	size_t		 pos;		/* current position */
+	size_t		 size;		/* allocated size */
+	size_t		 len;		/* length of the data */
+	int		 update;	/* open for update */
+};
+
+static int
+fmemopen_read(void *v, char *b, int l)
+{
+	struct state	*st = v;
+	int		 i;
+
+	for (i = 0; i < l && i + st->pos < st->len; i++)
+		b[i] = st->string[st->pos + i];
+	st->pos += i;
+
+	return (i);
+}
+
+static int
+fmemopen_write(void *v, const char *b, int l)
+{
+	struct state	*st = v;
+	int		i;
+
+	for (i = 0; i < l && i + st->pos < st->size; i++)
+		st->string[st->pos + i] = b[i];
+	st->pos += i;
+
+	if (st->pos >= st->len) {
+		st->len = st->pos;
+
+		if (st->len < st->size)
+			st->string[st->len] = '\0';
+		else if (!st->update)
+			st->string[st->size - 1] = '\0';
+	}
+
+	return (i);
+}
+
+static fpos_t
+fmemopen_seek(void *v, fpos_t off, int whence)
+{
+	struct state	*st = v;
+	ssize_t		 base = 0;
+
+	switch (whence) {
+	case SEEK_SET:
+		break;
+	case SEEK_CUR:
+		base = st->pos;
+		break;
+	case SEEK_END:
+		base = st->len;
+		break;
+	}
+
+	if (off > st->size - base || off < -base) {
+		errno = EOVERFLOW;
+		return (-1);
+	}
+
+	st->pos = base + off;
+
+	return (st->pos);
+}
+
+static int
+fmemopen_close(void *v)
+{
+	free(v);
+
+	return (0);
+}
+
+static int
+fmemopen_close_free(void *v)
+{
+	struct state	*st = v;
+
+	free(st->string);
+	free(st);
+
+	return (0);
+}
+
+FILE *
+fmemopen(void *buf, size_t size, const char *mode)
+{
+	struct state	*st;
+	FILE		*fp;
+	int		 flags, oflags;
+
+	if (size == 0) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((flags = __sflags(mode, &oflags)) == 0) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (buf == NULL && ((oflags & O_RDWR) == 0)) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((st = malloc(sizeof(*st))) == NULL)
+		return (NULL);
+
+	if ((fp = __sfp()) == NULL) {
+		free(st);
+		return (NULL);
+	}
+
+	st->pos = 0;
+	st->len = (oflags & O_WRONLY) ? 0 : size;
+	st->size = size;
+	st->update = oflags & O_RDWR;
+
+	if (buf == NULL) {
+		if ((st->string = malloc(size)) == NULL) {
+			free(st);
+			fp->_flags = 0;
+			return (NULL);
+		}
+		*st->string = '\0';
+	} else {
+		st->string = (char *)buf;
+
+		if (oflags & O_TRUNC)
+			*st->string = '\0';
+
+		if (oflags & O_APPEND) {
+			char	*p;
+
+			if ((p = memchr(st->string, '\0', size)) != NULL)
+				st->pos = st->len = (p - st->string);
+			else
+				st->pos = st->len = size;
+		}
+	}
+
+	fp->_flags = (short)flags;
+	fp->_file = -1;
+	fp->_cookie = (void *)st;
+	fp->_read = (flags & __SWR) ? NULL : fmemopen_read;
+	fp->_write = (flags & __SRD) ? NULL : fmemopen_write;
+	fp->_seek = fmemopen_seek;
+	fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close;
+
+	return (fp);
+}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
new file mode 100644
index 0000000..4610535
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
@@ -0,0 +1,158 @@
+/*	$OpenBSD: open_memstream.c,v 1.3 2013/04/03 03:11:53 guenther Exp $	*/
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+struct state {
+	char		 *string;	/* actual stream */
+	char		**pbuf;		/* point to the stream */
+	size_t		 *psize;	/* point to min(pos, len) */
+	size_t		  pos;		/* current position */
+	size_t		  size;		/* number of allocated char */
+	size_t		  len;		/* length of the data */
+};
+
+static int
+memstream_write(void *v, const char *b, int l)
+{
+	struct state	*st = v;
+	char		*p;
+	size_t		 i, end;
+
+	end = (st->pos + l);
+
+	if (end >= st->size) {
+		/* 1.6 is (very) close to the golden ratio. */
+		size_t	sz = st->size * 8 / 5;
+
+		if (sz < end + 1)
+			sz = end + 1;
+		p = realloc(st->string, sz);
+		if (!p)
+			return (-1);
+		bzero(p + st->size, sz - st->size);
+		*st->pbuf = st->string = p;
+		st->size = sz;
+	}
+
+	for (i = 0; i < l; i++)
+		st->string[st->pos + i] = b[i];
+	st->pos += l;
+
+	if (st->pos > st->len) {
+		st->len = st->pos;
+		st->string[st->len] = '\0';
+	}
+
+	*st->psize = st->pos;
+
+	return (i);
+}
+
+static fpos_t
+memstream_seek(void *v, fpos_t off, int whence)
+{
+	struct state	*st = v;
+	ssize_t		 base = 0;
+
+	switch (whence) {
+	case SEEK_SET:
+		break;
+	case SEEK_CUR:
+		base = st->pos;
+		break;
+	case SEEK_END:
+		base = st->len;
+		break;
+	}
+
+	if (off > SIZE_MAX - base || off < -base) {
+		errno = EOVERFLOW;
+		return (-1);
+	}
+
+	st->pos = base + off;
+	*st->psize = MIN(st->pos, st->len);
+
+	return (st->pos);
+}
+
+static int
+memstream_close(void *v)
+{
+	struct state	*st = v;
+
+	free(st);
+
+	return (0);
+}
+
+FILE *
+open_memstream(char **pbuf, size_t *psize)
+{
+	struct state	*st;
+	FILE		*fp;
+
+	if (pbuf == NULL || psize == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((st = malloc(sizeof(*st))) == NULL)
+		return (NULL);
+
+	if ((fp = __sfp()) == NULL) {
+		free(st);
+		return (NULL);
+	}
+
+	st->size = BUFSIZ;
+	if ((st->string = calloc(1, st->size)) == NULL) {
+		free(st);
+		fp->_flags = 0;
+		return (NULL);
+	}
+
+	*st->string = '\0';
+	st->pos = 0;
+	st->len = 0;
+	st->pbuf = pbuf;
+	st->psize = psize;
+
+	*pbuf = st->string;
+	*psize = st->len;
+
+	fp->_flags = __SWR;
+	fp->_file = -1;
+	fp->_cookie = st;
+	fp->_read = NULL;
+	fp->_write = memstream_write;
+	fp->_seek = memstream_seek;
+	fp->_close = memstream_close;
+	_SET_ORIENTATION(fp, -1);
+
+	return (fp);
+}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
new file mode 100644
index 0000000..9414187
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
@@ -0,0 +1,169 @@
+/*	$OpenBSD: open_wmemstream.c,v 1.3 2014/03/06 07:28:21 gerhard Exp $	*/
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "local.h"
+
+struct state {
+	wchar_t		 *string;	/* actual stream */
+	wchar_t		**pbuf;		/* point to the stream */
+	size_t		 *psize;	/* point to min(pos, len) */
+	size_t		  pos;		/* current position */
+	size_t		  size;		/* number of allocated wchar_t */
+	size_t		  len;		/* length of the data */
+	mbstate_t	  mbs;		/* conversion state of the stream */
+};
+
+static int
+wmemstream_write(void *v, const char *b, int l)
+{
+	struct state	*st = v;
+	wchar_t		*p;
+	size_t		 nmc, len, end;
+
+	end = (st->pos + l);
+
+	if (end >= st->size) {
+		/* 1.6 is (very) close to the golden ratio. */
+		size_t	sz = st->size * 8 / 5;
+
+		if (sz < end + 1)
+			sz = end + 1;
+		p = realloc(st->string, sz * sizeof(wchar_t));
+		if (!p)
+			return (-1);
+		bzero(p + st->size, (sz - st->size) * sizeof(wchar_t));
+		*st->pbuf = st->string = p;
+		st->size = sz;
+	}
+
+	nmc = (st->size - st->pos) * sizeof(wchar_t);
+	len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs);
+	if (len == (size_t)-1)
+		return (-1);
+	st->pos += len;
+
+	if (st->pos > st->len) {
+		st->len = st->pos;
+		st->string[st->len] = L'\0';
+	}
+
+	*st->psize = st->pos;
+
+	return (len);
+}
+
+static fpos_t
+wmemstream_seek(void *v, fpos_t off, int whence)
+{
+	struct state	*st = v;
+	ssize_t		 base = 0;
+
+	switch (whence) {
+	case SEEK_SET:
+		break;
+	case SEEK_CUR:
+		base = st->pos;
+		break;
+	case SEEK_END:
+		base = st->len;
+		break;
+	}
+
+	if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) {
+		errno = EOVERFLOW;
+		return (-1);
+	}
+
+	/*
+	 * XXX Clearing mbs here invalidates shift state for state-
+	 * dependent encodings, but they are not (yet) supported.
+	 */
+	bzero(&st->mbs, sizeof(st->mbs));
+
+	st->pos = base + off;
+	*st->psize = MIN(st->pos, st->len);
+
+	return (st->pos);
+}
+
+static int
+wmemstream_close(void *v)
+{
+	struct state	*st = v;
+
+	free(st);
+
+	return (0);
+}
+
+FILE *
+open_wmemstream(wchar_t **pbuf, size_t *psize)
+{
+	struct state	*st;
+	FILE		*fp;
+
+	if (pbuf == NULL || psize == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((st = malloc(sizeof(*st))) == NULL)
+		return (NULL);
+
+	if ((fp = __sfp()) == NULL) {
+		free(st);
+		return (NULL);
+	}
+
+	st->size = BUFSIZ * sizeof(wchar_t);
+	if ((st->string = calloc(1, st->size)) == NULL) {
+		free(st);
+		fp->_flags = 0;
+		return (NULL);
+	}
+
+	*st->string = L'\0';
+	st->pos = 0;
+	st->len = 0;
+	st->pbuf = pbuf;
+	st->psize = psize;
+	bzero(&st->mbs, sizeof(st->mbs));
+
+	*pbuf = st->string;
+	*psize = st->len;
+
+	fp->_flags = __SWR;
+	fp->_file = -1;
+	fp->_cookie = st;
+	fp->_read = NULL;
+	fp->_write = wmemstream_write;
+	fp->_seek = wmemstream_seek;
+	fp->_close = wmemstream_close;
+	_SET_ORIENTATION(fp, 1);
+
+	return (fp);
+}
diff --git a/libm/Android.mk b/libm/Android.mk
index 994caa0..f59b71f 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -255,6 +255,10 @@
 # libm.a for target.
 #
 include $(CLEAR_VARS)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+# Clang has wrong long double sizes for x86.
+LOCAL_CLANG := false
+endif
 LOCAL_MODULE:= libm
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_ARM_MODE := arm
@@ -287,6 +291,10 @@
 # libm.so for target.
 #
 include $(CLEAR_VARS)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+# Clang has wrong long double sizes for x86.
+LOCAL_CLANG := false
+endif
 LOCAL_MODULE:= libm
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
diff --git a/libm/include/math.h b/libm/include/math.h
index 3eca140..1fcc578 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/libstdc++/include/new b/libstdc++/include/new
index 0253e8b..c5a43de 100644
--- a/libstdc++/include/new
+++ b/libstdc++/include/new
@@ -13,19 +13,19 @@
 
 void* operator new(std::size_t);
 void* operator new[](std::size_t);
-void  operator delete(void*);
-void  operator delete[](void*);
+void  operator delete(void*) throw();
+void  operator delete[](void*) throw();
 void* operator new(std::size_t, const std::nothrow_t&);
 void* operator new[](std::size_t, const std::nothrow_t&);
-void  operator delete(void*, const std::nothrow_t&);
-void  operator delete[](void*, const std::nothrow_t&);
+void  operator delete(void*, const std::nothrow_t&) throw();
+void  operator delete[](void*, const std::nothrow_t&) throw();
 
 inline void* operator new(std::size_t, void* p) { return p; }
 inline void* operator new[](std::size_t, void* p) { return p; }
 
 // these next two are not really required, since exceptions are off
-inline void  operator delete(void*, void*) { }
-inline void  operator delete[](void*, void*) { }
+inline void  operator delete(void*, void*) throw() { }
+inline void  operator delete[](void*, void*) throw() { }
 
 }  // extern C++
 
diff --git a/linker/Android.mk b/linker/Android.mk
index 5853c90..d6e0095 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -8,6 +8,7 @@
     linker.cpp \
     linker_allocator.cpp \
     linker_environ.cpp \
+    linker_libc_support.c \
     linker_phdr.cpp \
     rt.cpp \
 
@@ -44,13 +45,11 @@
 # TODO: split out the asflags.
 LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/linker_executable.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_STATIC_LIBRARIES := libc_nomalloc
 
-LOCAL_FORCE_STATIC_EXECUTABLE := true # not necessary when not including BUILD_EXECUTABLE
-
-LOCAL_2ND_ARCH_VAR_PREFIX := $(linker_2nd_arch_var_prefix)
+LOCAL_FORCE_STATIC_EXECUTABLE := true
 
 LOCAL_MODULE := linker
 LOCAL_MODULE_STEM_32 := linker
@@ -61,17 +60,12 @@
 # meaningful name resolution.
 LOCAL_STRIP_MODULE := keep_symbols
 
-include $(LOCAL_PATH)/linker_executable.mk
-ifdef TARGET_2ND_ARCH
-LOCAL_2ND_ARCH_VAR_PREFIX := $(TARGET_2ND_ARCH_VAR_PREFIX)
-OVERRIDE_BUILT_MODULE_PATH :=
-LOCAL_BUILT_MODULE :=
-LOCAL_INSTALLED_MODULE :=
-LOCAL_MODULE_STEM :=
-LOCAL_BUILT_MODULE_STEM :=
-LOCAL_INSTALLED_MODULE_STEM :=
-LOCAL_INTERMEDIATE_TARGETS :=
-include $(LOCAL_PATH)/linker_executable.mk
-endif
+# Insert an extra objcopy step to add prefix to symbols.
+# Note we are using "=" instead of ":=" to defer the evaluation,
+# because LOCAL_2ND_ARCH_VAR_PREFIX or linked_module isn't set properly yet at this point.
+LOCAL_POST_LINK_CMD = $(hide) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) \
+  --prefix-symbols=__dl_ $(linked_module)
+
+include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index c316151..6565985 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -162,12 +162,12 @@
     thread_name[MAX_TASK_NAME_LEN] = 0;
   }
 
-  // "info" will be NULL if the siginfo_t information was not available.
+  // "info" will be null if the siginfo_t information was not available.
   // Many signals don't have an address or a code.
   char code_desc[32]; // ", code -6"
   char addr_desc[32]; // ", fault addr 0x1234"
   addr_desc[0] = code_desc[0] = 0;
-  if (info != NULL) {
+  if (info != nullptr) {
     // For a rethrown signal, this si_code will be right and the one debuggerd shows will
     // always be SI_TKILL.
     __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
@@ -198,7 +198,7 @@
   }
   bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
 
-  if (sigaction(signum, &old_action, NULL) == -1) {
+  if (sigaction(signum, &old_action, nullptr) == -1) {
     __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
                       strerror(errno));
   }
@@ -230,7 +230,7 @@
   msg.action = DEBUGGER_ACTION_CRASH;
   msg.tid = gettid();
   msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message);
-  msg.original_si_code = (info != NULL) ? info->si_code : 0;
+  msg.original_si_code = (info != nullptr) ? info->si_code : 0;
   int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
   if (ret == sizeof(msg)) {
     char debuggerd_ack;
@@ -255,7 +255,7 @@
   // It's possible somebody cleared the SA_SIGINFO flag, which would mean
   // our "info" arg holds an undefined value.
   if (!have_siginfo(signal_number)) {
-    info = NULL;
+    info = nullptr;
   }
 
   log_signal_summary(signal_number, info);
@@ -296,14 +296,14 @@
   // Use the alternate signal stack if available so we can catch stack overflows.
   action.sa_flags |= SA_ONSTACK;
 
-  sigaction(SIGABRT, &action, NULL);
-  sigaction(SIGBUS, &action, NULL);
-  sigaction(SIGFPE, &action, NULL);
-  sigaction(SIGILL, &action, NULL);
-  sigaction(SIGPIPE, &action, NULL);
-  sigaction(SIGSEGV, &action, NULL);
+  sigaction(SIGABRT, &action, nullptr);
+  sigaction(SIGBUS, &action, nullptr);
+  sigaction(SIGFPE, &action, nullptr);
+  sigaction(SIGILL, &action, nullptr);
+  sigaction(SIGPIPE, &action, nullptr);
+  sigaction(SIGSEGV, &action, nullptr);
 #if defined(SIGSTKFLT)
-  sigaction(SIGSTKFLT, &action, NULL);
+  sigaction(SIGSTKFLT, &action, nullptr);
 #endif
-  sigaction(SIGTRAP, &action, NULL);
+  sigaction(SIGTRAP, &action, nullptr);
 }
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 5d6db8e..38484d9 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -42,7 +42,7 @@
 static void __bionic_format_dlerror(const char* msg, const char* detail) {
   char* buffer = __get_thread()->dlerror_buffer;
   strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE);
-  if (detail != NULL) {
+  if (detail != nullptr) {
     strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE);
     strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE);
   }
@@ -51,7 +51,7 @@
 }
 
 const char* dlerror() {
-  const char* old_value = __bionic_set_dlerror(NULL);
+  const char* old_value = __bionic_set_dlerror(nullptr);
   return old_value;
 }
 
@@ -68,9 +68,9 @@
 static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
   soinfo* result = do_dlopen(filename, flags, extinfo);
-  if (result == NULL) {
+  if (result == nullptr) {
     __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
-    return NULL;
+    return nullptr;
   }
   return result;
 }
@@ -80,33 +80,33 @@
 }
 
 void* dlopen(const char* filename, int flags) {
-  return dlopen_ext(filename, flags, NULL);
+  return dlopen_ext(filename, flags, nullptr);
 }
 
 void* dlsym(void* handle, const char* symbol) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
 
 #if !defined(__LP64__)
-  if (handle == NULL) {
-    __bionic_format_dlerror("dlsym library handle is null", NULL);
-    return NULL;
+  if (handle == nullptr) {
+    __bionic_format_dlerror("dlsym library handle is null", nullptr);
+    return nullptr;
   }
 #endif
 
-  if (symbol == NULL) {
-    __bionic_format_dlerror("dlsym symbol name is null", NULL);
-    return NULL;
+  if (symbol == nullptr) {
+    __bionic_format_dlerror("dlsym symbol name is null", nullptr);
+    return nullptr;
   }
 
-  soinfo* found = NULL;
-  ElfW(Sym)* sym = NULL;
+  soinfo* found = nullptr;
+  ElfW(Sym)* sym = nullptr;
   if (handle == RTLD_DEFAULT) {
-    sym = dlsym_linear_lookup(symbol, &found, NULL);
+    sym = dlsym_linear_lookup(symbol, &found, nullptr);
   } else if (handle == RTLD_NEXT) {
     void* caller_addr = __builtin_return_address(0);
     soinfo* si = find_containing_library(caller_addr);
 
-    sym = NULL;
+    sym = nullptr;
     if (si && si->next) {
       sym = dlsym_linear_lookup(symbol, &found, si->next);
     }
@@ -114,7 +114,7 @@
     sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
   }
 
-  if (sym != NULL) {
+  if (sym != nullptr) {
     unsigned bind = ELF_ST_BIND(sym->st_info);
 
     if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
@@ -122,10 +122,10 @@
     }
 
     __bionic_format_dlerror("symbol found but not global", symbol);
-    return NULL;
+    return nullptr;
   } else {
     __bionic_format_dlerror("undefined symbol", symbol);
-    return NULL;
+    return nullptr;
   }
 }
 
@@ -134,7 +134,7 @@
 
   // Determine if this address can be found in any library currently mapped.
   soinfo* si = find_containing_library(addr);
-  if (si == NULL) {
+  if (si == nullptr) {
     return 0;
   }
 
@@ -146,7 +146,7 @@
 
   // Determine if any symbol in the library contains the specified address.
   ElfW(Sym)* sym = dladdr_find_symbol(si, addr);
-  if (sym != NULL) {
+  if (sym != nullptr) {
     info->dli_sname = si->strtab + sym->st_name;
     info->dli_saddr = reinterpret_cast<void*>(si->load_bias + sym->st_value);
   }
@@ -164,7 +164,7 @@
 // name_offset: starting index of the name in libdl_info.strtab
 #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
     { name_offset, \
-      reinterpret_cast<Elf32_Addr>(reinterpret_cast<void*>(value)), \
+      reinterpret_cast<Elf32_Addr>(value), \
       /* st_size */ 0, \
       (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
       /* st_other */ 0, \
@@ -176,7 +176,7 @@
       (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
       /* st_other */ 0, \
       shndx, \
-      reinterpret_cast<Elf64_Addr>(reinterpret_cast<void*>(value)), \
+      reinterpret_cast<Elf64_Addr>(value), \
       /* st_size */ 0, \
     }
 
@@ -199,7 +199,7 @@
   // This is actually the STH_UNDEF entry. Technically, it's
   // supposed to have st_name == 0, but instead, it points to an index
   // in the strtab with a \0 to make iterating through the symtab easier.
-  ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0),
+  ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0),
   ELFW(SYM_INITIALIZER)(  0, &dlopen, 1),
   ELFW(SYM_INITIALIZER)(  7, &dlclose, 1),
   ELFW(SYM_INITIALIZER)( 15, &dlsym, 1),
@@ -232,17 +232,12 @@
 static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 #endif
 
-// Defined as global because we do not yet have access
-// to synchronization functions __cxa_guard_* needed
-// to define statics inside functions.
-static soinfo __libdl_info;
+static soinfo __libdl_info("libdl.so", nullptr);
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
 soinfo* get_libdl_info() {
-  if (__libdl_info.name[0] == '\0') {
-    // initialize
-    strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name));
-    __libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO;
+  if ((__libdl_info.flags & FLAG_LINKED) == 0) {
+    __libdl_info.flags |= FLAG_LINKED;
     __libdl_info.strtab = ANDROID_LIBDL_STRTAB;
     __libdl_info.symtab = g_libdl_symtab;
     __libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned);
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 8096e62..5fbdc8f 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -32,6 +32,9 @@
 class LinkedList {
  public:
   LinkedList() : head_(nullptr), tail_(nullptr) {}
+  ~LinkedList() {
+    clear();
+  }
 
   void push_front(T* const element) {
     LinkedListEntry<T>* new_entry = Allocator::alloc();
@@ -83,26 +86,63 @@
   }
 
   template<typename F>
-  void for_each(F&& action) {
-    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
-      if (e->element != nullptr) {
-        action(e->element);
-      }
-    }
+  void for_each(F action) {
+    visit([&] (T* si) {
+      action(si);
+      return true;
+    });
   }
 
   template<typename F>
-  void remove_if(F&& predicate) {
+  bool visit(F action) {
     for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
-      if (e->element != nullptr && predicate(e->element)) {
-        e->element = nullptr;
+      if (!action(e->element)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  template<typename F>
+  void remove_if(F predicate) {
+    for (LinkedListEntry<T>* e = head_, *p = nullptr; e != nullptr;) {
+      if (predicate(e->element)) {
+        LinkedListEntry<T>* next = e->next;
+        if (p == nullptr) {
+          head_ = next;
+        } else {
+          p->next = next;
+        }
+        Allocator::free(e);
+        e = next;
+      } else {
+        p = e;
+        e = e->next;
       }
     }
   }
 
-  bool contains(const T* el) {
+  size_t size() const {
+    size_t sz = 0;
     for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
-      if (e->element != nullptr && e->element == el) {
+      ++sz;
+    }
+
+    return sz;
+  }
+
+  size_t copy_to_array(T* array[], size_t array_length) const {
+    size_t sz = 0;
+    for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
+      array[sz++] = e->element;
+    }
+
+    return sz;
+  }
+
+  bool contains(const T* el) const {
+    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+      if (e->element == el) {
         return true;
       }
     }
diff --git a/linker/linker.cpp b/linker/linker.cpp
index cf65705..2186b3d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -35,9 +35,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
+#include <new>
+
 // Private C library headers.
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
@@ -78,7 +79,6 @@
 #define SEARCH_NAME(x) get_base_name(x)
 #endif
 
-static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo);
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
 static LinkerAllocator<soinfo> g_soinfo_allocator;
@@ -96,7 +96,7 @@
   "/vendor/lib",
   "/system/lib",
 #endif
-  NULL
+  nullptr
 };
 
 #define LDPATH_BUFSIZE (LDPATH_MAX*64)
@@ -115,7 +115,7 @@
 
 __LIBC_HIDDEN__ int g_ld_debug_verbosity;
 
-__LIBC_HIDDEN__ abort_msg_t* g_abort_message = NULL; // For debuggerd.
+__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
 
 enum RelocationKind {
     kRelocAbsolute = 0,
@@ -188,7 +188,7 @@
 extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
 
 static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
-static r_debug _r_debug = {1, NULL, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
+static r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
 static link_map* r_debug_tail = 0;
 
 static void insert_soinfo_into_debug_map(soinfo* info) {
@@ -287,20 +287,10 @@
 static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) {
   if (strlen(name) >= SOINFO_NAME_LEN) {
     DL_ERR("library name \"%s\" too long", name);
-    return NULL;
+    return nullptr;
   }
 
-  soinfo* si = g_soinfo_allocator.alloc();
-
-  // Initialize the new element.
-  memset(si, 0, sizeof(soinfo));
-  strlcpy(si->name, name, sizeof(si->name));
-  si->flags = FLAG_NEW_SOINFO;
-
-  if (file_stat != NULL) {
-    si->set_st_dev(file_stat->st_dev);
-    si->set_st_ino(file_stat->st_ino);
-  }
+  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat);
 
   sonext->next = si;
   sonext = si;
@@ -310,7 +300,7 @@
 }
 
 static void soinfo_free(soinfo* si) {
-    if (si == NULL) {
+    if (si == nullptr) {
         return;
     }
 
@@ -318,16 +308,16 @@
       munmap(reinterpret_cast<void*>(si->base), si->size);
     }
 
-    soinfo *prev = NULL, *trav;
+    soinfo *prev = nullptr, *trav;
 
     TRACE("name %s: freeing soinfo @ %p", si->name, si);
 
-    for (trav = solist; trav != NULL; trav = trav->next) {
+    for (trav = solist; trav != nullptr; trav = trav->next) {
         if (trav == si)
             break;
         prev = trav;
     }
-    if (trav == NULL) {
+    if (trav == nullptr) {
         /* si was not in solist */
         DL_ERR("name \"%s\" is not in solist!", si->name);
         return;
@@ -336,7 +326,7 @@
     // clear links to/from si
     si->remove_all_links();
 
-    /* prev will never be NULL, because the first entry in solist is
+    /* prev will never be null, because the first entry in solist is
        always the static libdl_info.
     */
     prev->next = si->next;
@@ -350,7 +340,7 @@
 
 static void parse_path(const char* path, const char* delimiters,
                        const char** array, char* buf, size_t buf_size, size_t max_count) {
-  if (path == NULL) {
+  if (path == nullptr) {
     return;
   }
 
@@ -367,9 +357,9 @@
   // Forget the last path if we had to truncate; this occurs if the 2nd to
   // last char isn't '\0' (i.e. wasn't originally a delimiter).
   if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
-    array[i - 1] = NULL;
+    array[i - 1] = nullptr;
   } else {
-    array[i] = NULL;
+    array[i] = nullptr;
   }
 }
 
@@ -405,7 +395,7 @@
         }
     }
     *pcount = 0;
-    return NULL;
+    return nullptr;
 }
 
 #endif
@@ -414,7 +404,7 @@
  * loaded libraries. gcc_eh does the rest. */
 int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
     int rv = 0;
-    for (soinfo* si = solist; si != NULL; si = si->next) {
+    for (soinfo* si = solist; 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;
@@ -463,7 +453,46 @@
              name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
 
 
-  return NULL;
+  return nullptr;
+}
+
+soinfo::soinfo(const char* name, const struct stat* file_stat) {
+  memset(this, 0, sizeof(*this));
+
+  strlcpy(this->name, name, sizeof(this->name));
+  flags = FLAG_NEW_SOINFO;
+  version = SOINFO_VERSION;
+
+  if (file_stat != nullptr) {
+    set_st_dev(file_stat->st_dev);
+    set_st_ino(file_stat->st_ino);
+  }
+}
+
+void soinfo::resolve_ifunc_symbols() {
+  if (!get_has_ifuncs()) {
+    return;
+  }
+
+  phdr_table_unprotect_segments(phdr, phnum, load_bias);
+
+  TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES");
+
+  for (size_t i = 0; i < nchain; ++i) {
+    ElfW(Sym)* s = &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 + base);
+      s->st_value = (ifunc_ptr() - base);
+      TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value);
+    }
+  }
+  phdr_table_protect_segments(phdr, phnum, load_bias);
 }
 
 static unsigned elfhash(const char* _name) {
@@ -479,11 +508,11 @@
     return h;
 }
 
-static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) {
+static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) {
     unsigned elf_hash = elfhash(name);
-    ElfW(Sym)* s = NULL;
+    ElfW(Sym)* s = nullptr;
 
-    if (si != NULL && somain != NULL) {
+    if (si != nullptr && somain != nullptr) {
         /*
          * Local scope is executable scope. Just start looking into it right away
          * for the shortcut.
@@ -491,7 +520,7 @@
 
         if (si == somain) {
             s = soinfo_elf_lookup(si, elf_hash, name);
-            if (s != NULL) {
+            if (s != nullptr) {
                 *lsi = si;
                 goto done;
             }
@@ -517,7 +546,7 @@
                 DEBUG("%s: looking up %s in executable %s",
                       si->name, name, somain->name);
                 s = soinfo_elf_lookup(somain, elf_hash, name);
-                if (s != NULL) {
+                if (s != nullptr) {
                     *lsi = somain;
                     goto done;
                 }
@@ -543,7 +572,7 @@
              * Here we return the first definition found for simplicity.  */
 
             s = soinfo_elf_lookup(si, elf_hash, name);
-            if (s != NULL) {
+            if (s != nullptr) {
                 *lsi = si;
                 goto done;
             }
@@ -557,7 +586,7 @@
                 DEBUG("%s: looking up %s in executable %s after local scope",
                       si->name, name, somain->name);
                 s = soinfo_elf_lookup(somain, elf_hash, name);
-                if (s != NULL) {
+                if (s != nullptr) {
                     *lsi = somain;
                     goto done;
                 }
@@ -574,18 +603,18 @@
         }
     }
 
-    for (int i = 0; needed[i] != NULL; i++) {
-        DEBUG("%s: looking up %s in %s",
-              si->name, name, needed[i]->name);
-        s = soinfo_elf_lookup(needed[i], elf_hash, name);
-        if (s != NULL) {
-            *lsi = needed[i];
-            goto done;
+    si->get_children().visit([&](soinfo* child) {
+        DEBUG("%s: looking up %s in %s", si->name, name, child->name);
+        s = soinfo_elf_lookup(child, elf_hash, name);
+        if (s != nullptr) {
+            *lsi = child;
+            return false;
         }
-    }
+        return true;
+    });
 
 done:
-    if (s != NULL) {
+    if (s != nullptr) {
         TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
                    "found in %s, base = %p, load bias = %p",
                    si->name, name, reinterpret_cast<void*>(s->st_value),
@@ -594,11 +623,45 @@
         return s;
     }
 
-    return NULL;
+    return nullptr;
 }
 
-// Another soinfo list allocator to use in dlsym. We don't reuse
-// SoinfoListAllocator because it is write-protected most of the time.
+// Each size has it's own allocator.
+template<size_t size>
+class SizeBasedAllocator {
+ public:
+  static void* alloc() {
+    return allocator_.alloc();
+  }
+
+  static void free(void* ptr) {
+    allocator_.free(ptr);
+  }
+
+ private:
+  static LinkerBlockAllocator allocator_;
+};
+
+template<size_t size>
+LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
+
+template<typename T>
+class TypeBasedAllocator {
+ public:
+  static T* alloc() {
+    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
+  }
+
+  static void free(T* ptr) {
+    SizeBasedAllocator<sizeof(T)>::free(ptr);
+  }
+};
+
+template <typename T>
+using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
+
+typedef linked_list_t<soinfo> SoinfoLinkedList;
+
 static LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_list_allocator_rw;
 class SoinfoListAllocatorRW {
  public:
@@ -614,8 +677,9 @@
 // This is used by dlsym(3).  It performs symbol lookup only within the
 // specified soinfo object and its dependencies in breadth first order.
 ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
-  LinkedList<soinfo, SoinfoListAllocatorRW> visit_list;
-  LinkedList<soinfo, SoinfoListAllocatorRW> visited;
+  SoinfoLinkedList visit_list;
+  SoinfoLinkedList visited;
+
   visit_list.push_back(si);
   soinfo* current_soinfo;
   while ((current_soinfo = visit_list.pop_front()) != nullptr) {
@@ -627,8 +691,6 @@
 
     if (result != nullptr) {
       *found = current_soinfo;
-      visit_list.clear();
-      visited.clear();
       return result;
     }
     visited.push_back(current_soinfo);
@@ -638,8 +700,6 @@
     });
   }
 
-  visit_list.clear();
-  visited.clear();
   return nullptr;
 }
 
@@ -651,20 +711,20 @@
 ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
   unsigned elf_hash = elfhash(name);
 
-  if (start == NULL) {
+  if (start == nullptr) {
     start = solist;
   }
 
-  ElfW(Sym)* s = NULL;
-  for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
+  ElfW(Sym)* s = nullptr;
+  for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
     s = soinfo_elf_lookup(si, elf_hash, name);
-    if (s != NULL) {
+    if (s != nullptr) {
       *found = si;
       break;
     }
   }
 
-  if (s != NULL) {
+  if (s != nullptr) {
     TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
                name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
   }
@@ -674,12 +734,12 @@
 
 soinfo* find_containing_library(const void* p) {
   ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
-  for (soinfo* si = solist; si != NULL; si = si->next) {
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
     if (address >= si->base && address - si->base < si->size) {
       return si;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) {
@@ -696,12 +756,12 @@
     }
   }
 
-  return NULL;
+  return nullptr;
 }
 
 static int open_library_on_path(const char* name, const char* const paths[]) {
   char buf[512];
-  for (size_t i = 0; paths[i] != NULL; ++i) {
+  for (size_t i = 0; paths[i] != nullptr; ++i) {
     int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
     if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
       PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name);
@@ -719,7 +779,7 @@
   TRACE("[ opening %s ]", name);
 
   // If the name contains a slash, we should attempt to open it directly and not search the paths.
-  if (strchr(name, '/') != NULL) {
+  if (strchr(name, '/') != nullptr) {
     int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
     if (fd != -1) {
       return fd;
@@ -742,14 +802,14 @@
     int fd = -1;
     ScopedFd file_guard(-1);
 
-    if (extinfo != NULL && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+    if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
       fd = extinfo->library_fd;
     } else {
       // Open the file.
       fd = open_library(name);
       if (fd == -1) {
         DL_ERR("library \"%s\" not found", name);
-        return NULL;
+        return nullptr;
       }
 
       file_guard.reset(fd);
@@ -760,12 +820,12 @@
     struct stat file_stat;
     if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
       DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno));
-      return NULL;
+      return nullptr;
     }
 
     // Check for symlink and other situations where
     // file can have different names.
-    for (soinfo* si = solist; si != NULL; si = si->next) {
+    for (soinfo* si = solist; si != nullptr; si = si->next) {
       if (si->get_st_dev() != 0 &&
           si->get_st_ino() != 0 &&
           si->get_st_dev() == file_stat.st_dev &&
@@ -776,17 +836,17 @@
     }
 
     if ((dlflags & RTLD_NOLOAD) != 0) {
-      return NULL;
+      return nullptr;
     }
 
     // Read the ELF header and load the segments.
     if (!elf_reader.Load(extinfo)) {
-        return NULL;
+        return nullptr;
     }
 
     soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat);
-    if (si == NULL) {
-        return NULL;
+    if (si == nullptr) {
+        return nullptr;
     }
     si->base = elf_reader.load_start();
     si->size = elf_reader.load_size();
@@ -799,9 +859,9 @@
     TRACE("[ load_library base=%p size=%zu name='%s' ]",
           reinterpret_cast<void*>(si->base), si->size, si->name);
 
-    if (!soinfo_link_image(si, extinfo)) {
+    if (!si->LinkImage(extinfo)) {
       soinfo_free(si);
-      return NULL;
+      return nullptr;
     }
 
     return si;
@@ -809,16 +869,16 @@
 
 static soinfo *find_loaded_library_by_name(const char* name) {
   const char* search_name = SEARCH_NAME(name);
-  for (soinfo* si = solist; si != NULL; si = si->next) {
+  for (soinfo* si = solist; si != nullptr; si = si->next) {
     if (!strcmp(search_name, si->name)) {
       return si;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) {
-  if (name == NULL) {
+  if (name == nullptr) {
     return somain;
   }
 
@@ -826,14 +886,14 @@
 
   // Library might still be loaded, the accurate detection
   // of this fact is done by load_library
-  if (si == NULL) {
+  if (si == nullptr) {
     TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
     si = load_library(name, dlflags, extinfo);
   }
 
-  if (si != NULL && (si->flags & FLAG_LINKED) == 0) {
+  if (si != nullptr && (si->flags & FLAG_LINKED) == 0) {
     DL_ERR("recursive link to \"%s\"", si->name);
-    return NULL;
+    return nullptr;
   }
 
   return si;
@@ -841,7 +901,7 @@
 
 static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
   soinfo* si = find_library_internal(name, dlflags, extinfo);
-  if (si != NULL) {
+  if (si != nullptr) {
     si->ref_count++;
   }
   return si;
@@ -852,18 +912,25 @@
     TRACE("unloading '%s'", si->name);
     si->CallDestructors();
 
-    if ((si->flags | FLAG_NEW_SOINFO) != 0) {
-      si->get_children().for_each([&] (soinfo* child) {
-        TRACE("%s needs to unload %s", si->name, child->name);
-        soinfo_unload(child);
-      });
+    if (si->has_min_version(0)) {
+      // It is not safe to do si->get_children().for_each, because
+      // during soinfo_free the child will concurrently modify the si->children
+      // list, therefore we create a copy and use it to unload children.
+      size_t children_count = si->get_children().size();
+      soinfo* children[children_count];
+      si->get_children().copy_to_array(children, children_count);
+
+      for (size_t i = 0; i < children_count; ++i) {
+        TRACE("%s needs to unload %s", si->name, children[i]->name);
+        soinfo_unload(children[i]);
+      }
     } else {
       for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
         if (d->d_tag == DT_NEEDED) {
           const char* library_name = si->strtab + d->d_un.d_val;
           TRACE("%s needs to unload %s", si->name, library_name);
-          soinfo* needed = find_library(library_name, RTLD_NOLOAD, NULL);
-          if (needed != NULL) {
+          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
+          if (needed != nullptr) {
             soinfo_unload(needed);
           } else {
             // Not found: for example if symlink was deleted between dlopen and dlclose
@@ -910,15 +977,15 @@
 soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
   if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) {
     DL_ERR("invalid flags to dlopen: %x", flags);
-    return NULL;
+    return nullptr;
   }
-  if (extinfo != NULL && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
+  if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
     DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags);
-    return NULL;
+    return nullptr;
   }
   protect_data(PROT_READ | PROT_WRITE);
   soinfo* si = find_library(name, flags, extinfo);
-  if (si != NULL) {
+  if (si != nullptr) {
     si->CallConstructors();
   }
   protect_data(PROT_READ);
@@ -931,30 +998,77 @@
   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) {
+  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 = nullptr;
+    sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
+    s = soinfo_do_lookup(si, sym_name, &lsi);
+
+    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) {
+  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 = nullptr;
+    sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
+    s = soinfo_do_lookup(si, sym_name, &lsi);
+
+    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[]) {
+int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) {
   ElfW(Sym)* s;
   soinfo* lsi;
 
   for (size_t idx = 0; idx < count; ++idx, ++rela) {
     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) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias);
     ElfW(Addr) sym_addr = 0;
-    const char* sym_name = NULL;
+    const char* sym_name = nullptr;
 
-    DEBUG("Processing '%s' relocation at index %zd", si->name, idx);
+    DEBUG("Processing '%s' relocation at index %zd", name, idx);
     if (type == 0) { // R_*_NONE
       continue;
     }
     if (sym != 0) {
-      sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
-      s = soinfo_do_lookup(si, sym_name, &lsi, needed);
-      if (s == NULL) {
+      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+      s = soinfo_do_lookup(this, sym_name, &lsi);
+      if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
-        s = &si->symtab[sym];
+        s = &symtab[sym];
         if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
-          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
+          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
           return -1;
         }
 
@@ -1006,7 +1120,7 @@
       }
       count_relocation(kRelocSymbol);
     } else {
-      s = NULL;
+      s = nullptr;
     }
 
     switch (type) {
@@ -1112,8 +1226,8 @@
             return -1;
         }
         TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n",
-                   reloc, (si->base + rela->r_addend));
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = (si->base + rela->r_addend);
+                   reloc, (base + rela->r_addend));
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend);
         break;
 
     case R_AARCH64_COPY:
@@ -1126,7 +1240,7 @@
          * R_AARCH64_COPY may only appear in executable objects where e_type is
          * set to ET_EXEC.
          */
-        DL_ERR("%s R_AARCH64_COPY relocations are not supported", si->name);
+        DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
         return -1;
     case R_AARCH64_TLS_TPREL64:
         TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
@@ -1142,7 +1256,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) {
+        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);
@@ -1159,8 +1277,8 @@
         return -1;
       }
       TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc),
-                 static_cast<size_t>(si->base));
-      *reinterpret_cast<ElfW(Addr)*>(reloc) = si->base + rela->r_addend;
+                 static_cast<size_t>(base));
+      *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend;
       break;
     case R_X86_64_32:
       count_relocation(kRelocRelative);
@@ -1195,8 +1313,7 @@
 }
 
 #else // REL, not RELA.
-
-static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) {
+int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) {
     ElfW(Sym)* s;
     soinfo* lsi;
 
@@ -1204,22 +1321,22 @@
         unsigned type = ELFW(R_TYPE)(rel->r_info);
         // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead.
         unsigned sym = ELFW(R_SYM)(rel->r_info);
-        ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias);
+        ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
         ElfW(Addr) sym_addr = 0;
-        const char* sym_name = NULL;
+        const char* sym_name = nullptr;
 
-        DEBUG("Processing '%s' relocation at index %zd", si->name, idx);
+        DEBUG("Processing '%s' relocation at index %zd", name, idx);
         if (type == 0) { // R_*_NONE
             continue;
         }
         if (sym != 0) {
-            sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
-            s = soinfo_do_lookup(si, sym_name, &lsi, needed);
-            if (s == NULL) {
+            sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+            s = soinfo_do_lookup(this, sym_name, &lsi);
+            if (s == nullptr) {
                 // We only allow an undefined symbol if this is a weak reference...
-                s = &si->symtab[sym];
+                s = &symtab[sym];
                 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
-                    DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
+                    DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
                     return -1;
                 }
 
@@ -1274,7 +1391,7 @@
             }
             count_relocation(kRelocSymbol);
         } else {
-            s = NULL;
+            s = nullptr;
         }
 
         switch (type) {
@@ -1314,14 +1431,18 @@
              * R_ARM_COPY may only appear in executable objects where e_type is
              * set to ET_EXEC.
              */
-            DL_ERR("%s R_ARM_COPY relocations are not supported", si->name);
+            DL_ERR("%s R_ARM_COPY relocations are not supported", name);
             return -1;
 #elif defined(__i386__)
         case R_386_JMP_SLOT:
             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) {
+              set_has_ifuncs(true);
+            } else {
+              *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
+            }
             break;
         case R_386_GLOB_DAT:
             count_relocation(kRelocAbsolute);
@@ -1362,7 +1483,7 @@
             if (s) {
                 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
             } else {
-                *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base;
+                *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
             }
             break;
 #endif
@@ -1379,8 +1500,8 @@
                 return -1;
             }
             TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p",
-                       reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(si->base));
-            *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base;
+                       reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
+            *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
             break;
 
         default:
@@ -1393,9 +1514,9 @@
 #endif
 
 #if defined(__mips__)
-static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
+static bool mips_relocate_got(soinfo* si) {
     ElfW(Addr)** got = si->plt_got;
-    if (got == NULL) {
+    if (got == nullptr) {
         return true;
     }
     unsigned local_gotno = si->mips_local_gotno;
@@ -1426,8 +1547,8 @@
         // This is an undefined reference... try to locate it.
         const char* sym_name = si->strtab + sym->st_name;
         soinfo* lsi;
-        ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, needed);
-        if (s == NULL) {
+        ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
+        if (s == nullptr) {
             // We only allow an undefined symbol if this is a weak reference.
             s = &symtab[g];
             if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
@@ -1447,7 +1568,7 @@
 #endif
 
 void soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
-  if (functions == NULL) {
+  if (functions == nullptr) {
     return;
   }
 
@@ -1466,7 +1587,7 @@
 }
 
 void soinfo::CallFunction(const char* function_name __unused, linker_function_t function) {
-  if (function == NULL || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
+  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
     return;
   }
 
@@ -1502,7 +1623,7 @@
   //    out above, the libc constructor will be called again (recursively!).
   constructors_called = true;
 
-  if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
+  if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) {
     // The GNU dynamic linker silently ignores these, but we warn the developer.
     PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
           name, preinit_array_count);
@@ -1517,6 +1638,8 @@
   // DT_INIT should be called before DT_INIT_ARRAY if both are present.
   CallFunction("DT_INIT", init_func);
   CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
+
+  resolve_ifunc_symbols();
 }
 
 void soinfo::CallDestructors() {
@@ -1534,16 +1657,14 @@
 }
 
 void soinfo::add_child(soinfo* child) {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return;
+  if (has_min_version(0)) {
+    child->parents.push_back(this);
+    this->children.push_back(child);
   }
-
-  this->children.push_front(child);
-  child->parents.push_front(this);
 }
 
 void soinfo::remove_all_links() {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
+  if (!has_min_version(0)) {
     return;
   }
 
@@ -1555,7 +1676,7 @@
   });
 
   parents.for_each([&] (soinfo* parent) {
-    parent->children.for_each([&] (const soinfo* child) {
+    parent->children.remove_if([&] (const soinfo* child) {
       return child == this;
     });
   });
@@ -1566,35 +1687,45 @@
 }
 
 void soinfo::set_st_dev(dev_t dev) {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return;
+  if (has_min_version(0)) {
+    st_dev = dev;
   }
-
-  st_dev = dev;
 }
 
 void soinfo::set_st_ino(ino_t ino) {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return;
+  if (has_min_version(0)) {
+    st_ino = ino;
   }
+}
 
-  st_ino = ino;
+void soinfo::set_has_ifuncs(bool ifuncs) {
+  if (has_min_version(1)) {
+    has_ifuncs = ifuncs;
+  }
 }
 
 dev_t soinfo::get_st_dev() {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return 0;
+  if (has_min_version(0)) {
+    return st_dev;
   }
 
-  return st_dev;
+  return 0;
 };
 
 ino_t soinfo::get_st_ino() {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return 0;
+  if (has_min_version(0)) {
+    return st_ino;
   }
 
-  return st_ino;
+  return 0;
+}
+
+bool soinfo::get_has_ifuncs() {
+  if (has_min_version(1)) {
+    return has_ifuncs;
+  }
+
+  return false;
 }
 
 // This is a return on get_children() in case
@@ -1602,11 +1733,11 @@
 static soinfo::soinfo_list_t g_empty_list;
 
 soinfo::soinfo_list_t& soinfo::get_children() {
-  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
-    return g_empty_list;
+  if (has_min_version(0)) {
+    return this->children;
   }
 
-  return this->children;
+  return g_empty_list;
 }
 
 /* Force any of the closed stdin, stdout and stderr to be associated with
@@ -1670,84 +1801,80 @@
     return return_value;
 }
 
-static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
-    /* "base" might wrap around UINT32_MAX. */
-    ElfW(Addr) base = si->load_bias;
-    const ElfW(Phdr)* phdr = si->phdr;
-    int phnum = si->phnum;
-    bool relocating_linker = (si->flags & FLAG_LINKER) != 0;
+bool soinfo::LinkImage(const android_dlextinfo* extinfo) {
+    bool relocating_linker = (flags & FLAG_LINKER) != 0;
 
     /* We can't debug anything until the linker is relocated */
     if (!relocating_linker) {
-        INFO("[ linking %s ]", si->name);
-        DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(si->base), si->flags);
+        INFO("[ linking %s ]", name);
+        DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags);
     }
 
     /* Extract dynamic section */
     size_t dynamic_count;
     ElfW(Word) dynamic_flags;
-    phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
+    phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic,
                                    &dynamic_count, &dynamic_flags);
-    if (si->dynamic == NULL) {
+    if (dynamic == nullptr) {
         if (!relocating_linker) {
-            DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name);
+            DL_ERR("missing PT_DYNAMIC in \"%s\"", name);
         }
         return false;
     } else {
         if (!relocating_linker) {
-            DEBUG("dynamic = %p", si->dynamic);
+            DEBUG("dynamic = %p", dynamic);
         }
     }
 
 #if defined(__arm__)
-    (void) phdr_table_get_arm_exidx(phdr, phnum, base,
-                                    &si->ARM_exidx, &si->ARM_exidx_count);
+    (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
+                                    &ARM_exidx, &ARM_exidx_count);
 #endif
 
     // Extract useful information from dynamic section.
     uint32_t needed_count = 0;
-    for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+    for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
         DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
               d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
         switch (d->d_tag) {
         case DT_HASH:
-            si->nbucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[0];
-            si->nchain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[1];
-            si->bucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8);
-            si->chain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8 + si->nbucket * 4);
+            nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
+            nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
+            bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
+            chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4);
             break;
         case DT_STRTAB:
-            si->strtab = reinterpret_cast<const char*>(base + d->d_un.d_ptr);
+            strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
             break;
         case DT_SYMTAB:
-            si->symtab = reinterpret_cast<ElfW(Sym)*>(base + d->d_un.d_ptr);
+            symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
             break;
 #if !defined(__LP64__)
         case DT_PLTREL:
             if (d->d_un.d_val != DT_REL) {
-                DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
+                DL_ERR("unsupported DT_RELA in \"%s\"", name);
                 return false;
             }
             break;
 #endif
         case DT_JMPREL:
 #if defined(USE_RELA)
-            si->plt_rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr);
+            plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
 #else
-            si->plt_rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr);
+            plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
 #endif
             break;
         case DT_PLTRELSZ:
 #if defined(USE_RELA)
-            si->plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
+            plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
 #else
-            si->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
+            plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
 #endif
             break;
 #if defined(__mips__)
         case DT_PLTGOT:
             // Used by mips and mips64.
-            si->plt_got = reinterpret_cast<ElfW(Addr)**>(base + d->d_un.d_ptr);
+            plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
             break;
 #endif
         case DT_DEBUG:
@@ -1765,67 +1892,67 @@
 #endif
 #if defined(USE_RELA)
          case DT_RELA:
-            si->rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr);
+            rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
             break;
          case DT_RELASZ:
-            si->rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
+            rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
             break;
         case DT_REL:
-            DL_ERR("unsupported DT_REL in \"%s\"", si->name);
+            DL_ERR("unsupported DT_REL in \"%s\"", name);
             return false;
         case DT_RELSZ:
-            DL_ERR("unsupported DT_RELSZ in \"%s\"", si->name);
+            DL_ERR("unsupported DT_RELSZ in \"%s\"", name);
             return false;
 #else
         case DT_REL:
-            si->rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr);
+            rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
             break;
         case DT_RELSZ:
-            si->rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
+            rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
             break;
          case DT_RELA:
-            DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
+            DL_ERR("unsupported DT_RELA in \"%s\"", name);
             return false;
 #endif
         case DT_INIT:
-            si->init_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
-            DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
+            init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+            DEBUG("%s constructors (DT_INIT) found at %p", name, init_func);
             break;
         case DT_FINI:
-            si->fini_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
-            DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
+            fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+            DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func);
             break;
         case DT_INIT_ARRAY:
-            si->init_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
-            DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
+            init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+            DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array);
             break;
         case DT_INIT_ARRAYSZ:
-            si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+            init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
             break;
         case DT_FINI_ARRAY:
-            si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
-            DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
+            fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+            DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array);
             break;
         case DT_FINI_ARRAYSZ:
-            si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+            fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
             break;
         case DT_PREINIT_ARRAY:
-            si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
-            DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
+            preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+            DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array);
             break;
         case DT_PREINIT_ARRAYSZ:
-            si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+            preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
             break;
         case DT_TEXTREL:
 #if defined(__LP64__)
-            DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", si->name);
+            DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name);
             return false;
 #else
-            si->has_text_relocations = true;
+            has_text_relocations = true;
             break;
 #endif
         case DT_SYMBOLIC:
-            si->has_DT_SYMBOLIC = true;
+            has_DT_SYMBOLIC = true;
             break;
         case DT_NEEDED:
             ++needed_count;
@@ -1833,14 +1960,14 @@
         case DT_FLAGS:
             if (d->d_un.d_val & DF_TEXTREL) {
 #if defined(__LP64__)
-                DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", si->name);
+                DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name);
                 return false;
 #else
-                si->has_text_relocations = true;
+                has_text_relocations = true;
 #endif
             }
             if (d->d_un.d_val & DF_SYMBOLIC) {
-                si->has_DT_SYMBOLIC = true;
+                has_DT_SYMBOLIC = true;
             }
             break;
 #if defined(__mips__)
@@ -1851,7 +1978,7 @@
         case DT_MIPS_RLD_MAP:
             // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
             {
-              r_debug** dp = reinterpret_cast<r_debug**>(base + d->d_un.d_ptr);
+              r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
               *dp = &_r_debug;
             }
             break;
@@ -1862,15 +1989,15 @@
             break;
 
         case DT_MIPS_SYMTABNO:
-            si->mips_symtabno = d->d_un.d_val;
+            mips_symtabno = d->d_un.d_val;
             break;
 
         case DT_MIPS_LOCAL_GOTNO:
-            si->mips_local_gotno = d->d_un.d_val;
+            mips_local_gotno = d->d_un.d_val;
             break;
 
         case DT_MIPS_GOTSYM:
-            si->mips_gotsym = d->d_un.d_val;
+            mips_gotsym = d->d_un.d_val;
             break;
 #endif
 
@@ -1882,150 +2009,157 @@
     }
 
     DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
-          reinterpret_cast<void*>(si->base), si->strtab, si->symtab);
+          reinterpret_cast<void*>(base), strtab, symtab);
 
     // Sanity checks.
     if (relocating_linker && needed_count != 0) {
         DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
         return false;
     }
-    if (si->nbucket == 0) {
-        DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
+    if (nbucket == 0) {
+        DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name);
         return false;
     }
-    if (si->strtab == 0) {
-        DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name);
+    if (strtab == 0) {
+        DL_ERR("empty/missing DT_STRTAB in \"%s\"", name);
         return false;
     }
-    if (si->symtab == 0) {
-        DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name);
+    if (symtab == 0) {
+        DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name);
         return false;
     }
 
     // If this is the main executable, then load all of the libraries from LD_PRELOAD now.
-    if (si->flags & FLAG_EXE) {
+    if (flags & FLAG_EXE) {
         memset(g_ld_preloads, 0, sizeof(g_ld_preloads));
         size_t preload_count = 0;
-        for (size_t i = 0; g_ld_preload_names[i] != NULL; i++) {
-            soinfo* lsi = find_library(g_ld_preload_names[i], 0, NULL);
-            if (lsi != NULL) {
+        for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) {
+            soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr);
+            if (lsi != nullptr) {
                 g_ld_preloads[preload_count++] = lsi;
             } else {
                 // As with glibc, failure to load an LD_PRELOAD library is just a warning.
                 DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s",
-                        g_ld_preload_names[i], si->name, linker_get_error_buffer());
+                        g_ld_preload_names[i], name, linker_get_error_buffer());
             }
         }
     }
 
-    soinfo** needed = reinterpret_cast<soinfo**>(alloca((1 + needed_count) * sizeof(soinfo*)));
-    soinfo** pneeded = needed;
-
-    for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+    for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
         if (d->d_tag == DT_NEEDED) {
-            const char* library_name = si->strtab + d->d_un.d_val;
-            DEBUG("%s needs %s", si->name, library_name);
-            soinfo* lsi = find_library(library_name, 0, NULL);
-            if (lsi == NULL) {
+            const char* library_name = strtab + d->d_un.d_val;
+            DEBUG("%s needs %s", name, library_name);
+            soinfo* lsi = find_library(library_name, 0, nullptr);
+            if (lsi == nullptr) {
                 strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
                 DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
-                       library_name, si->name, tmp_err_buf);
+                       library_name, name, tmp_err_buf);
                 return false;
             }
 
-            si->add_child(lsi);
-            *pneeded++ = lsi;
+            add_child(lsi);
         }
     }
-    *pneeded = NULL;
 
 #if !defined(__LP64__)
-    if (si->has_text_relocations) {
+    if (has_text_relocations) {
         // Make segments writable to allow text relocations to work properly. We will later call
         // phdr_table_protect_segments() after all of them are applied and all constructors are run.
         DL_WARN("%s has text relocations. This is wasting memory and prevents "
-                "security hardening. Please fix.", si->name);
-        if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
+                "security hardening. Please fix.", name);
+        if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
             DL_ERR("can't unprotect loadable segments for \"%s\": %s",
-                   si->name, strerror(errno));
+                   name, strerror(errno));
             return false;
         }
     }
 #endif
 
 #if defined(USE_RELA)
-    if (si->plt_rela != NULL) {
-        DEBUG("[ relocating %s plt ]\n", si->name);
-        if (soinfo_relocate(si, si->plt_rela, si->plt_rela_count, needed)) {
+    if (plt_rela != nullptr) {
+        DEBUG("[ relocating %s plt ]\n", name);
+        if (Relocate(plt_rela, plt_rela_count)) {
             return false;
         }
     }
-    if (si->rela != NULL) {
-        DEBUG("[ relocating %s ]\n", si->name);
-        if (soinfo_relocate(si, si->rela, si->rela_count, needed)) {
+    if (rela != nullptr) {
+        DEBUG("[ relocating %s ]\n", name);
+        if (Relocate(rela, rela_count)) {
             return false;
         }
     }
 #else
-    if (si->plt_rel != NULL) {
-        DEBUG("[ relocating %s plt ]", si->name);
-        if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) {
+    if (plt_rel != nullptr) {
+        DEBUG("[ relocating %s plt ]", name);
+        if (Relocate(plt_rel, plt_rel_count)) {
             return false;
         }
     }
-    if (si->rel != NULL) {
-        DEBUG("[ relocating %s ]", si->name);
-        if (soinfo_relocate(si, si->rel, si->rel_count, needed)) {
+    if (rel != nullptr) {
+        DEBUG("[ relocating %s ]", name);
+        if (Relocate(rel, rel_count)) {
             return false;
         }
     }
 #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(get_has_ifuncs()) {
+#if defined(__i386__)
+      soinfo_ifunc_relocate(this, plt_rel, plt_rel_count);
+#elif defined(__x86_64__)
+      soinfo_ifunc_relocate(this, plt_rela, plt_rela_count);
+#endif
+    }
+
 #if defined(__mips__)
-    if (!mips_relocate_got(si, needed)) {
+    if (!mips_relocate_got(this)) {
         return false;
     }
 #endif
 
-    si->flags |= FLAG_LINKED;
-    DEBUG("[ finished linking %s ]", si->name);
+    flags |= FLAG_LINKED;
+    DEBUG("[ finished linking %s ]", name);
 
 #if !defined(__LP64__)
-    if (si->has_text_relocations) {
+    if (has_text_relocations) {
         // All relocations are done, we can protect our segments back to read-only.
-        if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
+        if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
             DL_ERR("can't protect segments for \"%s\": %s",
-                   si->name, strerror(errno));
+                   name, strerror(errno));
             return false;
         }
     }
 #endif
 
     /* We can also turn on GNU RELRO protection */
-    if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) {
+    if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
         DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
-               si->name, strerror(errno));
+               name, strerror(errno));
         return false;
     }
 
     /* Handle serializing/sharing the RELRO segment */
     if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
-      if (phdr_table_serialize_gnu_relro(si->phdr, si->phnum, si->load_bias,
+      if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
                                          extinfo->relro_fd) < 0) {
         DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
-               si->name, strerror(errno));
+               name, strerror(errno));
         return false;
       }
     } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
-      if (phdr_table_map_gnu_relro(si->phdr, si->phnum, si->load_bias,
+      if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
                                    extinfo->relro_fd) < 0) {
         DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
-               si->name, strerror(errno));
+               name, strerror(errno));
         return false;
       }
     }
 
-    notify_gdb_of_load(si);
+    notify_gdb_of_load(this);
     return true;
 }
 
@@ -2037,11 +2171,11 @@
 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 == NULL) {
+  if (ehdr_vdso == nullptr) {
     return;
   }
 
-  soinfo* si = soinfo_alloc("[vdso]", NULL);
+  soinfo* si = soinfo_alloc("[vdso]", nullptr);
 
   si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
   si->phnum = ehdr_vdso->e_phnum;
@@ -2049,14 +2183,19 @@
   si->size = phdr_table_get_load_size(si->phdr, si->phnum);
   si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
 
-  soinfo_link_image(si, NULL);
+  si->LinkImage(nullptr);
 #endif
 }
 
 /*
  * This is linker soinfo for GDB. See details below.
  */
-static soinfo linker_soinfo_for_gdb;
+#if defined(__LP64__)
+#define LINKER_PATH "/system/bin/linker64"
+#else
+#define LINKER_PATH "/system/bin/linker"
+#endif
+static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr);
 
 /* gdb expects the linker to be in the debug shared object list.
  * Without this, gdb has trouble locating the linker's ".text"
@@ -2066,12 +2205,6 @@
  * be on the soinfo list.
  */
 static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
-#if defined(__LP64__)
-  strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker64", sizeof(linker_soinfo_for_gdb.name));
-#else
-  strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker", sizeof(linker_soinfo_for_gdb.name));
-#endif
-  linker_soinfo_for_gdb.flags = FLAG_NEW_SOINFO;
   linker_soinfo_for_gdb.base = linker_base;
 
   /*
@@ -2083,7 +2216,7 @@
   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_soinfo_for_gdb.dynamic, NULL, NULL);
+                                 &linker_soinfo_for_gdb.dynamic, nullptr, nullptr);
   insert_soinfo_into_debug_map(&linker_soinfo_for_gdb);
 }
 
@@ -2093,16 +2226,6 @@
  * and other non-local data at this point.
  */
 static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
-    /* NOTE: we store the args pointer on a special location
-     *       of the temporary TLS area in order to pass it to
-     *       the C Library's runtime initializer.
-     *
-     *       The initializer must clear the slot and reset the TLS
-     *       to point to a different location to ensure that no other
-     *       shared library constructor can access it.
-     */
-  __libc_init_tls(args);
-
 #if TIMING
     struct timeval t0, t1;
     gettimeofday(&t0, 0);
@@ -2121,14 +2244,14 @@
 
     // Get a few environment variables.
     const char* LD_DEBUG = linker_env_get("LD_DEBUG");
-    if (LD_DEBUG != NULL) {
+    if (LD_DEBUG != nullptr) {
       g_ld_debug_verbosity = atoi(LD_DEBUG);
     }
 
     // Normally, these are cleaned by linker_env_init, but the test
     // doesn't cost us anything.
-    const char* ldpath_env = NULL;
-    const char* ldpreload_env = NULL;
+    const char* ldpath_env = nullptr;
+    const char* ldpreload_env = nullptr;
     if (!get_AT_SECURE()) {
       ldpath_env = linker_env_get("LD_LIBRARY_PATH");
       ldpreload_env = linker_env_get("LD_PRELOAD");
@@ -2136,8 +2259,8 @@
 
     INFO("[ android linker & debugger ]");
 
-    soinfo* si = soinfo_alloc(args.argv[0], NULL);
-    if (si == NULL) {
+    soinfo* si = soinfo_alloc(args.argv[0], nullptr);
+    if (si == nullptr) {
         exit(EXIT_FAILURE);
     }
 
@@ -2147,8 +2270,8 @@
 
     map->l_addr = 0;
     map->l_name = args.argv[0];
-    map->l_prev = NULL;
-    map->l_next = NULL;
+    map->l_prev = nullptr;
+    map->l_next = nullptr;
 
     _r_debug.r_map = map;
     r_debug_tail = map;
@@ -2174,7 +2297,7 @@
         break;
       }
     }
-    si->dynamic = NULL;
+    si->dynamic = nullptr;
     si->ref_count = 1;
 
     ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
@@ -2189,7 +2312,7 @@
 
     somain = si;
 
-    if (!soinfo_link_image(si, NULL)) {
+    if (!si->LinkImage(nullptr)) {
         __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
         exit(EXIT_FAILURE);
     }
@@ -2198,11 +2321,11 @@
 
     si->CallPreInitConstructors();
 
-    for (size_t i = 0; g_ld_preloads[i] != NULL; ++i) {
+    for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) {
         g_ld_preloads[i]->CallConstructors();
     }
 
-    /* After the link_image, the si->load_bias is initialized.
+    /* After the LinkImage, 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.
@@ -2211,7 +2334,7 @@
     si->CallConstructors();
 
 #if TIMING
-    gettimeofday(&t1, NULL);
+    gettimeofday(&t1, nullptr);
     PRINT("LINKER TIME: %s: %d microseconds", args.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)));
@@ -2290,10 +2413,6 @@
  * function, or other GOT reference will generate a segfault.
  */
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
-  // Initialize static variables.
-  solist = get_libdl_info();
-  sonext = get_libdl_info();
-
   KernelArgumentBlock args(raw_args);
 
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
@@ -2301,8 +2420,7 @@
   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;
-  memset(&linker_so, 0, sizeof(soinfo));
+  soinfo linker_so("[dynamic linker]", nullptr);
 
   // 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
@@ -2314,16 +2432,15 @@
     __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
   }
 
-  strcpy(linker_so.name, "[dynamic linker]");
   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 = NULL;
+  linker_so.dynamic = nullptr;
   linker_so.phdr = phdr;
   linker_so.phnum = elf_hdr->e_phnum;
   linker_so.flags |= FLAG_LINKER;
 
-  if (!soinfo_link_image(&linker_so, NULL)) {
+  if (!linker_so.LinkImage(nullptr)) {
     // It would be nice to print an error message, but if the linker
     // can't link itself, there's no guarantee that we'll be able to
     // call write() (because it involves a GOT reference). We may as
@@ -2335,9 +2452,17 @@
     _exit(EXIT_FAILURE);
   }
 
+  __libc_init_tls(args);
+
   // Initialize the linker's own global variables
   linker_so.CallConstructors();
 
+  // 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();
+
   // 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;
diff --git a/linker/linker.h b/linker/linker.h
index 374652e..6547d68 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -30,6 +30,7 @@
 #define _LINKER_H_
 
 #include <elf.h>
+#include <inttypes.h>
 #include <link.h>
 #include <unistd.h>
 #include <android/dlext.h>
@@ -88,6 +89,8 @@
 #define FLAG_LINKER     0x00000010 // The linker itself
 #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
 
+#define SOINFO_VERSION 1
+
 #define SOINFO_NAME_LEN 128
 
 typedef void (*linker_function_t)();
@@ -195,29 +198,45 @@
   bool has_text_relocations;
 #endif
   bool has_DT_SYMBOLIC;
+
+  soinfo(const char* name, const struct stat* file_stat);
+
   void CallConstructors();
   void CallDestructors();
   void CallPreInitConstructors();
+  bool LinkImage(const android_dlextinfo* extinfo);
 
   void add_child(soinfo* child);
   void remove_all_links();
 
   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();
 
+  bool inline has_min_version(uint32_t min_version) {
+    return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
+  }
  private:
   void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
   void CallFunction(const char* function_name, linker_function_t function);
+  void resolve_ifunc_symbols();
+#if defined(USE_RELA)
+  int Relocate(ElfW(Rela)* rela, unsigned count);
+#else
+  int Relocate(ElfW(Rel)* rel, unsigned count);
+#endif
 
  private:
   // This part of the structure is only available
   // when FLAG_NEW_SOINFO is set in this->flags.
-  unsigned int version;
+  uint32_t version;
 
+  // version >= 0
   dev_t st_dev;
   ino_t st_ino;
 
@@ -225,6 +244,8 @@
   soinfo_list_t children;
   soinfo_list_t parents;
 
+  // version >= 1
+  bool has_ifuncs;
 };
 
 extern soinfo* get_libdl_info();
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/linker/linker_environ.cpp b/linker/linker_environ.cpp
index 846624b..daee56f 100644
--- a/linker/linker_environ.cpp
+++ b/linker/linker_environ.cpp
@@ -58,7 +58,7 @@
 
 // Check if the environment variable definition at 'envstr'
 // starts with '<name>=', and if so return the address of the
-// first character after the equal sign. Otherwise return NULL.
+// first character after the equal sign. Otherwise return null.
 static const char* env_match(const char* envstr, const char* name) {
   size_t i = 0;
 
@@ -70,7 +70,7 @@
     return envstr + i + 1;
   }
 
-  return NULL;
+  return nullptr;
 }
 
 static bool __is_valid_environment_variable(const char* name) {
@@ -78,7 +78,7 @@
   // as the maximum size for an env. variable definition.
   const int MAX_ENV_LEN = 32*4096;
 
-  if (name == NULL) {
+  if (name == nullptr) {
     return false;
   }
 
@@ -136,10 +136,10 @@
       "RES_OPTIONS",
       "TMPDIR",
       "TZDIR",
-      NULL
+      nullptr
   };
-  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) {
-    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) {
+  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
+    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
       return true;
     }
   }
@@ -149,7 +149,7 @@
 static void __sanitize_environment_variables() {
   char** src  = _envp;
   char** dst = _envp;
-  for (; src[0] != NULL; ++src) {
+  for (; src[0] != nullptr; ++src) {
     if (!__is_valid_environment_variable(src[0])) {
       continue;
     }
@@ -160,11 +160,11 @@
     dst[0] = src[0];
     ++dst;
   }
-  dst[0] = NULL;
+  dst[0] = nullptr;
 }
 
 void linker_env_init(KernelArgumentBlock& args) {
-  // Store environment pointer - can't be NULL.
+  // Store environment pointer - can't be null.
   _envp = args.envp;
 
   __init_AT_SECURE(args);
@@ -172,18 +172,18 @@
 }
 
 const char* linker_env_get(const char* name) {
-  if (name == NULL || name[0] == '\0') {
-    return NULL;
+  if (name == nullptr || name[0] == '\0') {
+    return nullptr;
   }
 
-  for (char** p = _envp; p[0] != NULL; ++p) {
+  for (char** p = _envp; p[0] != nullptr; ++p) {
     const char* val = env_match(p[0], name);
-    if (val != NULL) {
+    if (val != nullptr) {
       if (val[0] == '\0') {
-        return NULL; // Return NULL for empty strings.
+        return nullptr; // Return null for empty strings.
       }
       return val;
     }
   }
-  return NULL;
+  return nullptr;
 }
diff --git a/linker/linker_environ.h b/linker/linker_environ.h
index d3f54fd..0f6ac08 100644
--- a/linker/linker_environ.h
+++ b/linker/linker_environ.h
@@ -35,7 +35,7 @@
 extern void linker_env_init(KernelArgumentBlock& args);
 
 // Returns the value of environment variable 'name' if defined and not
-// empty, or NULL otherwise.
+// empty, or null otherwise.
 extern const char* linker_env_get(const char* name);
 
 // Returns the value of this program's AT_SECURE variable.
diff --git a/linker/linker_executable.mk b/linker/linker_executable.mk
deleted file mode 100644
index 4902a0c..0000000
--- a/linker/linker_executable.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-
-#
-# Instead of including $(BUILD_EXECUTABLE), we execute the steps to create an executable by
-# hand, as we want to insert an extra objcopy step that is not supported by the build
-# system, and is probably specific the linker only, so there's no need to modify the build
-# system for the purpose.
-#
-
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_SUFFIX := $(TARGET_EXECUTABLE_SUFFIX)
-
-include $(BUILD_SYSTEM)/dynamic_binary.mk
-
-# See build/core/executable_internal.mk
-$(linked_module): PRIVATE_TARGET_GLOBAL_LD_DIRS := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LD_DIRS)
-$(linked_module): PRIVATE_TARGET_GLOBAL_LDFLAGS := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LDFLAGS)
-$(linked_module): PRIVATE_TARGET_FDO_LIB := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_LIB)
-$(linked_module): PRIVATE_TARGET_LIBGCC := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCC)
-$(linked_module): PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTBEGIN_DYNAMIC_O)
-$(linked_module): PRIVATE_TARGET_CRTBEGIN_STATIC_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTBEGIN_STATIC_O)
-$(linked_module): PRIVATE_TARGET_CRTEND_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTEND_O)
-$(linked_module): PRIVATE_TARGET_OBJCOPY := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY)
-$(linked_module): $(TARGET_CRTBEGIN_STATIC_O) $(all_objects) $(all_libraries) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTEND_O)
-	$(transform-o-to-static-executable)
-	@echo "target PrefixSymbols: $(PRIVATE_MODULE) ($@)"
-	$(hide) $(PRIVATE_TARGET_OBJCOPY) --prefix-symbols=__dl_ $@
diff --git a/linker/linker_libc_support.c b/linker/linker_libc_support.c
new file mode 100644
index 0000000..17db6d4
--- /dev/null
+++ b/linker/linker_libc_support.c
@@ -0,0 +1,17 @@
+/*
+ * 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 "../libc/arch-common/bionic/__dso_handle.h"
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 0b99d20..1bbd577 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -121,13 +121,13 @@
 
 ElfReader::ElfReader(const char* name, int fd)
     : name_(name), fd_(fd),
-      phdr_num_(0), phdr_mmap_(NULL), phdr_table_(NULL), phdr_size_(0),
-      load_start_(NULL), load_size_(0), load_bias_(0),
-      loaded_phdr_(NULL) {
+      phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
+      load_start_(nullptr), load_size_(0), load_bias_(0),
+      loaded_phdr_(nullptr) {
 }
 
 ElfReader::~ElfReader() {
-  if (phdr_mmap_ != NULL) {
+  if (phdr_mmap_ != nullptr) {
     munmap(phdr_mmap_, phdr_size_);
   }
 }
@@ -225,7 +225,7 @@
 
   phdr_size_ = page_max - page_min;
 
-  void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
+  void* mmap_result = mmap(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
   if (mmap_result == MAP_FAILED) {
     DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
     return false;
@@ -242,7 +242,7 @@
  * process' address space. If there are no loadable segments, 0 is
  * returned.
  *
- * If out_min_vaddr or out_max_vaddr are non-NULL, they will be
+ * If out_min_vaddr or out_max_vaddr are not null, they will be
  * set to the minimum and maximum addresses of pages to be reserved,
  * or 0 if there is nothing to load.
  */
@@ -276,10 +276,10 @@
   min_vaddr = PAGE_START(min_vaddr);
   max_vaddr = PAGE_END(max_vaddr);
 
-  if (out_min_vaddr != NULL) {
+  if (out_min_vaddr != nullptr) {
     *out_min_vaddr = min_vaddr;
   }
-  if (out_max_vaddr != NULL) {
+  if (out_max_vaddr != nullptr) {
     *out_max_vaddr = max_vaddr;
   }
   return max_vaddr - min_vaddr;
@@ -301,7 +301,7 @@
   size_t reserved_size = 0;
   bool reserved_hint = true;
 
-  if (extinfo != NULL) {
+  if (extinfo != nullptr) {
     if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
       reserved_size = extinfo->reserved_size;
       reserved_hint = false;
@@ -585,9 +585,9 @@
     return -1;
   }
   off_t file_size = file_stat.st_size;
-  void* temp_mapping = NULL;
+  void* temp_mapping = nullptr;
   if (file_size > 0) {
-    temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
     if (temp_mapping == MAP_FAILED) {
       return -1;
     }
@@ -667,7 +667,7 @@
  *   phdr_count  -> number of entries in tables
  *   load_bias   -> load bias
  * Output:
- *   arm_exidx       -> address of table in memory (NULL on failure).
+ *   arm_exidx       -> address of table in memory (null on failure).
  *   arm_exidx_count -> number of items in table (0 on failure).
  * Return:
  *   0 on error, -1 on failure (_no_ error code in errno)
@@ -687,21 +687,21 @@
     *arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
     return 0;
   }
-  *arm_exidx = NULL;
+  *arm_exidx = nullptr;
   *arm_exidx_count = 0;
   return -1;
 }
 #endif
 
 /* Return the address and size of the ELF file's .dynamic section in memory,
- * or NULL if missing.
+ * or null if missing.
  *
  * Input:
  *   phdr_table  -> program header table
  *   phdr_count  -> number of entries in tables
  *   load_bias   -> load bias
  * Output:
- *   dynamic       -> address of table in memory (NULL on failure).
+ *   dynamic       -> address of table in memory (null on failure).
  *   dynamic_count -> number of items in table (0 on failure).
  *   dynamic_flags -> protection flags for section (unset on failure)
  * Return:
@@ -727,7 +727,7 @@
     }
     return;
   }
-  *dynamic = NULL;
+  *dynamic = nullptr;
   if (dynamic_count) {
     *dynamic_count = 0;
   }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 611f1a7..50708a0 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -81,7 +81,7 @@
 };
 
 size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                ElfW(Addr)* min_vaddr = NULL, ElfW(Addr)* max_vaddr = NULL);
+                                ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
 
 int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias);
 
diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp
index b9816fa..a555edb 100644
--- a/linker/tests/linked_list_test.cpp
+++ b/linker/tests/linked_list_test.cpp
@@ -80,7 +80,7 @@
   });
 
   ASSERT_TRUE(!alloc_called);
-  ASSERT_TRUE(!free_called);
+  ASSERT_TRUE(free_called);
 
   ASSERT_EQ("dba", test_list_to_string(list));
   alloc_called = free_called = false;
@@ -103,15 +103,118 @@
   ASSERT_EQ("ab", test_list_to_string(list));
   list.push_back("c");
   ASSERT_EQ("abc", test_list_to_string(list));
-  ASSERT_EQ("a", list.pop_front());
+  ASSERT_STREQ("a", list.pop_front());
   ASSERT_EQ("bc", test_list_to_string(list));
-  ASSERT_EQ("b", list.pop_front());
+  ASSERT_STREQ("b", list.pop_front());
   ASSERT_EQ("c", test_list_to_string(list));
-  ASSERT_EQ("c", list.pop_front());
+  ASSERT_STREQ("c", list.pop_front());
   ASSERT_EQ("", test_list_to_string(list));
   ASSERT_TRUE(list.pop_front() == nullptr);
   list.push_back("r");
   ASSERT_EQ("r", test_list_to_string(list));
-  ASSERT_EQ("r", list.pop_front());
+  ASSERT_STREQ("r", list.pop_front());
   ASSERT_TRUE(list.pop_front() == nullptr);
 }
+
+TEST(linked_list, remove_if_then_pop) {
+  test_list_t list;
+  list.push_back("a");
+  list.push_back("b");
+  list.push_back("c");
+  list.push_back("d");
+  list.remove_if([](const char* c) {
+    return *c == 'b' || *c == 'c';
+  });
+
+  ASSERT_EQ("ad", test_list_to_string(list));
+  ASSERT_STREQ("a", list.pop_front());
+  ASSERT_EQ("d", test_list_to_string(list));
+  ASSERT_STREQ("d", list.pop_front());
+  ASSERT_TRUE(list.pop_front() == nullptr);
+}
+
+TEST(linked_list, copy_to_array) {
+  test_list_t list;
+  const size_t max_size = 128;
+  const char* buf[max_size];
+  memset(buf, 0, sizeof(buf));
+
+  ASSERT_EQ(0U, list.size());
+  ASSERT_EQ(0U, list.copy_to_array(buf, max_size));
+  ASSERT_EQ(nullptr, buf[0]);
+
+  list.push_back("a");
+  list.push_back("b");
+  list.push_back("c");
+  list.push_back("d");
+
+  memset(buf, 0, sizeof(buf));
+  ASSERT_EQ(4U, list.size());
+  ASSERT_EQ(2U, list.copy_to_array(buf, 2));
+  ASSERT_STREQ("a", buf[0]);
+  ASSERT_STREQ("b", buf[1]);
+  ASSERT_EQ(nullptr, buf[2]);
+
+  ASSERT_EQ(4U, list.copy_to_array(buf, max_size));
+  ASSERT_STREQ("a", buf[0]);
+  ASSERT_STREQ("b", buf[1]);
+  ASSERT_STREQ("c", buf[2]);
+  ASSERT_STREQ("d", buf[3]);
+  ASSERT_EQ(nullptr, buf[4]);
+
+  memset(buf, 0, sizeof(buf));
+  list.remove_if([](const char* c) {
+    return *c != 'c';
+  });
+  ASSERT_EQ(1U, list.size());
+  ASSERT_EQ(1U, list.copy_to_array(buf, max_size));
+  ASSERT_STREQ("c", buf[0]);
+  ASSERT_EQ(nullptr, buf[1]);
+
+  memset(buf, 0, sizeof(buf));
+
+  list.remove_if([](const char* c) {
+    return *c == 'c';
+  });
+
+  ASSERT_EQ(0U, list.size());
+  ASSERT_EQ(0U, list.copy_to_array(buf, max_size));
+  ASSERT_EQ(nullptr, buf[0]);
+}
+
+TEST(linked_list, test_visit) {
+  test_list_t list;
+  list.push_back("a");
+  list.push_back("b");
+  list.push_back("c");
+  list.push_back("d");
+
+  int visits = 0;
+  std::stringstream ss;
+  bool result = list.visit([&](const char* c) {
+    ++visits;
+    ss << c;
+    return true;
+  });
+
+  ASSERT_TRUE(result);
+  ASSERT_EQ(4, visits);
+  ASSERT_EQ("abcd", ss.str());
+
+  visits = 0;
+  ss.str(std::string());
+
+  result = list.visit([&](const char* c) {
+    if (++visits == 3) {
+      return false;
+    }
+
+    ss << c;
+    return true;
+  });
+
+  ASSERT_TRUE(!result);
+  ASSERT_EQ(3, visits);
+  ASSERT_EQ("ab", ss.str());
+}
+
diff --git a/tests/Android.mk b/tests/Android.mk
index 8184bf7..3bd4ec0 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -92,8 +92,10 @@
     stdatomic_test.cpp \
     stdint_test.cpp \
     stdio_test.cpp \
+    stdio_ext_test.cpp \
     stdlib_test.cpp \
     string_test.cpp \
+    string_posix_strerror_r_test.cpp \
     strings_test.cpp \
     stubs_test.cpp \
     sstream_test.cpp \
@@ -129,6 +131,7 @@
 
 libBionicStandardTests_c_includes := \
     bionic/libc \
+    external/tinyxml2 \
 
 libBionicStandardTests_ldlibs_host := \
     -lrt \
@@ -243,6 +246,10 @@
 bionic-unit-tests_whole_static_libraries := \
     libBionicTests \
 
+bionic-unit-tests_static_libraries := \
+    libtinyxml2 \
+    liblog \
+
 bionic-unit-tests_src_files := \
     atexit_test.cpp \
     dlext_test.cpp \
@@ -256,6 +263,7 @@
     -Wl,-u,DlSymTestFunction \
 
 bionic-unit-tests_c_includes := \
+    bionic/libc \
     $(call include-path-for, libpagemap) \
 
 bionic-unit-tests_shared_libraries_target := \
@@ -281,6 +289,8 @@
     libm \
     libc \
     libstdc++ \
+    libtinyxml2 \
+    liblog \
 
 bionic-unit-tests-static_force_static_executable := true
 
@@ -356,6 +366,22 @@
 		$(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS)
 endif
 
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64))
+# add target to run lp32 tests
+bionic-unit-tests-run-on-host32: bionic-unit-tests_32 $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh
+	if [ ! -d /system -o ! -d /system/bin ]; then \
+	  echo "Attempting to create /system/bin"; \
+	  sudo mkdir -p -m 0777 /system/bin; \
+	fi
+	mkdir -p $(TARGET_OUT_DATA)/local/tmp
+	cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin
+	cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+	ANDROID_DATA=$(TARGET_OUT_DATA) \
+	ANDROID_ROOT=$(TARGET_OUT) \
+	LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \
+		$(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS)
+endif
+
 endif # linux-x86
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
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/dlext_test.cpp b/tests/dlext_test.cpp
index da63046..7bd59c8 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -117,7 +117,7 @@
   ASSERT_DL_NOTNULL(handle_);
   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
   ASSERT_DL_NOTNULL(f);
-  EXPECT_GE(f, start);
+  EXPECT_GE(reinterpret_cast<void*>(f), start);
   EXPECT_LT(reinterpret_cast<void*>(f),
             reinterpret_cast<char*>(start) + LIBSIZE);
   EXPECT_EQ(4, f());
@@ -147,7 +147,7 @@
   ASSERT_DL_NOTNULL(handle_);
   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
   ASSERT_DL_NOTNULL(f);
-  EXPECT_GE(f, start);
+  EXPECT_GE(reinterpret_cast<void*>(f), start);
   EXPECT_LT(reinterpret_cast<void*>(f),
             reinterpret_cast<char*>(start) + LIBSIZE);
   EXPECT_EQ(4, f());
@@ -165,8 +165,9 @@
   ASSERT_DL_NOTNULL(handle_);
   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
   ASSERT_DL_NOTNULL(f);
-  EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >=
-                            reinterpret_cast<char*>(start) + PAGE_SIZE));
+  EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
+              (reinterpret_cast<void*>(f) >=
+               reinterpret_cast<char*>(start) + PAGE_SIZE));
   EXPECT_EQ(4, f());
 }
 
@@ -259,6 +260,11 @@
 }
 
 TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
+  if (geteuid() != 0) {
+    GTEST_LOG_(INFO) << "This test must be run as root.\n";
+    return;
+  }
+
   ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
   int relro_fd = open(relro_file_, O_RDONLY);
   ASSERT_NOERROR(relro_fd);
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 457fcd5..1613ee8 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -22,6 +22,8 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#include "private/ScopeGuard.h"
+
 #include <string>
 
 #define ASSERT_SUBSTR(needle, haystack) \
@@ -87,6 +89,75 @@
   ASSERT_EQ(0, dlclose(handle2));
 }
 
+// ifuncs are only supported on intel for now
+#if defined(__i386__) || defined(__x86_64__)
+TEST(dlfcn, ifunc) {
+  typedef const char* (*fn_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);
+  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+  fn_ptr foo_library_ptr = reinterpret_cast<fn_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);
+  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+  foo_library_ptr = reinterpret_cast<fn_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);
+}
+
+TEST(dlfcn, ifunc_ctor_call) {
+  typedef const char* (*fn_ptr)();
+
+  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+  ASSERT_TRUE(handle != NULL) << dlerror();
+  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called"));
+  ASSERT_TRUE(is_ctor_called != NULL) << dlerror();
+  ASSERT_STREQ("true", is_ctor_called());
+  dlclose(handle);
+}
+#endif
+
+TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
+  // This is the structure of the test library and
+  // its dt_needed libraries
+  // libtest_relo_check_dt_needed_order.so
+  // |
+  // +-> libtest_relo_check_dt_needed_order_1.so
+  // |
+  // +-> libtest_relo_check_dt_needed_order_2.so
+  //
+  // The root library references relo_test_get_answer_lib - which is defined
+  // in both dt_needed libraries, the correct relocation should
+  // use the function defined in libtest_relo_check_dt_needed_order_1.so
+  void* handle = nullptr;
+  auto guard = create_scope_guard([&]() {
+    dlclose(handle);
+  });
+
+  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef int (*fn_t) (void);
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(1, fn());
+}
+
 TEST(dlfcn, dlopen_failure) {
   void* self = dlopen("/does/not/exist", RTLD_NOW);
   ASSERT_TRUE(self == NULL);
@@ -295,4 +366,6 @@
   ASSERT_TRUE(handle1 != NULL);
   ASSERT_TRUE(handle2 != NULL);
   ASSERT_EQ(handle1, handle2);
+  dlclose(handle1);
+  dlclose(handle2);
 }
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/libc_logging_test.cpp b/tests/libc_logging_test.cpp
index 950161e..d4ceded 100644
--- a/tests/libc_logging_test.cpp
+++ b/tests/libc_logging_test.cpp
@@ -176,3 +176,15 @@
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif // __BIONIC__
 }
+
+TEST(libc_logging, buffer_overrun) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world"));
+  EXPECT_STREQ("hello world", buf);
+  ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world"));
+  EXPECT_STREQ("hello w", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
diff --git a/tests/libgen_test.cpp b/tests/libgen_test.cpp
index 3958f81..e9a5d5c 100644
--- a/tests/libgen_test.cpp
+++ b/tests/libgen_test.cpp
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
 #include <libgen.h>
 
 #include <errno.h>
+#include <gtest/gtest.h>
 
 static void TestBasename(const char* in, const char* expected_out) {
   char* writable_in = (in != NULL) ? strdup(in) : NULL;
@@ -40,7 +39,7 @@
 
 // Do not use basename as the test name, it's defined to another value in glibc
 // so leads to a differently named test on host versus target architectures.
-TEST(libgen, basename_smoke) {
+TEST(libgen, posix_basename) {
   TestBasename(NULL, ".");
   TestBasename("", ".");
   TestBasename("/usr/lib", "lib");
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 75df539..dc38ae5 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.
 # -----------------------------------------------------------------------------
@@ -102,6 +103,29 @@
 include $(TEST_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
+# libtest_relo_check_dt_needed_order.so
+# |
+# +-> libtest_relo_check_dt_needed_order_1.so
+# |
+# +-> libtest_relo_check_dt_needed_order_2.so
+# -----------------------------------------------------------------------------
+libtest_relo_check_dt_needed_order_shared_libraries := \
+    libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2
+
+libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp
+libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp
+libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp
+build_type := target
+build_target := SHARED_LIBRARY
+
+module := libtest_relo_check_dt_needed_order
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_1
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_2
+include $(TEST_PATH)/Android.build.mk
+
+# -----------------------------------------------------------------------------
 # Library with dependency used by dlfcn tests
 # -----------------------------------------------------------------------------
 libtest_with_dependency_src_files := \
@@ -115,6 +139,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..4874841
--- /dev/null
+++ b/tests/libs/dlopen_testlib_ifunc.c
@@ -0,0 +1,56 @@
+/*
+ * 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>
+
+static int g_flag = 0;
+
+static void __attribute__((constructor)) init_flag() {
+  g_flag = 1;
+}
+
+const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+const char* return_true() {
+  return "true";
+}
+
+const char* return_false() {
+  return "false";
+}
+
+const char* f1() {
+  return "unset";
+}
+
+const char* f2() {
+  return "set";
+}
+
+void* is_ctor_called_ifun() {
+  return g_flag == 0 ? return_false : return_true;
+}
+
+void* foo_ifunc() {
+   char* choice = getenv("IFUNC_CHOICE");
+   return choice == NULL ? f1 : f2;
+}
+
+const char* foo_library() {
+   return foo();
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
new file mode 100644
index 0000000..d8fb543
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib();
+
+extern "C" int relo_test_get_answer() {
+  return relo_test_get_answer_lib();
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
new file mode 100644
index 0000000..4c877d0
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+  return 1;
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
new file mode 100644
index 0000000..10288a0
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+  return 2;
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 6b7a28b..b76625a 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -22,6 +22,8 @@
 #include <malloc.h>
 #include <unistd.h>
 
+#include <tinyxml2.h>
+
 #include "private/bionic_config.h"
 
 TEST(malloc, malloc_std) {
@@ -322,3 +324,51 @@
   ASSERT_EQ(NULL, valloc(SIZE_MAX));
 }
 #endif
+
+TEST(malloc, malloc_info) {
+#ifdef __BIONIC__
+  char* buf;
+  size_t bufsize;
+  FILE* memstream = open_memstream(&buf, &bufsize);
+  ASSERT_NE(nullptr, memstream);
+  ASSERT_EQ(0, malloc_info(0, memstream));
+  ASSERT_EQ(0, fclose(memstream));
+
+  tinyxml2::XMLDocument doc;
+  ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf));
+
+  auto root = doc.FirstChildElement();
+  ASSERT_NE(nullptr, root);
+  ASSERT_STREQ("malloc", root->Name());
+  ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
+
+  auto arena = root->FirstChildElement();
+  for (; arena != nullptr; arena = arena->NextSiblingElement()) {
+    int val;
+
+    ASSERT_STREQ("heap", arena->Name());
+    ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
+    ASSERT_EQ(tinyxml2::XML_SUCCESS,
+              arena->FirstChildElement("allocated-large")->QueryIntText(&val));
+    ASSERT_EQ(tinyxml2::XML_SUCCESS,
+              arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
+    ASSERT_EQ(tinyxml2::XML_SUCCESS,
+              arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
+    ASSERT_EQ(tinyxml2::XML_SUCCESS,
+              arena->FirstChildElement("bins-total")->QueryIntText(&val));
+
+    auto bin = arena->FirstChildElement("bin");
+    for (; bin != nullptr; bin = bin ->NextSiblingElement()) {
+      if (strcmp(bin->Name(), "bin") == 0) {
+        ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val));
+        ASSERT_EQ(tinyxml2::XML_SUCCESS,
+                  bin->FirstChildElement("allocated")->QueryIntText(&val));
+        ASSERT_EQ(tinyxml2::XML_SUCCESS,
+                  bin->FirstChildElement("nmalloc")->QueryIntText(&val));
+        ASSERT_EQ(tinyxml2::XML_SUCCESS,
+                  bin->FirstChildElement("ndalloc")->QueryIntText(&val));
+      }
+    }
+  }
+#endif
+}
diff --git a/tests/math_cos_test.cpp b/tests/math_cos_test.cpp
index c0a2d82..4917e87 100644
--- a/tests/math_cos_test.cpp
+++ b/tests/math_cos_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -5634,6 +5636,7 @@
 
 TEST(math_cos, cos_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_cos_intel_data)/sizeof(cos_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_cos_intel_data[i].expected, cos(g_cos_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_cosf_test.cpp b/tests/math_cosf_test.cpp
index ea95ff3..8520c1d 100644
--- a/tests/math_cosf_test.cpp
+++ b/tests/math_cosf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -4346,6 +4348,7 @@
 
 TEST(math_cosf, cosf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_cosf_intel_data)/sizeof(cosf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_cosf_intel_data[i].expected, cosf(g_cosf_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_exp_test.cpp b/tests/math_exp_test.cpp
index beb2584..c9c6ad5 100644
--- a/tests/math_exp_test.cpp
+++ b/tests/math_exp_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -1966,6 +1968,7 @@
 
 TEST(math_exp, exp_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_exp_intel_data)/sizeof(exp_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_exp_intel_data[i].expected, exp(g_exp_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_expf_test.cpp b/tests/math_expf_test.cpp
index 257aa26..30bc946 100644
--- a/tests/math_expf_test.cpp
+++ b/tests/math_expf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -1430,6 +1432,7 @@
 
 TEST(math_expf, expf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_expf_intel_data)/sizeof(expf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_expf_intel_data[i].expected, expf(g_expf_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_log_test.cpp b/tests/math_log_test.cpp
index da2a848..4f136a7 100644
--- a/tests/math_log_test.cpp
+++ b/tests/math_log_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -1666,6 +1668,7 @@
 
 TEST(math_log, log_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_log_intel_data)/sizeof(log_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_log_intel_data[i].expected, log(g_log_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_logf_test.cpp b/tests/math_logf_test.cpp
index e5d0921..ca02095 100644
--- a/tests/math_logf_test.cpp
+++ b/tests/math_logf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -1318,6 +1320,7 @@
 
 TEST(math_logf, logf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_logf_intel_data)/sizeof(logf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_logf_intel_data[i].expected, logf(g_logf_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_pow_test.cpp b/tests/math_pow_test.cpp
index c185424..a4caa36 100644
--- a/tests/math_pow_test.cpp
+++ b/tests/math_pow_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -3291,6 +3293,7 @@
 
 TEST(math_pow, pow_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_pow_intel_data)/sizeof(pow_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_pow_intel_data[i].expected, pow(g_pow_intel_data[i].x_call_data, g_pow_intel_data[i].y_call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_powf_test.cpp b/tests/math_powf_test.cpp
index f77b23a..7272644 100644
--- a/tests/math_powf_test.cpp
+++ b/tests/math_powf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -2779,6 +2781,7 @@
 
 TEST(math_powf, powf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_powf_intel_data)/sizeof(powf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_powf_intel_data[i].expected, powf(g_powf_intel_data[i].x_call_data, g_powf_intel_data[i].y_call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_sin_test.cpp b/tests/math_sin_test.cpp
index ffa4340..509642c 100644
--- a/tests/math_sin_test.cpp
+++ b/tests/math_sin_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -5786,6 +5788,7 @@
 
 TEST(math_sin, sin_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_sin_intel_data)/sizeof(sin_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_sin_intel_data[i].expected, sin(g_sin_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_sincos_test.cpp b/tests/math_sincos_test.cpp
index 0fab2c2..4093fb9 100644
--- a/tests/math_sincos_test.cpp
+++ b/tests/math_sincos_test.cpp
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE 1
+
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -4776,6 +4780,7 @@
 
 TEST(math_sincos, sincos_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_sincos_intel_data)/sizeof(sincos_intel_data_t); i++) {
    double dsin, dcos;
    sincos(g_sincos_intel_data[i].call_data, &dsin, &dcos);
diff --git a/tests/math_sincosf_test.cpp b/tests/math_sincosf_test.cpp
index c1a32c9..d30f72e 100644
--- a/tests/math_sincosf_test.cpp
+++ b/tests/math_sincosf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -4646,6 +4648,7 @@
 
 TEST(math_sincosf, sincosf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_sincosf_intel_data)/sizeof(sincosf_intel_data_t); i++) {
    float fsin, fcos;
    sincosf(g_sincosf_intel_data[i].call_data, &fsin, &fcos);
diff --git a/tests/math_sinf_test.cpp b/tests/math_sinf_test.cpp
index bb1e2c9..0c2e6f1 100644
--- a/tests/math_sinf_test.cpp
+++ b/tests/math_sinf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -4386,6 +4388,7 @@
 
 TEST(math_sinf, sinf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_sinf_intel_data)/sizeof(sinf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_sinf_intel_data[i].expected, sinf(g_sinf_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_tan_test.cpp b/tests/math_tan_test.cpp
index 6862019..e555ef3 100644
--- a/tests/math_tan_test.cpp
+++ b/tests/math_tan_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -5194,6 +5196,7 @@
 
 TEST(math_tan, tan_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_tan_intel_data)/sizeof(tan_intel_data_t); i++) {
     EXPECT_DOUBLE_EQ(g_tan_intel_data[i].expected, tan(g_tan_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_tanf_test.cpp b/tests/math_tanf_test.cpp
index 9319046..db04116 100644
--- a/tests/math_tanf_test.cpp
+++ b/tests/math_tanf_test.cpp
@@ -16,6 +16,8 @@
 
 #include <math.h>
 
+#include <fenv.h>
+
 #include <gtest/gtest.h>
 
 #if defined(__BIONIC__)
@@ -4450,6 +4452,7 @@
 
 TEST(math_tanf, tanf_intel) {
 #if defined(__BIONIC__)
+  fesetenv(FE_DFL_ENV);
   for (size_t i = 0; i < sizeof(g_tanf_intel_data)/sizeof(tanf_intel_data_t); i++) {
     EXPECT_FLOAT_EQ(g_tanf_intel_data[i].expected, tanf(g_tanf_intel_data[i].call_data)) << "Failed on element " << i;
   }
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index b4f5b14..ad4654e 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -53,6 +53,8 @@
 #include <limits.h>
 #include <stdint.h>
 
+#include <private/ScopeGuard.h>
+
 float float_subnormal() {
   union {
     float f;
@@ -760,6 +762,10 @@
 }
 
 TEST(math, lrint) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
+
   fesetround(FE_UPWARD); // lrint/lrintf/lrintl obey the rounding mode.
   ASSERT_EQ(1235, lrint(1234.01));
   ASSERT_EQ(1235, lrintf(1234.01f));
@@ -780,6 +786,10 @@
 }
 
 TEST(math, rint) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
+
   fesetround(FE_UPWARD); // rint/rintf/rintl obey the rounding mode.
   feclearexcept(FE_ALL_EXCEPT); // rint/rintf/rintl do set the FE_INEXACT flag.
   ASSERT_EQ(1234.0, rint(1234.0));
@@ -806,6 +816,9 @@
 }
 
 TEST(math, nearbyint) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // nearbyint/nearbyintf/nearbyintl obey the rounding mode.
   feclearexcept(FE_ALL_EXCEPT); // nearbyint/nearbyintf/nearbyintl don't set the FE_INEXACT flag.
   ASSERT_EQ(1234.0, nearbyint(1234.0));
@@ -832,6 +845,9 @@
 }
 
 TEST(math, lround) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // lround ignores the rounding mode.
   ASSERT_EQ(1234, lround(1234.01));
   ASSERT_EQ(1234, lroundf(1234.01f));
@@ -839,6 +855,9 @@
 }
 
 TEST(math, llround) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // llround ignores the rounding mode.
   ASSERT_EQ(1234L, llround(1234.01));
   ASSERT_EQ(1234L, llroundf(1234.01f));
@@ -933,6 +952,9 @@
 }
 
 TEST(math, round) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_TOWARDZERO); // round ignores the rounding mode and always rounds away from zero.
   ASSERT_DOUBLE_EQ(1.0, round(0.5));
   ASSERT_DOUBLE_EQ(-1.0, round(-0.5));
@@ -943,6 +965,9 @@
 }
 
 TEST(math, roundf) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_TOWARDZERO); // roundf ignores the rounding mode and always rounds away from zero.
   ASSERT_FLOAT_EQ(1.0f, roundf(0.5f));
   ASSERT_FLOAT_EQ(-1.0f, roundf(-0.5f));
@@ -953,6 +978,9 @@
 }
 
 TEST(math, roundl) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_TOWARDZERO); // roundl ignores the rounding mode and always rounds away from zero.
   ASSERT_DOUBLE_EQ(1.0L, roundl(0.5L));
   ASSERT_DOUBLE_EQ(-1.0L, roundl(-0.5L));
@@ -963,6 +991,9 @@
 }
 
 TEST(math, trunc) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // trunc ignores the rounding mode and always rounds toward zero.
   ASSERT_DOUBLE_EQ(1.0, trunc(1.5));
   ASSERT_DOUBLE_EQ(-1.0, trunc(-1.5));
@@ -973,6 +1004,9 @@
 }
 
 TEST(math, truncf) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // truncf ignores the rounding mode and always rounds toward zero.
   ASSERT_FLOAT_EQ(1.0f, truncf(1.5f));
   ASSERT_FLOAT_EQ(-1.0f, truncf(-1.5f));
@@ -983,6 +1017,9 @@
 }
 
 TEST(math, truncl) {
+  auto guard = create_scope_guard([]() {
+    fesetenv(FE_DFL_ENV);
+  });
   fesetround(FE_UPWARD); // truncl ignores the rounding mode and always rounds toward zero.
   ASSERT_DOUBLE_EQ(1.0L, truncl(1.5L));
   ASSERT_DOUBLE_EQ(-1.0L, truncl(-1.5L));
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 4a7c6bd..9a9e515 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -106,6 +106,7 @@
   ASSERT_EQ(99, WEXITSTATUS(status));
 
   ASSERT_EQ(expected, pthread_getspecific(key));
+  ASSERT_EQ(0, pthread_key_delete(key));
 }
 
 static void* DirtyKeyFn(void* key) {
@@ -133,6 +134,7 @@
   ASSERT_EQ(nullptr, result); // Not ~0!
 
   ASSERT_EQ(0, munmap(stack, stack_size));
+  ASSERT_EQ(0, pthread_key_delete(key));
 }
 
 static void* IdFn(void* arg) {
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 89b8088..8fd8b72 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <signal.h>
 
 #include <errno.h>
-#include <signal.h>
+#include <gtest/gtest.h>
 
 #include "ScopedSignalHandler.h"
 
@@ -198,13 +198,19 @@
 static void EmptySignalAction(int, siginfo_t*, void*) {}
 
 TEST(signal, sigaction) {
+  // Both bionic and glibc set SA_RESTORER when talking to the kernel on arm,
+  // arm64, x86, and x86-64. The version of glibc we're using also doesn't
+  // define SA_RESTORER, but luckily it's the same value everywhere, and mips
+  // doesn't use the bit for anything.
+  static const unsigned sa_restorer = 0x4000000;
+
   // See what's currently set for SIGALRM.
   struct sigaction original_sa;
   memset(&original_sa, 0, sizeof(original_sa));
   ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa));
   ASSERT_TRUE(original_sa.sa_handler == NULL);
   ASSERT_TRUE(original_sa.sa_sigaction == NULL);
-  ASSERT_TRUE(original_sa.sa_flags == 0);
+  ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer);
 
   // Set a traditional sa_handler signal handler.
   struct sigaction sa;
@@ -219,7 +225,7 @@
   ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
   ASSERT_TRUE(sa.sa_handler == EmptySignalHandler);
   ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
-  ASSERT_TRUE(sa.sa_flags == SA_ONSTACK);
+  ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer);
 
   // Set a new-style sa_sigaction signal handler.
   memset(&sa, 0, sizeof(sa));
@@ -233,7 +239,7 @@
   ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
   ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction);
   ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
-  ASSERT_TRUE(sa.sa_flags == (SA_ONSTACK | SA_SIGINFO));
+  ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer);
 
   // Put everything back how it was.
   ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL));
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
new file mode 100644
index 0000000..3dbc485
--- /dev/null
+++ b/tests/stdio_ext_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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_ext.h>
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <locale.h>
+
+#include "TemporaryFile.h"
+
+TEST(stdio_ext, __fbufsize) {
+  FILE* fp = fopen("/proc/version", "r");
+
+  char buf[128];
+
+  ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 1));
+  ASSERT_EQ(1U, __fbufsize(fp));
+
+  ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 8));
+  ASSERT_EQ(8U, __fbufsize(fp));
+
+  fclose(fp);
+}
+
+TEST(stdio_ext, __flbf) {
+  FILE* fp = fopen("/proc/version", "r");
+
+  ASSERT_FALSE(__flbf(fp));
+
+  char buf[128];
+  ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf)));
+
+  ASSERT_TRUE(__flbf(fp));
+
+  fclose(fp);
+}
+
+TEST(stdio_ext, __fpending) {
+  FILE* fp = fopen("/dev/null", "w");
+  ASSERT_EQ(0U, __fpending(fp));
+  ASSERT_EQ('x', fputc('x', fp));
+  ASSERT_EQ(1U, __fpending(fp));
+  ASSERT_EQ('y', fputc('y', fp));
+  ASSERT_EQ(2U, __fpending(fp));
+  fflush(fp);
+  ASSERT_EQ(0U, __fpending(fp));
+  fclose(fp);
+}
+
+TEST(stdio_ext, __fpurge) {
+  FILE* fp = tmpfile();
+
+  ASSERT_EQ('a', fputc('a', fp));
+  ASSERT_EQ(1U, __fpending(fp));
+  __fpurge(fp);
+  ASSERT_EQ(0U, __fpending(fp));
+
+  ASSERT_EQ('b', fputc('b', fp));
+  ASSERT_EQ('\n', fputc('\n', fp));
+  ASSERT_EQ(2U, __fpending(fp));
+
+  rewind(fp);
+
+  char buf[16];
+  char* s = fgets(buf, sizeof(buf), fp);
+  ASSERT_TRUE(s != NULL);
+  ASSERT_STREQ("b\n", s);
+
+  fclose(fp);
+}
+
+TEST(stdio_ext, _flushlbf) {
+  FILE* fp = fopen("/dev/null", "w");
+
+  char buf[128];
+  ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf)));
+
+  ASSERT_EQ('a', fputc('a', fp));
+  ASSERT_EQ(1U, __fpending(fp));
+
+  _flushlbf();
+
+  ASSERT_EQ(0U, __fpending(fp));
+
+  fclose(fp);
+}
+
+TEST(stdio_ext, __freadable__fwritable) {
+  FILE* fp = fopen("/dev/null", "r");
+  ASSERT_TRUE(__freadable(fp));
+  ASSERT_FALSE(__fwritable(fp));
+  fclose(fp);
+
+  fp = fopen("/dev/null", "w");
+  ASSERT_FALSE(__freadable(fp));
+  ASSERT_TRUE(__fwritable(fp));
+  fclose(fp);
+
+  fp = fopen("/dev/null", "w+");
+  ASSERT_TRUE(__freadable(fp));
+  ASSERT_TRUE(__fwritable(fp));
+  fclose(fp);
+}
+
+TEST(stdio_ext, __fsetlocking) {
+  FILE* fp = fopen("/proc/version", "r");
+  // Android doesn't actually support the other modes.
+  ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY));
+  fclose(fp);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 8c8c235..c01ab68 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -677,3 +677,82 @@
 
   fclose(fp);
 }
+
+TEST(stdio, fmemopen) {
+  char buf[16];
+  memset(buf, 0, sizeof(buf));
+  FILE* fp = fmemopen(buf, sizeof(buf), "r+");
+  ASSERT_EQ('<', fputc('<', fp));
+  ASSERT_NE(EOF, fputs("abc>\n", fp));
+  fflush(fp);
+
+  ASSERT_STREQ("<abc>\n", buf);
+
+  rewind(fp);
+
+  char line[16];
+  char* s = fgets(line, sizeof(line), fp);
+  ASSERT_TRUE(s != NULL);
+  ASSERT_STREQ("<abc>\n", s);
+
+  fclose(fp);
+}
+
+TEST(stdio, fmemopen_NULL) {
+  FILE* fp = fmemopen(nullptr, 128, "r+");
+  ASSERT_NE(EOF, fputs("xyz\n", fp));
+
+  rewind(fp);
+
+  char line[16];
+  char* s = fgets(line, sizeof(line), fp);
+  ASSERT_TRUE(s != NULL);
+  ASSERT_STREQ("xyz\n", s);
+
+  fclose(fp);
+}
+
+TEST(stdio, fmemopen_EINVAL) {
+  char buf[16];
+
+  // Invalid size.
+  errno = 0;
+  ASSERT_EQ(nullptr, fmemopen(buf, 0, "r+"));
+  ASSERT_EQ(EINVAL, errno);
+
+  // No '+' with NULL buffer.
+  errno = 0;
+  ASSERT_EQ(nullptr, fmemopen(nullptr, 0, "r"));
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(stdio, open_memstream) {
+  char* p = nullptr;
+  size_t size = 0;
+  FILE* fp = open_memstream(&p, &size);
+  ASSERT_NE(EOF, fputs("hello, world!", fp));
+  fclose(fp);
+
+  ASSERT_STREQ("hello, world!", p);
+  ASSERT_EQ(strlen("hello, world!"), size);
+  free(p);
+}
+
+TEST(stdio, open_memstream_EINVAL) {
+#if defined(__BIONIC__)
+  char* p;
+  size_t size;
+
+  // Invalid buffer.
+  errno = 0;
+  ASSERT_EQ(nullptr, open_memstream(nullptr, &size));
+  ASSERT_EQ(EINVAL, errno);
+
+  // Invalid size.
+  errno = 0;
+  ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
+  ASSERT_EQ(EINVAL, errno);
+#else
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
diff --git a/tests/string_posix_strerror_r_test.cpp b/tests/string_posix_strerror_r_test.cpp
new file mode 100644
index 0000000..09cebfe
--- /dev/null
+++ b/tests/string_posix_strerror_r_test.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#undef _GNU_SOURCE
+
+// Old versions of glibc (like our current host prebuilt sysroot one) have
+// headers that don't work if you #undef _GNU_SOURCE, which makes it
+// impossible to build this test.
+#include <features.h>
+
+#if !defined(__GLIBC__)
+#include <string.h>
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(string, posix_strerror_r) {
+  char buf[256];
+
+  // Valid.
+  ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf)));
+  ASSERT_STREQ("Success", buf);
+  ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf)));
+  ASSERT_STREQ("Operation not permitted", buf);
+
+  // Invalid.
+  ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error -1", buf);
+  ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error 1234", buf);
+
+  // Buffer too small.
+  errno = 0;
+  memset(buf, 0, sizeof(buf));
+  ASSERT_EQ(-1, strerror_r(4567, buf, 2));
+  ASSERT_STREQ("U", buf);
+  // The POSIX strerror_r sets errno to ERANGE (the GNU one doesn't).
+  ASSERT_EQ(ERANGE, errno);
+}
+#else
+# if __GLIBC_PREREQ(2, 15)
+#  error this test should work now
+# endif
+#endif
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 73c94c6..6ecbb64 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#define _GNU_SOURCE 1
+
+#include <string.h>
 
 #include <errno.h>
+#include <gtest/gtest.h>
 #include <malloc.h>
 #include <math.h>
-#include <string.h>
 
 #include "buffer_tests.h"
 
@@ -72,28 +74,34 @@
 #endif // __BIONIC__
 }
 
-TEST(string, strerror_r) {
-#if defined(__BIONIC__) // glibc's strerror_r doesn't even have the same signature as the POSIX one.
+TEST(string, gnu_strerror_r) {
   char buf[256];
 
+  // Note that glibc doesn't necessarily write into the buffer.
+
   // Valid.
-  ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf)));
+  ASSERT_STREQ("Success", strerror_r(0, buf, sizeof(buf)));
+#if defined(__BIONIC__)
   ASSERT_STREQ("Success", buf);
-  ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf)));
+#endif
+  ASSERT_STREQ("Operation not permitted", strerror_r(1, buf, sizeof(buf)));
+#if defined(__BIONIC__)
   ASSERT_STREQ("Operation not permitted", buf);
+#endif
 
   // Invalid.
-  ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error -1", strerror_r(-1, buf, sizeof(buf)));
   ASSERT_STREQ("Unknown error -1", buf);
-  ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf)));
+  ASSERT_STREQ("Unknown error 1234", strerror_r(1234, buf, sizeof(buf)));
   ASSERT_STREQ("Unknown error 1234", buf);
 
   // Buffer too small.
-  ASSERT_EQ(-1, strerror_r(0, buf, 2));
-  ASSERT_EQ(ERANGE, errno);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
+  errno = 0;
+  memset(buf, 0, sizeof(buf));
+  ASSERT_EQ(buf, strerror_r(4567, buf, 2));
+  ASSERT_STREQ("U", buf);
+  // The GNU strerror_r doesn't set errno (the POSIX one sets it to ERANGE).
+  ASSERT_EQ(0, errno);
 }
 
 TEST(string, strsignal) {
@@ -129,8 +137,7 @@
   ASSERT_STREQ("Unknown signal 1001", strsignal1001);
 }
 
-// TODO: where did these numbers come from?
-#define POS_ITER    10
+// TODO: where did this number come from?
 #define ITER        500
 
 // For every length we want to test, vary and change alignment
@@ -139,8 +146,9 @@
 // These tests contributed by Intel Corporation.
 // TODO: make these tests more intention-revealing and less random.
 template<class Character>
-struct StringTestState {
-  StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN) {
+class StringTestState {
+ public:
+  StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN), align1_index_(0), align2_index_(0) {
     int max_alignment = 64;
 
     // TODO: fix the tests to not sometimes use twice their specified "MAX_LEN".
@@ -159,24 +167,42 @@
     free(glob_ptr2);
   }
 
-  void NewIteration() {
-    int alignments[] = { 24, 32, 16, 48, 1, 2, 3, 0, 5, 11 };
-    int usable_alignments = 10;
-    int align1 = alignments[random() % (usable_alignments - 1)];
-    int align2 = alignments[random() % (usable_alignments - 1)];
+  void BeginIterations() {
+    align1_index_ = 0;
+    align2_index_ = 0;
 
-    ptr = glob_ptr + align1;
-    ptr1 = glob_ptr1 + align1;
-    ptr2 = glob_ptr2 + align2;
+    ResetPointers();
+  }
+
+  bool HasNextIteration() {
+    return (align1_index_ != (alignments_size - 1) || align2_index_ != (alignments_size - 1));
+  }
+
+  void NextIteration() {
+    if (align1_index_ == (alignments_size - 1) && align2_index_ == (alignments_size - 1)) {
+      return;
+    }
+
+    if (align1_index_ == (alignments_size - 1)) {
+      align1_index_ = 0;
+      align2_index_++;
+    } else {
+      align1_index_++;
+    }
+
+    ResetPointers();
   }
 
   const size_t MAX_LEN;
   Character *ptr, *ptr1, *ptr2;
   size_t n;
-  int len[ITER + 1];
+  size_t len[ITER + 1];
 
  private:
+  static size_t alignments[];
+  static size_t alignments_size;
   Character *glob_ptr, *glob_ptr1, *glob_ptr2;
+  size_t align1_index_, align2_index_;
 
   // Calculate input lengths and fill state.len with them.
   // Test small lengths with more density than big ones. Manually push
@@ -186,26 +212,40 @@
     n = 0;
     len[n++] = 0;
     for (size_t i = 1; i < ITER; ++i) {
-      int l = (int) exp(log((double) MAX_LEN) * i / ITER);
+      size_t l = static_cast<size_t>(exp(log(static_cast<double>(MAX_LEN)) * i / ITER));
       if (l != len[n - 1]) {
         len[n++] = l;
       }
     }
     len[n++] = MAX_LEN;
   }
+
+  void ResetPointers() {
+    if (align1_index_ == alignments_size || align2_index_ == alignments_size) {
+      ptr = ptr1 = ptr2 = nullptr;
+    } else {
+      ptr = glob_ptr + alignments[align1_index_];
+      ptr1 = glob_ptr1 + alignments[align1_index_];
+      ptr2 = glob_ptr2 + alignments[align2_index_];
+    }
+  }
 };
 
+template<class Character>
+size_t StringTestState<Character>::alignments[] = { 24, 32, 16, 48, 0, 1, 2, 3, 4, 5, 6, 7, 11 };
+
+template<class Character>
+size_t StringTestState<Character>::alignments_size = sizeof(alignments)/sizeof(size_t);
+
 TEST(string, strcat) {
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr2, '\2', state.MAX_LEN);
       state.ptr2[state.MAX_LEN - 1] = '\0';
       memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN);
 
-      memset(state.ptr1, random() & 255, state.len[i]);
+      memset(state.ptr1, 'L', state.len[i]);
       state.ptr1[random() % state.len[i]] = '\0';
       state.ptr1[state.len[i] - 1] = '\0';
 
@@ -378,13 +418,11 @@
 }
 
 TEST(string, strchr) {
-  int seek_char = random() & 255;
+  int seek_char = 'R';
 
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       if (~seek_char > 0) {
         memset(state.ptr1, ~seek_char, state.len[i]);
       } else {
@@ -392,7 +430,7 @@
       }
       state.ptr1[state.len[i] - 1] = '\0';
 
-      int pos = random() % state.MAX_LEN;
+      size_t pos = random() % state.MAX_LEN;
       char* expected;
       if (pos >= state.len[i] - 1) {
         if (seek_char == 0) {
@@ -413,15 +451,13 @@
 TEST(string, strcmp) {
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr1, 'v', state.MAX_LEN);
       memset(state.ptr2, 'n', state.MAX_LEN);
       state.ptr1[state.len[i] - 1] = '\0';
       state.ptr2[state.len[i] - 1] = '\0';
 
-      int pos = 1 + (random() % (state.MAX_LEN - 1));
+      size_t pos = 1 + (random() % (state.MAX_LEN - 1));
       int actual;
       int expected;
       if (pos >= state.len[i] - 1) {
@@ -449,9 +485,7 @@
 
 TEST(string, stpcpy) {
   StringTestState<char> state(SMALL);
-  for (size_t j = 0; j < POS_ITER; j++) {
-    state.NewIteration();
-
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
     size_t pos = random() % state.MAX_LEN;
 
     memset(state.ptr1, '\2', pos);
@@ -475,9 +509,7 @@
 
 TEST(string, strcpy) {
   StringTestState<char> state(SMALL);
-  for (size_t j = 0; j < POS_ITER; j++) {
-    state.NewIteration();
-
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
     size_t pos = random() % state.MAX_LEN;
 
     memset(state.ptr1, '\2', pos);
@@ -503,14 +535,12 @@
 #if defined(__BIONIC__)
   StringTestState<char> state(SMALL);
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr2, '\2', state.MAX_LEN + state.len[i]);
       state.ptr2[state.MAX_LEN - 1] = '\0';
       memcpy(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]);
 
-      int pos = random() % state.MAX_LEN;
+      size_t pos = random() % state.MAX_LEN;
       memset(state.ptr1, '\3', pos);
       state.ptr1[pos] = '\0';
       if (pos < state.len[i]) {
@@ -533,13 +563,8 @@
 TEST(string, strlcpy) {
 #if defined(__BIONIC__)
   StringTestState<char> state(SMALL);
-  for (size_t j = 0; j < POS_ITER; j++) {
-    state.NewIteration();
-
-    int rand = random() & 255;
-    if (rand < 1) {
-      rand = 1;
-    }
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+    int rand = 'O';
     memset(state.ptr1, rand, state.MAX_LEN);
 
     size_t pos = random() % state.MAX_LEN;
@@ -548,7 +573,7 @@
     }
     memcpy(state.ptr, state.ptr1, state.MAX_LEN);
 
-    memset(state.ptr2, random() & 255, state.MAX_LEN);
+    memset(state.ptr2, 'I', state.MAX_LEN);
     memcpy(state.ptr + state.MAX_LEN, state.ptr2, state.MAX_LEN);
 
     if (pos > state.MAX_LEN - 1) {
@@ -570,14 +595,12 @@
 TEST(string, strncat) {
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr2, '\2', state.MAX_LEN);
       state.ptr2[state.MAX_LEN - 1] = '\0';
       memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN);
 
-      memset(state.ptr1, random() & 255, state.len[i]);
+      memset(state.ptr1, 'I', state.len[i]);
       state.ptr1[random() % state.len[i]] = '\0';
       state.ptr1[state.len[i] - 1] = '\0';
 
@@ -596,15 +619,13 @@
 TEST(string, strncmp) {
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr1, 'v', state.MAX_LEN);
       memset(state.ptr2, 'n', state.MAX_LEN);
       state.ptr1[state.len[i] - 1] = '\0';
       state.ptr2[state.len[i] - 1] = '\0';
 
-      int pos = 1 + (random() % (state.MAX_LEN - 1));
+      size_t pos = 1 + (random() % (state.MAX_LEN - 1));
       int actual;
       int expected;
       if (pos >= state.len[i] - 1) {
@@ -632,12 +653,8 @@
 
 TEST(string, stpncpy) {
   StringTestState<char> state(SMALL);
-  for (size_t j = 0; j < ITER; j++) {
-    state.NewIteration();
-
-    // Choose a random value to fill the string, except \0 (string terminator),
-    // or \1 (guarantees it's different from anything in ptr2).
-    memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN);
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+    memset(state.ptr1, 'J', state.MAX_LEN);
     // Choose a random size for our src buffer.
     size_t ptr1_len = random() % state.MAX_LEN;
     state.ptr1[ptr1_len] = '\0';
@@ -671,12 +688,10 @@
 
 TEST(string, strncpy) {
   StringTestState<char> state(SMALL);
-  for (size_t j = 0; j < ITER; j++) {
-    state.NewIteration();
-
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
     // Choose a random value to fill the string, except \0 (string terminator),
     // or \1 (guarantees it's different from anything in ptr2).
-    memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN);
+    memset(state.ptr1, 'K', state.MAX_LEN);
     // Choose a random size for our src buffer.
     size_t ptr1_len = random() % state.MAX_LEN;
     state.ptr1[ptr1_len] = '\0';
@@ -709,12 +724,10 @@
 }
 
 TEST(string, strrchr) {
-  int seek_char = random() & 255;
+  int seek_char = 'M';
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       if (~seek_char > 0) {
         memset(state.ptr1, ~seek_char, state.len[i]);
       } else {
@@ -722,7 +735,7 @@
       }
       state.ptr1[state.len[i] - 1] = '\0';
 
-      int pos = random() % state.MAX_LEN;
+      size_t pos = random() % state.MAX_LEN;
       char* expected;
       if (pos >= state.len[i] - 1) {
         if (seek_char == 0) {
@@ -741,15 +754,13 @@
 }
 
 TEST(string, memchr) {
-  int seek_char = random() & 255;
+  int seek_char = 'N';
   StringTestState<char> state(SMALL);
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr1, ~seek_char, state.len[i]);
 
-      int pos = random() % state.MAX_LEN;
+      size_t pos = random() % state.MAX_LEN;
       char* expected;
       if (pos >= state.len[i]) {
         expected = NULL;
@@ -772,15 +783,13 @@
 }
 
 TEST(string, memrchr) {
-  int seek_char = random() & 255;
+  int seek_char = 'P';
   StringTestState<char> state(SMALL);
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr1, ~seek_char, state.len[i]);
 
-      int pos = random() % state.MAX_LEN;
+      size_t pos = random() % state.MAX_LEN;
       char* expected;
       if (pos >= state.len[i]) {
         expected = NULL;
@@ -797,11 +806,9 @@
 TEST(string, memcmp) {
   StringTestState<char> state(SMALL);
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
-      int c1 = random() & 0xff;
-      int c2 = random() & 0xff;
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+      int c1 = 'A';
+      int c2 = 'N';
       memset(state.ptr1, c1, state.MAX_LEN);
       memset(state.ptr2, c1, state.MAX_LEN);
 
@@ -820,9 +827,7 @@
   StringTestState<wchar_t> state(SMALL);
 
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       long long mask = ((long long) 1 << 8 * sizeof(wchar_t)) - 1;
       int c1 = rand() & mask;
       int c2 = rand() & mask;
@@ -842,11 +847,9 @@
 
 TEST(string, memcpy) {
   StringTestState<char> state(LARGE);
-  int rand = random() & 255;
+  int rand = 4;
   for (size_t i = 0; i < state.n - 1; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       size_t pos = random() % (state.MAX_LEN - state.len[i]);
 
       memset(state.ptr1, rand, state.len[i]);
@@ -864,11 +867,9 @@
 
 TEST(string, memset) {
   StringTestState<char> state(LARGE);
-  char ch = random () & 255;
+  char ch = 'P';
   for (size_t i = 0; i < state.n - 1; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
       memset(state.ptr1, ~ch, state.MAX_LEN);
       memcpy(state.ptr2, state.ptr1, state.MAX_LEN);
 
@@ -887,14 +888,12 @@
 TEST(string, memmove) {
   StringTestState<char> state(LARGE);
   for (size_t i = 0; i < state.n - 1; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
-      memset(state.ptr1, random() & 255, 2 * state.MAX_LEN);
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+      memset(state.ptr1, 'Q', 2 * state.MAX_LEN);
 
       size_t pos = random() % (state.MAX_LEN - state.len[i]);
 
-      memset(state.ptr1, random() & 255, state.len[i]);
+      memset(state.ptr1, 'R', state.len[i]);
       memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN);
       memcpy(state.ptr, state.ptr1, state.len[i]);
       memcpy(state.ptr1 + pos, state.ptr, state.len[i]);
@@ -920,8 +919,8 @@
 
   for (int i = 0; i < 5; i++) {
     char* ptr2 = glob_ptr2 + alignments[i];
-    memset(ptr1, random() & 255, 2 * len);
-    memset(ptr1, random() & 255, len);
+    memset(ptr1, 'S', 2 * len);
+    memset(ptr1, 'T', len);
     memcpy(ptr2, ptr1, 2 * len);
     memcpy(ptr, ptr1, len);
     memcpy(ptr1 + pos, ptr, len);
@@ -987,11 +986,9 @@
 TEST(string, bcopy) {
   StringTestState<char> state(LARGE);
   for (size_t i = 0; i < state.n; i++) {
-    for (size_t j = 0; j < POS_ITER; j++) {
-      state.NewIteration();
-
-      memset(state.ptr1, random() & 255, state.MAX_LEN);
-      memset(state.ptr1 + state.MAX_LEN, random() & 255, state.MAX_LEN);
+    for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+      memset(state.ptr1, '4', state.MAX_LEN);
+      memset(state.ptr1 + state.MAX_LEN, 'a', state.MAX_LEN);
       memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN);
 
       size_t start = random() % (2 * state.MAX_LEN - state.len[i]);
@@ -1005,10 +1002,8 @@
 
 TEST(string, bzero) {
   StringTestState<char> state(LARGE);
-  for (size_t j = 0; j < ITER; j++) {
-    state.NewIteration();
-
-    memset(state.ptr1, random() & 255, state.MAX_LEN);
+  for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+    memset(state.ptr1, 'R', state.MAX_LEN);
 
     size_t start = random() % state.MAX_LEN;
     size_t end = start + random() % (state.MAX_LEN - start);
@@ -1287,3 +1282,22 @@
 TEST(string, strchr_overread) {
   RunSingleBufferOverreadTest(DoStrchrTest);
 }
+
+static void TestBasename(const char* in, const char* expected_out) {
+  errno = 0;
+  const char* out = basename(in);
+  ASSERT_STREQ(expected_out, out) << in;
+  ASSERT_EQ(0, errno) << in;
+}
+
+TEST(string, __gnu_basename) {
+  TestBasename("", "");
+  TestBasename("/usr/lib", "lib");
+  TestBasename("/usr/", "");
+  TestBasename("usr", "usr");
+  TestBasename("/", "");
+  TestBasename(".", ".");
+  TestBasename("..", "..");
+  TestBasename("///", "");
+  TestBasename("//usr//lib//", "");
+}
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
index 0bde024..38ef68a 100644
--- a/tests/sys_socket_test.cpp
+++ b/tests/sys_socket_test.cpp
@@ -23,13 +23,9 @@
 #include <fcntl.h>
 
 #if defined(__BIONIC__)
-  #define ACCEPT4_SUPPORTED 1
   #define RECVMMSG_SUPPORTED 1
   #define SENDMMSG_SUPPORTED 1
 #elif defined(__GLIBC_PREREQ)
-  #if __GLIBC_PREREQ(2, 9)
-    #define ACCEPT4_SUPPORTED 1
-  #endif
   #if __GLIBC_PREREQ(2, 12)
     #define RECVMMSG_SUPPORTED 1
   #endif
@@ -38,8 +34,6 @@
   #endif
 #endif
 
-#if defined(ACCEPT4_SUPPORTED) || defined(RECVMMSG_SUPPORTED) || defined(SENDMMSG_SUPPORTED)
-
 #define SOCK_PATH "test"
 
 static void* ConnectFn(void* data) {
@@ -105,18 +99,12 @@
 
   close(fd);
 }
-#endif
 
 TEST(sys_socket, accept4_error) {
-#if defined(ACCEPT4_SUPPORTED)
   ASSERT_EQ(-1, accept4(-1, NULL, NULL, 0));
   ASSERT_EQ(EBADF, errno);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
-#if defined(ACCEPT4_SUPPORTED)
 static void TestAccept4(struct sockaddr_un* addr, int fd) {
   socklen_t len = sizeof(*addr);
   int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(addr), &len, SOCK_CLOEXEC);
@@ -127,14 +115,9 @@
 
   close(fd_acc);
 }
-#endif
 
 TEST(sys_socket, accept4_smoke) {
-#if defined(ACCEPT4_SUPPORTED)
   RunTest(TestAccept4, NULL);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
 #if defined(RECVMMSG_SUPPORTED)
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
 
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index d02c4bf..760475f 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -489,3 +489,34 @@
   EXPECT_EQ(4U, n);
   EXPECT_EQ(L'𤭢', wc);
 }
+
+TEST(wchar, open_wmemstream) {
+  wchar_t* p = nullptr;
+  size_t size = 0;
+  FILE* fp = open_wmemstream(&p, &size);
+  ASSERT_NE(EOF, fputws(L"hello, world!", fp));
+  fclose(fp);
+
+  ASSERT_STREQ(L"hello, world!", p);
+  ASSERT_EQ(wcslen(L"hello, world!"), size);
+  free(p);
+}
+
+TEST(stdio, open_wmemstream_EINVAL) {
+#if defined(__BIONIC__)
+  wchar_t* p;
+  size_t size;
+
+  // Invalid buffer.
+  errno = 0;
+  ASSERT_EQ(nullptr, open_wmemstream(nullptr, &size));
+  ASSERT_EQ(EINVAL, errno);
+
+  // Invalid size.
+  errno = 0;
+  ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr));
+  ASSERT_EQ(EINVAL, errno);
+#else
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}