Merge "Add cleaned headers for ion to bionic"
diff --git a/libc/Android.mk b/libc/Android.mk
index d8a4b1c..ef0ee47 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -523,6 +523,10 @@
 #
 libc_crt_target_cflags += -I$(LOCAL_PATH)/private
 
+ifeq ($(TARGET_ARCH),arm)
+libc_crt_target_cflags += -DCRT_LEGACY_WORKAROUND
+endif
+
 # Define some common includes
 # ========================================================
 libc_common_c_includes := \
@@ -551,18 +555,24 @@
 # that will call __cxa_finalize(&__dso_handle) in order to ensure that
 # static C++ destructors are properly called on dlclose().
 #
+
+libc_crt_target_so_cflags := $(libc_crt_target_cflags)
+ifeq ($(TARGET_ARCH),x86)
+    # This flag must be added for x86 targets, but not for ARM
+    libc_crt_target_so_cflags += -fPIC
+endif
 GEN := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_so.o
 $(GEN): $(LOCAL_PATH)/arch-$(TARGET_ARCH)/bionic/crtbegin_so.S
 	@mkdir -p $(dir $@)
-	$(TARGET_CC) $(libc_crt_target_cflags) -o $@ -c $<
+	$(TARGET_CC) $(libc_crt_target_so_cflags) -o $@ -c $<
 ALL_GENERATED_SOURCES += $(GEN)
 
 GEN := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_so.o
 $(GEN): $(LOCAL_PATH)/arch-$(TARGET_ARCH)/bionic/crtend_so.S
 	@mkdir -p $(dir $@)
-	$(TARGET_CC) $(libc_crt_target_cflags) -o $@ -c $<
+	$(TARGET_CC) $(libc_crt_target_so_cflags) -o $@ -c $<
 ALL_GENERATED_SOURCES += $(GEN)
-endif # TARGET_ARCH == x86
+endif # TARGET_ARCH == x86 || TARGET_ARCH == arm
 
 
 GEN := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_static.o
@@ -598,6 +608,9 @@
 
 LOCAL_SRC_FILES := $(libc_common_src_files)
 LOCAL_CFLAGS := $(libc_common_cflags)
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DCRT_LEGACY_WORKAROUND
+endif
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_MODULE := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
diff --git a/libc/arch-arm/bionic/atexit.S b/libc/arch-arm/bionic/atexit.S
new file mode 100644
index 0000000..aa1e18d
--- /dev/null
+++ b/libc/arch-arm/bionic/atexit.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 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 CRT_LEGACY_WORKAROUND
+	.arch armv5te
+	.fpu softvfp
+	.eabi_attribute 20, 1
+	.eabi_attribute 21, 1
+	.eabi_attribute 23, 3
+	.eabi_attribute 24, 1
+	.eabi_attribute 25, 1
+	.eabi_attribute 26, 2
+	.eabi_attribute 30, 4
+	.eabi_attribute 18, 4
+	.code	16
+	.section	.text.atexit,"ax",%progbits
+	.align	2
+	.global	atexit
+	.hidden	atexit
+	.code	16
+	.thumb_func
+	.type	atexit, %function
+atexit:
+	.fnstart
+.LFB0:
+	.save	{r4, lr}
+	push	{r4, lr}
+.LCFI0:
+	ldr	r3, .L3
+	mov	r1, #0
+	@ sp needed for prologue
+.LPIC0:
+	add	r3, pc
+	ldr	r2, [r3]
+	bl	__cxa_atexit
+	pop	{r4, pc}
+.L4:
+	.align	2
+.L3:
+	.word	__dso_handle-(.LPIC0+4)
+.LFE0:
+	.fnend
+	.size	atexit, .-atexit
+#endif
diff --git a/libc/arch-arm/bionic/crtbegin_dynamic.S b/libc/arch-arm/bionic/crtbegin_dynamic.S
index d18e715..0999084 100644
--- a/libc/arch-arm/bionic/crtbegin_dynamic.S
+++ b/libc/arch-arm/bionic/crtbegin_dynamic.S
@@ -85,3 +85,4 @@
 	.long -1
 
 #include "__dso_handle.S"
+#include "atexit.S"
diff --git a/libc/arch-arm/bionic/crtbegin_so.S b/libc/arch-arm/bionic/crtbegin_so.S
index bb6b3e2..9275b1e 100644
--- a/libc/arch-arm/bionic/crtbegin_so.S
+++ b/libc/arch-arm/bionic/crtbegin_so.S
@@ -52,4 +52,10 @@
         .long -1
         .long __on_dlclose
 
+#ifdef CRT_LEGACY_WORKAROUND
 #include "__dso_handle.S"
+#else
+#include "__dso_handle_so.S"
+#endif
+
+#include "atexit.S"
diff --git a/libc/arch-arm/bionic/crtbegin_static.S b/libc/arch-arm/bionic/crtbegin_static.S
index 6f9cf25..13b05b2 100644
--- a/libc/arch-arm/bionic/crtbegin_static.S
+++ b/libc/arch-arm/bionic/crtbegin_static.S
@@ -86,3 +86,4 @@
 
 
 #include "__dso_handle.S"
