am 2e23e292: Backport (simple cherry-pick) d33019030c1f0cddca557f9659e3c471bde0e6a9 to gingerbread.

* commit '2e23e29245aa42d0f9419187c94e72dba3888eef':
  Backport (simple cherry-pick) d33019030c1f0cddca557f9659e3c471bde0e6a9 to gingerbread.
diff --git a/libc/Android.mk b/libc/Android.mk
index 9e6bdfb..351ad02 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -187,7 +187,6 @@
 	string/strcat.c \
 	string/strchr.c \
 	string/strcoll.c \
-	string/strcpy.c \
 	string/strcspn.c \
 	string/strdup.c \
 	string/strerror.c \
@@ -241,13 +240,14 @@
 	inet/inet_ntoa.c \
 	inet/inet_ntop.c \
 	inet/inet_pton.c \
+	inet/ether_aton.c \
+	inet/ether_ntoa.c \
 	tzcode/asctime.c \
 	tzcode/difftime.c \
 	tzcode/localtime.c \
 	tzcode/strftime.c \
 	tzcode/strptime.c \
 	bionic/__set_errno.c \
-	bionic/_rand48.c \
 	bionic/cpuacct.c \
 	bionic/arc4random.c \
 	bionic/basename.c \
@@ -354,6 +354,7 @@
 	arch-arm/bionic/setjmp.S \
 	arch-arm/bionic/sigsetjmp.S \
 	arch-arm/bionic/strlen.c.arm \
+	arch-arm/bionic/strcpy.S \
 	arch-arm/bionic/syscall.S \
 	string/memmove.c.arm \
 	string/bcopy.c \
@@ -365,6 +366,7 @@
 # can set breakpoints in them without messing
 # up any thumb code.
 libc_common_src_files += \
+	bionic/pthread-atfork.c.arm \
 	bionic/pthread-rwlocks.c.arm \
 	bionic/pthread-timers.c.arm \
 	bionic/ptrace.c.arm
@@ -391,6 +393,7 @@
 	arch-x86/bionic/_exit_with_stack_teardown.S \
 	arch-x86/bionic/setjmp.S \
 	arch-x86/bionic/_setjmp.S \
+	arch-x86/bionic/sigsetjmp.S \
 	arch-x86/bionic/vfork.S \
 	arch-x86/bionic/syscall.S \
 	arch-x86/string/bcopy_wrapper.S \
@@ -401,7 +404,9 @@
 	arch-x86/string/memset_wrapper.S \
 	arch-x86/string/strcmp_wrapper.S \
 	arch-x86/string/strncmp_wrapper.S \
-	arch-x86/string/strlen.S \
+	arch-x86/string/strlen_wrapper.S \
+	string/strcpy.c \
+	bionic/pthread-atfork.c \
 	bionic/pthread-rwlocks.c \
 	bionic/pthread-timers.c \
 	bionic/ptrace.c
@@ -441,6 +446,8 @@
 	string/strncmp.c \
 	string/memcmp.c \
 	string/strlen.c \
+	string/strcpy.c \
+	bionic/pthread-atfork.c \
 	bionic/pthread-rwlocks.c \
 	bionic/pthread-timers.c \
 	bionic/ptrace.c \
@@ -495,13 +502,7 @@
     libc_common_cflags += -DHAVE_ARM_TLS_REGISTER
   endif
 else # !arm
-  ifeq ($(TARGET_ARCH),x86)
-    libc_crt_target_cflags := -m32
-
-    # Enable recent IA friendly memory routines (such as for Atom)
-    # These will not work on the earlier x86 machines
-    libc_common_cflags += -mtune=i686 -DUSE_SSSE3 -DUSE_SSE2
-  endif # x86
+  libc_crt_target_cflags :=
 endif # !arm
 
 # Define ANDROID_SMP appropriately.
@@ -523,6 +524,10 @@
 		$(LOCAL_PATH)/string  \
 		$(LOCAL_PATH)/stdio
 
+# Needed to access private/__dso_handle.S from
+# crtbegin_xxx.S and crtend_xxx.S
+#
+libc_crt_target_cflags += -I$(LOCAL_PATH)/private
 
 # Define the libc run-time (crt) support object files that must be built,
 # which are needed to build all other objects (shared/static libs and
@@ -703,6 +708,7 @@
 LOCAL_SHARED_LIBRARIES := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
+LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 # Don't prelink
 LOCAL_PRELINK_MODULE := false
 # Don't install on release build
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 0850b82..0a08e12 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -264,3 +264,5 @@
 # ARM-specific ARM_NR_BASE == 0x0f0000 == 983040
 int     __set_tls:ARM_set_tls(void*)                                 983045,-1
 int     cacheflush:ARM_cacheflush(long start, long end, long flags)  983042,-1
+
+int     eventfd(int count, int flags) 351,323
diff --git a/libc/arch-arm/bionic/strcpy.S b/libc/arch-arm/bionic/strcpy.S
new file mode 100644
index 0000000..70c353f
--- /dev/null
+++ b/libc/arch-arm/bionic/strcpy.S
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (c) 2008 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Android adaptation and tweak by Jim Huang <jserv@0xlab.org>.
+ */
+
+#include <machine/cpu-features.h>
+
+	.text
+
+	.global strcpy
+	.type strcpy, %function
+	.align 4
+
+strcpy:
+	.fnstart
+	PLD(r1, #0)
+	eor	r2, r0, r1
+	mov	ip, r0
+	tst	r2, #3
+	bne	4f
+	tst	r1, #3
+	bne	3f
+5:
+	str	r5, [sp, #-4]!
+	mov	r5, #0x01
+	orr	r5, r5, r5, lsl #8
+	orr	r5, r5, r5, lsl #16
+
+	str	r4, [sp, #-4]!
+	tst	r1, #4
+	ldr	r3, [r1], #4
+	beq	2f
+	sub	r2, r3, r5
+	bics	r2, r2, r3
+	tst	r2, r5, lsl #7
+	itt	eq
+	streq	r3, [ip], #4
+	ldreq	r3, [r1], #4
+	bne	1f
+       /* Inner loop.  We now know that r1 is 64-bit aligned, so we
+	  can safely fetch up to two words.  This allows us to avoid
+	  load stalls.  */
+	.p2align 2
+2:
+	PLD(r1, #8)
+	ldr	r4, [r1], #4
+	sub	r2, r3, r5
+	bics	r2, r2, r3
+	tst	r2, r5, lsl #7
+	sub	r2, r4, r5
+	bne	1f
+	str	r3, [ip], #4
+	bics	r2, r2, r4
+	tst	r2, r5, lsl #7
+	itt	eq
+	ldreq	r3, [r1], #4
+	streq	r4, [ip], #4
+	beq	2b
+	mov	r3, r4
+1:
+#ifdef __ARMEB__
+	rors	r3, r3, #24
+#endif
+	strb	r3, [ip], #1
+	tst	r3, #0xff
+#ifdef __ARMEL__
+	ror	r3, r3, #8
+#endif
+	bne	1b
+	ldr	r4, [sp], #4
+	ldr	r5, [sp], #4
+	bx	lr
+
+       /* Strings have the same offset from word alignment, but it's
+	  not zero.  */
+3:
+	tst	r1, #1
+	beq	1f
+	ldrb	r2, [r1], #1
+	strb	r2, [ip], #1
+	cmp	r2, #0
+	it	eq
+	bxeq	lr
+1:
+	tst	r1, #2
+	beq	5b
+	ldrh	r2, [r1], #2
+#ifdef __ARMEB__
+	tst	r2, #0xff00
+	iteet	ne
+	strneh	r2, [ip], #2
+	lsreq	r2, r2, #8
+	streqb	r2, [ip]
+	tstne	r2, #0xff
+#else
+	tst	r2, #0xff
+	itet	ne
+	strneh	r2, [ip], #2
+	streqb	r2, [ip]
+	tstne	r2, #0xff00
+#endif
+	bne	5b
+	bx	lr
+
+       /* src and dst do not have a common word-alignement.  Fall back to
+	  byte copying.  */
+4:
+	ldrb	r2, [r1], #1
+	strb	r2, [ip], #1
+	cmp	r2, #0
+	bne	4b
+	bx	lr
diff --git a/libc/arch-arm/include/endian.h b/libc/arch-arm/include/endian.h
index 04204ed..6de0889 100644
--- a/libc/arch-arm/include/endian.h
+++ b/libc/arch-arm/include/endian.h
@@ -1,10 +1,89 @@
 /*	$OpenBSD: endian.h,v 1.3 2005/12/13 00:35:23 millert Exp $	*/
 
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_ENDIAN_H_
+#define _ARM_ENDIAN_H_
+
+#ifdef __GNUC__
+
+/*
+ * REV and REV16 weren't available on ARM5 or ARM4.
+ * We don't include <machine/cpu-features.h> because it pollutes the
+ * namespace with macros like PLD.
+ */
+#if !defined __ARM_ARCH_5__ && !defined __ARM_ARCH_5T__ && \
+    !defined __ARM_ARCH_5TE__ && !defined __ARM_ARCH_5TEJ__ && \
+    !defined __ARM_ARCH_4T__ && !defined __ARM_ARCH_4__
+
+/* According to RealView Assembler User's Guide, REV and REV16 are available
+ * in Thumb code and 16-bit instructions when used in Thumb-2 code.
+ *
+ * REV Rd, Rm
+ *   Rd and Rm must both be Lo registers.
+ *
+ * REV16 Rd, Rm
+ *   Rd and Rm must both be Lo registers.
+ *
+ * The +l constraint takes care of this without constraining us in ARM mode.
+ */
+#define __swap16md(x) ({                                        \
+    register u_int16_t _x = (x);                                \
+    __asm volatile ("rev16 %0, %0" : "+l" (_x));                \
+    _x;                                                         \
+})
+
+#define __swap32md(x) ({                                        \
+    register u_int32_t _x = (x);                                \
+    __asm volatile ("rev %0, %0" : "+l" (_x));                  \
+    _x;                                                         \
+})
+
+#define __swap64md(x) ({                                        \
+    u_int64_t _swap64md_x = (x);                                \
+    (u_int64_t) __swap32md(_swap64md_x >> 32) |                 \
+        (u_int64_t) __swap32md(_swap64md_x & 0xffffffff) << 32; \
+})
+
+/* Tell sys/endian.h we have MD variants of the swap macros.  */
+#define MD_SWAP
+
+#endif  /* __ARM_ARCH__ */
+#endif  /* __GNUC__ */
+
 #ifdef __ARMEB__
 #define _BYTE_ORDER _BIG_ENDIAN
 #else
 #define _BYTE_ORDER _LITTLE_ENDIAN
 #endif