+#include "atexit.S"
diff --git a/libc/arch-x86/bionic/__stack_chk_fail_local.S b/libc/arch-x86/bionic/__stack_chk_fail_local.S
new file mode 100644
index 0000000..59fe86e
--- /dev/null
+++ b/libc/arch-x86/bionic/__stack_chk_fail_local.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+	.text
+	.p2align 4,,15
+	.globl	__stack_chk_fail_local
+	.hidden	__stack_chk_fail_local
+	.type	__stack_chk_fail_local, @function
+
+__stack_chk_fail_local:
+#ifdef __PIC__
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	call	__stack_chk_fail@PLT
+#else /* PIC */
+	jmp   __stack_chk_fail
+#endif /* not PIC */
+
+	.size	__stack_chk_fail_local, .-__stack_chk_fail_local
diff --git a/libc/arch-x86/bionic/atexit.S b/libc/arch-x86/bionic/atexit.S
new file mode 100644
index 0000000..b28f40b
--- /dev/null
+++ b/libc/arch-x86/bionic/atexit.S
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+	.text
+	.p2align 4,,15
+	.globl	atexit
+	.hidden	atexit
+	.type	atexit, @function
+atexit:
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$20, %esp
+	movl	$0, 4(%esp)
+	movl	__dso_handle@GOTOFF(%ebx), %eax
+	movl	%eax, 8(%esp)
+	movl	8(%ebp), %eax
+	movl	%eax, (%esp)
+	call	__cxa_atexit@PLT
+	addl	$20, %esp
+	popl	%ebx
+	popl	%ebp
+	ret
+	.size	atexit, .-atexit
+
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	.type	__x86.get_pc_thunk.bx, @function
+__x86.get_pc_thunk.bx:
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	movl	(%esp), %ebx
+	ret
diff --git a/libc/arch-x86/bionic/crtbegin_dynamic.S b/libc/arch-x86/bionic/crtbegin_dynamic.S
index 0a7bc62..9ba0d2f 100644
--- a/libc/arch-x86/bionic/crtbegin_dynamic.S
+++ b/libc/arch-x86/bionic/crtbegin_dynamic.S
@@ -76,10 +76,62 @@
 	.globl __INIT_ARRAY__
 __INIT_ARRAY__:
 	.long -1
+	.long	frame_dummy
 
 	.section .fini_array, "aw"
 	.globl __FINI_ARRAY__
 __FINI_ARRAY__:
 	.long -1
+	.long	__do_global_dtors_aux
+
+	.section	.eh_frame,"a",@progbits
+	.align 4
+	.type	__EH_FRAME_BEGIN__, @object
+__EH_FRAME_BEGIN__:
+	.text
+	.p2align 4,,15
+	.type	__do_global_dtors_aux, @function
+__do_global_dtors_aux:
+	pushl	%ebp
+	movl	%esp, %ebp
+	subl	$24, %esp
+	cmpb	$0, completed.4454
+	jne	.L4
+	movl	$__deregister_frame_info_bases, %eax
+	testl	%eax, %eax
+	je	.L3
+	movl	$__EH_FRAME_BEGIN__, (%esp)
+	call	__deregister_frame_info_bases
+.L3:
+	movb	$1, completed.4454
+.L4:
+	leave
+	ret
+	.text
+	.p2align 4,,15
+	.type	frame_dummy, @function
+frame_dummy:
+	pushl	%ebp
+	movl	$__register_frame_info_bases, %eax
+	movl	%esp, %ebp
+	subl	$24, %esp
+	testl	%eax, %eax
+	je	.L7
+	movl	%ebx, 12(%esp)
+	movl	$0, 8(%esp)
+	movl	$object.4466, 4(%esp)
+	movl	$__EH_FRAME_BEGIN__, (%esp)
+	call	__register_frame_info_bases
+.L7:
+	leave
+	ret
+	.local	completed.4454
+	.comm	completed.4454,1,1
+	.local	object.4466
+	.comm	object.4466,24,4
+	.weak	__register_frame_info_bases
+	.weak	__deregister_frame_info_bases
 
 #include "__dso_handle.S"
+#include "atexit.S"
+#include "__stack_chk_fail_local.S"
diff --git a/libc/arch-x86/bionic/crtbegin_so.S b/libc/arch-x86/bionic/crtbegin_so.S
index b3a01b5..99662fe 100644
--- a/libc/arch-x86/bionic/crtbegin_so.S
+++ b/libc/arch-x86/bionic/crtbegin_so.S
@@ -1,9 +1,30 @@
-# This function is to be called when the shared library
-# is unloaded through dlclose()
-_on_dlclose:
-    lea __dso_handle, %eax
-    call __cxa_finalize
-    ret
+/*
+ * 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.
+ */
 
 .section .init_array, "aw"
 .align 4
@@ -11,6 +32,7 @@
 .globl __INIT_ARRAY__
 __INIT_ARRAY__:
     .long -1
+    .long frame_dummy
 
 .section .fini_array, "aw"
 .align 4
@@ -18,6 +40,72 @@
 .globl __FINI_ARRAY__
 __FINI_ARRAY__:
     .long -1
-    .long _on_dlclose
+    .long __do_global_dtors_aux
 
-#include "__dso_handle.S"
+	.section	.eh_frame,"a",@progbits
+	.align 4
+	.type	__EH_FRAME_BEGIN__, @object
+__EH_FRAME_BEGIN__:
+	.text
+	.p2align 4,,15
+	.type	__do_global_dtors_aux, @function
+__do_global_dtors_aux:
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$20, %esp
+	cmpb	$0, completed.4454@GOTOFF(%ebx)
+	jne	.L5
+	movl	__dso_handle@GOTOFF(%ebx), %eax
+	movl	%eax, (%esp)
+	call	__cxa_finalize@PLT
+	movl	__deregister_frame_info_bases@GOT(%ebx), %eax
+	testl	%eax, %eax
+	je	.L4
+	leal	__EH_FRAME_BEGIN__@GOTOFF(%ebx), %eax
+	movl	%eax, (%esp)
+	call	__deregister_frame_info_bases@PLT
+.L4:
+	movb	$1, completed.4454@GOTOFF(%ebx)
+.L5:
+	addl	$20, %esp
+	popl	%ebx
+	popl	%ebp
+	ret
+	.text
+	.p2align 4,,15
+	.type	frame_dummy, @function
+frame_dummy:
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$20, %esp
+	movl	__register_frame_info_bases@GOT(%ebx), %eax
+	testl	%eax, %eax
+	je	.L8
+	leal	object.4469@GOTOFF(%ebx), %eax
+	movl	%eax, 4(%esp)
+	leal	__EH_FRAME_BEGIN__@GOTOFF(%ebx), %eax
+	movl	%ebx, 12(%esp)
+	movl	$0, 8(%esp)
+	movl	%eax, (%esp)
+	call	__register_frame_info_bases@PLT
+.L8:
+	addl	$20, %esp
+	popl	%ebx
+	popl	%ebp
+	ret
+	.local	completed.4454
+	.comm	completed.4454,1,1
+	.local	object.4469
+	.comm	object.4469,24,4
+	.weak	__register_frame_info_bases
+	.weak	__deregister_frame_info_bases
+
+#include "__dso_handle_so.S"
+#include "atexit.S"
+#include "__stack_chk_fail_local.S"
diff --git a/libc/arch-x86/bionic/crtbegin_static.S b/libc/arch-x86/bionic/crtbegin_static.S
index d5c2430..8e70330 100644
--- a/libc/arch-x86/bionic/crtbegin_static.S
+++ b/libc/arch-x86/bionic/crtbegin_static.S
@@ -75,10 +75,62 @@
 	.globl __INIT_ARRAY__
 __INIT_ARRAY__:
 	.long -1
+	.long	frame_dummy
 
 	.section .fini_array, "aw"
 	.globl __FINI_ARRAY__
 __FINI_ARRAY__:
 	.long -1
+	.long	__do_global_dtors_aux
+
+	.section	.eh_frame,"a",@progbits
+	.align 4
+	.type	__EH_FRAME_BEGIN__, @object
+__EH_FRAME_BEGIN__:
+	.text
+	.p2align 4,,15
+	.type	__do_global_dtors_aux, @function
+__do_global_dtors_aux:
+	pushl	%ebp
+	movl	%esp, %ebp
+	subl	$24, %esp
+	cmpb	$0, completed.4454
+	jne	.L4
+	movl	$__deregister_frame_info_bases, %eax
+	testl	%eax, %eax
+	je	.L3
+	movl	$__EH_FRAME_BEGIN__, (%esp)
+	call	__deregister_frame_info_bases
+.L3:
+	movb	$1, completed.4454
+.L4:
+	leave
+	ret
+	.text
+	.p2align 4,,15
+	.type	frame_dummy, @function
+frame_dummy:
+	pushl	%ebp
+	movl	$__register_frame_info_bases, %eax
+	movl	%esp, %ebp
+	subl	$24, %esp
+	testl	%eax, %eax
+	je	.L7
+	movl	%ebx, 12(%esp)
+	movl	$0, 8(%esp)
+	movl	$object.4466, 4(%esp)
+	movl	$__EH_FRAME_BEGIN__, (%esp)
+	call	__register_frame_info_bases
+.L7:
+	leave
+	ret
+	.local	completed.4454
+	.comm	completed.4454,1,1
+	.local	object.4466
+	.comm	object.4466,24,4
+	.weak	__register_frame_info_bases
+	.weak	__deregister_frame_info_bases
 
 #include "__dso_handle.S"
+#include "atexit.S"
+#include "__stack_chk_fail_local.S"
diff --git a/libc/arch-x86/bionic/crtend.S b/libc/arch-x86/bionic/crtend.S
index 884ba8b..68447e7 100644
--- a/libc/arch-x86/bionic/crtend.S
+++ b/libc/arch-x86/bionic/crtend.S
@@ -6,3 +6,10 @@
 
 	.section .fini_array, "aw"
 	.long 0
+
+	.section	.eh_frame,"a",@progbits
+	.align 4
+	.type	__FRAME_END__, @object
+	.size	__FRAME_END__, 4
+__FRAME_END__:
+	.zero	4
diff --git a/libc/arch-x86/bionic/crtend_so.S b/libc/arch-x86/bionic/crtend_so.S
index 8c9d419..63e58b9 100644
--- a/libc/arch-x86/bionic/crtend_so.S
+++ b/libc/arch-x86/bionic/crtend_so.S
@@ -1,6 +1,12 @@
-
 .section .init_array, "aw"
     .long 0
 
 .section .fini_array, "aw"
     .long 0
+
+	.section	.eh_frame,"a",@progbits
+	.align 4
+	.type	__FRAME_END__, @object
+	.size	__FRAME_END__, 4
+__FRAME_END__:
+	.zero	4
diff --git a/libc/include/resolv.h b/libc/include/resolv.h
index 4247d68..bb21c23 100644
--- a/libc/include/resolv.h
+++ b/libc/include/resolv.h
@@ -34,6 +34,7 @@
 #include <sys/socket.h>
 #include <stdio.h>
 #include <arpa/nameser.h>
+#include <netinet/in.h>
 
 __BEGIN_DECLS
 
@@ -49,6 +50,21 @@
 extern int   b64_ntop(u_char const *, size_t, char *, size_t);
 extern int   b64_pton(char const *, u_char *, size_t);
 
+/* Set name of default interface */
+extern void _resolv_set_default_iface(const char* ifname);
+
+/* set name servers for an interface */
+extern void _resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers);
+
+/* tell resolver of the address of an interface */
+extern void _resolv_set_addr_of_iface(const char* ifname, struct in_addr* addr);
+
+/* flush the cache associated with the default interface */
+extern void _resolv_flush_cache_for_default_iface();
+
+/* flush the cache associated with a certain interface */
+extern void _resolv_flush_cache_for_iface(const char* ifname);
+
 __END_DECLS
 
 #endif /* _RESOLV_H_ */
diff --git a/libc/include/sys/_errdefs.h b/libc/include/sys/_errdefs.h
index e27ab7a..51d921b 100644
--- a/libc/include/sys/_errdefs.h
+++ b/libc/include/sys/_errdefs.h
@@ -36,6 +36,7 @@
 #ifndef __BIONIC_ERRDEF
 #error "__BIONIC_ERRDEF must be defined before including this file"
 #endif
+__BIONIC_ERRDEF( 0              ,   0, "Success" )
 __BIONIC_ERRDEF( EPERM          ,   1, "Operation not permitted" )
 __BIONIC_ERRDEF( ENOENT         ,   2, "No such file or directory" )
 __BIONIC_ERRDEF( ESRCH          ,   3, "No such process" )
diff --git a/libc/inet/inet_pton.c b/libc/inet/inet_pton.c
index 4caf981..6e74e6a 100644
--- a/libc/inet/inet_pton.c
+++ b/libc/inet/inet_pton.c
@@ -1,36 +1,64 @@
-/*	$OpenBSD: inet_pton.c,v 1.7 2006/12/30 23:37:37 itojun Exp $	*/
+/*	$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $	*/
 