-#define	__STRICT_ALIGNMENT
+#define __STRICT_ALIGNMENT
 #include <sys/types.h>
 #include <sys/endian.h>
+
+#endif  /* !_ARM_ENDIAN_H_ */
diff --git a/libc/arch-arm/include/machine/cpu-features.h b/libc/arch-arm/include/machine/cpu-features.h
index 39c1db3..80d3fda 100644
--- a/libc/arch-arm/include/machine/cpu-features.h
+++ b/libc/arch-arm/include/machine/cpu-features.h
@@ -185,6 +185,7 @@
 #endif
 
 /* Assembly-only macros */
+#ifdef __ASSEMBLY__
 
 /* define a handy PLD(address) macro since the cache preload
  * is an optional opcode
@@ -195,4 +196,6 @@
 #  define  PLD(reg,offset)    /* nothing */
 #endif
 
+#endif /* ! __ASSEMBLY__ */
+
 #endif /* _ARM_MACHINE_CPU_FEATURES_H */
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index ba78c18..c3cf785 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -175,3 +175,4 @@
 syscall_src += arch-arm/syscalls/eventfd.S
 syscall_src += arch-arm/syscalls/__set_tls.S
 syscall_src += arch-arm/syscalls/cacheflush.S
+syscall_src += arch-arm/syscalls/eventfd.S
diff --git a/libc/arch-x86/bionic/clone.S b/libc/arch-x86/bionic/clone.S
index 3b50cc3..44fce1e 100644
--- a/libc/arch-x86/bionic/clone.S
+++ b/libc/arch-x86/bionic/clone.S
@@ -52,4 +52,4 @@
 /* XXX: TODO: Add __bionic_clone here
  *            See bionic/bionic_clone.c and arch-arm/bionic/clone.S
  *            for more details...
- */
\ No newline at end of file
+ */
diff --git a/libc/arch-x86/bionic/sigsetjmp.S b/libc/arch-x86/bionic/sigsetjmp.S
new file mode 100644
index 0000000..c990a05
--- /dev/null
+++ b/libc/arch-x86/bionic/sigsetjmp.S
@@ -0,0 +1,92 @@
+/* $OpenBSD: sigsetjmp.S,v 1.7 2005/08/07 11:30:38 espie Exp $ */
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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 <machine/asm.h>
+
+ENTRY(sigsetjmp)
+	movl	4(%esp),%ecx
+	movl	8(%esp),%eax
+	movl	%eax,28(%ecx)
+	testl	%eax,%eax
+	jz	1f
+
+	PIC_PROLOGUE
+	pushl	$0
+#ifdef PIC
+	call	PIC_PLT(_C_LABEL(sigblock))
+#else
+	call	_C_LABEL(sigblock)
+#endif
+	addl	$4,%esp
+	PIC_EPILOGUE
+
+	movl	4(%esp),%ecx
+	movl	%eax,24(%ecx)
+1:	movl	0(%esp),%edx
+	movl	%edx, 0(%ecx)
+	movl	%ebx, 4(%ecx)
+	movl	%esp, 8(%ecx)
+	movl	%ebp,12(%ecx)
+	movl	%esi,16(%ecx)
+	movl	%edi,20(%ecx)
+	xorl	%eax,%eax
+	ret
+
+ENTRY(siglongjmp)
+	movl	4(%esp),%edx
+	cmpl	$0,28(%edx)
+	jz	1f
+
+	PIC_PROLOGUE
+	pushl	24(%edx)
+#ifdef PIC
+	call	PIC_PLT(_C_LABEL(sigsetmask))
+#else
+	call	_C_LABEL(sigsetmask)
+#endif
+	addl	$4,%esp
+	PIC_EPILOGUE
+
+1:	movl	4(%esp),%edx
+	movl	8(%esp),%eax
+	movl	0(%edx),%ecx
+	movl	4(%edx),%ebx
+	movl	8(%edx),%esp
+	movl	12(%edx),%ebp
+	movl	16(%edx),%esi
+	movl	20(%edx),%edi
+	testl	%eax,%eax
+	jnz	2f
+	incl	%eax
+2:	movl	%ecx,0(%esp)
+	ret
diff --git a/libc/arch-x86/include/endian.h b/libc/arch-x86/include/endian.h
index ad37919..4a70536 100644
--- a/libc/arch-x86/include/endian.h
+++ b/libc/arch-x86/include/endian.h
@@ -31,14 +31,14 @@
 
 #if defined(_KERNEL) && !defined(I386_CPU)
 #define	__swap32md(x) ({						\
-	u_int32_t __swap32md_x = (x);					\
+	uint32_t __swap32md_x = (x);					\
 									\
 	__asm ("bswap %1" : "+r" (__swap32md_x));			\
 	__swap32md_x;							\
 })
 #else
 #define	__swap32md(x) ({						\
-	u_int32_t __swap32md_x = (x);					\
+	uint32_t __swap32md_x = (x);					\
 									\
 	__asm ("rorw $8, %w1; rorl $16, %1; rorw $8, %w1" :		\
 	    "+r" (__swap32md_x));					\
@@ -47,13 +47,13 @@
 #endif	/* _KERNEL && !I386_CPU */
 
 #define	__swap64md(x) ({						\
-	u_int64_t __swap64md_x = (x);					\
+	uint64_t __swap64md_x = (x);					\
 									\
-	(u_int64_t)__swap32md(__swap64md_x >> 32) |			\
-	    (u_int64_t)__swap32md(__swap64md_x & 0xffffffff) << 32;	\
+	(uint64_t)__swap32md(__swap64md_x >> 32) |			\
+	    (uint64_t)__swap32md(__swap64md_x & 0xffffffff) << 32;	\
 })
 #define	__swap16md(x) ({						\
-	u_int16_t __swap16md_x = (x);					\
+	uint16_t __swap16md_x = (x);					\
 									\
 	__asm ("rorw $8, %w1" : "+r" (__swap16md_x));			\
 	__swap16md_x;							\
diff --git a/libc/arch-x86/include/machine/_types.h b/libc/arch-x86/include/machine/_types.h
index be4f6e4..e9280a5 100644
--- a/libc/arch-x86/include/machine/_types.h
+++ b/libc/arch-x86/include/machine/_types.h
@@ -36,8 +36,8 @@
 #define _I386__TYPES_H_
 
 /* the kernel defines size_t as unsigned int, but g++ wants it to be unsigned long */
-#ifndef _SIZE_T
-#  define _SIZE_T
+#ifndef _SIZE_T_DEFINED_
+#  define _SIZE_T_DEFINED_
 #  ifdef ANDROID
      typedef unsigned int  size_t;
 #  else
@@ -54,9 +54,6 @@
 typedef long           ptrdiff_t;
 #endif
 
-#define _OFF_T_DEFINED_
-#define _SIZE_T_DEFINED_
-
 #include <linux/types.h>
 
 /* 7.18.1.1 Exact-width integer types */
diff --git a/libc/arch-x86/string/memcmp_wrapper.S b/libc/arch-x86/string/memcmp_wrapper.S
index 7e28c1e..fa0c672 100644
--- a/libc/arch-x86/string/memcmp_wrapper.S
+++ b/libc/arch-x86/string/memcmp_wrapper.S
@@ -31,7 +31,7 @@
 #if defined(USE_SSSE3)
 
 # define MEMCMP memcmp
-# include "ssse3-memcmp3.S"
+# include "ssse3-memcmp3-new.S"
 
 #else
 
diff --git a/libc/arch-x86/string/sse2-memset5-atom.S b/libc/arch-x86/string/sse2-memset5-atom.S
index 59a598c..4b7f71b 100644
--- a/libc/arch-x86/string/sse2-memset5-atom.S
+++ b/libc/arch-x86/string/sse2-memset5-atom.S
@@ -49,7 +49,7 @@
 #endif
 
 #ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore (reg)
+# define cfi_restore(reg)		.cfi_restore reg
 #endif
 
 #ifndef cfi_adjust_cfa_offset
@@ -285,7 +285,6 @@
 	pxor	%xmm0, %xmm0
 #else
 	movd	%eax, %xmm0
-	punpcklbw %xmm0, %xmm0
 	pshufd	$0, %xmm0, %xmm0
 #endif
 	testl	$0xf, %edx
@@ -329,14 +328,17 @@
 
 #ifdef DATA_CACHE_SIZE
 	POP (%ebx)
+# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
 	cmp	$DATA_CACHE_SIZE, %ecx
 #else
 # ifdef SHARED
+#  define RESTORE_EBX_STATE
 	call	__i686.get_pc_thunk.bx
 	add	$_GLOBAL_OFFSET_TABLE_, %ebx
 	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
 # else
 	POP (%ebx)
+#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
 	cmp	__x86_data_cache_size, %ecx
 # endif
 #endif
@@ -370,7 +372,7 @@
 	jae	L(128bytesormore_normal)
 
 L(128bytesless_normal):
-	lea	128(%ecx), %ecx
+	add	$128, %ecx
 	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
 
 	ALIGN (4)
@@ -393,8 +395,13 @@
 L(128bytesless_L2_normal):
 	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
 
+	RESTORE_EBX_STATE
 L(128bytesormore_nt_start):
 	sub	%ebx, %ecx
+	mov	%ebx, %eax
+	and	$0x7f, %eax
+	add	%eax, %ecx
+	movd	%xmm0, %eax
 	ALIGN (4)
 L(128bytesormore_shared_cache_loop):
 	prefetcht0	0x3c0(%edx)