-/* Copyright (c) 1996 by Internet Software Consortium.
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
  *
  * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC 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/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
+#else
+__RCSID("$NetBSD: inet_pton.c,v 1.6.10.1 2011/01/10 00:42:17 riz Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+// BEGIN android-added
+#define _DIAGASSERT(exp) assert(exp)
+#include "../private/arpa_nameser.h"
+// END android-added
+
+// android-removed: #include "port_before.h"
+
+// android-removed: #include "namespace.h"
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include "arpa_nameser.h"
+#include <arpa/nameser.h>
 #include <string.h>
+#include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 
-/*
+// android-removed: #include "port_after.h"
+
+// BEGIN android-removed
+// #ifdef __weak_alias
+// __weak_alias(inet_pton,_inet_pton)
+// #endif
+// END android-removed
+
+/*%
  * WARNING: Don't even consider trying to compile this on a system where
  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  */
 
-static int	inet_pton4(const char *src, u_char *dst);
+static int	inet_pton4(const char *src, u_char *dst, int pton);
 static int	inet_pton6(const char *src, u_char *dst);
 
 /* int
@@ -47,9 +75,13 @@
 int
 inet_pton(int af, const char *src, void *dst)
 {
+
+	_DIAGASSERT(src != NULL);
+	_DIAGASSERT(dst != NULL);
+
 	switch (af) {
 	case AF_INET:
-		return (inet_pton4(src, dst));
+		return (inet_pton4(src, dst, 1));
 	case AF_INET6:
 		return (inet_pton6(src, dst));
 	default:
@@ -60,51 +92,123 @@
 }
 
 /* int
- * inet_pton4(src, dst)
- *	like inet_aton() but without all the hexadecimal and shorthand.
+ * inet_pton4(src, dst, pton)
+ *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
+ *	when last arg is 1: inet_pton(). decimal dotted-quad only.
  * return:
- *	1 if `src' is a valid dotted quad, else 0.
+ *	1 if `src' is a valid input, else 0.
  * notice:
  *	does not touch `dst' unless it's returning 1.
  * author:
  *	Paul Vixie, 1996.
  */
 static int