diff --git a/libc/arch-x86/string/sse2-strlen-atom.S b/libc/arch-x86/string/sse2-strlen-atom.S
new file mode 100644
index 0000000..8911868
--- /dev/null
+++ b/libc/arch-x86/string/sse2-strlen-atom.S
@@ -0,0 +1,369 @@
+#define STRLEN sse2_strlen_atom
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef cfi_rel_offset
+# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
+#endif
+
+#ifndef cfi_restore
+# define cfi_restore(reg)		.cfi_restore reg
+#endif
+
+#ifndef cfi_adjust_cfa_offset
+# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
+#endif
+
+#ifndef cfi_remember_state
+# define cfi_remember_state		.cfi_remember_state
+#endif
+
+#ifndef cfi_restore_state
+# define cfi_restore_state		.cfi_restore_state
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define CFI_PUSH(REG)						\
+  cfi_adjust_cfa_offset (4);					\
+  cfi_rel_offset (REG, 0)
+
+#define CFI_POP(REG)						\
+  cfi_adjust_cfa_offset (-4);					\
+  cfi_restore (REG)
+
+#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
+#define POP(REG)	popl REG; CFI_POP (REG)
+#define PARMS		4
+#define	STR		PARMS
+#define ENTRANCE
+#define RETURN		ret
+
+	.text
+ENTRY (STRLEN)
+	ENTRANCE
+	mov	STR(%esp), %edx
+	xor	%eax, %eax
+	cmpb	$0, (%edx)
+	jz	L(exit_tail0)
+	cmpb	$0, 1(%edx)
+	jz	L(exit_tail1)
+	cmpb	$0, 2(%edx)
+	jz	L(exit_tail2)
+	cmpb	$0, 3(%edx)
+	jz	L(exit_tail3)
+	cmpb	$0, 4(%edx)
+	jz	L(exit_tail4)
+	cmpb	$0, 5(%edx)
+	jz	L(exit_tail5)
+	cmpb	$0, 6(%edx)
+	jz	L(exit_tail6)
+	cmpb	$0, 7(%edx)
+	jz	L(exit_tail7)
+	cmpb	$0, 8(%edx)
+	jz	L(exit_tail8)
+	cmpb	$0, 9(%edx)
+	jz	L(exit_tail9)
+	cmpb	$0, 10(%edx)
+	jz	L(exit_tail10)
+	cmpb	$0, 11(%edx)
+	jz	L(exit_tail11)
+	cmpb	$0, 12(%edx)
+	jz	L(exit_tail12)
+	cmpb	$0, 13(%edx)
+	jz	L(exit_tail13)
+	cmpb	$0, 14(%edx)
+	jz	L(exit_tail14)
+	cmpb	$0, 15(%edx)
+	jz	L(exit_tail15)
+	pxor	%xmm0, %xmm0
+	mov	%edx, %eax
+	mov	%edx, %ecx
+	and	$-16, %eax
+	add	$16, %ecx
+	add	$16, %eax
+
+	pcmpeqb	(%eax), %xmm0
+	pmovmskb %xmm0, %edx
+	pxor	%xmm1, %xmm1
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm1
+	pmovmskb %xmm1, %edx
+	pxor	%xmm2, %xmm2
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+
+	pcmpeqb	(%eax), %xmm2
+	pmovmskb %xmm2, %edx
+	pxor	%xmm3, %xmm3
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm3
+	pmovmskb %xmm3, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm0
+	pmovmskb %xmm0, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm1
+	pmovmskb %xmm1, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm2
+	pmovmskb %xmm2, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm3
+	pmovmskb %xmm3, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm0
+	pmovmskb %xmm0, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm1
+	pmovmskb %xmm1, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm2
+	pmovmskb %xmm2, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm3
+	pmovmskb %xmm3, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm0
+	pmovmskb %xmm0, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm1
+	pmovmskb %xmm1, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm2
+	pmovmskb %xmm2, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	pcmpeqb	(%eax), %xmm3
+	pmovmskb %xmm3, %edx
+	test	%edx, %edx
+	lea	16(%eax), %eax
+	jnz	L(exit)
+
+	and	$-0x40, %eax
+	PUSH (%esi)
+	PUSH (%edi)
+	PUSH (%ebx)
+	PUSH (%ebp)
+	xor	%ebp, %ebp
+L(aligned_64):
+	pcmpeqb	(%eax), %xmm0
+	pcmpeqb	16(%eax), %xmm1
+	pcmpeqb	32(%eax), %xmm2
+	pcmpeqb	48(%eax), %xmm3
+	pmovmskb %xmm0, %edx
+	pmovmskb %xmm1, %esi
+	pmovmskb %xmm2, %edi
+	pmovmskb %xmm3, %ebx
+	or	%edx, %ebp
+	or	%esi, %ebp
+	or	%edi, %ebp
+	or	%ebx, %ebp
+	lea	64(%eax), %eax
+	jz	L(aligned_64)
+L(48leave):
+	test	%edx, %edx
+	jnz	L(aligned_64_exit_16)
+	test	%esi, %esi
+	jnz	L(aligned_64_exit_32)
+	test	%edi, %edi
+	jnz	L(aligned_64_exit_48)
+	mov	%ebx, %edx
+	lea	(%eax), %eax
+	jmp	L(aligned_64_exit)
+L(aligned_64_exit_48):
+	lea	-16(%eax), %eax
+	mov	%edi, %edx
+	jmp	L(aligned_64_exit)
+L(aligned_64_exit_32):
+	lea	-32(%eax), %eax
+	mov	%esi, %edx
+	jmp	L(aligned_64_exit)
+L(aligned_64_exit_16):
+	lea	-48(%eax), %eax
+L(aligned_64_exit):
+	POP (%ebp)
+	POP (%ebx)
+	POP (%edi)
+	POP (%esi)
+L(exit):
+	sub	%ecx, %eax
+	test	%dl, %dl
+	jz	L(exit_high)
+	test	$0x01, %dl
+	jnz	L(exit_tail0)
+
+	test	$0x02, %dl
+	jnz	L(exit_tail1)
+
+	test	$0x04, %dl
+	jnz	L(exit_tail2)
+
+	test	$0x08, %dl
+	jnz	L(exit_tail3)
+
+	test	$0x10, %dl
+	jnz	L(exit_tail4)
+
+	test	$0x20, %dl
+	jnz	L(exit_tail5)
+
+	test	$0x40, %dl
+	jnz	L(exit_tail6)
+	add	$7, %eax
+L(exit_tail0):
+	RETURN
+
+L(exit_high):
+	add	$8, %eax
+	test	$0x01, %dh
+	jnz	L(exit_tail0)
+
+	test	$0x02, %dh
+	jnz	L(exit_tail1)
+
+	test	$0x04, %dh
+	jnz	L(exit_tail2)
+
+	test	$0x08, %dh
+	jnz	L(exit_tail3)
+
+	test	$0x10, %dh
+	jnz	L(exit_tail4)
+
+	test	$0x20, %dh
+	jnz	L(exit_tail5)
+
+	test	$0x40, %dh
+	jnz	L(exit_tail6)
+	add	$7, %eax
+	RETURN
+
+	.p2align 4
+L(exit_tail1):
+	add	$1, %eax
+	RETURN
+
+L(exit_tail2):
+	add	$2, %eax
+	RETURN
+
+L(exit_tail3):
+	add	$3, %eax
+	RETURN
+
+L(exit_tail4):
+	add	$4, %eax
+	RETURN
+
+L(exit_tail5):
+	add	$5, %eax
+	RETURN
+
+L(exit_tail6):
+	add	$6, %eax
+	RETURN
+
+L(exit_tail7):
+	add	$7, %eax
+	RETURN
+
+L(exit_tail8):
+	add	$8, %eax
+	RETURN
+
+L(exit_tail9):
+	add	$9, %eax
+	RETURN
+
+L(exit_tail10):
+	add	$10, %eax
+	RETURN
+
+L(exit_tail11):
+	add	$11, %eax
+	RETURN
+
+L(exit_tail12):
+	add	$12, %eax
+	RETURN
+
+L(exit_tail13):
+	add	$13, %eax
+	RETURN
+
+L(exit_tail14):
+	add	$14, %eax
+	RETURN
+
+L(exit_tail15):
+	add	$15, %eax
+	ret
+
+END (STRLEN)
diff --git a/libc/arch-x86/string/ssse3-memcmp3.S b/libc/arch-x86/string/ssse3-memcmp3-new.S
similarity index 95%
rename from libc/arch-x86/string/ssse3-memcmp3.S
rename to libc/arch-x86/string/ssse3-memcmp3-new.S
index a7ce819..5ad8791 100644
--- a/libc/arch-x86/string/ssse3-memcmp3.S
+++ b/libc/arch-x86/string/ssse3-memcmp3-new.S
@@ -53,13 +53,21 @@
 #endif
 
 #ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore (reg)
+# define cfi_restore(reg)		.cfi_restore reg
 #endif
 
 #ifndef cfi_adjust_cfa_offset
 # define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
 #endif
 
+#ifndef cfi_remember_state
+# define cfi_remember_state		.cfi_remember_state
+#endif
+
+#ifndef cfi_restore_state
+# define cfi_restore_state		.cfi_restore_state
+#endif
+
 #ifndef ENTRY
 # define ENTRY(name)			\
 	.type name,  @function; 	\
@@ -91,8 +99,7 @@
 #define BLK2		BLK1+4
 #define LEN		BLK2+4
 #define RETURN_END	POP (%edi); POP (%esi); POP (%ebx); ret
-#define RETURN		RETURN_END; CFI_PUSH (%ebx); CFI_PUSH (%edi); \
-			CFI_PUSH (%esi)
+#define RETURN		RETURN_END; cfi_restore_state; cfi_remember_state
 
 	.section .text.ssse3,"ax",@progbits
 ENTRY (MEMCMP)
@@ -131,6 +138,7 @@
 	PUSH (%ebx)
 	PUSH (%esi)
 	PUSH (%edi)
+	cfi_remember_state
 	movdqu    (%eax), %xmm3
 	movdqu    (%edx), %xmm0
 	movl	%eax, %edi
@@ -211,8 +219,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_0_gobble):
 	lea	-48(%ecx), %ecx
@@ -257,8 +265,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_1):
 	cmp	$80, %ecx
@@ -287,8 +295,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_1_gobble):
 	sub	$32, %ecx
@@ -340,8 +348,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_2):
 	cmp	$80, %ecx
@@ -370,8 +378,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_2_gobble):
 	sub	$32, %ecx
@@ -423,8 +431,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_3):
 	cmp	$80, %ecx
@@ -453,8 +461,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_3_gobble):
 	sub	$32, %ecx
@@ -506,8 +514,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_4):
 	cmp	$80, %ecx
@@ -536,8 +544,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_4_gobble):
 	sub	$32, %ecx
@@ -589,8 +597,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_5):
 	cmp	$80, %ecx
@@ -619,8 +627,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_5_gobble):
 	sub	$32, %ecx
@@ -672,8 +680,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_6):
 	cmp	$80, %ecx
@@ -702,8 +710,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_6_gobble):
 	sub	$32, %ecx
@@ -755,8 +763,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_7):
 	cmp	$80, %ecx
@@ -785,8 +793,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_7_gobble):
 	sub	$32, %ecx
@@ -838,8 +846,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_8):
 	cmp	$80, %ecx
@@ -868,8 +876,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_8_gobble):
 	sub	$32, %ecx
@@ -921,8 +929,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_9):
 	cmp	$80, %ecx
@@ -951,8 +959,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_9_gobble):
 	sub	$32, %ecx
@@ -1004,8 +1012,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_10):
 	cmp	$80, %ecx
@@ -1034,8 +1042,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_10_gobble):
 	sub	$32, %ecx