-inet_pton4(const char *src, u_char *dst)
+inet_pton4(const char *src, u_char *dst, int pton)
 {
-	static const char digits[] = "0123456789";
-	int saw_digit, octets, ch;
-	u_char tmp[INADDRSZ], *tp;
+	u_int32_t val;
+	u_int digit, base;
+	int n;
+	unsigned char c;
+	u_int parts[4];
+	register u_int *pp = parts;
 
-	saw_digit = 0;
-	octets = 0;
-	*(tp = tmp) = 0;
-	while ((ch = *src++) != '\0') {
-		const char *pch;
+	_DIAGASSERT(src != NULL);
+	_DIAGASSERT(dst != NULL);
 
-		if ((pch = strchr(digits, ch)) != NULL) {
-			u_int new = *tp * 10 + (pch - digits);
-
-			if (new > 255)
-				return (0);
-			if (! saw_digit) {
-				if (++octets > 4)
-					return (0);
-				saw_digit = 1;
-			}
-			*tp = new;
-		} else if (ch == '.' && saw_digit) {
-			if (octets == 4)
-				return (0);
-			*++tp = 0;
-			saw_digit = 0;
-		} else
+	c = *src;
+	for (;;) {
+		/*
+		 * Collect number up to ``.''.
+		 * Values are specified as for C:
+		 * 0x=hex, 0=octal, isdigit=decimal.
+		 */
+		if (!isdigit(c))
 			return (0);
+		val = 0; base = 10;
+		if (c == '0') {
+			c = *++src;
+			if (c == 'x' || c == 'X')
+				base = 16, c = *++src;
+			else if (isdigit(c) && c != '9')
+				base = 8;
+		}
+		/* inet_pton() takes decimal only */
+		if (pton && base != 10)
+			return (0);
+		for (;;) {
+			if (isdigit(c)) {
+				digit = c - '0';
+				if (digit >= base)
+					break;
+				val = (val * base) + digit;
+				c = *++src;
+			} else if (base == 16 && isxdigit(c)) {
+				digit = c + 10 - (islower(c) ? 'a' : 'A');
+				if (digit >= 16)
+					break;
+				val = (val << 4) | digit;
+				c = *++src;
+			} else
+				break;
+		}
+		if (c == '.') {
+			/*
+			 * Internet format:
+			 *	a.b.c.d
+			 *	a.b.c	(with c treated as 16 bits)
+			 *	a.b	(with b treated as 24 bits)
+			 *	a	(with a treated as 32 bits)
+			 */
+			if (pp >= parts + 3)
+				return (0);
+			*pp++ = val;
+			c = *++src;
+		} else
+			break;
 	}
-	if (octets < 4)
+	/*
+	 * Check for trailing characters.
+	 */
+	if (c != '\0' && !isspace(c))
 		return (0);
+	/*
+	 * Concoct the address according to
+	 * the number of parts specified.
+	 */
+	n = pp - parts + 1;
+	/* inet_pton() takes dotted-quad only.  it does not take shorthand. */
+	if (pton && n != 4)
+		return (0);
+	switch (n) {
 
-	memcpy(dst, tmp, INADDRSZ);
+	case 0:
+		return (0);		/* initial nondigit */
+
+	case 1:				/* a -- 32 bits */
+		break;
+
+	case 2:				/* a.b -- 8.24 bits */
+		if (parts[0] > 0xff || val > 0xffffff)
+			return (0);
+		val |= parts[0] << 24;
+		break;
+
+	case 3:				/* a.b.c -- 8.8.16 bits */
+		if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
+			return (0);
+		val |= (parts[0] << 24) | (parts[1] << 16);
+		break;
+
+	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
+		if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
+			return (0);
+		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+		break;
+	}
+	if (dst) {
+		val = htonl(val);
+		memcpy(dst, &val, NS_INADDRSZ);
+	}
 	return (1);
 }
 
@@ -126,20 +230,23 @@
 {
 	static const char xdigits_l[] = "0123456789abcdef",
 			  xdigits_u[] = "0123456789ABCDEF";
-	u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
 	const char *xdigits, *curtok;
-	int ch, saw_xdigit, count_xdigit;
+	int ch, seen_xdigits;
 	u_int val;
 
-	memset((tp = tmp), '\0', IN6ADDRSZ);
-	endp = tp + IN6ADDRSZ;
+	_DIAGASSERT(src != NULL);
+	_DIAGASSERT(dst != NULL);
+
+	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+	endp = tp + NS_IN6ADDRSZ;
 	colonp = NULL;
 	/* Leading :: requires some special handling. */
 	if (*src == ':')
 		if (*++src != ':')
 			return (0);
 	curtok = src;
-	saw_xdigit = count_xdigit = 0;
+	seen_xdigits = 0;
 	val = 0;
 	while ((ch = *src++) != '\0') {
 		const char *pch;
@@ -147,46 +254,39 @@
 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
 			pch = strchr((xdigits = xdigits_u), ch);
 		if (pch != NULL) {
-			if (count_xdigit >= 4)
-				return (0);
 			val <<= 4;
 			val |= (pch - xdigits);
-			if (val > 0xffff)
+			if (++seen_xdigits > 4)
 				return (0);
-			saw_xdigit = 1;
-			count_xdigit++;
 			continue;
 		}
 		if (ch == ':') {
 			curtok = src;
-			if (!saw_xdigit) {
+			if (!seen_xdigits) {
 				if (colonp)
 					return (0);
 				colonp = tp;
 				continue;
-			} else if (*src == '\0') {
+			} else if (*src == '\0')
 				return (0);
-			}
-			if (tp + INT16SZ > endp)
+			if (tp + NS_INT16SZ > endp)
 				return (0);
 			*tp++ = (u_char) (val >> 8) & 0xff;
 			*tp++ = (u_char) val & 0xff;
-			saw_xdigit = 0;
-			count_xdigit = 0;
+			seen_xdigits = 0;
 			val = 0;
 			continue;
 		}
-		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
-		    inet_pton4(curtok, tp) > 0) {
-			tp += INADDRSZ;
-			saw_xdigit = 0;
-			count_xdigit = 0;
-			break;	/* '\0' was seen by inet_pton4(). */
+		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+		    inet_pton4(curtok, tp, 1) > 0) {
+			tp += NS_INADDRSZ;
+			seen_xdigits = 0;
+			break;	/*%< '\\0' was seen by inet_pton4(). */
 		}
 		return (0);
 	}
-	if (saw_xdigit) {
-		if (tp + INT16SZ > endp)
+	if (seen_xdigits) {
+		if (tp + NS_INT16SZ > endp)
 			return (0);
 		*tp++ = (u_char) (val >> 8) & 0xff;
 		*tp++ = (u_char) val & 0xff;
@@ -199,6 +299,8 @@
 		const int n = tp - colonp;
 		int i;
 
+		if (tp == endp)
+			return (0);
 		for (i = 1; i <= n; i++) {
 			endp[- i] = colonp[n - i];
 			colonp[n - i] = 0;
@@ -207,6 +309,8 @@
 	}
 	if (tp != endp)
 		return (0);
-	memcpy(dst, tmp, IN6ADDRSZ);
+	memcpy(dst, tmp, NS_IN6ADDRSZ);
 	return (1);
 }
+
+/*! \file */
diff --git a/libc/kernel/common/asm-generic/resource.h b/libc/kernel/common/asm-generic/resource.h
index a7f7dec..c49b476 100644
--- a/libc/kernel/common/asm-generic/resource.h
+++ b/libc/kernel/common/asm-generic/resource.h
@@ -7,51 +7,57 @@
  ***   structures, and macros generated from the original header, and thus,
  ***   contains no copyrightable information.
  ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
  ****************************************************************************
  ****************************************************************************/
 #ifndef _ASM_GENERIC_RESOURCE_H
 #define _ASM_GENERIC_RESOURCE_H
-
 #define RLIMIT_CPU 0  
 #define RLIMIT_FSIZE 1  
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define RLIMIT_DATA 2  
 #define RLIMIT_STACK 3  
 #define RLIMIT_CORE 4  
-
 #ifndef RLIMIT_RSS
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define RLIMIT_RSS 5  
 #endif
-
 #ifndef RLIMIT_NPROC
 #define RLIMIT_NPROC 6  
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #endif
-
 #ifndef RLIMIT_NOFILE
 #define RLIMIT_NOFILE 7  
 #endif
-
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifndef RLIMIT_MEMLOCK
 #define RLIMIT_MEMLOCK 8  
 #endif
-
 #ifndef RLIMIT_AS
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define RLIMIT_AS 9  
 #endif
-
 #define RLIMIT_LOCKS 10  
 #define RLIMIT_SIGPENDING 11  
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define RLIMIT_MSGQUEUE 12  
 #define RLIMIT_NICE 13  
 #define RLIMIT_RTPRIO 14  
-
-#define RLIM_NLIMITS 15
-
+#define RLIMIT_RTTIME 15  
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RLIM_NLIMITS 16
 #ifndef RLIM_INFINITY
 #define RLIM_INFINITY (~0UL)
 #endif
-
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #ifndef _STK_LIM_MAX
 #define _STK_LIM_MAX RLIM_INFINITY
 #endif
-
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c
index e6302ed..efce7dc 100644
--- a/libc/netbsd/resolv/res_cache.c
+++ b/libc/netbsd/resolv/res_cache.c
@@ -27,6 +27,7 @@
  */
 
 #include "resolv_cache.h"
+#include <resolv.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -35,6 +36,12 @@
 #include <errno.h>
 #include "arpa_nameser.h"
 #include <sys/system_properties.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <linux/if.h>
+
+#include <arpa/inet.h>
+#include "resolv_private.h"
 
 /* This code implements a small and *simple* DNS resolver cache.
  *
@@ -159,9 +166,6 @@
 #include <stdio.h>
 #include <stdarg.h>
 
-#include <arpa/inet.h>
-#include "resolv_private.h"
-
 /** BOUNDED BUFFER FORMATTING
  **/
 
@@ -1165,6 +1169,14 @@
     Entry*           entries;
 } Cache;
 
+typedef struct resolv_cache_info {
+    char                        ifname[IF_NAMESIZE + 1];
+    struct in_addr              ifaddr;
+    Cache*                      cache;
+    struct resolv_cache_info*   next;
+    char*                       nameservers[MAXNS +1];
+    struct addrinfo*            nsaddrinfo[MAXNS + 1];
+} CacheInfo;
 
 #define  HTABLE_VALID(x)  ((x) != NULL && (x) != HTABLE_DELETED)
 
@@ -1543,11 +1555,47 @@
 /****************************************************************************/
 /****************************************************************************/
 
-static struct resolv_cache*  _res_cache;
 static pthread_once_t        _res_cache_once;
 
+// Head of the list of caches.  Protected by _res_cache_list_lock.
+static struct resolv_cache_info _res_cache_list;
+
+// name of the current default inteface
+static char            _res_default_ifname[IF_NAMESIZE + 1];
+
+// lock protecting everything in the _resolve_cache_info structs (next ptr, etc)
+static pthread_mutex_t _res_cache_list_lock;
+
+
+/* lookup the default interface name */
+static char *_get_default_iface_locked();
+/* insert resolv_cache_info into the list of resolv_cache_infos */
+static void _insert_cache_info_locked(struct resolv_cache_info* cache_info);
+/* creates a resolv_cache_info */
+static struct resolv_cache_info* _create_cache_info( void );
+/* gets cache associated with an interface name, or NULL if none exists */
+static struct resolv_cache* _find_named_cache_locked(const char* ifname);
+/* gets a resolv_cache_info associated with an interface name, or NULL if not found */
+static struct resolv_cache_info* _find_cache_info_locked(const char* ifname);
+/* free dns name server list of a resolv_cache_info structure */
+static void _free_nameservers(struct resolv_cache_info* cache_info);
+/* look up the named cache, and creates one if needed */
+static struct resolv_cache* _get_res_cache_for_iface_locked(const char* ifname);
+/* empty the named cache */
+static void _flush_cache_for_iface_locked(const char* ifname);
+/* empty the nameservers set for the named cache */
+static void _free_nameservers_locked(struct resolv_cache_info* cache_info);
+/* lookup the namserver for the name interface */
+static int _get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen);
+/* lookup the addr of the nameserver for the named interface */
+static struct addrinfo* _get_nameserver_addr_locked(const char* ifname, int n);
+/* lookup the inteface's address */
+static struct in_addr* _get_addr_locked(const char * ifname);
+
+
+
 static void