@@ -1087,8 +1095,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_11):
 	cmp	$80, %ecx
@@ -1117,8 +1125,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_11_gobble):
 	sub	$32, %ecx
@@ -1170,8 +1178,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_12):
 	cmp	$80, %ecx
@@ -1200,8 +1208,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_12_gobble):
 	sub	$32, %ecx
@@ -1253,8 +1261,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_13):
 	cmp	$80, %ecx
@@ -1283,8 +1291,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_13_gobble):
 	sub	$32, %ecx
@@ -1336,8 +1344,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_14):
 	cmp	$80, %ecx
@@ -1366,8 +1374,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_14_gobble):
 	sub	$32, %ecx
@@ -1419,8 +1427,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_15):
 	cmp	$80, %ecx
@@ -1449,8 +1457,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shr_15_gobble):
 	sub	$32, %ecx
@@ -1502,8 +1510,8 @@
 	POP (%esi)
 	jmp	L(less48bytes)
 
-	CFI_PUSH (%esi)
-	CFI_PUSH (%edi)
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(exit):
 	pmovmskb %xmm1, %ebx
diff --git a/libc/arch-x86/string/ssse3-memcpy5.S b/libc/arch-x86/string/ssse3-memcpy5.S
index 6b90402..b4773df 100644
--- a/libc/arch-x86/string/ssse3-memcpy5.S
+++ b/libc/arch-x86/string/ssse3-memcpy5.S
@@ -53,13 +53,21 @@
 #endif
 
 #ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore (reg)
+# define cfi_restore(reg)		.cfi_restore reg
 #endif
 
 #ifndef cfi_adjust_cfa_offset
 # define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
 #endif
 
+#ifndef cfi_remember_state
+# define cfi_remember_state		.cfi_remember_state
+#endif
+
+#ifndef cfi_restore_state
+# define cfi_restore_state		.cfi_restore_state
+#endif
+
 #ifndef ENTRY
 # define ENTRY(name)			\
 	.type name,  @function; 	\
@@ -118,8 +126,8 @@
     jmp		*%ebx
 
 # define BRANCH_TO_JMPTBL_ENTRY_VALUE(TABLE)			\
-    addl	$(TABLE - .), %ebx	
-			
+    addl	$(TABLE - .), %ebx
+
 # define BRANCH_TO_JMPTBL_ENTRY_TAIL(TABLE, INDEX, SCALE)	\
     addl	(%ebx,INDEX,SCALE), %ebx;			\
     /* We loaded the jump table.  Go.  */			\
@@ -146,7 +154,7 @@
 # define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE)		\
     jmp		*TABLE(,INDEX,SCALE)
 
-# define BRANCH_TO_JMPTBL_ENTRY_VALUE(TABLE)			
+# define BRANCH_TO_JMPTBL_ENTRY_VALUE(TABLE)
 
 # define BRANCH_TO_JMPTBL_ENTRY_TAIL(TABLE, INDEX, SCALE)		\
     jmp		*TABLE(,INDEX,SCALE)
@@ -198,6 +206,7 @@
 	movl	%edx, %edi
 	and	$-16, %edx
 	PUSH (%esi)
+	cfi_remember_state
 	add	$16, %edx
 	movl	%edi, %esi
 	sub	%edx, %edi
@@ -223,6 +232,8 @@
 
 	BRANCH_TO_JMPTBL_ENTRY (L(shl_table), %edi, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_0):
 	movdqu	%xmm0, (%esi)
@@ -270,6 +281,7 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd), %ecx, 4)
 
+	CFI_PUSH (%edi)
 L(shl_0_gobble):
 
 #ifdef DATA_CACHE_SIZE_HALF
@@ -419,7 +431,8 @@
 	add	%ecx, %eax
 	BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd), %ecx, 4)
 
-
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_1):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -463,6 +476,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_2):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -506,6 +521,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_3):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -549,6 +566,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_4):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -592,6 +611,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_5):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -635,7 +656,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
-
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_6):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -679,6 +701,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_7):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -722,6 +746,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_8):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -765,6 +791,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_9):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -808,6 +836,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_10):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -851,6 +881,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_11):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -894,6 +926,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_12):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -937,6 +971,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_13):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -980,6 +1016,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_14):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -1023,7 +1061,8 @@
 	POP (%edi)
 	BRANCH_TO_JMPTBL_ENTRY_TAIL(L(table_48bytes_fwd), %ecx, 4)
 
-
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(shl_15):
 	BRANCH_TO_JMPTBL_ENTRY_VALUE(L(table_48bytes_fwd))
@@ -1264,8 +1303,10 @@
 	movl	DEST(%esp), %eax
 # endif
 #endif
-	RETURN
+	RETURN_END
 
+	cfi_restore_state
+	cfi_remember_state
 	ALIGN (4)
 L(large_page):
 	movdqu	(%eax), %xmm1
@@ -1688,6 +1729,7 @@
 L(bk_write_less32bytes_2):
 	BRANCH_TO_JMPTBL_ENTRY (L(table_48_bytes_bwd), %ecx, 4)
 
+	CFI_PUSH (%esi)
 	ALIGN (4)
 L(bk_align):
 	cmp	$8, %ecx
diff --git a/libc/arch-x86/string/ssse3-strcmp.S b/libc/arch-x86/string/ssse3-strcmp-latest.S
similarity index 98%
rename from libc/arch-x86/string/ssse3-strcmp.S
rename to libc/arch-x86/string/ssse3-strcmp-latest.S
index cfb2e9f..69c6425 100644
--- a/libc/arch-x86/string/ssse3-strcmp.S
+++ b/libc/arch-x86/string/ssse3-strcmp-latest.S
@@ -45,13 +45,21 @@
 #endif
 
 #ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore (reg)
+# define cfi_restore(reg)		.cfi_restore reg
 #endif
 
 #ifndef cfi_adjust_cfa_offset
 # define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
 #endif
 
+#ifndef cfi_remember_state
+# define cfi_remember_state		.cfi_remember_state
+#endif
+
+#ifndef cfi_restore_state
+# define cfi_restore_state		.cfi_restore_state
+#endif
+
 #ifndef ENTRY
 # define ENTRY(name)			\
 	.type name,  @function; 	\
@@ -201,6 +209,9 @@
 	PUSH	(%ebx)
 	PUSH	(%edi)
 	PUSH	(%esi)
+#ifdef USE_AS_STRNCMP
+	cfi_remember_state
+#endif
 
 	movl	%edx, %edi
 	movl	%eax, %ecx
@@ -1521,17 +1532,18 @@
 	sub	$0xffff, %esi
 	jnz	L(exit)
 
+#ifdef USE_AS_STRNCMP
+	cmp	$16, %ebp
+	lea	-16(%ebp), %ebp
+	jbe	L(more8byteseq)
+#endif
+
 	add	$16, %ecx
 	movdqa	%xmm4, %xmm3
 
 	add	$16, %edi
 	jg	L(nibble_ashr_12)
 
-#ifdef USE_AS_STRNCMP
-	cmp	$16, %ebp
-	lea	-16(%ebp), %ebp
-	jbe	L(more8byteseq)
-#endif
 	movdqa	(%eax, %ecx), %xmm1
 	movdqa	(%edx, %ecx), %xmm2
 	movdqa	%xmm2, %xmm4
@@ -2087,10 +2099,7 @@
 	RETURN
 
 #ifdef USE_AS_STRNCMP
-	CFI_PUSH (%ebx)
-	CFI_PUSH (%edi)
-	CFI_PUSH (%esi)
-
+	cfi_restore_state
 	.p2align 4
 L(more8byteseq):
 	POP	(%esi)
diff --git a/libc/arch-x86/string/strcmp_wrapper.S b/libc/arch-x86/string/strcmp_wrapper.S
index 69b7f0b..20f3064 100644
--- a/libc/arch-x86/string/strcmp_wrapper.S
+++ b/libc/arch-x86/string/strcmp_wrapper.S
@@ -31,7 +31,7 @@
 #if defined(USE_SSSE3)
 
 # define ssse3_strcmp_latest strcmp
-# include "ssse3-strcmp.S"
+# include "ssse3-strcmp-latest.S"
 
 #else
 
diff --git a/libc/arch-x86/string/strlen_wrapper.S b/libc/arch-x86/string/strlen_wrapper.S
new file mode 100644
index 0000000..e62786b
--- /dev/null
+++ b/libc/arch-x86/string/strlen_wrapper.S
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2010, Intel Corporation
+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.
+
+    * Neither the name of Intel Corporation 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 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.
+*/
+
+#if defined(USE_SSE2)
+
+# define sse2_strlen_atom strlen
+# include "sse2-strlen-atom.S"
+
+#else
+
+# include "strlen.S"
+
+#endif
diff --git a/libc/arch-x86/string/strncmp_wrapper.S b/libc/arch-x86/string/strncmp_wrapper.S
index 2050184..191d755 100644
--- a/libc/arch-x86/string/strncmp_wrapper.S
+++ b/libc/arch-x86/string/strncmp_wrapper.S
@@ -32,7 +32,7 @@
 
 # define USE_AS_STRNCMP
 # define ssse3_strcmp_latest strncmp
-# include "ssse3-strcmp.S"
+# include "ssse3-strcmp-latest.S"
 
 #else
 
diff --git a/libc/bionic/__set_errno.c b/libc/bionic/__set_errno.c
index c72d4f7..163d404 100644
--- a/libc/bionic/__set_errno.c
+++ b/libc/bionic/__set_errno.c
@@ -40,6 +40,7 @@
  * (tail-called in the case of 0-4 arg versions)
  */
 