-_res_cache_init( void )
+_res_cache_init(void)
 {
     const char*  env = getenv(CONFIG_ENV);
 
@@ -1556,29 +1604,392 @@
         return;
     }
 
-    _res_cache = _resolv_cache_create();
+    memset(&_res_default_ifname, 0, sizeof(_res_default_ifname));
+    memset(&_res_cache_list, 0, sizeof(_res_cache_list));
+    pthread_mutex_init(&_res_cache_list_lock, NULL);
 }
 
-
 struct resolv_cache*
-__get_res_cache( void )
+__get_res_cache(void)
 {
-    pthread_once( &_res_cache_once, _res_cache_init );
-    return _res_cache;
+    struct resolv_cache *cache;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    char* ifname = _get_default_iface_locked();
+
+    // if default interface not set then use the first cache
+    // associated with an interface as the default one.
+    if (ifname[0] == '\0') {
+        struct resolv_cache_info* cache_info = _res_cache_list.next;
+        while (cache_info) {
+            if (cache_info->ifname[0] != '\0') {
+                ifname = cache_info->ifname;
+            }
+
+            cache_info = cache_info->next;
+        }
+    }
+    cache = _get_res_cache_for_iface_locked(ifname);
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+    XLOG("_get_res_cache. default_ifname = %s\n", ifname);
+    return cache;
+}
+
+static struct resolv_cache*
+_get_res_cache_for_iface_locked(const char* ifname)
+{
+    if (ifname == NULL)
+        return NULL;
+
+    struct resolv_cache* cache = _find_named_cache_locked(ifname);
+    if (!cache) {
+        struct resolv_cache_info* cache_info = _create_cache_info();
+        if (cache_info) {
+            cache = _resolv_cache_create();
+            if (cache) {
+                int len = sizeof(cache_info->ifname);
+                cache_info->cache = cache;
+                strncpy(cache_info->ifname, ifname, len - 1);
+                cache_info->ifname[len - 1] = '\0';
+
+                _insert_cache_info_locked(cache_info);
+            } else {
+                free(cache_info);
+            }
+        }
+    }
+    return cache;
 }
 
 void