+__LIBC_HIDDEN__
 int __set_syscall_errno(int n)
 {
         /* some syscalls, mmap() for example, have valid return
diff --git a/libc/bionic/_rand48.c b/libc/bionic/_rand48.c
deleted file mode 100644
index e422781..0000000
--- a/libc/bionic/_rand48.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 1993 Martin Birgmeier
- * All rights reserved.
- *
- * You may redistribute unmodified or modified versions of this source
- * code provided that the above copyright notice and this and the
- * following conditions are retained.
- *
- * This software is provided ``as is'', and comes with no warranties
- * of any kind. I shall in no event be liable for anything that happens
- * to anyone/anything when using this software.
- */
-
-#include <sys/cdefs.h>
-#include "rand48.h"
-
-unsigned short _rand48_seed[3] = {
-	RAND48_SEED_0,
-	RAND48_SEED_1,
-	RAND48_SEED_2
-};
-unsigned short _rand48_mult[3] = {
-	RAND48_MULT_0,
-	RAND48_MULT_1,
-	RAND48_MULT_2
-};
-unsigned short _rand48_add = RAND48_ADD;
-
-void
-_dorand48(unsigned short xseed[3])
-{
-	unsigned long accu;
-	unsigned short temp[2];
-
-	accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
-	 (unsigned long) _rand48_add;
-	temp[0] = (unsigned short) accu;	/* lower 16 bits */
-	accu >>= sizeof(unsigned short) * 8;
-	accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
-	 (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
-	temp[1] = (unsigned short) accu;	/* middle 16 bits */
-	accu >>= sizeof(unsigned short) * 8;
-	accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
-	xseed[0] = temp[0];
-	xseed[1] = temp[1];
-	xseed[2] = (unsigned short) accu;
-}
diff --git a/libc/bionic/drand48.c b/libc/bionic/drand48.c
index fd48196..93272cf 100644
--- a/libc/bionic/drand48.c
+++ b/libc/bionic/drand48.c
@@ -15,10 +15,10 @@
 
 #include "rand48.h"
 
-extern unsigned short _rand48_seed[3];
+extern unsigned short __rand48_seed[3];
 
 double
 drand48(void)
 {
-	return erand48(_rand48_seed);
+	return erand48(__rand48_seed);
 }
diff --git a/libc/bionic/erand48.c b/libc/bionic/erand48.c
index 843ff34..4ecbead 100644
--- a/libc/bionic/erand48.c
+++ b/libc/bionic/erand48.c
@@ -18,7 +18,7 @@
 double
 erand48(unsigned short xseed[3])
 {
-	_dorand48(xseed);
+	__dorand48(xseed);
 	return ldexp((double) xseed[0], -48) +
 	       ldexp((double) xseed[1], -32) +
 	       ldexp((double) xseed[2], -16);
diff --git a/libc/bionic/fork.c b/libc/bionic/fork.c
index 79b8fff..0eedb01 100644
--- a/libc/bionic/fork.c
+++ b/libc/bionic/fork.c
@@ -41,9 +41,12 @@
      * of error, or in the parent process
      */
     __timer_table_start_stop(1);
+    __bionic_atfork_run_prepare();
+
     ret = __fork();
     if (ret != 0) {  /* not a child process */
         __timer_table_start_stop(0);
+        __bionic_atfork_run_parent();
     } else {
         /*
          * Newly created process must update cpu accounting.
@@ -52,6 +55,7 @@
          * as a parameter.
          */
         cpuacct_add(getuid());
+        __bionic_atfork_run_child();
     }
     return ret;
 }
diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c
index f7579bd..b6a6379 100644
--- a/libc/bionic/libc_init_common.c
+++ b/libc/bionic/libc_init_common.c
@@ -62,7 +62,7 @@
     static pthread_internal_t  thread;
     static void*               tls_area[BIONIC_TLS_SLOTS];
 
-    /* setup pthread runtime and maint thread descriptor */
+    /* setup pthread runtime and main thread descriptor */
     unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
     unsigned stacksize = 128 * 1024;
     unsigned stackbottom = stacktop - stacksize;
diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c
index f64b6f2..4bb2a81 100644
--- a/libc/bionic/libc_init_dynamic.c
+++ b/libc/bionic/libc_init_dynamic.c
@@ -61,7 +61,7 @@
 
 void __libc_preinit(void)
 {
-    /* Read the ELF data pointer form a special slot of the
+    /* Read the ELF data pointer from a special slot of the
      * TLS area, then call __libc_init_common with it.
      *
      * Note that:
diff --git a/libc/bionic/pthread-atfork.c b/libc/bionic/pthread-atfork.c
new file mode 100644
index 0000000..3a5189d
--- /dev/null
+++ b/libc/bionic/pthread-atfork.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/queue.h>
+
+static pthread_mutex_t handler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+
+struct atfork_t
+{
+    CIRCLEQ_ENTRY(atfork_t) entries;
+
+    void (*prepare)(void);
+    void (*child)(void);
+    void (*parent)(void);
+};
+static CIRCLEQ_HEAD(atfork_head_t, atfork_t) atfork_head = \
+    CIRCLEQ_HEAD_INITIALIZER(atfork_head);
+
+void __bionic_atfork_run_prepare()
+{
+    struct atfork_t *cursor;
+
+    /* We will lock this here, and unlock it in the parent and child functions.
+     * This ensures that nobody can modify the handler array between the calls
+     * to the prepare and parent/child handlers.
+     *
+     * TODO: If a handler mucks with the list, it could cause problems.  Right
+     *       now it's ok because all they can do is add new items to the end
+     *       of the list, but if/when we implement cleanup in dlclose() things
+     *       will get more interesting...
+     */
+    pthread_mutex_lock(&handler_mutex);
+
+    /* Call pthread_atfork() prepare handlers.  Posix states that the prepare
+     * handlers should be called in the reverse order of the parent/child
+     * handlers, so we iterate backwards.
+     */
+    for (cursor = atfork_head.cqh_last;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_prev) {
+        if (cursor->prepare != NULL) {
+            cursor->prepare();
+        }
+    }
+}
+
+void __bionic_atfork_run_child()
+{
+    struct atfork_t *cursor;
+
+    /* Call pthread_atfork() child handlers */
+    for (cursor = atfork_head.cqh_first;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_next) {
+        if (cursor->child != NULL) {
+            cursor->child();
+        }
+    }
+
+    pthread_mutex_unlock(&handler_mutex);
+}
+
+void __bionic_atfork_run_parent()
+{
+    struct atfork_t *cursor;
+
+    /* Call pthread_atfork() parent handlers */
+    for (cursor = atfork_head.cqh_first;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_next) {
+        if (cursor->parent != NULL) {
+            cursor->parent();
+        }
+    }
+
+    pthread_mutex_unlock(&handler_mutex);
+}
+
+int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void))
+{
+    struct atfork_t *entry = malloc(sizeof(struct atfork_t));
+
+    if (entry == NULL) {
+        return ENOMEM;
+    }
+
+    entry->prepare = prepare;
+    entry->parent = parent;
+    entry->child = child;
+
+    pthread_mutex_lock(&handler_mutex);
+    CIRCLEQ_INSERT_TAIL(&atfork_head, entry, entries);
+    pthread_mutex_unlock(&handler_mutex);
+
+    return 0;
+}
diff --git a/libc/bionic/pthread-timers.c b/libc/bionic/pthread-timers.c
index 7b9c99e..ae04029 100644
--- a/libc/bionic/pthread-timers.c
+++ b/libc/bionic/pthread-timers.c
@@ -260,7 +260,7 @@
  ** requirements: the timers of fork child processes must be
  ** disarmed but not deleted.
  **/