-_resolv_cache_reset( unsigned  generation )
+_resolv_cache_reset(unsigned  generation)
 {
     XLOG("%s: generation=%d", __FUNCTION__, generation);
 
-    if (_res_cache == NULL)
-        return;
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
 
-    pthread_mutex_lock( &_res_cache->lock );
-    if (_res_cache->generation != generation) {
-        _cache_flush_locked(_res_cache);
-        _res_cache->generation = generation;
+    char* ifname = _get_default_iface_locked();
+    // if default interface not set then use the first cache
+    // associated with an interface as the default one.
+    // Note: Copied the code from __get_res_cache since this
+    // method will be deleted/obsolete when cache per interface
+    // implemented all over
+    if (ifname[0] == '\0') {
+        struct resolv_cache_info* cache_info = _res_cache_list.next;
+        while (cache_info) {
+            if (cache_info->ifname[0] != '\0') {
+                ifname = cache_info->ifname;
+            }
+
+            cache_info = cache_info->next;
+        }
     }
-    pthread_mutex_unlock( &_res_cache->lock );
+    struct resolv_cache* cache = _get_res_cache_for_iface_locked(ifname);
+
+    if (cache == NULL) {
+        pthread_mutex_unlock(&_res_cache_list_lock);
+        return;
+    }
+
+    pthread_mutex_lock( &cache->lock );
+    if (cache->generation != generation) {
+        _cache_flush_locked(cache);
+        cache->generation = generation;
+    }
+    pthread_mutex_unlock( &cache->lock );
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+void
+_resolv_flush_cache_for_default_iface(void)
+{
+    char* ifname;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    ifname = _get_default_iface_locked();
+    _flush_cache_for_iface_locked(ifname);
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+void
+_resolv_flush_cache_for_iface(const char* ifname)
+{
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    _flush_cache_for_iface_locked(ifname);
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+static void
+_flush_cache_for_iface_locked(const char* ifname)
+{
+    struct resolv_cache* cache = _find_named_cache_locked(ifname);
+    if (cache) {
+        pthread_mutex_lock(&cache->lock);
+        _cache_flush_locked(cache);
+        pthread_mutex_unlock(&cache->lock);
+    }
+}
+
+static struct resolv_cache_info*
+_create_cache_info(void)
+{
+    struct resolv_cache_info*  cache_info;
+
+    cache_info = calloc(sizeof(*cache_info), 1);
+    return cache_info;
+}
+
+static void
+_insert_cache_info_locked(struct resolv_cache_info* cache_info)
+{
+    struct resolv_cache_info* last;
+
+    for (last = &_res_cache_list; last->next; last = last->next);
+
+    last->next = cache_info;
+
+}
+
+static struct resolv_cache*
+_find_named_cache_locked(const char* ifname) {
+
+    struct resolv_cache_info* info = _find_cache_info_locked(ifname);
+
+    if (info != NULL) return info->cache;
+
+    return NULL;
+}
+
+static struct resolv_cache_info*
+_find_cache_info_locked(const char* ifname)
+{
+    if (ifname == NULL)
+        return NULL;
+
+    struct resolv_cache_info* cache_info = _res_cache_list.next;
+
+    while (cache_info) {
+        if (strcmp(cache_info->ifname, ifname) == 0) {
+            break;
+        }
+
+        cache_info = cache_info->next;
+    }
+    return cache_info;
+}
+
+static char*
+_get_default_iface_locked(void)
+{
+    char* iface = _res_default_ifname;
+
+    return iface;
+}
+
+void
+_resolv_set_default_iface(const char* ifname)
+{
+    XLOG("_resolv_set_default_if ifname %s\n",ifname);
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    int size = sizeof(_res_default_ifname);
+    memset(_res_default_ifname, 0, size);
+    strncpy(_res_default_ifname, ifname, size - 1);
+    _res_default_ifname[size - 1] = '\0';
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+void
+_resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers)
+{
+    int i, rt, index;
+    struct addrinfo hints;
+    char sbuf[NI_MAXSERV];
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+
+    pthread_mutex_lock(&_res_cache_list_lock);
+    // creates the cache if not created
+    _get_res_cache_for_iface_locked(ifname);
+
+    struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
+
+    if (cache_info != NULL) {
+        // free current before adding new
+        _free_nameservers_locked(cache_info);
+
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_family = PF_UNSPEC;
+        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+        hints.ai_flags = AI_NUMERICHOST;
+        sprintf(sbuf, "%u", NAMESERVER_PORT);
+
+        index = 0;
+        for (i = 0; i < numservers && i < MAXNS; i++) {
+            rt = getaddrinfo(servers[i], sbuf, &hints, &cache_info->nsaddrinfo[index]);
+            if (rt == 0) {
+                cache_info->nameservers[index] = strdup(servers[i]);
+                index++;
+            } else {
+                cache_info->nsaddrinfo[index] = NULL;
+            }
+        }
+    }
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+static void
+_free_nameservers_locked(struct resolv_cache_info* cache_info)
+{
+    int i;
+    for (i = 0; i <= MAXNS; i++) {
+        free(cache_info->nameservers[i]);
+        cache_info->nameservers[i] = NULL;
+        freeaddrinfo(cache_info->nsaddrinfo[i]);
+        cache_info->nsaddrinfo[i] = NULL;
+    }
+}
+
+int
+_resolv_cache_get_nameserver(int n, char* addr, int addrLen)
+{
+    char *ifname;
+    int result = 0;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    ifname = _get_default_iface_locked();
+    result = _get_nameserver_locked(ifname, n, addr, addrLen);
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+    return result;
+}
+
+static int
+_get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen)
+{
+    int len = 0;
+    char* ns;
+    struct resolv_cache_info* cache_info;
+
+    if (n < 1 || n > MAXNS || !addr)
+        return 0;
+
+    cache_info = _find_cache_info_locked(ifname);
+    if (cache_info) {
+        ns = cache_info->nameservers[n - 1];
+        if (ns) {
+            len = strlen(ns);
+            if (len < addrLen) {
+                strncpy(addr, ns, len);
+                addr[len] = '\0';
+            } else {
+                len = 0;
+            }
+        }
+    }
+
+    return len;
+}
+
+struct addrinfo*
+_cache_get_nameserver_addr(int n)
+{
+    struct addrinfo *result;
+    char* ifname;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    ifname = _get_default_iface_locked();
+
+    result = _get_nameserver_addr_locked(ifname, n);
+    pthread_mutex_unlock(&_res_cache_list_lock);
+    return result;
+}
+
+static struct addrinfo*
+_get_nameserver_addr_locked(const char* ifname, int n)
+{
+    struct addrinfo* ai = NULL;
+    struct resolv_cache_info* cache_info;
+
+    if (n < 1 || n > MAXNS)
+        return NULL;
+
+    cache_info = _find_cache_info_locked(ifname);
+    if (cache_info) {
+        ai = cache_info->nsaddrinfo[n - 1];
+    }
+    return ai;
+}
+
+void
+_resolv_set_addr_of_iface(const char* ifname, struct in_addr* addr)
+{
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+    struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
+    if (cache_info) {
+        memcpy(&cache_info->ifaddr, addr, sizeof(*addr));
+
+        if (DEBUG) {
+            char* addr_s = inet_ntoa(cache_info->ifaddr);
+            XLOG("address of interface %s is %s\n", ifname, addr_s);
+        }
+    }
+    pthread_mutex_unlock(&_res_cache_list_lock);
+}
+
+struct in_addr*
+_resolv_get_addr_of_default_iface(void)
+{
+    struct in_addr* ai = NULL;
+    char* ifname;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+    ifname = _get_default_iface_locked();
+    ai = _get_addr_locked(ifname);
+    pthread_mutex_unlock(&_res_cache_list_lock);
+
+    return ai;
+}
+
+struct in_addr*
+_resolv_get_addr_of_iface(const char* ifname)
+{
+    struct in_addr* ai = NULL;
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+    ai =_get_addr_locked(ifname);
+    pthread_mutex_unlock(&_res_cache_list_lock);
+    return ai;
+}
+
+static struct in_addr*
+_get_addr_locked(const char * ifname)
+{
+    struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
+    if (cache_info) {
+        return &cache_info->ifaddr;
+    }
+    return NULL;
 }
diff --git a/libc/private/__dso_handle.S b/libc/private/__dso_handle.S
index fcebab6..3e80128 100644
--- a/libc/private/__dso_handle.S
+++ b/libc/private/__dso_handle.S
@@ -32,6 +32,11 @@
 #
         .section .bss
         .align 4
+
+#ifndef CRT_LEGACY_WORKAROUND
+	.hidden __dso_handle
+#endif
+
         .globl __dso_handle
 __dso_handle:
         .long 0
diff --git a/libc/private/__dso_handle_so.S b/libc/private/__dso_handle_so.S
new file mode 100644
index 0000000..77a5d7f
--- /dev/null
+++ b/libc/private/__dso_handle_so.S
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+# The __dso_handle global variable is used by static
+# C++ constructors and destructors in the binary.
+# See http://www.codesourcery.com/public/cxx-abi/abi.html#dso-dtor
+#
+	.data
+        .align 4
+	.hidden __dso_handle
+        .globl __dso_handle
+__dso_handle:
+        .long __dso_handle
diff --git a/libc/private/resolv_cache.h b/libc/private/resolv_cache.h
index cd876fb..2a54453 100644
--- a/libc/private/resolv_cache.h
+++ b/libc/private/resolv_cache.h
@@ -30,13 +30,45 @@
 
 struct resolv_cache;  /* forward */
 
-/* get cache instance, can be NULL if cache is disabled
- * (e.g. through an environment variable) */
+/* gets the cache for the default interface. Might be NULL*/
 extern struct resolv_cache*  __get_res_cache(void);
 
+/* get the cache for a specified interface. Can be NULL*/
+extern struct resolv_cache* __get_res_cache_for_iface(const char* ifname);
+
 /* this gets called everytime we detect some changes in the DNS configuration
  * and will flush the cache */
-extern void   _resolv_cache_reset( unsigned  generation );
+extern void  _resolv_cache_reset( unsigned  generation );
+
+/* Gets the address of the n:th name server for the default interface
+ * Return length of address on success else 0.
+ * Note: The first name server is at n = 1 */
+extern int _resolv_cache_get_nameserver(int n, char* addr, int addrLen);
+
+/* Gets the address of the n:th name server for a certain interface
+ * Return length of address on success else 0.
+ * Note: The first name server is at n = 1 */
+extern int _resolv_cache_get_nameserver_for_iface(const char* ifname, int n,
+        char* addr, int addrLen);
+
+/* Gets addrinfo of the n:th name server associated with an interface.
+ * NULL is returned if no address if found.
+ * Note: The first name server is at n = 1. */
+extern struct addrinfo* _resolv_cache_get_nameserver_addr_for_iface(const char* ifname, int n);
+
+/* Gets addrinfo of the n:th name server associated with the default interface
+ * NULL is returned if no address if found.
+ * Note: The first name server is at n = 1. */
+extern struct addrinfo* _resolv_cache_get_nameserver_addr(int n);
+
+/* gets the address associated with the default interface */
+extern struct in_addr* _resolv_get_addr_of_default_iface();
+
+/* gets the address associated with the specified interface */
+extern struct in_addr* _resolv_get_addr_of_iface(const char* ifname);
+
+/* Get name of default interface */
+extern char* _resolv_get_default_iface();
 
 typedef enum {
     RESOLV_CACHE_UNSUPPORTED,  /* the cache can't handle that kind of queries */
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index 4ba2177..f4bcab9 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -104,6 +104,7 @@
 	return (ret);
 }
 
+#ifdef CRT_LEGACY_WORKAROUND
 /*
  * Register a function to be performed at exit.
  */
@@ -112,6 +113,7 @@
 {
 	return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
 }
+#endif
 
 /*
  * Call all handlers registered with __cxa_atexit() for the shared
diff --git a/libc/string/strerror_r.c b/libc/string/strerror_r.c
index f43d417..2f26f17 100644
--- a/libc/string/strerror_r.c
+++ b/libc/string/strerror_r.c
@@ -21,7 +21,7 @@
 
     for (;;)
     {
-        if (strings[nn].code == 0)
+        if (strings[nn].msg == NULL)
             break;
 
         if (strings[nn].code == code)
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index ab713fb..a2cc3b3 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -407,9 +407,9 @@
                     tm = *t;
                     mkt = mktime64(&tm);
                     if (TYPE_SIGNED(time64_t))
-                        (void) sprintf(buf, "%lld",
+                        (void) snprintf(buf, sizeof(buf), "%lld",
                             (long long) mkt);
-                    else    (void) sprintf(buf, "%llu",
+                    else    (void) snprintf(buf, sizeof(buf), "%llu",
                             (unsigned long long) mkt);
                     pt = _add(buf, pt, ptlim, modifier);
                 }
diff --git a/libc/unistd/time.c b/libc/unistd/time.c
index 4b51675..18aa62c 100644
--- a/libc/unistd/time.c
+++ b/libc/unistd/time.c
@@ -34,12 +34,15 @@
 time(time_t *t)
 {
 	struct timeval tt;
+	time_t ret;
 
 	if (gettimeofday(&tt, (struct timezone *)0) < 0)
-		return (-1);
-	if (t)
-		*t = (time_t)tt.tv_sec;
-	return (tt.tv_sec);
+		ret = -1;
+	else
+		ret = tt.tv_sec;
+	if (t != NULL)
+		*t = ret;
+	return ret;
 }
 
 // return monotonically increasing CPU time in ticks relative to unspecified epoch
diff --git a/libc/zoneinfo/zoneinfo.dat b/libc/zoneinfo/zoneinfo.dat
index 7b1bd49..bac23f0 100644
--- a/libc/zoneinfo/zoneinfo.dat
+++ b/libc/zoneinfo/zoneinfo.dat
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.idx b/libc/zoneinfo/zoneinfo.idx
index 984aa00..7750e4d 100644
--- a/libc/zoneinfo/zoneinfo.idx
+++ b/libc/zoneinfo/zoneinfo.idx
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.version b/libc/zoneinfo/zoneinfo.version
index 2a4dffc..4abe0cc 100644
--- a/libc/zoneinfo/zoneinfo.version
+++ b/libc/zoneinfo/zoneinfo.version
@@ -1 +1 @@
-2011g
+2011h