-void
+__LIBC_HIDDEN__ void
 __timer_table_start_stop( int  stop )
 {
     if (__timer_table != NULL) {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index eb4e80c..655b8f3 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -109,6 +109,9 @@
 
 /* needed by fork.c */
 extern void __timer_table_start_stop(int  stop);
+extern void __bionic_atfork_run_prepare();
+extern void __bionic_atfork_run_child();
+extern void __bionic_atfork_run_parent();
 
 __END_DECLS
 
diff --git a/libc/bionic/rand48.h b/libc/bionic/rand48.h
deleted file mode 100644
index 0a3d83d..0000000
--- a/libc/bionic/rand48.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 1993 Martin Birgmeier
- * All rights reserved.
- *
- * You may redistribute unmodified or modified versions of this source
- * code provided that the above copyright notice and this and the
- * following conditions are retained.
- *
- * This software is provided ``as is'', and comes with no warranties
- * of any kind. I shall in no event be liable for anything that happens
- * to anyone/anything when using this software.
- *
- * $FreeBSD: src/lib/libc/gen/rand48.h,v 1.2 2002/02/01 01:32:19 obrien Exp $
- */
-
-#ifndef _RAND48_H_
-#define _RAND48_H_
-
-#include <math.h>
-#include <stdlib.h>
-
-void		_dorand48(unsigned short[3]);
-
-#define	RAND48_SEED_0	(0x330e)
-#define	RAND48_SEED_1	(0xabcd)
-#define	RAND48_SEED_2	(0x1234)
-#define	RAND48_MULT_0	(0xe66d)
-#define	RAND48_MULT_1	(0xdeec)
-#define	RAND48_MULT_2	(0x0005)
-#define	RAND48_ADD	(0x000b)
-
-#endif /* _RAND48_H_ */
diff --git a/libc/bionic/stubs.c b/libc/bionic/stubs.c
index d495674..a01d64c 100644
--- a/libc/bionic/stubs.c
+++ b/libc/bionic/stubs.c
@@ -40,8 +40,8 @@
 /** Thread-specific state for the stubs functions
  **/
 
-pthread_once_t   the_once = PTHREAD_ONCE_INIT;
-pthread_key_t    the_key;
+static pthread_once_t   the_once = PTHREAD_ONCE_INIT;
+static pthread_key_t    the_key;
 
 typedef struct {
     struct passwd  passwd;
diff --git a/libc/bionic/time64.c b/libc/bionic/time64.c
index 1e1f881..9aa5d4f 100644
--- a/libc/bionic/time64.c
+++ b/libc/bionic/time64.c
@@ -364,7 +364,7 @@
 }
 
 
-void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
+static void copy_tm_to_TM(const struct tm *src, struct TM *dest) {
     if( src == NULL ) {
         memset(dest, 0, sizeof(*dest));
     }
@@ -396,7 +396,7 @@
 }
 
 
-void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
+static void copy_TM_to_tm(const struct TM *src, struct tm *dest) {
     if( src == NULL ) {
         memset(dest, 0, sizeof(*dest));
     }
@@ -735,14 +735,14 @@
 }
 
 
-int valid_tm_wday( const struct TM* date ) {
+static int valid_tm_wday( const struct TM* date ) {
     if( 0 <= date->tm_wday && date->tm_wday <= 6 )
         return 1;
     else
         return 0;
 }
 
-int valid_tm_mon( const struct TM* date ) {
+static int valid_tm_mon( const struct TM* date ) {
     if( 0 <= date->tm_mon && date->tm_mon <= 11 )
         return 1;
     else
diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT
index 4d094d0..0eab879 100644
--- a/libc/docs/CHANGES.TXT
+++ b/libc/docs/CHANGES.TXT
@@ -70,6 +70,8 @@
 - <sys/vfs.h>: fixed implementation of fstatfs() (also fixes fpathconf()
   which uses it).
 
+- Added an implementation of pthread_atfork()
+
 - <dlfcn.h>: fixed dlopen() implementation to support dlopen(NULL, ...).
   This allows one to look at the dynamic symbols exported by an executable.
 
diff --git a/libc/include/byteswap.h b/libc/include/byteswap.h
index 16d2ad4..74b0e91 100644
--- a/libc/include/byteswap.h
+++ b/libc/include/byteswap.h
@@ -28,7 +28,8 @@
 #ifndef _BYTESWAP_H_
 #define _BYTESWAP_H_
 
-#include <sys/endian.h>
+/* endian.h rather than sys/endian.h so we get the machine-specific file. */
+#include <endian.h>
 
 #define  bswap_16(x)   swap16(x)
 #define  bswap_32(x)   swap32(x)
diff --git a/libc/include/net/if_ether.h b/libc/include/net/if_ether.h
index 121f9ac..8daa16b 100644
--- a/libc/include/net/if_ether.h
+++ b/libc/include/net/if_ether.h
@@ -34,6 +34,8 @@
 #ifndef _NET_IF_ETHER_H_
 #define _NET_IF_ETHER_H_
 
+#include <sys/types.h>
+
 #ifdef _KERNEL
 #ifdef _KERNEL_OPT
 #include "opt_mbuftrace.h"
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 99e747a..a43e47c 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -268,6 +268,8 @@
 
 int pthread_setname_np(pthread_t thid, const char *thname);
 
+int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
+
 typedef void  (*__pthread_cleanup_func_t)(void*);
 
 typedef struct __pthread_cleanup_t {
diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h
index e051b1d..1e57470 100644
--- a/libc/include/sys/cdefs_elf.h
+++ b/libc/include/sys/cdefs_elf.h
@@ -95,6 +95,10 @@
 	__asm__(".section _sec\n\t.asciz _str\n\t.previous")
 #endif
 
+/* GCC visibility helper macro */
+#define __LIBC_HIDDEN__							\
+	__attribute__ ((visibility ("hidden")))
+
 #define	__IDSTRING(_n,_s)		__SECTIONSTRING(.ident,_s)
 
 #define	__RCSID(_s)			__IDSTRING(rcsid,_s)
diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h
index 23853da..51070bd 100644
--- a/libc/include/sys/linux-unistd.h
+++ b/libc/include/sys/linux-unistd.h
@@ -205,6 +205,7 @@
 int              eventfd (unsigned int, int);
 int              __set_tls (void*);
 int              cacheflush (long start, long end, long flags);
+int              eventfd (int count, int flags);
 #ifdef __cplusplus
 }
 #endif
diff --git a/libc/inet/ether_aton.c b/libc/inet/ether_aton.c
new file mode 100644
index 0000000..6540c07
--- /dev/null
+++ b/libc/inet/ether_aton.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 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.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <net/if_ether.h>
+#include <ctype.h>
+
+static inline int
+xdigit (char c) {
+    unsigned d;
+    d = (unsigned)(c-'0');
+    if (d < 10) return (int)d;
+    d = (unsigned)(c-'a');
+    if (d < 6) return (int)(10+d);
+    d = (unsigned)(c-'A');
+    if (d < 6) return (int)(10+d);
+    return -1;
+}
+
+/*
+ * Convert Ethernet address in the standard hex-digits-and-colons to binary
+ * representation.
+ * Re-entrant version (GNU extensions)
+ */
+struct ether_addr *
+ether_aton_r (const char *asc, struct ether_addr * addr)
+{
+    int i, val0, val1;
+    for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+        val0 = xdigit(*asc);
+        asc++;
+        if (val0 < 0)
+            return NULL;
+
+        val1 = xdigit(*asc);
+        asc++;
+        if (val1 < 0)
+            return NULL;
+
+        addr->ether_addr_octet[i] = (u_int8_t)((val0 << 4) + val1);
+
+        if (i < ETHER_ADDR_LEN - 1) {
+            if (*asc != ':')
+                return NULL;
+            asc++;
+        }
+    }
+    if (*asc != '\0')
+        return NULL;
+    return addr;
+}
+
+/*
+ * Convert Ethernet address in the standard hex-digits-and-colons to binary
+ * representation.
+ */
+struct ether_addr *
+ether_aton (const char *asc)
+{
+    static struct ether_addr addr;
+    return ether_aton_r(asc, &addr);
+}
diff --git a/libc/inet/ether_ntoa.c b/libc/inet/ether_ntoa.c
new file mode 100644
index 0000000..f56e48b
--- /dev/null
+++ b/libc/inet/ether_ntoa.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 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.h>
+#include <sys/types.h>
+#include <net/if_ether.h>
+
+/*
+ * Convert Ethernet address to standard hex-digits-and-colons printable form.
+ * Re-entrant version (GNU extensions).
+ */
+char *
+ether_ntoa_r (const struct ether_addr *addr, char * buf)
+{
+    snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+            addr->ether_addr_octet[0], addr->ether_addr_octet[1],
+            addr->ether_addr_octet[2], addr->ether_addr_octet[3],
+            addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
+    return buf;
+}
+
+/*
+ * Convert Ethernet address to standard hex-digits-and-colons printable form.
+ */
+char *
+ether_ntoa (const struct ether_addr *addr)
+{
+    static char buf[18];
+    return ether_ntoa_r(addr, buf);
+}
diff --git a/libc/kernel/arch-arm/asm/byteorder.h b/libc/kernel/arch-arm/asm/byteorder.h
index 4da37bf..b869695 100644
--- a/libc/kernel/arch-arm/asm/byteorder.h
+++ b/libc/kernel/arch-arm/asm/byteorder.h
@@ -22,7 +22,7 @@
 #ifndef __thumb__
  if (!__builtin_constant_p(x)) {
 
- asm ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
+ __asm__ ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
  } else
 #endif
  t = x ^ ((x << 16) | (x >> 16));
diff --git a/libc/kernel/common/linux/if_ether.h b/libc/kernel/common/linux/if_ether.h
index 1ba7a99..7e235a5 100644
--- a/libc/kernel/common/linux/if_ether.h
+++ b/libc/kernel/common/linux/if_ether.h
@@ -84,6 +84,7 @@
 #define ETH_P_TRAILER 0x001C  
 #define ETH_P_PHONET 0x00F5  
 #define ETH_P_IEEE802154 0x00F6  
+#define ETH_P_CAIF 0x00F7  
 
 struct ethhdr {
  unsigned char h_dest[ETH_ALEN];
diff --git a/libc/kernel/common/linux/ipv6_route.h b/libc/kernel/common/linux/ipv6_route.h
new file mode 100644
index 0000000..3791e87
--- /dev/null
+++ b/libc/kernel/common/linux/ipv6_route.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _LINUX_IPV6_ROUTE_H
+#define _LINUX_IPV6_ROUTE_H
+
+#include <linux/types.h>
+
+#define RTF_DEFAULT 0x00010000  
+#define RTF_ALLONLINK 0x00020000  
+#define RTF_ADDRCONF 0x00040000  
+#define RTF_PREFIX_RT 0x00080000  
+#define RTF_ANYCAST 0x00100000  
+
+#define RTF_NONEXTHOP 0x00200000  
+#define RTF_EXPIRES 0x00400000
+
+#define RTF_ROUTEINFO 0x00800000  
+
+#define RTF_CACHE 0x01000000  
+#define RTF_FLOW 0x02000000  
+#define RTF_POLICY 0x04000000  
+
+#define RTF_PREF(pref) ((pref) << 27)
+#define RTF_PREF_MASK 0x18000000
+
+#define RTF_LOCAL 0x80000000
+
+struct in6_rtmsg {
+ struct in6_addr rtmsg_dst;
+ struct in6_addr rtmsg_src;
+ struct in6_addr rtmsg_gateway;
+ __u32 rtmsg_type;
+ __u16 rtmsg_dst_len;
+ __u16 rtmsg_src_len;
+ __u32 rtmsg_metric;
+ unsigned long rtmsg_info;
+ __u32 rtmsg_flags;
+ int rtmsg_ifindex;
+};
+
+#define RTMSG_NEWDEVICE 0x11
+#define RTMSG_DELDEVICE 0x12
+#define RTMSG_NEWROUTE 0x21
+#define RTMSG_DELROUTE 0x22
+
+#endif
diff --git a/libc/kernel/common/linux/netfilter_ipv6/ip6_tables.h b/libc/kernel/common/linux/netfilter_ipv6/ip6_tables.h
index 1687e4f..d76a529 100644
--- a/libc/kernel/common/linux/netfilter_ipv6/ip6_tables.h
+++ b/libc/kernel/common/linux/netfilter_ipv6/ip6_tables.h
@@ -173,6 +173,15 @@
 
 #define IP6T_ERROR_TARGET XT_ERROR_TARGET
 
+static __inline__ struct ip6t_entry_target *
+ip6t_get_target(struct ip6t_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
 #define IP6T_MATCH_ITERATE(e, fn, args...)  ({   unsigned int __i;   int __ret = 0;   struct ip6t_entry_match *__m;     for (__i = sizeof(struct ip6t_entry);   __i < (e)->target_offset;   __i += __m->u.match_size) {   __m = (void *)(e) + __i;     __ret = fn(__m , ## args);   if (__ret != 0)   break;   }   __ret;  })
+
 #define IP6T_ENTRY_ITERATE(entries, size, fn, args...)  ({   unsigned int __i;   int __ret = 0;   struct ip6t_entry *__e;     for (__i = 0; __i < (size); __i += __e->next_offset) {   __e = (void *)(entries) + __i;     __ret = fn(__e , ## args);   if (__ret != 0)   break;   }   __ret;  })
+
 #endif
+
diff --git a/libc/kernel/common/linux/socket.h b/libc/kernel/common/linux/socket.h
index b578df9..c30dae0 100644
--- a/libc/kernel/common/linux/socket.h
+++ b/libc/kernel/common/linux/socket.h
@@ -138,7 +138,8 @@
 #define AF_LLC 26  
 #define AF_TIPC 30  
 #define AF_BLUETOOTH 31  
-#define AF_MAX 32  
+#define AF_CAIF 38  
+#define AF_MAX 39  
 
 #define PF_UNSPEC AF_UNSPEC
 #define PF_UNIX AF_UNIX
@@ -170,6 +171,7 @@
 #define PF_LLC AF_LLC
 #define PF_TIPC AF_TIPC
 #define PF_BLUETOOTH AF_BLUETOOTH
+#define PF_CAIF AF_CAIF
 #define PF_MAX AF_MAX
 
 #define SOMAXCONN 128
diff --git a/libc/kernel/common/linux/tty.h b/libc/kernel/common/linux/tty.h
index b28791c..b1f2eab 100644
--- a/libc/kernel/common/linux/tty.h
+++ b/libc/kernel/common/linux/tty.h
@@ -12,4 +12,6 @@
 #ifndef _LINUX_TTY_H
 #define _LINUX_TTY_H
 
+#define N_CAIF 20  
+
 #endif
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 28cb05e..dad9120 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -71,6 +71,7 @@
     list.removeEmptyLines()
     list.removeMacroDefines( kernel_ignored_macros )
     list.insertDisclaimer( kernel.kernel_disclaimer )
+    list.replaceTokens( kernel_token_replacements )
 
     out = StringOutput()
     list.write(out)
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 4b4bd38..8828a5d 100644
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1863,6 +1863,16 @@
         tokens = tokens[:-1]  # remove trailing tokLN
         self.blocks = [ Block(tokens) ] + self.blocks
 
+    def replaceTokens(self,replacements=dict()):
+        """replace tokens according to the given dict
+           """
+        for b in self.blocks:
+            if not b.isDirective():
+                for tok in b.tokens:
+                    if tok.id == tokIDENT:
+                        if tok.value in replacements:
+                            tok.value = replacements[tok.value]
+
 class BlockParser:
     """a class used to convert an input source file into a BlockList object"""
 
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 4227de7..ca7e6bb 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -43,6 +43,11 @@
     "x86": {"__i386__": "1"},
     }
 
+# Replace tokens in the output according to this mapping
+kernel_token_replacements = {
+    {"asm": "__asm__"},
+    }
+
 # this is the set of known static inline functions that we want to keep
 # in the final ARM headers. this is only used to keep optimized byteswapping
 # static functions and stuff like that.
@@ -71,6 +76,7 @@
           "__cmsg_nxthdr",                    # linux/socket.h
           "cmsg_nxthdr",                      # linux/socket.h
           "ipt_get_target",
+          "ip6t_get_target",
         ]
     )
 
diff --git a/libc/netbsd/gethnamaddr.c b/libc/netbsd/gethnamaddr.c
index 1c219b2..3ebe53e 100644
--- a/libc/netbsd/gethnamaddr.c
+++ b/libc/netbsd/gethnamaddr.c
@@ -104,9 +104,9 @@
 static void map_v4v6_hostent(struct hostent *, char **, char *);
 static void addrsort(char **, int, res_state);
 
-void _sethtent(int);
-void _endhtent(void);
-struct hostent *_gethtent(void);
+static void _sethtent(int);
+static void _endhtent(void);
+static struct hostent *_gethtent(void);
 void ht_sethostent(int);
 void ht_endhostent(void);
 struct hostent *ht_gethostbyname(char *);
@@ -114,11 +114,11 @@
 void dns_service(void);
 #undef dn_skipname
 int dn_skipname(const u_char *, const u_char *);
-int _gethtbyaddr(void *, void *, va_list);
-int _gethtbyname(void *, void *, va_list);
-struct hostent *_gethtbyname2(const char *, int);
-int _dns_gethtbyaddr(void *, void *, va_list);
-int _dns_gethtbyname(void *, void *, va_list);
+static int _gethtbyaddr(void *, void *, va_list);
+static int _gethtbyname(void *, void *, va_list);
+static struct hostent *_gethtbyname2(const char *, int);
+static int _dns_gethtbyaddr(void *, void *, va_list);
+static int _dns_gethtbyname(void *, void *, va_list);
 
 static struct hostent *gethostbyname_internal(const char *, int, res_state);
 
@@ -692,7 +692,7 @@
 	return hp;
 }
 
-void
+static void
 _sethtent(int f)
 {
     res_static  rs = __res_get_static();
@@ -704,7 +704,7 @@
 	rs->stayopen = f;
 }
 
-void
+static void
 _endhtent(void)
 {
     res_static  rs = __res_get_static();
@@ -716,7 +716,7 @@
 	}
 }
 
-struct hostent *
+static struct hostent *
 _gethtent(void)
 {
 	char *p;
@@ -829,7 +829,7 @@
 	return NS_SUCCESS;
 }
 
-struct hostent *
+static struct hostent *
 _gethtbyname2(const char *name, int af)
 {
 	struct hostent *p;
@@ -920,7 +920,7 @@
 }
 
 /*ARGSUSED*/
-int
+static int
 _gethtbyaddr(void *rv, void *cb_data, va_list ap)
 {
 	struct hostent *p;
@@ -1053,7 +1053,7 @@
 }
 
 /*ARGSUSED*/
-int
+static int
 _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
 {
 	querybuf *buf;
@@ -1113,7 +1113,7 @@
 }
 
 /*ARGSUSED*/
-int
+static int
 _dns_gethtbyaddr(void *rv, void	*cb_data, va_list ap)
 {
 	char qbuf[MAXDNAME + 1], *qp, *ep;
diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c
index 2621a7b..84194c2 100644
--- a/libc/netbsd/resolv/res_cache.c
+++ b/libc/netbsd/resolv/res_cache.c
@@ -1143,7 +1143,7 @@
          "*************************");
 }
 
-struct resolv_cache*
+static struct resolv_cache*
 _resolv_cache_create( void )
 {
     struct resolv_cache*  cache;
diff --git a/libc/netbsd/resolv/res_data.c b/libc/netbsd/resolv/res_data.c
index e60ecfd..014c99b 100644
--- a/libc/netbsd/resolv/res_data.c
+++ b/libc/netbsd/resolv/res_data.c
@@ -46,6 +46,7 @@
 #include <unistd.h>
 
 
+__LIBC_HIDDEN__
 const char * const _res_opcodes[] = {
 	"QUERY",
 	"IQUERY",
@@ -82,7 +83,7 @@
 int  res_ourserver_p(const res_state, const struct sockaddr *);
 
 #ifdef ANDROID_CHANGES
-int res_need_init() {
+static int res_need_init() {
 	return ((_nres.options & RES_INIT) == 0U) || res_get_dns_changed();
 }
 #else
diff --git a/libc/netbsd/resolv/res_debug.c b/libc/netbsd/resolv/res_debug.c
index 84c6afc..721e015 100644
--- a/libc/netbsd/resolv/res_debug.c
+++ b/libc/netbsd/resolv/res_debug.c
@@ -385,7 +385,7 @@
 /*
  * Names of message sections.
  */
-const struct res_sym __p_default_section_syms[] = {
+static const struct res_sym __p_default_section_syms[] = {
 	{ns_s_qd,	"QUERY",	(char *)0},
 	{ns_s_an,	"ANSWER",	(char *)0},
 	{ns_s_ns,	"AUTHORITY",	(char *)0},
@@ -393,7 +393,7 @@
 	{0,             (char *)0,	(char *)0}
 };
 
-const struct res_sym __p_update_section_syms[] = {
+static const struct res_sym __p_update_section_syms[] = {
 	{S_ZONE,	"ZONE",		(char *)0},
 	{S_PREREQ,	"PREREQUISITE",	(char *)0},
 	{S_UPDATE,	"UPDATE",	(char *)0},
diff --git a/libc/netbsd/resolv/res_init.c b/libc/netbsd/resolv/res_init.c
index 81e570f..2158f20 100644
--- a/libc/netbsd/resolv/res_init.c
+++ b/libc/netbsd/resolv/res_init.c
@@ -113,8 +113,8 @@
 #define DNS_PROP_NAME_PREFIX "net.dns"
 #define DNS_CHANGE_PROP_NAME "net.dnschange"
 #define DNS_SEARCH_PROP_NAME "net.dns.search"
-const prop_info *dns_change_prop;
-int dns_last_change_counter;
+static const prop_info *dns_change_prop;
+static int dns_last_change_counter;
 static int _get_dns_change_count();
 #else
 #include <resolv.h>
@@ -170,7 +170,7 @@
 }
 
 #ifdef ANDROID_CHANGES
-int load_domain_search_list(res_state statp) {
+static int load_domain_search_list(res_state statp) {
 	char propvalue[PROP_VALUE_MAX];
 	register char *cp, **pp;
 
diff --git a/libc/netbsd/resolv/res_send.c b/libc/netbsd/resolv/res_send.c
index 696f8cf..b118956 100644
--- a/libc/netbsd/resolv/res_send.c
+++ b/libc/netbsd/resolv/res_send.c
@@ -222,7 +222,7 @@
  * author:
  *	paul vixie, 29may94
  */
-int
+__LIBC_HIDDEN__ int
 res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
 	const struct sockaddr_in *inp, *srv;
 	const struct sockaddr_in6 *in6p, *srv6;
diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c
index 3a2301d..3209b6f 100644
--- a/libc/netbsd/resolv/res_state.c
+++ b/libc/netbsd/resolv/res_state.c
@@ -134,6 +134,7 @@
     return rt;
 }
 
+__LIBC_HIDDEN__
 struct __res_state _nres;
 
 #if 0
diff --git a/libc/stdio/fgetln.c b/libc/stdio/fgetln.c
index 946e1b7..95a5b31 100644
--- a/libc/stdio/fgetln.c
+++ b/libc/stdio/fgetln.c
@@ -43,7 +43,7 @@
  * so we add 1 here.
 #endif
  */
-int
+static int
 __slbexpand(FILE *fp, size_t newsize)
 {
 	void *p;
diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c
index 039293f..1d0f9c5 100644
--- a/libc/stdio/findfp.c
+++ b/libc/stdio/findfp.c
@@ -55,7 +55,7 @@
 static struct __sfileext usualext[FOPEN_MAX - 3];
 static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
 
-struct __sfileext __sFext[3];
+static struct __sfileext __sFext[3];
 FILE __sF[3] = {
 	std(__SRD, STDIN_FILENO),		/* stdin */
 	std(__SWR, STDOUT_FILENO),		/* stdout */
diff --git a/libc/stdio/flockfile.c b/libc/stdio/flockfile.c
index bfb081c..e8c74c5 100644
--- a/libc/stdio/flockfile.c
+++ b/libc/stdio/flockfile.c
@@ -191,7 +191,7 @@
 
 
 /* called from fclose() to remove the file lock */
-void
+__LIBC_HIDDEN__ void
 __fremovelock(FILE*  fp)
 {
     LockTable*  t = lock_table_lock();
diff --git a/libc/stdio/fvwrite.c b/libc/stdio/fvwrite.c
index ee39400..57a57e6 100644
--- a/libc/stdio/fvwrite.c
+++ b/libc/stdio/fvwrite.c
@@ -44,7 +44,7 @@
  * This routine is large and unsightly, but most of the ugliness due
  * to the three different kinds of output buffering is handled here.
  */
-int
+__LIBC_HIDDEN__ int
 __sfvwrite(FILE *fp, struct __suio *uio)
 {
 	size_t len;
diff --git a/libc/stdio/mktemp.c b/libc/stdio/mktemp.c
index 951f803..aaa5640 100644
--- a/libc/stdio/mktemp.c
+++ b/libc/stdio/mktemp.c
@@ -65,7 +65,7 @@
 
 char *_mktemp(char *);
 
-char *
+__LIBC_HIDDEN__ char *
 _mktemp(char *path)
 {
 	return(_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL);
diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c
index 9d599b0..2851506 100644
--- a/libc/stdlib/strtod.c
+++ b/libc/stdlib/strtod.c
@@ -2062,7 +2062,7 @@
  *	   calculation.
  */
 
- char *
+__LIBC_HIDDEN__  char *
 __dtoa
 #ifdef KR_headers
 	(_d, mode, ndigits, decpt, sign, rve)
diff --git a/libc/unistd/abort.c b/libc/unistd/abort.c
index 3e3aab0..8b8659b 100644
--- a/libc/unistd/abort.c
+++ b/libc/unistd/abort.c
@@ -40,7 +40,7 @@
     __libc_android_log_print(ANDROID_LOG_DEBUG, "libc-abort", (format), ##__VA_ARGS__ )
 
 #ifdef __arm__
-void
+__LIBC_HIDDEN__ void
 __libc_android_abort(void)
 #else
 void
diff --git a/libc/unistd/sigsetmask.c b/libc/unistd/sigsetmask.c
index b987595..4f46458 100644
--- a/libc/unistd/sigsetmask.c
+++ b/libc/unistd/sigsetmask.c
@@ -38,6 +38,8 @@
         sigset_t  the_sigset;
     } in, out;
 
+    in.the_mask = mask;
+
     n = sigprocmask(SIG_SETMASK, &in.the_sigset, &out.the_sigset);
     if (n)
         return n;
diff --git a/libm/i387/fenv.c b/libm/i387/fenv.c
index 2794faf..aabe270 100644
--- a/libm/i387/fenv.c
+++ b/libm/i387/fenv.c
@@ -153,7 +153,8 @@
 int
 feupdateenv(const fenv_t *envp)
 {
-	int mxcsr, status;
+	int mxcsr;
+	short status;
 
 	__fnstsw(&status);
 	if (__HAS_SSE())
diff --git a/libm/i387/fenv.h b/libm/i387/fenv.h
deleted file mode 100644
index b124366..0000000
--- a/libm/i387/fenv.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*-
- * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/lib/msun/i387/fenv.h,v 1.4 2005/03/17 22:21:46 das Exp $
- */
-
-#ifndef	_FENV_H_
-#define	_FENV_H_
-
-#include <sys/cdefs.h>
-#include <sys/_types.h>
-
-/*                   
- * To preserve binary compatibility with FreeBSD 5.3, we pack the
- * mxcsr into some reserved fields, rather than changing sizeof(fenv_t).
- */
-typedef struct {
-	__uint16_t	__control;
-	__uint16_t      __mxcsr_hi;
-	__uint16_t	__status;
-	__uint16_t      __mxcsr_lo;
-	__uint32_t	__tag;
-	char		__other[16];
-} fenv_t;
-
-#define	__get_mxcsr(env)	(((env).__mxcsr_hi << 16) |	\
-				 ((env).__mxcsr_lo))
-#define	__set_mxcsr(env, x)	do {				\
-	(env).__mxcsr_hi = (__uint32_t)(x) >> 16;		\
-	(env).__mxcsr_lo = (__uint16_t)(x);			\
-} while (0)
-
-typedef	__uint16_t	fexcept_t;
-
-/* Exception flags */
-#define	FE_INVALID	0x01
-#define	FE_DENORMAL	0x02
-#define	FE_DIVBYZERO	0x04
-#define	FE_OVERFLOW	0x08
-#define	FE_UNDERFLOW	0x10
-#define	FE_INEXACT	0x20
-#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
-			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
-
-/* Rounding modes */
-#define	FE_TONEAREST	0x0000
-#define	FE_DOWNWARD	0x0400
-#define	FE_UPWARD	0x0800
-#define	FE_TOWARDZERO	0x0c00
-#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
-			 FE_UPWARD | FE_TOWARDZERO)
-
-/*
- * As compared to the x87 control word, the SSE unit's control word
- * has the rounding control bits offset by 3 and the exception mask
- * bits offset by 7.
- */
-#define	_SSE_ROUND_SHIFT	3
-#define	_SSE_EMASK_SHIFT	7
-
-/* After testing for SSE support once, we cache the result in __has_sse. */
-enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK };
-extern enum __sse_support __has_sse;
-int __test_sse(void);
-#ifdef __SSE__
-#define	__HAS_SSE()	1
-#else
-#define	__HAS_SSE()	(__has_sse == __SSE_YES ||			\
-			 (__has_sse == __SSE_UNK && __test_sse()))
-#endif
-
-__BEGIN_DECLS
-
-/* Default floating-point environment */
-extern const fenv_t	__fe_dfl_env;
-#define	FE_DFL_ENV	(&__fe_dfl_env)
-
-#define	__fldcw(__cw)		__asm __volatile("fldcw %0" : : "m" (__cw))
-#define	__fldenv(__env)		__asm __volatile("fldenv %0" : : "m" (__env))
-#define	__fnclex()		__asm __volatile("fnclex")
-#define	__fnstenv(__env)	__asm __volatile("fnstenv %0" : "=m" (*(__env)))
-#define	__fnstcw(__cw)		__asm __volatile("fnstcw %0" : "=m" (*(__cw)))
-#define	__fnstsw(__sw)		__asm __volatile("fnstsw %0" : "=am" (*(__sw)))
-#define	__fwait()		__asm __volatile("fwait")
-#define	__ldmxcsr(__csr)	__asm __volatile("ldmxcsr %0" : : "m" (__csr))
-#define	__stmxcsr(__csr)	__asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
-
-static __inline int
-feclearexcept(int __excepts)
-{
-	fenv_t __env;
-	int __mxcsr;
-
-	if (__excepts == FE_ALL_EXCEPT) {
-		__fnclex();
-	} else {
-		__fnstenv(&__env);
-		__env.__status &= ~__excepts;
-		__fldenv(__env);
-	}
-	if (__HAS_SSE()) {
-		__stmxcsr(&__mxcsr);
-		__mxcsr &= ~__excepts;
-		__ldmxcsr(__mxcsr);
-	}
-	return (0);
-}
-
-static __inline int
-fegetexceptflag(fexcept_t *__flagp, int __excepts)
-{
-	int __mxcsr, __status;
-
-	__fnstsw(&__status);
-	if (__HAS_SSE())
-		__stmxcsr(&__mxcsr);
-	else
-		__mxcsr = 0;
-	*__flagp = (__mxcsr | __status) & __excepts;
-	return (0);
-}
-
-int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
-int feraiseexcept(int __excepts);
-
-static __inline int
-fetestexcept(int __excepts)
-{
-	int __mxcsr, __status;
-
-	__fnstsw(&__status);
-	if (__HAS_SSE())
-		__stmxcsr(&__mxcsr);
-	else
-		__mxcsr = 0;
-	return ((__status | __mxcsr) & __excepts);
-}
-
-static __inline int
-fegetround(void)
-{
-	int __control;
-
-	/*
-	 * We assume that the x87 and the SSE unit agree on the
-	 * rounding mode.  Reading the control word on the x87 turns
-	 * out to be about 5 times faster than reading it on the SSE
-	 * unit on an Opteron 244.
-	 */
-	__fnstcw(&__control);
-	return (__control & _ROUND_MASK);
-}
-
-static __inline int
-fesetround(int __round)
-{
-	int __mxcsr, __control;
-
-	if (__round & ~_ROUND_MASK)
-		return (-1);
-
-	__fnstcw(&__control);
-	__control &= ~_ROUND_MASK;
-	__control |= __round;
-	__fldcw(__control);
-
-	if (__HAS_SSE()) {
-		__stmxcsr(&__mxcsr);
-		__mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
-		__mxcsr |= __round << _SSE_ROUND_SHIFT;
-		__ldmxcsr(__mxcsr);
-	}
-
-	return (0);
-}
-
-int fegetenv(fenv_t *__envp);
-int feholdexcept(fenv_t *__envp);
-
-static __inline int
-fesetenv(const fenv_t *__envp)
-{
-	fenv_t __env = *__envp;
-	int __mxcsr;
-
-	__mxcsr = __get_mxcsr(__env);
-	__set_mxcsr(__env, 0xffffffff);
-	__fldenv(__env);
-	if (__HAS_SSE())
-		__ldmxcsr(__mxcsr);
-	return (0);
-}
-
-int feupdateenv(const fenv_t *__envp);
-
-#if __BSD_VISIBLE
-
-int feenableexcept(int __mask);
-int fedisableexcept(int __mask);
-
-static __inline int
-fegetexcept(void)
-{
-	int __control;
-
-	/*
-	 * We assume that the masks for the x87 and the SSE unit are
-	 * the same.
-	 */
-	__fnstcw(&__control);
-	return (~__control & FE_ALL_EXCEPT);
-}
-
-#endif /* __BSD_VISIBLE */
-
-__END_DECLS
-
-#endif	/* !_FENV_H_ */
diff --git a/libm/include/i387/fenv.h b/libm/include/i387/fenv.h
index b124366..5fe64e2 100644
--- a/libm/include/i387/fenv.h
+++ b/libm/include/i387/fenv.h
@@ -102,7 +102,7 @@
 #define	__fnclex()		__asm __volatile("fnclex")
 #define	__fnstenv(__env)	__asm __volatile("fnstenv %0" : "=m" (*(__env)))
 #define	__fnstcw(__cw)		__asm __volatile("fnstcw %0" : "=m" (*(__cw)))
-#define	__fnstsw(__sw)		__asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define	__fnstsw(__sw)		__asm __volatile("fnstsw %0" : "=a" (*(__sw)))
 #define	__fwait()		__asm __volatile("fwait")
 #define	__ldmxcsr(__csr)	__asm __volatile("ldmxcsr %0" : : "m" (__csr))
 #define	__stmxcsr(__csr)	__asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
@@ -131,7 +131,8 @@
 static __inline int
 fegetexceptflag(fexcept_t *__flagp, int __excepts)
 {
-	int __mxcsr, __status;
+	int __mxcsr;
+	short __status;
 
 	__fnstsw(&__status);
 	if (__HAS_SSE())
@@ -148,7 +149,8 @@
 static __inline int
 fetestexcept(int __excepts)
 {
-	int __mxcsr, __status;
+	int __mxcsr;
+	short __status;
 
 	__fnstsw(&__status);
 	if (__HAS_SSE())