am 00cef820: am 64e9e71c: Define nonportable pthread mutex macros with the _NP suffix.

* commit '00cef82013c0826bb43c11651d25de8b99335618':
  Define nonportable pthread mutex macros with the _NP suffix.
diff --git a/libc/Android.mk b/libc/Android.mk
index 2c33a8f..620f438 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -129,8 +129,11 @@
     bionic/fchmod.cpp \
     bionic/fchmodat.cpp \
     bionic/ffs.cpp \
+    bionic/fgetxattr.cpp \
     bionic/flockfile.cpp \
     bionic/fpclassify.cpp \
+    bionic/fsetxattr.cpp \
+    bionic/ftruncate.cpp \
     bionic/futimens.cpp \
     bionic/getcwd.cpp \
     bionic/gethostname.cpp \
@@ -546,14 +549,16 @@
 libc_arch_static_src_files := \
     bionic/dl_iterate_phdr_static.cpp \
 
-# Various kinds of LP32 cruft.
+# Various kinds of cruft.
 # ========================================================
-libc_bionic_src_files_32 += \
+libc_common_src_files += \
+    bionic/ndk_cruft.cpp \
+
+libc_bionic_ndk_src_files_32 += \
     bionic/mmap.cpp \
 
 libc_common_src_files_32 += \
     bionic/legacy_32_bit_support.cpp \
-    bionic/ndk_cruft.cpp \
     bionic/time64.c \
 
 libc_netbsd_src_files_32 += \
@@ -941,13 +946,6 @@
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -Wframe-larger-than=2048 \
 
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
 LOCAL_C_INCLUDES := $(libc_common_c_includes) bionic/libstdc++/include
@@ -960,6 +958,7 @@
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_src_files))
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -975,13 +974,6 @@
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -Wframe-larger-than=2048 \
 
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
 LOCAL_C_INCLUDES := $(libc_common_c_includes) bionic/libstdc++/include
@@ -994,7 +986,7 @@
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
-$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_src_files))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_ndk_src_files))
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -1030,13 +1022,6 @@
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -Wframe-larger-than=2048 \
 
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
@@ -1361,6 +1346,9 @@
 # meaningful name resolution.
 LOCAL_STRIP_MODULE := keep_symbols
 
+# Do not pack libc.so relocations; see http://b/20645321 for details.
+LOCAL_PACK_MODULE_RELOCATIONS := false
+
 # WARNING: The only library libc.so should depend on is libdl.so!  If you add other libraries,
 # make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries.  This
 # ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
@@ -1385,11 +1373,11 @@
 # We'd really like to do this for all architectures, but since this wasn't done
 # before, these symbols must continue to be exported on LP32 for binary
 # compatibility.
-# TODO: disabled for http://b/20065774.
-#LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
+LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
 
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
 $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_arch_dynamic_src_files))
@@ -1519,7 +1507,8 @@
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
 LOCAL_SRC_FILES := $(libstdcxx_common_src_files)
 LOCAL_MODULE:= libstdc++
diff --git a/libc/NOTICE b/libc/NOTICE
index 1fa31c2..dbe3944 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -307,34 +307,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (C) 2008-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.
-
--------------------------------------------------------------------
-
 Copyright (C) 2009 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -455,22 +427,6 @@
 -------------------------------------------------------------------
 
 Copyright (C) 2011 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
-Copyright (C) 2011 The Android Open Source Project
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -688,6 +644,50 @@
 
 -------------------------------------------------------------------
 
+Copyright (C) 2015 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 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.
+
+-------------------------------------------------------------------
+
 Copyright (c) 1980, 1983, 1988, 1993
    The Regents of the University of California.  All rights reserved.
 
@@ -2550,33 +2550,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 1995, 1996 Carnegie-Mellon University.
-All rights reserved.
-
-Author: Chris G. Demetriou
-
-Permission to use, copy, modify and distribute this software and
-its documentation is hereby granted, provided that both the copyright
-notice and this permission notice appear in all copies of the
-software, derivative works or modified versions, and any portions
-thereof, and that both notices appear in supporting documentation.
-
-CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
-CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
-FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
-
-Carnegie Mellon requests users of this software to return to
-
- Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
- School of Computer Science
- Carnegie Mellon University
- Pittsburgh PA 15213-3890
-
-any improvements or extensions that they make and grant Carnegie the
-rights to redistribute these changes.
-
--------------------------------------------------------------------
-
 Copyright (c) 1996 by Internet Software Consortium.
 
 Permission to use, copy, modify, and distribute this software for any
@@ -3795,6 +3768,22 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
 Copyright (c) 2007-2008  Michael G Schwern
 
 This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
@@ -4733,31 +4722,6 @@
 
 -------------------------------------------------------------------
 
-Copyright 2000 David E. O'Brien, John D. Polstra.
-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 ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
 Copyright 2008  Android Open Source Project (source port randomization)
 Copyright (c) 1985, 1989, 1993
    The Regents of the University of California.  All rights reserved.
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 33e30eb..ffab9f6 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -122,8 +122,8 @@
 int         fchown:fchown32(int, uid_t, gid_t)  arm,x86
 int         fchown:fchown(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
 void        sync(void)  all
-int         fsetxattr(int, const char*, const void*, size_t, int) all
-ssize_t     fgetxattr(int, const char*, void*, size_t) all
+int         ___fsetxattr:fsetxattr(int, const char*, const void*, size_t, int) all
+ssize_t     ___fgetxattr:fgetxattr(int, const char*, void*, size_t) all
 ssize_t     flistxattr(int, char*, size_t) all
 int         fremovexattr(int, const char*) all
 
@@ -151,7 +151,6 @@
 off_t lseek(int, off_t, int) arm,mips,x86
 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
 off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64
-int ftruncate(int, off_t) arm,mips,x86
 int ftruncate64(int, off64_t) arm,mips,x86
 int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64
 ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86
@@ -223,7 +222,7 @@
 int     __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t)  all
 int     __rt_sigsuspend:rt_sigsuspend(const sigset_t*, size_t)  all
 int     __rt_sigtimedwait:rt_sigtimedwait(const sigset_t*, struct siginfo_t*, struct timespec_t*, size_t)  all
-int     __rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*)  all
+int     ___rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*)  all
 int     __signalfd4:signalfd4(int, const sigset_t*, size_t, int)  all
 
 # sockets
@@ -309,6 +308,9 @@
 int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*)  all
 int __ppoll:ppoll(pollfd*, unsigned int, timespec*, const sigset_t*, size_t)  all
 
+ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long)  all
+ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long)  all
+
 int __set_tid_address:set_tid_address(int*)  all
 
 int setfsgid(gid_t)  all
diff --git a/libc/arch-arm/bionic/__bionic_clone.S b/libc/arch-arm/bionic/__bionic_clone.S
index a268f9d..b771357 100644
--- a/libc/arch-arm/bionic/__bionic_clone.S
+++ b/libc/arch-arm/bionic/__bionic_clone.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2010 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index 299f5a2..8ee6ac2 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -35,6 +35,7 @@
  */
 
     .fpu    neon
+    .syntax unified
 
 ENTRY(__memset_chk)
         cmp         r2, r3
@@ -100,9 +101,9 @@
 1:      bge         2f
         vst1.32     {d0[0]}, [r0]!
 2:      movs        ip, r2, lsl #31
-        strmib      r1, [r0], #1
-        strcsb      r1, [r0], #1
-        strcsb      r1, [r0], #1
+        strbmi      r1, [r0], #1
+        strbcs      r1, [r0], #1
+        strbcs      r1, [r0], #1
         ldmfd       sp!, {r0}
         bx          lr
 END(memset)
@@ -131,11 +132,11 @@
         orr         r1, r1, r1, lsr #16
 
         movs        r12, r3, lsl #31
-        strcsb      r1, [r0], #1    /* can't use strh (alignment unknown) */
-        strcsb      r1, [r0], #1
-        strmib      r1, [r0], #1
+        strbcs      r1, [r0], #1    /* can't use strh (alignment unknown) */
+        strbcs      r1, [r0], #1
+        strbmi      r1, [r0], #1
         subs        r2, r2, r3
-        ldmlsfd     sp!, {r0, r4-r7, lr}   /* return */
+        popls       {r0, r4-r7, lr}   /* return */
         bxls        lr
 
         /* align the destination to a cache-line */
@@ -155,9 +156,9 @@
 
         /* conditionally writes 0 to 7 words (length in r3) */
         movs        r3, r3, lsl #28
-        stmcsia     r0!, {r1, lr}
-        stmcsia     r0!, {r1, lr}
-        stmmiia     r0!, {r1, lr}
+        stmcs       r0!, {r1, lr}
+        stmcs       r0!, {r1, lr}
+        stmmi       r0!, {r1, lr}
         movs        r3, r3, lsl #2
         strcs       r1, [r0], #4
 
@@ -172,13 +173,13 @@
 
         /* conditionally stores 0 to 31 bytes */
         movs        r2, r2, lsl #28
-        stmcsia     r0!, {r1,r3,r12,lr}
-        stmmiia     r0!, {r1, lr}
+        stmcs       r0!, {r1,r3,r12,lr}
+        stmmi       r0!, {r1, lr}
         movs        r2, r2, lsl #2
         strcs       r1, [r0], #4
-        strmih      r1, [r0], #2
+        strhmi      r1, [r0], #2
         movs        r2, r2, lsl #2
-        strcsb      r1, [r0]
+        strbcs      r1, [r0]
         ldmfd       sp!, {r0, r4-r7, lr}
         bx          lr
 END(__memset_large_copy)
diff --git a/libc/arch-arm/generic/bionic/memcmp.S b/libc/arch-arm/generic/bionic/memcmp.S
index 70a2a58..c78dbd4 100644
--- a/libc/arch-arm/generic/bionic/memcmp.S
+++ b/libc/arch-arm/generic/bionic/memcmp.S
@@ -40,6 +40,8 @@
  * Optimized memcmp() for Cortex-A9.
  */
 
+.syntax unified
+
 ENTRY(memcmp)
         pld         [r0, #(CACHE_LINE_SIZE * 0)]
         pld         [r0, #(CACHE_LINE_SIZE * 1)]
@@ -161,25 +163,25 @@
         eors        r0, r0, ip
         ldreq       r0, [r4], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r4], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r4], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r4], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r4], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r4], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r4], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         bne         2f
         subs        r2, r2, #32
         bhs         0b
@@ -263,17 +265,17 @@
         ldreq       lr, [r1], #4
         ldreq       r0, [r4], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         moveq       ip, lr, lsr #16
         ldreq       lr, [r1], #4
         ldreq       r0, [r4], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         moveq       ip, lr, lsr #16
         ldreq       lr, [r1], #4
         ldreq       r0, [r4], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         bne         7f
         subs        r2, r2, #16
         bhs         6b
@@ -317,7 +319,7 @@
         ldreq       r7, [r1], #4
         ldreq       r0, [r4], #4
         orreq       ip, ip, r7, lsl r6
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         bne         7f
         subs        r2, r2, #8
         bhs         6b
diff --git a/libc/arch-arm/generic/bionic/memcpy.S b/libc/arch-arm/generic/bionic/memcpy.S
index b0c79ab..ea5a399 100644
--- a/libc/arch-arm/generic/bionic/memcpy.S
+++ b/libc/arch-arm/generic/bionic/memcpy.S
@@ -37,6 +37,8 @@
          * so we have to preserve R0.
          */
 
+         .syntax unified
+
 ENTRY(__memcpy_chk)
         cmp         r2, r3
         bhi         __memcpy_chk_fail
@@ -81,12 +83,12 @@
          */
         movs        r12, r3, lsl #31
         sub         r2, r2, r3      /* we know that r3 <= r2 because r2 >= 4 */
-        ldrmib      r3, [r1], #1
-        ldrcsb      r4, [r1], #1
-        ldrcsb      r12,[r1], #1
-        strmib      r3, [r0], #1
-        strcsb      r4, [r0], #1
-        strcsb      r12,[r0], #1
+        ldrbmi      r3, [r1], #1
+        ldrbcs      r4, [r1], #1
+        ldrbcs      r12,[r1], #1
+        strbmi      r3, [r0], #1
+        strbcs      r4, [r0], #1
+        strbcs      r12,[r0], #1
 
 .Lsrc_aligned:
 
@@ -109,10 +111,10 @@
 
         /* conditionally copies 0 to 7 words (length in r3) */
         movs        r12, r3, lsl #28
-        ldmcsia     r1!, {r4, r5, r6, r7}   /* 16 bytes */
-        ldmmiia     r1!, {r8, r9}           /*  8 bytes */
-        stmcsia     r0!, {r4, r5, r6, r7}
-        stmmiia     r0!, {r8, r9}
+        ldmcs       r1!, {r4, r5, r6, r7}   /* 16 bytes */
+        ldmmi       r1!, {r8, r9}           /*  8 bytes */
+        stmcs       r0!, {r4, r5, r6, r7}
+        stmmi       r0!, {r8, r9}
         tst         r3, #0x4
         ldrne       r10,[r1], #4            /*  4 bytes */
         strne       r10,[r0], #4
@@ -177,18 +179,18 @@
 
         /* conditionnaly copies 0 to 31 bytes */
         movs        r12, r2, lsl #28
-        ldmcsia     r1!, {r4, r5, r6, r7}   /* 16 bytes */
-        ldmmiia     r1!, {r8, r9}           /*  8 bytes */
-        stmcsia     r0!, {r4, r5, r6, r7}
-        stmmiia     r0!, {r8, r9}
+        ldmcs       r1!, {r4, r5, r6, r7}   /* 16 bytes */
+        ldmmi       r1!, {r8, r9}           /*  8 bytes */
+        stmcs       r0!, {r4, r5, r6, r7}
+        stmmi       r0!, {r8, r9}
         movs        r12, r2, lsl #30
         ldrcs       r3, [r1], #4            /*  4 bytes */
-        ldrmih      r4, [r1], #2            /*  2 bytes */
+        ldrhmi      r4, [r1], #2            /*  2 bytes */
         strcs       r3, [r0], #4
-        strmih      r4, [r0], #2
+        strhmi      r4, [r0], #2
         tst         r2, #0x1
-        ldrneb      r3, [r1]                /*  last byte  */
-        strneb      r3, [r0]
+        ldrbne      r3, [r1]                /*  last byte  */
+        strbne      r3, [r0]
 
         /* we're done! restore everything and return */
 1:      ldmfd       sp!, {r5-r11}
@@ -228,11 +230,11 @@
          * becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
          */
         movs        r5, r5, lsl #31
-        strmib      r3, [r0], #1
+        strbmi      r3, [r0], #1
         movmi       r3, r3, lsr #8
-        strcsb      r3, [r0], #1
+        strbcs      r3, [r0], #1
         movcs       r3, r3, lsr #8
-        strcsb      r3, [r0], #1
+        strbcs      r3, [r0], #1
         movcs       r3, r3, lsr #8
 
         cmp         r2, #4
@@ -363,23 +365,23 @@
 .Lpartial_word_tail:
         /* we have a partial word in the input buffer */
         movs        r5, lr, lsl #(31-3)
-        strmib      r3, [r0], #1
+        strbmi      r3, [r0], #1
         movmi       r3, r3, lsr #8
-        strcsb      r3, [r0], #1
+        strbcs      r3, [r0], #1
         movcs       r3, r3, lsr #8
-        strcsb      r3, [r0], #1
+        strbcs      r3, [r0], #1
 
         /* Refill spilled registers from the stack. Don't update sp. */
         ldmfd       sp, {r5-r11}
 
 .Lcopy_last_3_and_return:
         movs        r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */
-        ldrmib      r2, [r1], #1
-        ldrcsb      r3, [r1], #1
-        ldrcsb      r12,[r1]
-        strmib      r2, [r0], #1
-        strcsb      r3, [r0], #1
-        strcsb      r12,[r0]
+        ldrbmi      r2, [r1], #1
+        ldrbcs      r3, [r1], #1
+        ldrbcs      r12,[r1]
+        strbmi      r2, [r0], #1
+        strbcs      r3, [r0], #1
+        strbcs      r12,[r0]
 
         /* we're done! restore sp and spilled registers and return */
         add         sp,  sp, #28
diff --git a/libc/arch-arm/generic/bionic/memset.S b/libc/arch-arm/generic/bionic/memset.S
index be35de9..d17a9c4 100644
--- a/libc/arch-arm/generic/bionic/memset.S
+++ b/libc/arch-arm/generic/bionic/memset.S
@@ -35,6 +35,8 @@
          * memset() returns its first argument.
          */
 
+         .syntax unified
+
 ENTRY(__memset_chk)
         cmp         r2, r3
         bls         done
@@ -76,11 +78,11 @@
         orr         r1, r1, r1, lsr #16
 
         movs        r12, r3, lsl #31
-        strcsb      r1, [r0], #1    /* can't use strh (alignment unknown) */
-        strcsb      r1, [r0], #1
-        strmib      r1, [r0], #1
+        strbcs      r1, [r0], #1    /* can't use strh (alignment unknown) */
+        strbcs      r1, [r0], #1
+        strbmi      r1, [r0], #1
         subs        r2, r2, r3
-        ldmlsfd     sp!, {r0, r4-r7, lr}    /* return */
+        popls       {r0, r4-r7, lr}    /* return */
         bxls        lr
 
         /* align the destination to a cache-line */
@@ -100,9 +102,9 @@
 
         /* conditionally writes 0 to 7 words (length in r3) */
         movs        r3, r3, lsl #28
-        stmcsia     r0!, {r1, lr}
-        stmcsia     r0!, {r1, lr}
-        stmmiia     r0!, {r1, lr}
+        stmcs       r0!, {r1, lr}
+        stmcs       r0!, {r1, lr}
+        stmmi       r0!, {r1, lr}
         movs        r3, r3, lsl #2
         strcs       r1, [r0], #4
 
@@ -117,13 +119,13 @@
 
         /* conditionally stores 0 to 31 bytes */
         movs        r2, r2, lsl #28
-        stmcsia     r0!, {r1,r3,r12,lr}
-        stmmiia     r0!, {r1, lr}
+        stmcs       r0!, {r1,r3,r12,lr}
+        stmmi       r0!, {r1, lr}
         movs        r2, r2, lsl #2
         strcs       r1, [r0], #4
-        strmih      r1, [r0], #2
+        strhmi      r1, [r0], #2
         movs        r2, r2, lsl #2
-        strcsb      r1, [r0]
+        strbcs      r1, [r0]
         ldmfd       sp!, {r0, r4-r7, lr}
         bx          lr
 END(memset)
diff --git a/libc/arch-arm/generic/bionic/strcpy.S b/libc/arch-arm/generic/bionic/strcpy.S
index 802a62d..89ea098 100644
--- a/libc/arch-arm/generic/bionic/strcpy.S
+++ b/libc/arch-arm/generic/bionic/strcpy.S
@@ -32,6 +32,8 @@
 #include <machine/cpu-features.h>
 #include <private/bionic_asm.h>
 
+.syntax unified
+
 ENTRY(strcpy)
 	pld	[r1, #0]
 	eor	r2, r0, r1
@@ -108,15 +110,15 @@
 #ifdef __ARMEB__
 	tst	r2, #0xff00
 	iteet	ne
-	strneh	r2, [ip], #2
+	strhne	r2, [ip], #2
 	lsreq	r2, r2, #8
-	streqb	r2, [ip]
+	strbeq	r2, [ip]
 	tstne	r2, #0xff
 #else
 	tst	r2, #0xff
 	itet	ne
-	strneh	r2, [ip], #2
-	streqb	r2, [ip]
+	strhne	r2, [ip], #2
+	strbeq	r2, [ip]
 	tstne	r2, #0xff00
 #endif
 	bne	5b
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index e9f6431..a4fbe17 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -37,6 +37,7 @@
  */
 
     .fpu    neon
+    .syntax unified
 
 ENTRY(__memset_chk)
         cmp         r2, r3
@@ -98,9 +99,9 @@
 1:      bge         2f
         vst1.32     {d0[0]}, [r0]!
 2:      movs        ip, r2, lsl #31
-        strmib      r1, [r0], #1
-        strcsb      r1, [r0], #1
-        strcsb      r1, [r0], #1
+        strbmi      r1, [r0], #1
+        strbcs      r1, [r0], #1
+        strbcs      r1, [r0], #1
         ldmfd       sp!, {r0}
         bx          lr
 END(memset)
diff --git a/libc/arch-arm/syscalls/fgetxattr.S b/libc/arch-arm/syscalls/___fgetxattr.S
similarity index 81%
rename from libc/arch-arm/syscalls/fgetxattr.S
rename to libc/arch-arm/syscalls/___fgetxattr.S
index 3f1e5fc..e776cd6 100644
--- a/libc/arch-arm/syscalls/fgetxattr.S
+++ b/libc/arch-arm/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     mov     ip, r7
     ldr     r7, =__NR_fgetxattr
     swi     #0
@@ -11,4 +11,5 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-arm/syscalls/fsetxattr.S b/libc/arch-arm/syscalls/___fsetxattr.S
similarity index 89%
rename from libc/arch-arm/syscalls/fsetxattr.S
rename to libc/arch-arm/syscalls/___fsetxattr.S
index 0e33ad2..5445191 100644
--- a/libc/arch-arm/syscalls/fsetxattr.S
+++ b/libc/arch-arm/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     mov     ip, sp
     stmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 16
@@ -19,4 +19,5 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-arm/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm/syscalls/___rt_sigqueueinfo.S
similarity index 78%
rename from libc/arch-arm/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-arm/syscalls/___rt_sigqueueinfo.S
index c823cee..25b0d57 100644
--- a/libc/arch-arm/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-arm/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     mov     ip, r7
     ldr     r7, =__NR_rt_sigqueueinfo
     swi     #0
@@ -11,4 +11,5 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-arm/syscalls/ftruncate.S b/libc/arch-arm/syscalls/ftruncate.S
deleted file mode 100644
index 1bfe2f3..0000000
--- a/libc/arch-arm/syscalls/ftruncate.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(ftruncate)
-    mov     ip, r7
-    ldr     r7, =__NR_ftruncate
-    swi     #0
-    mov     r7, ip
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno_internal
-END(ftruncate)
diff --git a/libc/arch-arm/syscalls/fsetxattr.S b/libc/arch-arm/syscalls/process_vm_readv.S
similarity index 84%
copy from libc/arch-arm/syscalls/fsetxattr.S
copy to libc/arch-arm/syscalls/process_vm_readv.S
index 0e33ad2..48c49dc 100644
--- a/libc/arch-arm/syscalls/fsetxattr.S
+++ b/libc/arch-arm/syscalls/process_vm_readv.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_readv)
     mov     ip, sp
     stmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 16
@@ -11,7 +11,7 @@
     .cfi_rel_offset r6, 8
     .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
-    ldr     r7, =__NR_fsetxattr
+    ldr     r7, =__NR_process_vm_readv
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 0
@@ -19,4 +19,4 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(fsetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-arm/syscalls/fsetxattr.S b/libc/arch-arm/syscalls/process_vm_writev.S
similarity index 83%
copy from libc/arch-arm/syscalls/fsetxattr.S
copy to libc/arch-arm/syscalls/process_vm_writev.S
index 0e33ad2..4c21c43 100644
--- a/libc/arch-arm/syscalls/fsetxattr.S
+++ b/libc/arch-arm/syscalls/process_vm_writev.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_writev)
     mov     ip, sp
     stmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 16
@@ -11,7 +11,7 @@
     .cfi_rel_offset r6, 8
     .cfi_rel_offset r7, 12
     ldmfd   ip, {r4, r5, r6}
-    ldr     r7, =__NR_fsetxattr
+    ldr     r7, =__NR_process_vm_writev
     swi     #0
     ldmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 0
@@ -19,4 +19,4 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(fsetxattr)
+END(process_vm_writev)
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index 6a2f313..470a038 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -40,8 +40,6 @@
     arch-arm64/bionic/syscall.S \
     arch-arm64/bionic/vfork.S \
 
-# Work around for http://b/20065774.
-libc_bionic_src_files_arm64 += arch-arm64/bionic/libgcc_compat.c
 
 libc_crt_target_cflags_arm64 := \
     -I$(LOCAL_PATH)/arch-arm64/include
diff --git a/libc/arch-arm64/bionic/libgcc_compat.c b/libc/arch-arm64/bionic/libgcc_compat.c
deleted file mode 100644
index 2dae3f5..0000000
--- a/libc/arch-arm64/bionic/libgcc_compat.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* STOPSHIP: remove this once the flounder blobs have been rebuilt (http://b/20065774). */
-
-#if !defined(__clang__)
-
-extern void __clear_cache(char*, char*);
-extern char _Unwind_Backtrace;
-extern char _Unwind_GetIP;
-
-void* __bionic_libgcc_compat_symbols[] = {
-    &__clear_cache,
-    &_Unwind_Backtrace,
-    &_Unwind_GetIP,
-};
-
-#endif
diff --git a/libc/arch-arm64/generic/bionic/memchr.S b/libc/arch-arm64/generic/bionic/memchr.S
index e5ea57d..a00dd8d 100644
--- a/libc/arch-arm64/generic/bionic/memchr.S
+++ b/libc/arch-arm64/generic/bionic/memchr.S
@@ -101,7 +101,7 @@
 	and	vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b
 	addp	vend.16b, vhas_chr1.16b, vhas_chr2.16b		/* 256->128 */
 	addp	vend.16b, vend.16b, vend.16b			/* 128->64 */
-	mov	synd, vend.2d[0]
+	mov	synd, vend.d[0]
 	/* Clear the soff*2 lower bits */
 	lsl	tmp, soff, #1
 	lsr	synd, synd, tmp
@@ -121,7 +121,7 @@
 	/* Use a fast check for the termination condition */
 	orr	vend.16b, vhas_chr1.16b, vhas_chr2.16b
 	addp	vend.2d, vend.2d, vend.2d
-	mov	synd, vend.2d[0]
+	mov	synd, vend.d[0]
 	/* We're not out of data, loop if we haven't found the character */
 	cbz	synd, .Lloop
 
@@ -131,7 +131,7 @@
 	and	vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b
 	addp	vend.16b, vhas_chr1.16b, vhas_chr2.16b		/* 256->128 */
 	addp	vend.16b, vend.16b, vend.16b			/* 128->64 */
-	mov	synd, vend.2d[0]
+	mov	synd, vend.d[0]
 	/* Only do the clear for the last possible block */
 	b.hi	.Ltail
 
diff --git a/libc/arch-arm64/generic/bionic/strchr.S b/libc/arch-arm64/generic/bionic/strchr.S
index 469b83c..b54106d 100644
--- a/libc/arch-arm64/generic/bionic/strchr.S
+++ b/libc/arch-arm64/generic/bionic/strchr.S
@@ -109,7 +109,7 @@
 	addp	vend1.16b, vend1.16b, vend2.16b		// 128->64
 	lsr	tmp1, tmp3, tmp1
 
-	mov	tmp3, vend1.2d[0]
+	mov	tmp3, vend1.d[0]
 	bic	tmp1, tmp3, tmp1	// Mask padding bits.
 	cbnz	tmp1, .Ltail
 
@@ -124,7 +124,7 @@
 	orr	vend2.16b, vhas_nul2.16b, vhas_chr2.16b
 	orr	vend1.16b, vend1.16b, vend2.16b
 	addp	vend1.2d, vend1.2d, vend1.2d
-	mov	tmp1, vend1.2d[0]
+	mov	tmp1, vend1.d[0]
 	cbz	tmp1, .Lloop
 
 	/* Termination condition found.  Now need to establish exactly why
@@ -138,7 +138,7 @@
 	addp	vend1.16b, vend1.16b, vend2.16b		// 256->128
 	addp	vend1.16b, vend1.16b, vend2.16b		// 128->64
 
-	mov	tmp1, vend1.2d[0]
+	mov	tmp1, vend1.d[0]
 .Ltail:
 	/* Count the trailing zeros, by bit reversing...  */
 	rbit	tmp1, tmp1
diff --git a/libc/arch-arm64/syscalls/fgetxattr.S b/libc/arch-arm64/syscalls/___fgetxattr.S
similarity index 79%
rename from libc/arch-arm64/syscalls/fgetxattr.S
rename to libc/arch-arm64/syscalls/___fgetxattr.S
index 0d6ada7..c0334cc 100644
--- a/libc/arch-arm64/syscalls/fgetxattr.S
+++ b/libc/arch-arm64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     mov     x8, __NR_fgetxattr
     svc     #0
 
@@ -11,4 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-arm64/syscalls/fsetxattr.S b/libc/arch-arm64/syscalls/___fsetxattr.S
similarity index 79%
rename from libc/arch-arm64/syscalls/fsetxattr.S
rename to libc/arch-arm64/syscalls/___fsetxattr.S
index e69e718..92be8de 100644
--- a/libc/arch-arm64/syscalls/fsetxattr.S
+++ b/libc/arch-arm64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     mov     x8, __NR_fsetxattr
     svc     #0
 
@@ -11,4 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm64/syscalls/___rt_sigqueueinfo.S
similarity index 75%
rename from libc/arch-arm64/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-arm64/syscalls/___rt_sigqueueinfo.S
index 2b23e18..85ea132 100644
--- a/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-arm64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     mov     x8, __NR_rt_sigqueueinfo
     svc     #0
 
@@ -11,5 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-arm64/syscalls/fgetxattr.S b/libc/arch-arm64/syscalls/process_vm_readv.S
similarity index 69%
copy from libc/arch-arm64/syscalls/fgetxattr.S
copy to libc/arch-arm64/syscalls/process_vm_readv.S
index 0d6ada7..1dd113b 100644
--- a/libc/arch-arm64/syscalls/fgetxattr.S
+++ b/libc/arch-arm64/syscalls/process_vm_readv.S
@@ -2,8 +2,8 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
-    mov     x8, __NR_fgetxattr
+ENTRY(process_vm_readv)
+    mov     x8, __NR_process_vm_readv
     svc     #0
 
     cmn     x0, #(MAX_ERRNO + 1)
@@ -11,4 +11,4 @@
     b.hi    __set_errno_internal
 
     ret
-END(fgetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-arm64/syscalls/fgetxattr.S b/libc/arch-arm64/syscalls/process_vm_writev.S
similarity index 69%
copy from libc/arch-arm64/syscalls/fgetxattr.S
copy to libc/arch-arm64/syscalls/process_vm_writev.S
index 0d6ada7..fb29cf8 100644
--- a/libc/arch-arm64/syscalls/fgetxattr.S
+++ b/libc/arch-arm64/syscalls/process_vm_writev.S
@@ -2,8 +2,8 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
-    mov     x8, __NR_fgetxattr
+ENTRY(process_vm_writev)
+    mov     x8, __NR_process_vm_writev
     svc     #0
 
     cmn     x0, #(MAX_ERRNO + 1)
@@ -11,4 +11,4 @@
     b.hi    __set_errno_internal
 
     ret
-END(fgetxattr)
+END(process_vm_writev)
diff --git a/libc/arch-common/bionic/asm_multiarch.h b/libc/arch-common/bionic/asm_multiarch.h
index 85e1b57..91cb8af 100644
--- a/libc/arch-common/bionic/asm_multiarch.h
+++ b/libc/arch-common/bionic/asm_multiarch.h
@@ -28,9 +28,9 @@
 
 #ifdef __LP64__
 # define ASM_PTR_SIZE(x) .quad x
-# define ASM_ALIGN(x)
+# define ASM_ALIGN_TO_PTR_SIZE .balign 8
 #else
 # define ASM_PTR_SIZE(x) .long x
-# define ASM_ALIGN(x)    .align x
+# define ASM_ALIGN_TO_PTR_SIZE .balign 4
 #endif
 
diff --git a/libc/arch-common/bionic/crtend.S b/libc/arch-common/bionic/crtend.S
index a4cf8de..87d1120 100644
--- a/libc/arch-common/bionic/crtend.S
+++ b/libc/arch-common/bionic/crtend.S
@@ -29,12 +29,15 @@
 #include "asm_multiarch.h"
 
 	.section .preinit_array, "aw"
+	ASM_ALIGN_TO_PTR_SIZE
 	ASM_PTR_SIZE(0)
 
 	.section .init_array, "aw"
+	ASM_ALIGN_TO_PTR_SIZE
 	ASM_PTR_SIZE(0)
 
 	.section .fini_array, "aw"
+	ASM_ALIGN_TO_PTR_SIZE
 	ASM_PTR_SIZE(0)
 
 #if defined(__linux__) && defined(__ELF__)
@@ -42,7 +45,9 @@
 #endif
 #if defined(__i386__) || defined(__x86_64__)
 	.section	.eh_frame,"a",@progbits
-	ASM_ALIGN(4)
+#if defined(__i386__)
+	.balign 4
+#endif
 	.type	__FRAME_END__, @object
 	.size	__FRAME_END__, 4
 __FRAME_END__:
diff --git a/libc/arch-common/bionic/crtend_so.S b/libc/arch-common/bionic/crtend_so.S
index f745109..e7b8cac 100644
--- a/libc/arch-common/bionic/crtend_so.S
+++ b/libc/arch-common/bionic/crtend_so.S
@@ -26,22 +26,14 @@
  * SUCH DAMAGE.
  */
 
-#include "asm_multiarch.h"
-
-#ifndef __arm__
-	.section .init_array, "aw"
-	ASM_PTR_SIZE(0)
-
-	.section .fini_array, "aw"
-	ASM_PTR_SIZE(0)
-#endif
-
 #if defined(__linux__) && defined(__ELF__)
 	.section .note.GNU-stack,"",%progbits
 #endif
 #if defined(__i386__) || defined(__x86_64__)
 	.section	.eh_frame,"a",@progbits
-	ASM_ALIGN(4)
+#if defined(__i386__)
+	.balign 4
+#endif
 	.type	__FRAME_END__, @object
 	.size	__FRAME_END__, 4
 __FRAME_END__:
diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S
index bed9562..3ef0f11 100644
--- a/libc/arch-mips/bionic/setjmp.S
+++ b/libc/arch-mips/bionic/setjmp.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/libc/arch-mips/syscalls/fgetxattr.S b/libc/arch-mips/syscalls/___fgetxattr.S
similarity index 82%
rename from libc/arch-mips/syscalls/fgetxattr.S
rename to libc/arch-mips/syscalls/___fgetxattr.S
index 6516feb..50ab69c 100644
--- a/libc/arch-mips/syscalls/fgetxattr.S
+++ b/libc/arch-mips/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     .set noreorder
     .cpload t9
     li v0, __NR_fgetxattr
@@ -16,4 +16,5 @@
     j t9
     nop
     .set reorder
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-mips/syscalls/fsetxattr.S b/libc/arch-mips/syscalls/___fsetxattr.S
similarity index 82%
rename from libc/arch-mips/syscalls/fsetxattr.S
rename to libc/arch-mips/syscalls/___fsetxattr.S
index 663c0df..0312921 100644
--- a/libc/arch-mips/syscalls/fsetxattr.S
+++ b/libc/arch-mips/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     .set noreorder
     .cpload t9
     li v0, __NR_fsetxattr
@@ -16,4 +16,5 @@
     j t9
     nop
     .set reorder
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-mips/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips/syscalls/___rt_sigqueueinfo.S
similarity index 78%
rename from libc/arch-mips/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-mips/syscalls/___rt_sigqueueinfo.S
index a978bc4..95af36f 100644
--- a/libc/arch-mips/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-mips/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     .set noreorder
     .cpload t9
     li v0, __NR_rt_sigqueueinfo
@@ -16,4 +16,5 @@
     j t9
     nop
     .set reorder
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-mips/syscalls/ftruncate.S b/libc/arch-mips/syscalls/ftruncate.S
deleted file mode 100644
index 0589c81..0000000
--- a/libc/arch-mips/syscalls/ftruncate.S
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(ftruncate)
-    .set noreorder
-    .cpload t9
-    li v0, __NR_ftruncate
-    syscall
-    bnez a3, 1f
-    move a0, v0
-    j ra
-    nop
-1:
-    la t9,__set_errno_internal
-    j t9
-    nop
-    .set reorder
-END(ftruncate)
diff --git a/libc/arch-mips/syscalls/fsetxattr.S b/libc/arch-mips/syscalls/process_vm_readv.S
similarity index 75%
copy from libc/arch-mips/syscalls/fsetxattr.S
copy to libc/arch-mips/syscalls/process_vm_readv.S
index 663c0df..22b74f0 100644
--- a/libc/arch-mips/syscalls/fsetxattr.S
+++ b/libc/arch-mips/syscalls/process_vm_readv.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_readv)
     .set noreorder
     .cpload t9
-    li v0, __NR_fsetxattr
+    li v0, __NR_process_vm_readv
     syscall
     bnez a3, 1f
     move a0, v0
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(fsetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-mips/syscalls/fsetxattr.S b/libc/arch-mips/syscalls/process_vm_writev.S
similarity index 74%
copy from libc/arch-mips/syscalls/fsetxattr.S
copy to libc/arch-mips/syscalls/process_vm_writev.S
index 663c0df..dd1dc4b 100644
--- a/libc/arch-mips/syscalls/fsetxattr.S
+++ b/libc/arch-mips/syscalls/process_vm_writev.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_writev)
     .set noreorder
     .cpload t9
-    li v0, __NR_fsetxattr
+    li v0, __NR_process_vm_writev
     syscall
     bnez a3, 1f
     move a0, v0
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(fsetxattr)
+END(process_vm_writev)
diff --git a/libc/arch-mips64/syscalls/fgetxattr.S b/libc/arch-mips64/syscalls/___fgetxattr.S
similarity index 85%
rename from libc/arch-mips64/syscalls/fgetxattr.S
rename to libc/arch-mips64/syscalls/___fgetxattr.S
index 44c248a..935b080 100644
--- a/libc/arch-mips64/syscalls/fgetxattr.S
+++ b/libc/arch-mips64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     .set push
     .set noreorder
     li v0, __NR_fgetxattr
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-mips64/syscalls/fsetxattr.S b/libc/arch-mips64/syscalls/___fsetxattr.S
similarity index 85%
rename from libc/arch-mips64/syscalls/fsetxattr.S
rename to libc/arch-mips64/syscalls/___fsetxattr.S
index 0ad1f90..c02f406 100644
--- a/libc/arch-mips64/syscalls/fsetxattr.S
+++ b/libc/arch-mips64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     .set push
     .set noreorder
     li v0, __NR_fsetxattr
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips64/syscalls/___rt_sigqueueinfo.S
similarity index 82%
rename from libc/arch-mips64/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-mips64/syscalls/___rt_sigqueueinfo.S
index e97aeba..1503f51 100644
--- a/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-mips64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     .set push
     .set noreorder
     li v0, __NR_rt_sigqueueinfo
@@ -22,5 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-mips64/syscalls/fsetxattr.S b/libc/arch-mips64/syscalls/process_vm_readv.S
similarity index 80%
copy from libc/arch-mips64/syscalls/fsetxattr.S
copy to libc/arch-mips64/syscalls/process_vm_readv.S
index 0ad1f90..f3c7372 100644
--- a/libc/arch-mips64/syscalls/fsetxattr.S
+++ b/libc/arch-mips64/syscalls/process_vm_readv.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_readv)
     .set push
     .set noreorder
-    li v0, __NR_fsetxattr
+    li v0, __NR_process_vm_readv
     syscall
     bnez a3, 1f
     move a0, v0
@@ -22,4 +22,4 @@
     j t9
     move ra, t0
     .set pop
-END(fsetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-mips64/syscalls/fsetxattr.S b/libc/arch-mips64/syscalls/process_vm_writev.S
similarity index 79%
copy from libc/arch-mips64/syscalls/fsetxattr.S
copy to libc/arch-mips64/syscalls/process_vm_writev.S
index 0ad1f90..0e8140b 100644
--- a/libc/arch-mips64/syscalls/fsetxattr.S
+++ b/libc/arch-mips64/syscalls/process_vm_writev.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_writev)
     .set push
     .set noreorder
-    li v0, __NR_fsetxattr
+    li v0, __NR_process_vm_writev
     syscall
     bnez a3, 1f
     move a0, v0
@@ -22,4 +22,4 @@
     j t9
     move ra, t0
     .set pop
-END(fsetxattr)
+END(process_vm_writev)
diff --git a/libc/arch-x86/syscalls/fgetxattr.S b/libc/arch-x86/syscalls/___fgetxattr.S
similarity index 92%
rename from libc/arch-x86/syscalls/fgetxattr.S
rename to libc/arch-x86/syscalls/___fgetxattr.S
index 1eff931..2891511 100644
--- a/libc/arch-x86/syscalls/fgetxattr.S
+++ b/libc/arch-x86/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -33,4 +33,5 @@
     popl    %ecx
     popl    %ebx
     ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-x86/syscalls/fsetxattr.S b/libc/arch-x86/syscalls/___fsetxattr.S
similarity index 93%
rename from libc/arch-x86/syscalls/fsetxattr.S
rename to libc/arch-x86/syscalls/___fsetxattr.S
index 7af0ef0..287dafc 100644
--- a/libc/arch-x86/syscalls/fsetxattr.S
+++ b/libc/arch-x86/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -38,4 +38,5 @@
     popl    %ecx
     popl    %ebx
     ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-x86/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86/syscalls/___rt_sigqueueinfo.S
similarity index 89%
rename from libc/arch-x86/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-x86/syscalls/___rt_sigqueueinfo.S
index 4152100..97d167f 100644
--- a/libc/arch-x86/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-x86/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -28,4 +28,5 @@
     popl    %ecx
     popl    %ebx
     ret
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-x86/syscalls/ftruncate.S b/libc/arch-x86/syscalls/ftruncate.S
deleted file mode 100644
index 78d1e18..0000000
--- a/libc/arch-x86/syscalls/ftruncate.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(ftruncate)
-    pushl   %ebx
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset ebx, 0
-    pushl   %ecx
-    .cfi_adjust_cfa_offset 4
-    .cfi_rel_offset ecx, 0
-    mov     12(%esp), %ebx
-    mov     16(%esp), %ecx
-    movl    $__NR_ftruncate, %eax
-    int     $0x80
-    cmpl    $-MAX_ERRNO, %eax
-    jb      1f
-    negl    %eax
-    pushl   %eax
-    call    __set_errno_internal
-    addl    $4, %esp
-1:
-    popl    %ecx
-    popl    %ebx
-    ret
-END(ftruncate)
diff --git a/libc/arch-x86/syscalls/fsetxattr.S b/libc/arch-x86/syscalls/process_vm_readv.S
similarity index 66%
copy from libc/arch-x86/syscalls/fsetxattr.S
copy to libc/arch-x86/syscalls/process_vm_readv.S
index 7af0ef0..64965f6 100644
--- a/libc/arch-x86/syscalls/fsetxattr.S
+++ b/libc/arch-x86/syscalls/process_vm_readv.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_readv)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -18,12 +18,16 @@
     pushl   %edi
     .cfi_adjust_cfa_offset 4
     .cfi_rel_offset edi, 0
-    mov     24(%esp), %ebx
-    mov     28(%esp), %ecx
-    mov     32(%esp), %edx
-    mov     36(%esp), %esi
-    mov     40(%esp), %edi
-    movl    $__NR_fsetxattr, %eax
+    pushl   %ebp
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ebp, 0
+    mov     28(%esp), %ebx
+    mov     32(%esp), %ecx
+    mov     36(%esp), %edx
+    mov     40(%esp), %esi
+    mov     44(%esp), %edi
+    mov     48(%esp), %ebp
+    movl    $__NR_process_vm_readv, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
     jb      1f
@@ -32,10 +36,11 @@
     call    __set_errno_internal
     addl    $4, %esp
 1:
+    popl    %ebp
     popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
     popl    %ebx
     ret
-END(fsetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-x86/syscalls/fsetxattr.S b/libc/arch-x86/syscalls/process_vm_writev.S
similarity index 66%
copy from libc/arch-x86/syscalls/fsetxattr.S
copy to libc/arch-x86/syscalls/process_vm_writev.S
index 7af0ef0..555c822 100644
--- a/libc/arch-x86/syscalls/fsetxattr.S
+++ b/libc/arch-x86/syscalls/process_vm_writev.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_writev)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -18,12 +18,16 @@
     pushl   %edi
     .cfi_adjust_cfa_offset 4
     .cfi_rel_offset edi, 0
-    mov     24(%esp), %ebx
-    mov     28(%esp), %ecx
-    mov     32(%esp), %edx
-    mov     36(%esp), %esi
-    mov     40(%esp), %edi
-    movl    $__NR_fsetxattr, %eax
+    pushl   %ebp
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ebp, 0
+    mov     28(%esp), %ebx
+    mov     32(%esp), %ecx
+    mov     36(%esp), %edx
+    mov     40(%esp), %esi
+    mov     44(%esp), %edi
+    mov     48(%esp), %ebp
+    movl    $__NR_process_vm_writev, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
     jb      1f
@@ -32,10 +36,11 @@
     call    __set_errno_internal
     addl    $4, %esp
 1:
+    popl    %ebp
     popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
     popl    %ebx
     ret
-END(fsetxattr)
+END(process_vm_writev)
diff --git a/libc/arch-x86_64/string/ssse3-strcmp-slm.S b/libc/arch-x86_64/string/ssse3-strcmp-slm.S
index 0dd8c27..e8acd5b 100644
--- a/libc/arch-x86_64/string/ssse3-strcmp-slm.S
+++ b/libc/arch-x86_64/string/ssse3-strcmp-slm.S
@@ -1897,8 +1897,8 @@
 
 	.p2align 4
 L(Byte0):
-	movzx	(%rsi), %ecx
-	movzx	(%rdi), %eax
+	movzbl	(%rsi), %ecx
+	movzbl	(%rdi), %eax
 
 	sub	%ecx, %eax
 	ret
diff --git a/libc/arch-x86_64/syscalls/fgetxattr.S b/libc/arch-x86_64/syscalls/___fgetxattr.S
similarity index 82%
rename from libc/arch-x86_64/syscalls/fgetxattr.S
rename to libc/arch-x86_64/syscalls/___fgetxattr.S
index 7762474..302fd77 100644
--- a/libc/arch-x86_64/syscalls/fgetxattr.S
+++ b/libc/arch-x86_64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
     movq    %rcx, %r10
     movl    $__NR_fgetxattr, %eax
     syscall
@@ -13,4 +13,5 @@
     call    __set_errno_internal
 1:
     ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-x86_64/syscalls/fsetxattr.S b/libc/arch-x86_64/syscalls/___fsetxattr.S
similarity index 82%
rename from libc/arch-x86_64/syscalls/fsetxattr.S
rename to libc/arch-x86_64/syscalls/___fsetxattr.S
index 97822c4..125ef20 100644
--- a/libc/arch-x86_64/syscalls/fsetxattr.S
+++ b/libc/arch-x86_64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
     movq    %rcx, %r10
     movl    $__NR_fsetxattr, %eax
     syscall
@@ -13,4 +13,5 @@
     call    __set_errno_internal
 1:
     ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S
similarity index 77%
rename from libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S
rename to libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S
index 52b6863..8c6b30b 100644
--- a/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
     movl    $__NR_rt_sigqueueinfo, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
@@ -12,5 +12,5 @@
     call    __set_errno_internal
 1:
     ret
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-x86_64/syscalls/fsetxattr.S b/libc/arch-x86_64/syscalls/process_vm_readv.S
similarity index 73%
copy from libc/arch-x86_64/syscalls/fsetxattr.S
copy to libc/arch-x86_64/syscalls/process_vm_readv.S
index 97822c4..597649e 100644
--- a/libc/arch-x86_64/syscalls/fsetxattr.S
+++ b/libc/arch-x86_64/syscalls/process_vm_readv.S
@@ -2,9 +2,9 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_readv)
     movq    %rcx, %r10
-    movl    $__NR_fsetxattr, %eax
+    movl    $__NR_process_vm_readv, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
     jb      1f
@@ -13,4 +13,4 @@
     call    __set_errno_internal
 1:
     ret
-END(fsetxattr)
+END(process_vm_readv)
diff --git a/libc/arch-x86_64/syscalls/fsetxattr.S b/libc/arch-x86_64/syscalls/process_vm_writev.S
similarity index 73%
copy from libc/arch-x86_64/syscalls/fsetxattr.S
copy to libc/arch-x86_64/syscalls/process_vm_writev.S
index 97822c4..397c007 100644
--- a/libc/arch-x86_64/syscalls/fsetxattr.S
+++ b/libc/arch-x86_64/syscalls/process_vm_writev.S
@@ -2,9 +2,9 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fsetxattr)
+ENTRY(process_vm_writev)
     movq    %rcx, %r10
-    movl    $__NR_fsetxattr, %eax
+    movl    $__NR_process_vm_writev, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
     jb      1f
@@ -13,4 +13,4 @@
     call    __set_errno_internal
 1:
     ret
-END(fsetxattr)
+END(process_vm_writev)
diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp
index fb45398..6fd3842 100644
--- a/libc/bionic/dirent.cpp
+++ b/libc/bionic/dirent.cpp
@@ -41,13 +41,19 @@
 
 extern "C" int __getdents64(unsigned int, dirent*, unsigned int);
 
+// Apportable decided to copy the data structure from this file
+// and use it in their own code, but they also call into readdir.
+// In order to avoid a lockup, the structure must be maintained in
+// the exact same order as in L and below. New structure members
+// need to be added to the end of this structure.
+// See b/21037208 for more details.
 struct DIR {
   int fd_;
   size_t available_bytes_;
   dirent* next_;
-  long current_pos_;
   pthread_mutex_t mutex_;
   dirent buff_[15];
+  long current_pos_;
 };
 
 static DIR* __allocate_DIR(int fd) {
diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h
index 2f53c1b..054bd4f 100644
--- a/libc/bionic/dlmalloc.h
+++ b/libc/bionic/dlmalloc.h
@@ -44,11 +44,13 @@
 #define dlmalloc dlmalloc_real
 #endif
 
-/* Export two symbols used by the VM. */
-__BEGIN_DECLS
-int dlmalloc_trim(size_t) __LIBC_ABI_PUBLIC__;
-void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void*) __LIBC_ABI_PUBLIC__;
-__END_DECLS
+/* These two symbols are exported on devices that use dlmalloc.
+ * In order to be consistent across all devices, they will
+ * be exported everywhere. Move the real symbols out of the way
+ * so that ndk_cruft.cpp can export these symbols.
+ */
+#define dlmalloc_inspect_all dlmalloc_inspect_all_real
+#define dlmalloc_trim dlmalloc_trim_real
 
 /* Include the proper definitions. */
 #include "../upstream-dlmalloc/malloc.h"
diff --git a/libc/bionic/fgetxattr.cpp b/libc/bionic/fgetxattr.cpp
new file mode 100644
index 0000000..6d999bf
--- /dev/null
+++ b/libc/bionic/fgetxattr.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+extern "C" ssize_t ___fgetxattr(int, const char*, void*, size_t);
+
+ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) {
+  int saved_errno = errno;
+  ssize_t result = ___fgetxattr(fd, name, value, size);
+
+  if ((result != -1) || (errno != EBADF)) {
+    return result;
+  }
+
+  // fd could be an O_PATH file descriptor, and the kernel
+  // may not directly support fgetxattr() on such a file descriptor.
+  // Use /proc/self/fd instead to emulate this support.
+  int fd_flag = fcntl(fd, F_GETFL);
+  if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
+    errno = EBADF;
+    return -1;
+  }
+
+  char buf[40];
+  snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+  errno = saved_errno;
+  return getxattr(buf, name, value, size);
+}
diff --git a/libc/bionic/fsetxattr.cpp b/libc/bionic/fsetxattr.cpp
new file mode 100644
index 0000000..6d2e868
--- /dev/null
+++ b/libc/bionic/fsetxattr.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+extern "C" int ___fsetxattr(int, const char*, const void*, size_t, int);
+
+int fsetxattr(int fd, const char* name, const void* value, size_t size, int flags) {
+  int saved_errno = errno;
+  int result = ___fsetxattr(fd, name, value, size, flags);
+
+  if ((result == 0) || (errno != EBADF)) {
+    return result;
+  }
+
+  // fd could be an O_PATH file descriptor, and the kernel
+  // may not directly support fsetxattr() on such a file descriptor.
+  // Use /proc/self/fd instead to emulate this support.
+  int fd_flag = fcntl(fd, F_GETFL);
+  if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
+    errno = EBADF;
+    return -1;
+  }
+
+  char buf[40];
+  snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+  errno = saved_errno;
+  return setxattr(buf, name, value, size, flags);
+}
diff --git a/libc/bionic/ftruncate.cpp b/libc/bionic/ftruncate.cpp
new file mode 100644
index 0000000..9936df0
--- /dev/null
+++ b/libc/bionic/ftruncate.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+#if !defined(__LP64__)
+static_assert(sizeof(off_t) == 4,
+              "libc can't be built with _FILE_OFFSET_BITS=64.");
+
+// The kernel's implementation of ftruncate uses an unsigned long for the length
+// parameter, so it will not catch negative values. On the other hand
+// ftruncate64 does check for this, so just forward the call.
+int ftruncate(int filedes, off_t length) {
+  return ftruncate64(filedes, length);
+}
+#endif  // !defined(__LP64__)
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 36dc085..9b23ece 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -30,10 +30,12 @@
 
 #include <elf.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/auxv.h>
 #include <sys/time.h>
 #include <unistd.h>
@@ -120,6 +122,198 @@
   __libc_init_vdso();
 }
 
+__noreturn static void __early_abort(int line) {
+  // We can't write to stdout or stderr because we're aborting before we've checked that
+  // it's safe for us to use those file descriptors. We probably can't strace either, so
+  // we rely on the fact that if we dereference a low address, either debuggerd or the
+  // kernel's crash dump will show the fault address.
+  *reinterpret_cast<int*>(line) = 0;
+  _exit(EXIT_FAILURE);
+}
+
+// Force any of the closed stdin, stdout and stderr to be associated with /dev/null.
+static void __nullify_closed_stdio() {
+  int dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
+  if (dev_null == -1) {
+    // init won't have /dev/null available, but SELinux provides an equivalent.
+    dev_null = TEMP_FAILURE_RETRY(open("/sys/fs/selinux/null", O_RDWR));
+  }
+  if (dev_null == -1) {
+    __early_abort(__LINE__);
+  }
+
+  // If any of the stdio file descriptors is valid and not associated
+  // with /dev/null, dup /dev/null to it.
+  for (int i = 0; i < 3; i++) {
+    // If it is /dev/null already, we are done.
+    if (i == dev_null) {
+      continue;
+    }
+
+    // Is this fd already open?
+    int status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
+    if (status != -1) {
+      continue;
+    }
+
+    // The only error we allow is that the file descriptor does not
+    // exist, in which case we dup /dev/null to it.
+    if (errno == EBADF) {
+      // Try dupping /dev/null to this stdio file descriptor and
+      // repeat if there is a signal. Note that any errors in closing
+      // the stdio descriptor are lost.
+      status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
+      if (status == -1) {
+        __early_abort(__LINE__);
+      }
+    } else {
+      __early_abort(__LINE__);
+    }
+  }
+
+  // If /dev/null is not one of the stdio file descriptors, close it.
+  if (dev_null > 2) {
+    if (close(dev_null) == -1) {
+      __early_abort(__LINE__);
+    }
+  }
+}
+
+// Check if the environment variable definition at 'envstr'
+// starts with '<name>=', and if so return the address of the
+// first character after the equal sign. Otherwise return null.
+static const char* env_match(const char* envstr, const char* name) {
+  size_t i = 0;
+
+  while (envstr[i] == name[i] && name[i] != '\0') {
+    ++i;
+  }
+
+  if (name[i] == '\0' && envstr[i] == '=') {
+    return envstr + i + 1;
+  }
+
+  return nullptr;
+}
+
+static bool __is_valid_environment_variable(const char* name) {
+  // According to the kernel source, by default the kernel uses 32*PAGE_SIZE
+  // as the maximum size for an environment variable definition.
+  const int MAX_ENV_LEN = 32*4096;
+
+  if (name == nullptr) {
+    return false;
+  }
+
+  // Parse the string, looking for the first '=' there, and its size.
+  int pos = 0;
+  int first_equal_pos = -1;
+  while (pos < MAX_ENV_LEN) {
+    if (name[pos] == '\0') {
+      break;
+    }
+    if (name[pos] == '=' && first_equal_pos < 0) {
+      first_equal_pos = pos;
+    }
+    pos++;
+  }
+
+  // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
+  if (pos >= MAX_ENV_LEN) {
+    return false;
+  }
+
+  // Check that it contains at least one equal sign that is not the first character
+  if (first_equal_pos < 1) {
+    return false;
+  }
+
+  return true;
+}
+
+static bool __is_unsafe_environment_variable(const char* name) {
+  // None of these should be allowed in setuid programs.
+  static const char* const UNSAFE_VARIABLE_NAMES[] = {
+      "GCONV_PATH",
+      "GETCONF_DIR",
+      "HOSTALIASES",
+      "JE_MALLOC_CONF",
+      "LD_AOUT_LIBRARY_PATH",
+      "LD_AOUT_PRELOAD",
+      "LD_AUDIT",
+      "LD_DEBUG",
+      "LD_DEBUG_OUTPUT",
+      "LD_DYNAMIC_WEAK",
+      "LD_LIBRARY_PATH",
+      "LD_ORIGIN_PATH",
+      "LD_PRELOAD",
+      "LD_PROFILE",
+      "LD_SHOW_AUXV",
+      "LD_USE_LOAD_BIAS",
+      "LOCALDOMAIN",
+      "LOCPATH",
+      "MALLOC_CHECK_",
+      "MALLOC_CONF",
+      "MALLOC_TRACE",
+      "NIS_PATH",
+      "NLSPATH",
+      "RESOLV_HOST_CONF",
+      "RES_OPTIONS",
+      "TMPDIR",
+      "TZDIR",
+      nullptr
+  };
+  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
+    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static void __sanitize_environment_variables(char** env) {
+  bool is_AT_SECURE = getauxval(AT_SECURE);
+  char** src = env;
+  char** dst = env;
+  for (; src[0] != nullptr; ++src) {
+    if (!__is_valid_environment_variable(src[0])) {
+      continue;
+    }
+    // Remove various unsafe environment variables if we're loading a setuid program.
+    if (is_AT_SECURE && __is_unsafe_environment_variable(src[0])) {
+      continue;
+    }
+    dst[0] = src[0];
+    ++dst;
+  }
+  dst[0] = nullptr;
+}
+
+void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
+  __libc_auxv = args.auxv;
+
+  // Check that the kernel provided a value for AT_SECURE.
+  bool found_AT_SECURE = false;
+  for (ElfW(auxv_t)* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
+    if (v->a_type == AT_SECURE) {
+      found_AT_SECURE = true;
+      break;
+    }
+  }
+  if (!found_AT_SECURE) __early_abort(__LINE__);
+
+  if (getauxval(AT_SECURE)) {
+    // If this is a setuid/setgid program, close the security hole described in
+    // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
+    __nullify_closed_stdio();
+
+    __sanitize_environment_variables(args.envp);
+  }
+
+  // Now the environment has been sanitized, make it available.
+  environ = args.envp;
+}
+
 /* This function will be called during normal program termination
  * to run the destructors that are listed in the .fini_array section
  * of the executable, if any.
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 3032f99..673ad5b 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -49,8 +49,12 @@
 __END_DECLS
 
 #if defined(__cplusplus)
+
 class KernelArgumentBlock;
 __LIBC_HIDDEN__ void __libc_init_common(KernelArgumentBlock& args);
+
+__LIBC_HIDDEN__ void __libc_init_AT_SECURE(KernelArgumentBlock& args);
+
 #endif
 
 #endif
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index bc11f3d..7794fbe 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -91,6 +91,7 @@
                             structors_array_t const * const structors) {
   KernelArgumentBlock args(raw_args);
   __libc_init_tls(args);
+  __libc_init_AT_SECURE(args);
   __libc_init_common(args);
 
   apply_gnu_relro();
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 7ad21c4..cb0b334 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -56,6 +56,7 @@
   EVENT_TYPE_LONG     = 1,
   EVENT_TYPE_STRING   = 2,
   EVENT_TYPE_LIST     = 3,
+  EVENT_TYPE_FLOAT    = 4,
 };
 
 struct BufferOutputStream {
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 8b34495..b299684 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -340,7 +340,7 @@
   return pthread_gettid_np(t);
 }
 
-// Older versions of appportable used dlmalloc directly instead of malloc,
+// Older versions of apportable used dlmalloc directly instead of malloc,
 // so export this compatibility shim that simply calls malloc.
 extern "C" void* dlmalloc(size_t size) {
   return malloc(size);
@@ -369,3 +369,26 @@
 
 // This is never implemented in bionic, only needed for ABI compatibility with the NDK.
 extern "C" void endpwent() { }
+
+// Since dlmalloc_inspect_all and dlmalloc_trim are exported for systems
+// that use dlmalloc, be consistent and export them everywhere.
+#if defined(USE_JEMALLOC)
+extern "C" void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
+}
+#else
+extern "C" void dlmalloc_inspect_all_real(void (*)(void*, void*, size_t, void*), void*);
+extern "C" void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void* arg) {
+  dlmalloc_inspect_all_real(handler, arg);
+}
+#endif
+
+#if defined(USE_JEMALLOC)
+extern "C" int dlmalloc_trim(size_t) {
+  return 0;
+}
+#else
+extern "C" int dlmalloc_trim_real(size_t);
+extern "C" int dlmalloc_trim(size_t pad) {
+  return dlmalloc_trim_real(pad);
+}
+#endif
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 4fec753..851fc3d 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -501,6 +501,12 @@
 }
 
 int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
+#if !defined(__LP64__)
+    if (mutex_interface == NULL) {
+        return EINVAL;
+    }
+#endif
+
     pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
 
     uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
@@ -516,6 +522,12 @@
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
+#if !defined(__LP64__)
+    if (mutex_interface == NULL) {
+        return EINVAL;
+    }
+#endif
+
     pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
 
     uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
diff --git a/libc/bionic/sigqueue.cpp b/libc/bionic/sigqueue.cpp
index 39c8798..8741460 100644
--- a/libc/bionic/sigqueue.cpp
+++ b/libc/bionic/sigqueue.cpp
@@ -31,7 +31,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-extern "C" int __rt_sigqueueinfo(pid_t, int, siginfo_t*);
+extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_t*);
 
 int sigqueue(pid_t pid, int signo, const sigval value) {
   siginfo_t info;
@@ -42,5 +42,5 @@
   info.si_uid = getuid();
   info.si_value = value;
 
-  return __rt_sigqueueinfo(pid, signo, &info);
+  return ___rt_sigqueueinfo(pid, signo, &info);
 }
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index aae99b1..c436a16 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -598,6 +598,16 @@
     return map_prop_area_rw();
 }
 
+unsigned int __system_property_area_serial()
+{
+    prop_area *pa = __system_property_area__;
+    if (!pa) {
+        return -1;
+    }
+    // Make sure this read fulfilled before __system_property_serial
+    return atomic_load_explicit(&(pa->serial), memory_order_acquire);
+}
+
 const prop_info *__system_property_find(const char *name)
 {
     if (__predict_false(compat_mode)) {
diff --git a/libc/include/elf.h b/libc/include/elf.h
index df768ba..eaad1d3 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -34,6 +34,11 @@
 
 #include <machine/elf_machdep.h>
 
+#define ELF32_R_INFO(sym, type) ((((Elf32_Word)sym) << 8) | ((type) & 0xff))
+#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)sym) << 32) | ((type) & 0xffffffff))
+
+typedef __s64 Elf32_Sxword;
+
 typedef struct {
   __u32 a_type;
   union {
@@ -187,6 +192,11 @@
 #define STT_LOPROC    13
 #define STT_HIPROC    15
 
+#define STV_DEFAULT   0
+#define STV_INTERNAL  1
+#define STV_HIDDEN    2
+#define STV_PROTECTED 3
+
 /* The kernel uses NT_PRFPREG but glibc also offers NT_FPREGSET */
 #define NT_FPREGSET NT_PRFPREG
 
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index cf09445..6fb06fb 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -179,10 +179,18 @@
 
 int pthread_mutex_destroy(pthread_mutex_t*) __nonnull((1));
 int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*) __nonnull((1));
+#if !defined(__LP64__)
+int pthread_mutex_lock(pthread_mutex_t*) /* __nonnull((1)) */;
+#else
 int pthread_mutex_lock(pthread_mutex_t*) __nonnull((1));
+#endif
 int pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec*) __nonnull((1, 2));
 int pthread_mutex_trylock(pthread_mutex_t*) __nonnull((1));
+#if !defined(__LP4__)
+int pthread_mutex_unlock(pthread_mutex_t*) /* __nonnull((1)) */;
+#else
 int pthread_mutex_unlock(pthread_mutex_t*) __nonnull((1));
+#endif
 
 int pthread_once(pthread_once_t*, void (*)(void)) __nonnull((1, 2));
 
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index 7ff3ded..a0315b5 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -81,7 +81,6 @@
 #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
 #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
 #define PROP_PATH_VENDOR_BUILD     "/vendor/build.prop"
-#define PROP_PATH_BOOTIMAGE_BUILD  "/build.prop"
 #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"
 #define PROP_PATH_FACTORY          "/factory/factory.prop"
 
@@ -98,6 +97,30 @@
 */
 int __system_property_area_init();
 
+/* Read the global serial number of the system properties
+**
+** Called to predict if a series of cached __system_property_find
+** objects will have seen __system_property_serial values change.
+** But also aids the converse, as changes in the global serial can
+** also be used to predict if a failed __system_property_find
+** could in-turn now find a new object; thus preventing the
+** cycles of effort to poll __system_property_find.
+**
+** Typically called at beginning of a cache cycle to signal if _any_ possible
+** changes have occurred since last. If there is, one may check each individual
+** __system_property_serial to confirm dirty, or __system_property_find
+** to check if the property now exists. If a call to __system_property_add
+** or __system_property_update has completed between two calls to
+** __system_property_area_serial then the second call will return a larger
+** value than the first call. Beware of race conditions as changes to the
+** properties are not atomic, the main value of this call is to determine
+** whether the expensive __system_property_find is worth retrying to see if
+** a property now exists.
+**
+** Returns the serial number on success, -1 on error.
+*/
+unsigned int __system_property_area_serial();
+
 /* Add a new system property.  Can only be done by a single
 ** process that has write access to the property area, and
 ** that process must handle sequencing to ensure the property
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
index 0251716..187ec22 100644
--- a/libc/include/sys/uio.h
+++ b/libc/include/sys/uio.h
@@ -34,8 +34,13 @@
 
 __BEGIN_DECLS
 
-int readv(int, const struct iovec *, int);
-int writev(int, const struct iovec *, int);
+int readv(int, const struct iovec*, int);
+int writev(int, const struct iovec*, int);
+
+#if defined(__USE_GNU)
+ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long);
+ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long);
+#endif
 
 __END_DECLS
 
diff --git a/libc/private/ScopedFd.h b/libc/private/ScopedFd.h
deleted file mode 100644
index e56c139..0000000
--- a/libc/private/ScopedFd.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SCOPED_FD_H
-#define SCOPED_FD_H
-
-#include <unistd.h>
-#include "bionic_macros.h"
-
-// A smart pointer that closes the given fd on going out of scope.
-// Use this when the fd is incidental to the purpose of your function,
-// but needs to be cleaned up on exit.
-class ScopedFd {
-public:
-    explicit ScopedFd(int fd) : fd(fd) {
-    }
-
-    ~ScopedFd() {
-      reset();
-    }
-
-    int get() const {
-        return fd;
-    }
-
-    int release() __attribute__((warn_unused_result)) {
-        int localFd = fd;
-        fd = -1;
-        return localFd;
-    }
-
-    void reset(int new_fd = -1) {
-      if (fd != -1) {
-          TEMP_FAILURE_RETRY(close(fd));
-      }
-      fd = new_fd;
-    }
-
-private:
-    int fd;
-
-    // Disallow copy and assignment.
-    DISALLOW_COPY_AND_ASSIGN(ScopedFd);
-};
-
-#endif  // SCOPED_FD_H
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 13b9887..fc2115e 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -86,5 +86,5 @@
 int
 __sclose(void *cookie)
 {
-	return TEMP_FAILURE_RETRY(close(((FILE *)cookie)->_file));
+	return close(((FILE *)cookie)->_file);
 }
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index df2b1b5..a6970dd 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -37,7 +37,18 @@
 #include "atexit.h"
 #include "private/thread_private.h"
 
-struct atexit *__atexit;
+struct atexit {
+	struct atexit *next;		/* next in list */
+	int ind;			/* next index in this table */
+	int max;			/* max entries >= ATEXIT_SIZE */
+	struct atexit_fn {
+		void (*fn_ptr)(void *);
+		void *fn_arg;		/* argument for CXA callback */
+		void *fn_dso;		/* shared module handle */
+	} fns[1];			/* the table itself */
+};
+
+static struct atexit *__atexit;
 static int restartloop;
 
 /* BEGIN android-changed: __unregister_atfork is used by __cxa_finalize */
diff --git a/libc/stdlib/atexit.h b/libc/stdlib/atexit.h
index 3de2aa3..e01bb34 100644
--- a/libc/stdlib/atexit.h
+++ b/libc/stdlib/atexit.h
@@ -30,18 +30,5 @@
  *
  */
 
-struct atexit {
-	struct atexit *next;		/* next in list */
-	int ind;			/* next index in this table */
-	int max;			/* max entries >= ATEXIT_SIZE */
-	struct atexit_fn {
-		void (*fn_ptr)(void *);
-		void *fn_arg;		/* argument for CXA callback */
-		void *fn_dso;		/* shared module handle */
-	} fns[1];			/* the table itself */
-};
-
-extern struct atexit *__atexit;		/* points to head of LIFO stack */
-
 int	__cxa_atexit(void (*)(void *), void *, void *);
 void	__cxa_finalize(void *);
diff --git a/libc/tools/check-symbols.py b/libc/tools/check-symbols.py
index 0922548..a217ff7 100755
--- a/libc/tools/check-symbols.py
+++ b/libc/tools/check-symbols.py
@@ -41,10 +41,11 @@
   for line in subprocess.check_output(['readelf', '--dyn-syms', so_file]).split('\n'):
     m = r.match(line)
     if m:
+      symbol = string.split(m.group(2), '@')[0]
       if m.group(1) == 'FUNC' and functions_or_variables == 'functions':
-        actual_symbols.add(m.group(2))
+        actual_symbols.add(symbol)
       elif m.group(1) == 'OBJECT' and functions_or_variables == 'variables':
-        actual_symbols.add(m.group(2))
+        actual_symbols.add(symbol)
     #else:
       #print 'ignoring: ' % line
 
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 8f55a26..47bacc3 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -74,7 +74,6 @@
 __LIBC64_HIDDEN__ extern const short* _tolower_tab_;
 __LIBC64_HIDDEN__ extern const short* _toupper_tab_;
 
-__LIBC_HIDDEN__ extern struct atexit* __atexit;
 __LIBC_HIDDEN__ extern const char _C_ctype_[];
 __LIBC_HIDDEN__ extern const short _C_toupper_[];
 __LIBC_HIDDEN__ extern const short _C_tolower_[];
diff --git a/libc/version_script.txt b/libc/version_script.txt
index 349a2fc..afc5e5c 100644
--- a/libc/version_script.txt
+++ b/libc/version_script.txt
@@ -1,9 +1,4 @@
 LIBC {
-  global:
-    /* Work-around for http://b/20065774. */
-    __clear_cache;
-    _Unwind_Backtrace;
-    _Unwind_GetIP;
   local:
     _ZSt7nothrow;
     _ZdaPv;
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index 3661b68..2c734fa 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 2a0724a..7b97dc4 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -15,7 +15,7 @@
 #
 # DO NOT REMOVE --exclude-libs!
 
-LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a
+LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a -Wl,--version-script=$(LOCAL_PATH)/libdl.map
 
 # for x86, exclude libgcc_eh.a for the same reasons as above
 LOCAL_LDFLAGS_x86 := -Wl,--exclude-libs=libgcc_eh.a
diff --git a/libdl/libdl.c b/libdl/libdl.c
index dca51b0..9a858a3 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -17,6 +17,7 @@
 #include <dlfcn.h>
 #include <link.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <android/dlext.h>
 
 // These are stubs for functions that are actually defined
@@ -38,3 +39,6 @@
 void android_update_LD_LIBRARY_PATH(const char* ld_library_path __unused) { }
 
 void* android_dlopen_ext(const char* filename __unused, int flag __unused, const android_dlextinfo* extinfo __unused) { return 0; }
+
+void android_set_application_target_sdk_version(uint32_t target __unused) { }
+uint32_t android_get_application_target_sdk_version() { return 0; }
diff --git a/libdl/libdl.map b/libdl/libdl.map
new file mode 100644
index 0000000..a911cb6
--- /dev/null
+++ b/libdl/libdl.map
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+# begin arm-only
+    dl_unwind_find_exidx;
+# end arm-only
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_PRIVATE {
+  global:
+    android_get_application_target_sdk_version;
+    android_set_application_target_sdk_version;
+    android_get_LD_LIBRARY_PATH;
+    android_update_LD_LIBRARY_PATH;
+} LIBC;
diff --git a/libm/Android.mk b/libm/Android.mk
index 6472a15..4a5bbad 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -514,7 +514,8 @@
 include $(CLEAR_VARS)
 
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
 LOCAL_MODULE := libm
 LOCAL_CLANG := $(libm_clang)
diff --git a/libm/NOTICE b/libm/NOTICE
index 70f2f46..a2cfad3 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -1002,6 +1002,114 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
+Johhnny Qiu <joqiu@nvidia.com>
+Shu Zhang <chazhang@nvidia.com>
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
+Johnny Qiu <joqiu@nvidia.com>
+Shu Zhang <chazhang@nvidia.com>
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014, 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.
+
+-------------------------------------------------------------------
+
+Copyright 2015, The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
 From: @(#)s_ilogb.c 5.1 93/09/24
 ====================================================
 Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
diff --git a/linker/Android.mk b/linker/Android.mk
index 5bdc2f9..7a9b5d9 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -7,8 +7,8 @@
     dlfcn.cpp \
     linker.cpp \
     linker_allocator.cpp \
+    linker_sdk_versions.cpp \
     linker_block_allocator.cpp \
-    linker_environ.cpp \
     linker_libc_support.c \
     linker_memory.cpp \
     linker_phdr.cpp \
@@ -35,6 +35,9 @@
     -fvisibility=hidden \
     -Wall -Wextra -Wunused -Werror \
 
+LOCAL_CFLAGS_arm += -D__work_around_b_19059885__
+LOCAL_CFLAGS_x86 += -D__work_around_b_19059885__
+
 LOCAL_CONLYFLAGS += \
     -std=gnu99 \
 
diff --git a/linker/NOTICE b/linker/NOTICE
index cb3a1dd..139b26e 100644
--- a/linker/NOTICE
+++ b/linker/NOTICE
@@ -42,62 +42,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (C) 2008, 2009 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.
-
--------------------------------------------------------------------
-
-Copyright (C) 2008-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.
-
--------------------------------------------------------------------
-
 Copyright (C) 2010 The Android Open Source Project
 All rights reserved.
 
@@ -214,3 +158,47 @@
 
 -------------------------------------------------------------------
 
+Copyright (C) 2015 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 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.
+
+-------------------------------------------------------------------
+
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 357fbdc..46c97af 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -205,15 +205,6 @@
 }
 
 static void send_debuggerd_packet(siginfo_t* info) {
-  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
-    // process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
-    // Honor that intention by not connecting to debuggerd and asking it
-    // to dump our internal state.
-    __libc_format_log(ANDROID_LOG_INFO, "libc",
-                      "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
-    return;
-  }
-
   // Mutex to prevent multiple crashing threads from trying to talk
   // to debuggerd at the same time.
   static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 057c217..a70abf5 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <android/dlext.h>
+#include <android/api-level.h>
 
 #include <bionic/pthread_internal.h>
 #include "private/bionic_tls.h"
@@ -157,6 +158,16 @@
   return 0;
 }
 
+void android_set_application_target_sdk_version(uint32_t target) {
+  // lock to avoid modification in the middle of dlopen.
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  set_application_target_sdk_version(target);
+}
+
+uint32_t android_get_application_target_sdk_version() {
+  return get_application_target_sdk_version();
+}
+
 // name_offset: starting index of the name in libdl_info.strtab
 #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
     { name_offset, \
@@ -176,19 +187,21 @@
       /* st_size */ 0, \
     }
 
+static const char ANDROID_LIBDL_STRTAB[] =
+  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 99999
+  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 56789
+    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_it"
+  // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
+  // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
+    "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
+  // 0000000000111111
+  // 0123456789012345
+    "get_sdk_version\0"
 #if defined(__arm__)
-  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222 333333333344444444445
-  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789 012345678901234567890
-#  define ANDROID_LIBDL_STRTAB \
-    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0dl_unwind_find_exidx\0"
-#elif defined(__aarch64__) || defined(__i386__) || defined(__mips__) || defined(__x86_64__)
-  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222
-  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789
-#  define ANDROID_LIBDL_STRTAB \
-    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0"
-#else
-#  error Unsupported architecture. Only arm, arm64, mips, mips64, x86 and x86_64 are presently supported.
+  // 216
+    "dl_unwind_find_exidx\0"
 #endif
+    ;
 
 static ElfW(Sym) g_libdl_symtab[] = {
   // Total length of libdl_info.strtab, including trailing 0.
@@ -205,8 +218,10 @@
   ELFW(SYM_INITIALIZER)( 67, &android_get_LD_LIBRARY_PATH, 1),
   ELFW(SYM_INITIALIZER)( 95, &dl_iterate_phdr, 1),
   ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
+  ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
+  ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(130, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(216, &dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -223,9 +238,9 @@
 // Note that adding any new symbols here requires stubbing them out in libdl.
 static unsigned g_libdl_buckets[1] = { 1 };
 #if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
@@ -246,6 +261,7 @@
     __libdl_info->strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
     __libdl_info->local_group_root_ = __libdl_info;
     __libdl_info->soname_ = "libdl.so";
+    __libdl_info->target_sdk_version_ = __ANDROID_API__;
 #if defined(__arm__)
     strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
 #endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index be7b10c..bbdd1b0 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <android/api-level.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -47,36 +48,21 @@
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 #include "private/ScopedPthreadMutexLocker.h"
-#include "private/ScopedFd.h"
 #include "private/ScopeGuard.h"
 #include "private/UniquePtr.h"
 
 #include "linker.h"
 #include "linker_block_allocator.h"
 #include "linker_debug.h"
-#include "linker_environ.h"
 #include "linker_sleb128.h"
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
 #include "ziparchive/zip_archive.h"
 
-/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
- *
- * Do NOT use malloc() and friends or pthread_*() code here.
- * Don't use printf() either; it's caused mysterious memory
- * corruption in the past.
- * The linker runs before we bring up libc and it's easiest
- * to make sure it does not depend on any complex libc features
- *
- * open issues / todo:
- *
- * - cleaner error reporting
- * - after linking, set as much stuff as possible to READONLY
- *   and NOEXEC
- */
+extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
 
-// Override macros to use C++ style casts
+// Override macros to use C++ style casts.
 #undef ELF_ST_TYPE
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
@@ -267,7 +253,7 @@
 
   soinfo *prev = nullptr, *trav;
 
-  TRACE("name %s: freeing soinfo @ %p", si->get_soname(), si);
+  TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
 
   for (trav = solist; trav != nullptr; trav = trav->next) {
     if (trav == si) {
@@ -278,7 +264,7 @@
 
   if (trav == nullptr) {
     // si was not in solist
-    DL_ERR("name \"%s\"@%p is not in solist!", si->get_soname(), si);
+    DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
     return;
   }
 
@@ -332,6 +318,7 @@
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
   snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
+    PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
   }
 
@@ -443,7 +430,7 @@
 
     if (verdef->vd_version != 1) {
       DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
-          i, verdef->vd_version, si->get_soname());
+          i, verdef->vd_version, si->get_realpath());
       return false;
     }
 
@@ -513,7 +500,7 @@
     return s->st_shndx != SHN_UNDEF;
   } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
     DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
-        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_soname());
+        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
   }
 
   return false;
@@ -546,12 +533,12 @@
   *symbol_index = 0;
 
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
-      symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+      symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
   // test against bloom filter
   if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
     TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
-        symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
     return true;
   }
@@ -561,7 +548,7 @@
 
   if (n == 0) {
     TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
-        symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
     return true;
   }
@@ -589,7 +576,7 @@
         strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
         is_symbol_global_and_defined(this, s)) {
       TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
-          symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(s->st_value),
+          symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
           static_cast<size_t>(s->st_size));
       *symbol_index = n;
       return true;
@@ -597,7 +584,7 @@
   } while ((gnu_chain_[n++] & 1) == 0);
 
   TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
-             symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+             symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
   return true;
 }
@@ -608,7 +595,7 @@
   uint32_t hash = symbol_name.elf_hash();
 
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
-             symbol_name.get_name(), get_soname(),
+             symbol_name.get_name(), get_realpath(),
              reinterpret_cast<void*>(base), hash, hash % nbucket_);
 
   ElfW(Versym) verneed = 0;
@@ -629,7 +616,7 @@
         strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
         is_symbol_global_and_defined(this, s)) {
       TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
-                 symbol_name.get_name(), get_soname(),
+                 symbol_name.get_name(), get_realpath(),
                  reinterpret_cast<void*>(s->st_value),
                  static_cast<size_t>(s->st_size));
       *symbol_index = n;
@@ -638,7 +625,7 @@
   }
 
   TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
-             symbol_name.get_name(), get_soname(),
+             symbol_name.get_name(), get_realpath(),
              reinterpret_cast<void*>(base), hash, hash % nbucket_);
 
   *symbol_index = 0;
@@ -718,7 +705,7 @@
    * relocations for -Bsymbolic linked dynamic executables.
    */
   if (si_from->has_DT_SYMBOLIC) {
-    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_soname(), name);
+    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
     if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
       return false;
     }
@@ -733,7 +720,7 @@
     bool error = false;
     global_group.visit([&](soinfo* global_si) {
       DEBUG("%s: looking up %s in %s (from global group)",
-          si_from->get_soname(), name, global_si->get_soname());
+          si_from->get_realpath(), name, global_si->get_realpath());
       if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
         error = true;
         return false;
@@ -762,7 +749,7 @@
       }
 
       DEBUG("%s: looking up %s in %s (from local group)",
-          si_from->get_soname(), name, local_si->get_soname());
+          si_from->get_realpath(), name, local_si->get_realpath());
       if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
         error = true;
         return false;
@@ -784,8 +771,8 @@
   if (s != nullptr) {
     TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
                "found in %s, base = %p, load bias = %p",
-               si_from->get_soname(), name, reinterpret_cast<void*>(s->st_value),
-               (*si_found_in)->get_soname(), reinterpret_cast<void*>((*si_found_in)->base),
+               si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
+               (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
                reinterpret_cast<void*>((*si_found_in)->load_bias));
   }
 
@@ -933,13 +920,17 @@
 }
 
 
-// This is used by dlsym(3).  It performs symbol lookup only within the
-// specified soinfo object and its dependencies in breadth first order.
-const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
+                                            soinfo** found, SymbolName& symbol_name) {
   const ElfW(Sym)* result = nullptr;
-  SymbolName symbol_name(name);
+  bool skip_lookup = skip_until != nullptr;
 
-  walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) {
+  walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
+    if (skip_lookup) {
+      skip_lookup = current_soinfo != skip_until;
+      return true;
+    }
+
     if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
       result = nullptr;
       return false;
@@ -956,6 +947,24 @@
   return result;
 }
 
+// This is used by dlsym(3).  It performs symbol lookup only within the
+// specified soinfo object and its dependencies in breadth first order.
+const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+  // According to man dlopen(3) and posix docs in the case when si is handle
+  // of the main executable we need to search not only in the executable and its
+  // dependencies but also in all libraries loaded with RTLD_GLOBAL.
+  //
+  // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
+  // libraries and they are loaded in breath-first (correct) order we can just execute
+  // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
+  if (si == somain) {
+    return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
+  }
+
+  SymbolName symbol_name(name);
+  return dlsym_handle_lookup(si, nullptr, found, symbol_name);
+}
+
 /* This is used by dlsym(3) to performs a global symbol lookup. If the
    start value is null (for RTLD_DEFAULT), the search starts at the
    beginning of the global solist. Otherwise the search starts at the
@@ -970,7 +979,7 @@
   soinfo* start = solist;
 
   if (handle == RTLD_NEXT) {
-    if (caller == nullptr || caller->next == nullptr) {
+    if (caller == nullptr) {
       return nullptr;
     } else {
       start = caller->next;
@@ -979,7 +988,10 @@
 
   const ElfW(Sym)* s = nullptr;
   for (soinfo* si = start; si != nullptr; si = si->next) {
-    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+    // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
+    // if the library is opened by application with target api level <= 22
+    // See http://b/21565766
+    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
       continue;
     }
 
@@ -993,31 +1005,13 @@
     }
   }
 
-  // If not found - look into local_group unless
-  // caller is part of the global group in which
+  // If not found - use dlsym_handle_lookup for caller's
+  // local_group unless it is part of the global group in which
   // case we already did it.
   if (s == nullptr && caller != nullptr &&
       (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
-    soinfo* local_group_root = caller->get_local_group_root();
-
-    if (handle == RTLD_DEFAULT) {
-      start = local_group_root;
-    }
-
-    for (soinfo* si = start; si != nullptr; si = si->next) {
-      if (si->get_local_group_root() != local_group_root) {
-        break;
-      }
-
-      if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
-        return nullptr;
-      }
-
-      if (s != nullptr) {
-        *found = si;
-        break;
-      }
-    }
+    return dlsym_handle_lookup(caller->get_local_group_root(),
+        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
   }
 
   if (s != nullptr) {
@@ -1088,11 +1082,11 @@
                                    off64_t* file_offset) {
   TRACE("Trying zip file open from path '%s'", path);
 
-  // Treat an '!' character inside a path as the separator between the name
+  // Treat an '!/' separator inside a path as the separator between the name
   // of the zip file on disk and the subdirectory to search within it.
-  // For example, if path is "foo.zip!bar/bas/x.so", then we search for
+  // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
   // "bar/bas/x.so" within "foo.zip".
-  const char* separator = strchr(path, '!');
+  const char* separator = strstr(path, "!/");
   if (separator == nullptr) {
     return -1;
   }
@@ -1106,7 +1100,7 @@
   buf[separator - path] = '\0';
 
   const char* zip_path = buf;
-  const char* file_path = &buf[separator - path + 1];
+  const char* file_path = &buf[separator - path + 2];
   int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
   if (fd == -1) {
     return -1;
@@ -1223,38 +1217,34 @@
   return fd;
 }
 
+static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
+#if !defined(__LP64__)
+  // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
+  if (get_application_target_sdk_version() <= 22) {
+    const char* bname = basename(dt_needed);
+    if (bname != dt_needed) {
+      DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
+    }
+
+    return bname;
+  }
+#endif
+  return dt_needed;
+}
+
 template<typename F>
 static void for_each_dt_needed(const soinfo* si, F action) {
   for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
     if (d->d_tag == DT_NEEDED) {
-      action(si->get_string(d->d_un.d_val));
+      action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
     }
   }
 }
 
-static soinfo* load_library(LoadTaskList& load_tasks,
+static soinfo* load_library(int fd, off64_t file_offset,
+                            LoadTaskList& load_tasks,
                             const char* name, int rtld_flags,
                             const android_dlextinfo* extinfo) {
-  int fd = -1;
-  off64_t file_offset = 0;
-  ScopedFd file_guard(-1);
-
-  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
-    fd = extinfo->library_fd;
-    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
-      file_offset = extinfo->library_fd_offset;
-    }
-  } else {
-    // Open the file.
-    fd = open_library(name, &file_offset);
-    if (fd == -1) {
-      DL_ERR("library \"%s\" not found", name);
-      return nullptr;
-    }
-
-    file_guard.reset(fd);
-  }
-
   if ((file_offset % PAGE_SIZE) != 0) {
     DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
     return nullptr;
@@ -1298,7 +1288,7 @@
 
   std::string realpath = name;
   if (!realpath_fd(fd, &realpath)) {
-    PRINT("cannot resolve realpath for the library \"%s\": %s", name, strerror(errno));
+    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
     realpath = name;
   }
 
@@ -1330,6 +1320,29 @@
   return si;
 }
 
+static soinfo* load_library(LoadTaskList& load_tasks,
+                            const char* name, int rtld_flags,
+                            const android_dlextinfo* extinfo) {
+  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+    off64_t file_offset = 0;
+    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
+      file_offset = extinfo->library_fd_offset;
+    }
+    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  }
+
+  // Open the file.
+  off64_t file_offset;
+  int fd = open_library(name, &file_offset);
+  if (fd == -1) {
+    DL_ERR("library \"%s\" not found", name);
+    return nullptr;
+  }
+  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+  close(fd);
+  return result;
+}
+
 static soinfo *find_loaded_library_by_soname(const char* name) {
   // Ignore filename with path.
   if (strchr(name, '/') != nullptr) {
@@ -1513,7 +1526,7 @@
   }
 
   if (!root->can_unload()) {
-    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_soname());
+    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
     return;
   }
 
@@ -1536,7 +1549,9 @@
       if (si->has_min_version(0)) {
         soinfo* child = nullptr;
         while ((child = si->get_children().pop_front()) != nullptr) {
-          TRACE("%s@%p needs to unload %s@%p", si->get_soname(), si, child->get_soname(), child);
+          TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
+              child->get_realpath(), child);
+
           if (local_unload_list.contains(child)) {
             continue;
           } else if (child->is_linked() && child->get_local_group_root() != root) {
@@ -1546,20 +1561,20 @@
           }
         }
       } else {
-#if !defined(__arm__)
-        __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_soname(), si);
+#if !defined(__work_around_b_19059885__)
+        __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
 #else
-        PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_soname(), si);
+        PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
         for_each_dt_needed(si, [&] (const char* library_name) {
           TRACE("deprecated (old format of soinfo): %s needs to unload %s",
-              si->get_soname(), library_name);
+              si->get_realpath(), library_name);
 
           soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
           if (needed != nullptr) {
             // Not found: for example if symlink was deleted between dlopen and dlclose
             // Since we cannot really handle errors at this point - print and continue.
             PRINT("warning: couldn't find %s needed by %s on unload.",
-                library_name, si->get_soname());
+                library_name, si->get_realpath());
             return;
           } else if (local_unload_list.contains(needed)) {
             // already visited
@@ -1589,7 +1604,8 @@
       soinfo_unload(si);
     }
   } else {
-    TRACE("not unloading '%s' group, decrementing ref_count to %zd", root->get_soname(), ref_count);
+    TRACE("not unloading '%s' group, decrementing ref_count to %zd",
+        root->get_realpath(), ref_count);
   }
 }
 
@@ -1701,12 +1717,12 @@
     const char* target_soname = si_from->get_string(verneed->vn_file);
     // find it in dependencies
     soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
-      return strcmp(si->get_soname(), target_soname) == 0;
+      return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
     });
 
     if (target_si == nullptr) {
       DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
-          target_soname, i, si_from->get_soname());
+          target_soname, i, si_from->get_realpath());
       return false;
     }
 
@@ -1743,6 +1759,27 @@
   return init_verneed(si_from) && init_verdef(si_from);
 }
 
+bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+                                 const char* sym_name, const version_info** vi) {
+  const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
+  ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
+
+  if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
+    *vi = version_tracker.get_version_info(sym_ver);
+
+    if (*vi == nullptr) {
+      DL_ERR("cannot find verneed/verdef for version index=%d "
+          "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
+      return false;
+    }
+  } else {
+    // there is no version info
+    *vi = nullptr;
+  }
+
+  return true;
+}
+
 #if !defined(__mips__)
 #if defined(USE_RELA)
 static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
@@ -1759,14 +1796,8 @@
 #endif
 
 template<typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
-                      const soinfo_list_t& local_group) {
-  VersionTracker version_tracker;
-
-  if (!version_tracker.init(this)) {
-    return false;
-  }
-
+bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+                      const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
   for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
     const auto rel = rel_iterator.next();
     if (rel == nullptr) {
@@ -1781,7 +1812,7 @@
     const char* sym_name = nullptr;
     ElfW(Addr) addend = get_addend(rel, reloc);
 
-    DEBUG("Processing '%s' relocation at index %zd", get_soname(), idx);
+    DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
     if (type == R_GENERIC_NONE) {
       continue;
     }
@@ -1791,32 +1822,21 @@
 
     if (sym != 0) {
       sym_name = get_string(symtab_[sym].st_name);
-      const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
-      ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
+      const version_info* vi = nullptr;
 
-      if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
-        // there is no version info for this one
-        if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
-          return false;
-        }
-      } else {
-        const version_info* vi = version_tracker.get_version_info(sym_ver);
-
-        if (vi == nullptr) {
-          DL_ERR("cannot find verneed/verdef for version index=%d "
-              "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
-          return false;
-        }
-
-        if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
-          return false;
-        }
+      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+        return false;
       }
+
+      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+        return false;
+      }
+
       if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
         s = &symtab_[sym];
         if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
-          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_soname());
+          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
           return false;
         }
 
@@ -2012,7 +2032,7 @@
          * R_AARCH64_COPY may only appear in executable objects where e_type is
          * set to ET_EXEC.
          */
-        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_soname());
+        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
         return false;
       case R_AARCH64_TLS_TPREL64:
         TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
@@ -2069,7 +2089,7 @@
          * R_ARM_COPY may only appear in executable objects where e_type is
          * set to ET_EXEC.
          */
-        DL_ERR("%s R_ARM_COPY relocations are not supported", get_soname());
+        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
         return false;
 #elif defined(__i386__)
       case R_386_32:
@@ -2101,7 +2121,7 @@
     return;
   }
 
-  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_soname());
+  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
 
   int begin = reverse ? (count - 1) : 0;
   int end = reverse ? -1 : count;
@@ -2112,7 +2132,7 @@
     call_function("function", functions[i]);
   }
 
-  TRACE("[ Done calling %s for '%s' ]", array_name, get_soname());
+  TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
 }
 
 void soinfo::call_function(const char* function_name __unused, linker_function_t function) {
@@ -2120,9 +2140,9 @@
     return;
   }
 
-  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_soname());
+  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
   function();
-  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_soname());
+  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
 }
 
 void soinfo::call_pre_init_constructors() {
@@ -2151,14 +2171,14 @@
   if (!is_main_executable() && preinit_array_ != nullptr) {
     // The GNU dynamic linker silently ignores these, but we warn the developer.
     PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
-          get_soname(), preinit_array_count_);
+          get_realpath(), preinit_array_count_);
   }
 
   get_children().for_each([] (soinfo* si) {
     si->call_constructors();
   });
 
-  TRACE("\"%s\": calling constructors", get_soname());
+  TRACE("\"%s\": calling constructors", get_realpath());
 
   // DT_INIT should be called before DT_INIT_ARRAY if both are present.
   call_function("DT_INIT", init_func_);
@@ -2169,7 +2189,7 @@
   if (!constructors_called) {
     return;
   }
-  TRACE("\"%s\": calling destructors", get_soname());
+  TRACE("\"%s\": calling destructors", get_realpath());
 
   // DT_FINI_ARRAY must be parsed in reverse order.
   call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
@@ -2267,7 +2287,7 @@
 }
 
 const char* soinfo::get_realpath() const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
   if (has_min_version(2)) {
     return realpath_.c_str();
   } else {
@@ -2279,7 +2299,7 @@
 }
 
 const char* soinfo::get_soname() const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
   if (has_min_version(2)) {
     return soname_;
   } else {
@@ -2329,7 +2349,7 @@
 const char* soinfo::get_string(ElfW(Word) index) const {
   if (has_min_version(1) && (index >= strtab_size_)) {
     __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
-        get_soname(), strtab_size_, index);
+        get_realpath(), strtab_size_, index);
   }
 
   return strtab_ + index;
@@ -2375,65 +2395,15 @@
   return local_group_root_;
 }
 
-/* Force any of the closed stdin, stdout and stderr to be associated with
-   /dev/null. */
-static int nullify_closed_stdio() {
-  int dev_null, i, status;
-  int return_value = 0;
-
-  dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
-  if (dev_null < 0) {
-    DL_ERR("cannot open /dev/null: %s", strerror(errno));
-    return -1;
-  }
-  TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null);
-
-  /* If any of the stdio file descriptors is valid and not associated
-     with /dev/null, dup /dev/null to it.  */
-  for (i = 0; i < 3; i++) {
-    /* If it is /dev/null already, we are done. */
-    if (i == dev_null) {
-      continue;
-    }
-
-    TRACE("[ Nullifying stdio file descriptor %d]", i);
-    status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
-
-    /* If file is opened, we are good. */
-    if (status != -1) {
-      continue;
-    }
-
-    /* The only error we allow is that the file descriptor does not
-       exist, in which case we dup /dev/null to it. */
-    if (errno != EBADF) {
-      DL_ERR("fcntl failed: %s", strerror(errno));
-      return_value = -1;
-      continue;
-    }
-
-    /* Try dupping /dev/null to this stdio file descriptor and
-       repeat if there is a signal.  Note that any errors in closing
-       the stdio descriptor are lost.  */
-    status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
-    if (status < 0) {
-      DL_ERR("dup2 failed: %s", strerror(errno));
-      return_value = -1;
-      continue;
-    }
+// This function returns api-level at the time of
+// dlopen/load. Note that libraries opened by system
+// will always have 'current' api level.
+uint32_t soinfo::get_target_sdk_version() const {
+  if (!has_min_version(2)) {
+    return __ANDROID_API__;
   }
 
-  /* If /dev/null is not one of the stdio file descriptors, close it. */
-  if (dev_null > 2) {
-    TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null);
-    status = TEMP_FAILURE_RETRY(close(dev_null));
-    if (status == -1) {
-      DL_ERR("close failed: %s", strerror(errno));
-      return_value = -1;
-    }
-  }
-
-  return return_value;
+  return local_group_root_->target_sdk_version_;
 }
 
 bool soinfo::prelink_image() {
@@ -2444,13 +2414,13 @@
   /* We can't log anything until the linker is relocated */
   bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
   if (!relocating_linker) {
-    INFO("[ linking %s ]", get_soname());
+    INFO("[ linking %s ]", get_realpath());
     DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
   }
 
   if (dynamic == nullptr) {
     if (!relocating_linker) {
-      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_soname());
+      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
     }
     return false;
   } else {
@@ -2743,7 +2713,7 @@
         set_dt_flags_1(d->d_un.d_val);
 
         if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
-          DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
+          DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
         }
         break;
 #if defined(__mips__)
@@ -2813,17 +2783,6 @@
     }
   }
 
-  // second pass - parse entries relying on strtab
-  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
-    if (d->d_tag == DT_SONAME) {
-      soname_ = get_string(d->d_un.d_val);
-#if defined(__arm__)
-      strlcpy(old_name_, soname_, sizeof(old_name_));
-#endif
-      break;
-    }
-  }
-
   DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
         reinterpret_cast<void*>(base), strtab_, symtab_);
 
@@ -2834,17 +2793,41 @@
   }
   if (nbucket_ == 0 && gnu_nbucket_ == 0) {
     DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
-        "(new hash type from the future?)", get_soname());
+        "(new hash type from the future?)", get_realpath());
     return false;
   }
   if (strtab_ == 0) {
-    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_soname());
+    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
     return false;
   }
   if (symtab_ == 0) {
-    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_soname());
+    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
     return false;
   }
+
+  // second pass - parse entries relying on strtab
+  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_SONAME) {
+      soname_ = get_string(d->d_un.d_val);
+#if defined(__work_around_b_19059885__)
+      strlcpy(old_name_, soname_, sizeof(old_name_));
+#endif
+      break;
+    }
+  }
+
+  // Before M release linker was using basename in place of soname.
+  // In the case when dt_soname is absent some apps stop working
+  // because they can't find dt_needed library by soname.
+  // This workaround should keep them working. (applies only
+  // for apps targeting sdk version <=22). Make an exception for
+  // the main executable and linker; they do not need to have dt_soname
+  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
+      get_application_target_sdk_version() <= 22) {
+    soname_ = basename(realpath_.c_str());
+    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
+        get_realpath(), soname_);
+  }
   return true;
 }
 
@@ -2856,15 +2839,25 @@
     local_group_root_ = this;
   }
 
+  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
+    target_sdk_version_ = get_application_target_sdk_version();
+  }
+
+  VersionTracker version_tracker;
+
+  if (!version_tracker.init(this)) {
+    return false;
+  }
+
 #if !defined(__LP64__)
   if (has_text_relocations) {
     // Make segments writable to allow text relocations to work properly. We will later call
     // phdr_table_protect_segments() after all of them are applied and all constructors are run.
     DL_WARN("%s has text relocations. This is wasting memory and prevents "
-            "security hardening. Please fix.", get_soname());
+            "security hardening. Please fix.", get_realpath());
     if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
       DL_ERR("can't unprotect loadable segments for \"%s\": %s",
-             get_soname(), strerror(errno));
+             get_realpath(), strerror(errno));
       return false;
     }
   }
@@ -2877,13 +2870,14 @@
         android_relocs_[1] == 'P' &&
         android_relocs_[2] == 'S' &&
         android_relocs_[3] == '2') {
-      DEBUG("[ android relocating %s ]", get_soname());
+      DEBUG("[ android relocating %s ]", get_realpath());
 
       bool relocated = false;
       const uint8_t* packed_relocs = android_relocs_ + 4;
       const size_t packed_relocs_size = android_relocs_size_ - 4;
 
       relocated = relocate(
+          version_tracker,
           packed_reloc_iterator<sleb128_decoder>(
             sleb128_decoder(packed_relocs, packed_relocs_size)),
           global_group, local_group);
@@ -2899,46 +2893,50 @@
 
 #if defined(USE_RELA)
   if (rela_ != nullptr) {
-    DEBUG("[ relocating %s ]", get_soname());
-    if (!relocate(plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
+    DEBUG("[ relocating %s ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
       return false;
     }
   }
   if (plt_rela_ != nullptr) {
-    DEBUG("[ relocating %s plt ]", get_soname());
-    if (!relocate(plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
+    DEBUG("[ relocating %s plt ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
       return false;
     }
   }
 #else
   if (rel_ != nullptr) {
-    DEBUG("[ relocating %s ]", get_soname());
-    if (!relocate(plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
+    DEBUG("[ relocating %s ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
       return false;
     }
   }
   if (plt_rel_ != nullptr) {
-    DEBUG("[ relocating %s plt ]", get_soname());
-    if (!relocate(plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
+    DEBUG("[ relocating %s plt ]", get_realpath());
+    if (!relocate(version_tracker,
+            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
       return false;
     }
   }
 #endif
 
 #if defined(__mips__)
-  if (!mips_relocate_got(global_group, local_group)) {
+  if (!mips_relocate_got(version_tracker, global_group, local_group)) {
     return false;
   }
 #endif
 
-  DEBUG("[ finished linking %s ]", get_soname());
+  DEBUG("[ finished linking %s ]", get_realpath());
 
 #if !defined(__LP64__)
   if (has_text_relocations) {
     // All relocations are done, we can protect our segments back to read-only.
     if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
       DL_ERR("can't protect segments for \"%s\": %s",
-             get_soname(), strerror(errno));
+             get_realpath(), strerror(errno));
       return false;
     }
   }
@@ -2947,7 +2945,7 @@
   /* We can also turn on GNU RELRO protection */
   if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
     DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
-           get_soname(), strerror(errno));
+           get_realpath(), strerror(errno));
     return false;
   }
 
@@ -2956,14 +2954,14 @@
     if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
                                        extinfo->relro_fd) < 0) {
       DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
-             get_soname(), strerror(errno));
+             get_realpath(), strerror(errno));
       return false;
     }
   } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
     if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
                                  extinfo->relro_fd) < 0) {
       DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
-             get_soname(), strerror(errno));
+             get_realpath(), strerror(errno));
       return false;
     }
   }
@@ -3022,7 +3020,7 @@
 static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
   linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
 
-  linker_soinfo_for_gdb->base = linker_base;
+  linker_soinfo_for_gdb->load_bias = linker_base;
 
   /*
    * Set the dynamic field in the link map otherwise gdb will complain with
@@ -3037,6 +3035,8 @@
   insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
 }
 
+extern "C" int __system_properties_init(void);
+
 /*
  * This code is called after the linker has linked itself and
  * fixed it's own GOT. It is safe to make references to externs
@@ -3048,30 +3048,27 @@
   gettimeofday(&t0, 0);
 #endif
 
-  // Initialize environment functions, and get to the ELF aux vectors table.
-  linker_env_init(args);
+  // Sanitize the environment.
+  __libc_init_AT_SECURE(args);
 
-  // If this is a setuid/setgid program, close the security hole described in
-  // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
-  if (get_AT_SECURE()) {
-    nullify_closed_stdio();
-  }
+  // Initialize system properties
+  __system_properties_init(); // may use 'environ'
 
   debuggerd_init();
 
   // Get a few environment variables.
-  const char* LD_DEBUG = linker_env_get("LD_DEBUG");
+  const char* LD_DEBUG = getenv("LD_DEBUG");
   if (LD_DEBUG != nullptr) {
     g_ld_debug_verbosity = atoi(LD_DEBUG);
   }
 
-  // Normally, these are cleaned by linker_env_init, but the test
+  // These should have been sanitized by __libc_init_AT_SECURE, but the test
   // doesn't cost us anything.
   const char* ldpath_env = nullptr;
   const char* ldpreload_env = nullptr;
-  if (!get_AT_SECURE()) {
-    ldpath_env = linker_env_get("LD_LIBRARY_PATH");
-    ldpreload_env = linker_env_get("LD_PRELOAD");
+  if (!getauxval(AT_SECURE)) {
+    ldpath_env = getenv("LD_LIBRARY_PATH");
+    ldpreload_env = getenv("LD_PRELOAD");
   }
 
 #if !defined(__LP64__)
@@ -3150,6 +3147,7 @@
   for (const auto& ld_preload_name : g_ld_preload_names) {
     needed_library_name_list.push_back(ld_preload_name.c_str());
     ++needed_libraries_count;
+    ++ld_preloads_count;
   }
 
   for_each_dt_needed(si, [&](const char* name) {
@@ -3232,7 +3230,7 @@
   fflush(stdout);
 #endif
 
-  TRACE("[ Ready to execute '%s' @ %p ]", si->get_soname(), reinterpret_cast<void*>(si->entry));
+  TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
   return si->entry;
 }
 
@@ -3248,7 +3246,8 @@
  */
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
   ElfW(Addr) offset = elf->e_phoff;
-  const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
+  const ElfW(Phdr)* phdr_table =
+      reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
   const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
 
   for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
diff --git a/linker/linker.h b/linker/linker.h
index dae3972..6042cb8 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -97,7 +97,7 @@
 
 #define SOINFO_VERSION 2
 
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
 #define SOINFO_NAME_LEN 128
 #endif
 
@@ -172,7 +172,7 @@
 struct soinfo {
  public:
   typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
  private:
   char old_name_[SOINFO_NAME_LEN];
 #endif
@@ -183,13 +183,13 @@
   ElfW(Addr) base;
   size_t size;
 
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
   uint32_t unused1;  // DO NOT USE, maintained for compatibility.
 #endif
 
   ElfW(Dyn)* dynamic;
 
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
   uint32_t unused2; // DO NOT USE, maintained for compatibility
   uint32_t unused3; // DO NOT USE, maintained for compatibility
 #endif
@@ -247,7 +247,9 @@
   uint32_t mips_symtabno_;
   uint32_t mips_local_gotno_;
   uint32_t mips_gotsym_;
-  bool mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group);
+  bool mips_relocate_got(const VersionTracker& version_tracker,
+                         const soinfo_list_t& global_group,
+                         const soinfo_list_t& local_group);
 
 #endif
   size_t ref_count_;
@@ -303,7 +305,7 @@
   bool is_gnu_hash() const;
 
   bool inline has_min_version(uint32_t min_version __unused) const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
     return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
 #else
     return true;
@@ -332,17 +334,22 @@
 
   bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
 
+  uint32_t get_target_sdk_version() const;
+
  private:
   bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* elf_addr_lookup(const void* addr);
   bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* gnu_addr_lookup(const void* addr);
 
+  bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+                           const char* sym_name, const version_info** vi);
+
   void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
   void call_function(const char* function_name, linker_function_t function);
   template<typename ElfRelIteratorT>
-  bool relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
-                const soinfo_list_t& local_group);
+  bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+                const soinfo_list_t& global_group, const soinfo_list_t& local_group);
 
  private:
   // This part of the structure is only available
@@ -388,6 +395,8 @@
   ElfW(Addr) verneed_ptr_;
   size_t verneed_cnt_;
 
+  uint32_t target_sdk_version_;
+
   friend soinfo* get_libdl_info();
 };
 
@@ -424,4 +433,7 @@
 char* linker_get_error_buffer();
 size_t linker_get_error_buffer_size();
 
+void set_application_target_sdk_version(uint32_t target);
+uint32_t get_application_target_sdk_version();
+
 #endif
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 5ded5ab..51f8d4c 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2010 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp
deleted file mode 100644
index 9a0f009..0000000
--- a/linker/linker_environ.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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 "linker_environ.h"
-
-#include <linux/auxvec.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "private/KernelArgumentBlock.h"
-
-static char** _envp;
-static bool _AT_SECURE_value = true;
-
-bool get_AT_SECURE() {
-  return _AT_SECURE_value;
-}
-
-static void __init_AT_SECURE(KernelArgumentBlock& args) {
-  // Check auxv for AT_SECURE first to see if program is setuid, setgid,
-  // has file caps, or caused a SELinux/AppArmor domain transition.
-  bool kernel_supplied_AT_SECURE;
-  _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE);
-
-  // We don't support ancient kernels.
-  if (!kernel_supplied_AT_SECURE) {
-    const char* msg = "FATAL: kernel did not supply AT_SECURE\n";
-    write(2, msg, strlen(msg));
-    exit(EXIT_FAILURE);
-  }
-}
-
-// Check if the environment variable definition at 'envstr'
-// starts with '<name>=', and if so return the address of the
-// first character after the equal sign. Otherwise return null.
-static const char* env_match(const char* envstr, const char* name) {
-  size_t i = 0;
-
-  while (envstr[i] == name[i] && name[i] != '\0') {
-    ++i;
-  }
-
-  if (name[i] == '\0' && envstr[i] == '=') {
-    return envstr + i + 1;
-  }
-
-  return nullptr;
-}
-
-static bool __is_valid_environment_variable(const char* name) {
-  // According to its sources, the kernel uses 32*PAGE_SIZE by default
-  // as the maximum size for an env. variable definition.
-  const int MAX_ENV_LEN = 32*4096;
-
-  if (name == nullptr) {
-    return false;
-  }
-
-  // Parse the string, looking for the first '=' there, and its size.
-  int pos = 0;
-  int first_equal_pos = -1;
-  while (pos < MAX_ENV_LEN) {
-    if (name[pos] == '\0') {
-      break;
-    }
-    if (name[pos] == '=' && first_equal_pos < 0) {
-      first_equal_pos = pos;
-    }
-    pos++;
-  }
-
-  // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
-  if (pos >= MAX_ENV_LEN) {
-    return false;
-  }
-
-  // Check that it contains at least one equal sign that is not the first character
-  if (first_equal_pos < 1) {
-    return false;
-  }
-
-  return true;
-}
-
-static bool __is_unsafe_environment_variable(const char* name) {
-  // None of these should be allowed in setuid programs.
-  static const char* const UNSAFE_VARIABLE_NAMES[] = {
-      "GCONV_PATH",
-      "GETCONF_DIR",
-      "HOSTALIASES",
-      "JE_MALLOC_CONF",
-      "LD_AOUT_LIBRARY_PATH",
-      "LD_AOUT_PRELOAD",
-      "LD_AUDIT",
-      "LD_DEBUG",
-      "LD_DEBUG_OUTPUT",
-      "LD_DYNAMIC_WEAK",
-      "LD_LIBRARY_PATH",
-      "LD_ORIGIN_PATH",
-      "LD_PRELOAD",
-      "LD_PROFILE",
-      "LD_SHOW_AUXV",
-      "LD_USE_LOAD_BIAS",
-      "LOCALDOMAIN",
-      "LOCPATH",
-      "MALLOC_CHECK_",
-      "MALLOC_CONF",
-      "MALLOC_TRACE",
-      "NIS_PATH",
-      "NLSPATH",
-      "RESOLV_HOST_CONF",
-      "RES_OPTIONS",
-      "TMPDIR",
-      "TZDIR",
-      nullptr
-  };
-  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
-    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
-      return true;
-    }
-  }
-  return false;
-}
-
-static void __sanitize_environment_variables() {
-  char** src  = _envp;
-  char** dst = _envp;
-  for (; src[0] != nullptr; ++src) {
-    if (!__is_valid_environment_variable(src[0])) {
-      continue;
-    }
-    // Remove various unsafe environment variables if we're loading a setuid program.
-    if (get_AT_SECURE() && __is_unsafe_environment_variable(src[0])) {
-        continue;
-    }
-    dst[0] = src[0];
-    ++dst;
-  }
-  dst[0] = nullptr;
-}
-
-void linker_env_init(KernelArgumentBlock& args) {
-  // Store environment pointer - can't be null.
-  _envp = args.envp;
-
-  __init_AT_SECURE(args);
-  __sanitize_environment_variables();
-}
-
-const char* linker_env_get(const char* name) {
-  if (name == nullptr || name[0] == '\0') {
-    return nullptr;
-  }
-
-  for (char** p = _envp; p[0] != nullptr; ++p) {
-    const char* val = env_match(p[0], name);
-    if (val != nullptr) {
-      if (val[0] == '\0') {
-        return nullptr; // Return null for empty strings.
-      }
-      return val;
-    }
-  }
-  return nullptr;
-}
diff --git a/linker/linker_environ.h b/linker/linker_environ.h
deleted file mode 100644
index 0f6ac08..0000000
--- a/linker/linker_environ.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 LINKER_ENVIRON_H
-#define LINKER_ENVIRON_H
-
-class KernelArgumentBlock;
-
-// Call this function before any of the other functions in this header file.
-extern void linker_env_init(KernelArgumentBlock& args);
-
-// Returns the value of environment variable 'name' if defined and not
-// empty, or null otherwise.
-extern const char* linker_env_get(const char* name);
-
-// Returns the value of this program's AT_SECURE variable.
-extern bool get_AT_SECURE();
-
-#endif // LINKER_ENVIRON_H
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 0769f82..a7a4bc0 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -32,25 +32,22 @@
 #include "linker_reloc_iterators.h"
 #include "linker_sleb128.h"
 
-template bool soinfo::relocate<plain_reloc_iterator>(plain_reloc_iterator&& rel_iterator,
+template bool soinfo::relocate<plain_reloc_iterator>(const VersionTracker& version_tracker,
+                                                     plain_reloc_iterator&& rel_iterator,
                                                      const soinfo_list_t& global_group,
                                                      const soinfo_list_t& local_group);
 
 template bool soinfo::relocate<packed_reloc_iterator<sleb128_decoder>>(
+    const VersionTracker& version_tracker,
     packed_reloc_iterator<sleb128_decoder>&& rel_iterator,
     const soinfo_list_t& global_group,
     const soinfo_list_t& local_group);
 
 template <typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
+bool soinfo::relocate(const VersionTracker& version_tracker,
+                      ElfRelIteratorT&& rel_iterator,
                       const soinfo_list_t& global_group,
                       const soinfo_list_t& local_group) {
-  VersionTracker version_tracker;
-
-  if (!version_tracker.init(this)) {
-    return false;
-  }
-
   for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
     const auto rel = rel_iterator.next();
 
@@ -75,26 +72,14 @@
 
     if (sym != 0) {
       sym_name = get_string(symtab_[sym].st_name);
-      const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
-      ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
+      const version_info* vi = nullptr;
 
-      if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
-        // there is no version info for this one
-        if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
-          return false;
-        }
-      } else {
-        const version_info* vi = version_tracker.get_version_info(sym_ver);
+      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+        return false;
+      }
 
-        if (vi == nullptr) {
-          DL_ERR("cannot find verneed/verdef for version index=%d "
-              "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
-          return false;
-        }
-
-        if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
-          return false;
-        }
+      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+        return false;
       }
 
       if (s == nullptr) {
@@ -128,7 +113,7 @@
         if (s != nullptr) {
           *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
         } else {
-          *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
+          *reinterpret_cast<ElfW(Addr)*>(reloc) += load_bias;
         }
         break;
       default:
@@ -139,7 +124,8 @@
   return true;
 }
 
-bool soinfo::mips_relocate_got(const soinfo_list_t& global_group,
+bool soinfo::mips_relocate_got(const VersionTracker& version_tracker,
+                               const soinfo_list_t& global_group,
                                const soinfo_list_t& local_group) {
   ElfW(Addr)** got = plt_got_;
   if (got == nullptr) {
@@ -163,22 +149,42 @@
   }
 
   // Now for the global GOT entries...
-  ElfW(Sym)* sym = symtab_ + mips_gotsym_;
   got = plt_got_ + mips_local_gotno_;
-  for (size_t g = mips_gotsym_; g < mips_symtabno_; g++, sym++, got++) {
+  for (ElfW(Word) sym = mips_gotsym_; sym < mips_symtabno_; sym++, got++) {
     // This is an undefined reference... try to locate it.
-    const char* sym_name = get_string(sym->st_name);
+    const ElfW(Sym)* local_sym = symtab_ + sym;
+    const char* sym_name = get_string(local_sym->st_name);
     soinfo* lsi = nullptr;
     const ElfW(Sym)* s = nullptr;
-    if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
+
+    ElfW(Word) st_visibility = (local_sym->st_other & 0x3);
+
+    if (st_visibility == STV_DEFAULT) {
+      const version_info* vi = nullptr;
+
+      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+        return false;
+      }
+
+      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+        return false;
+      }
+    } else if (st_visibility == STV_PROTECTED) {
+      if (local_sym->st_value == 0) {
+        DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", get_soname(), sym_name);
+        return false;
+      }
+      s = local_sym;
+      lsi = this;
+    } else {
+      DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x", get_soname(), sym_name, st_visibility);
       return false;
     }
 
     if (s == nullptr) {
       // We only allow an undefined symbol if this is a weak reference.
-      s = &symtab_[g];
-      if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
-        DL_ERR("cannot locate \"%s\"...", sym_name);
+      if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) {
+        DL_ERR("%s: cannot locate \"%s\"...", get_soname(), sym_name);
         return false;
       }
       *got = 0;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
new file mode 100644
index 0000000..e9ad3dc
--- /dev/null
+++ b/linker/linker_sdk_versions.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker.h"
+#include <android/api-level.h>
+#include <atomic>
+
+static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
+
+void set_application_target_sdk_version(uint32_t target) {
+  g_target_sdk_version = target;
+}
+
+uint32_t get_application_target_sdk_version() {
+  return g_target_sdk_version;
+}
+
diff --git a/tests/Android.mk b/tests/Android.mk
index cd65c10..29e9e1e 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -49,6 +49,9 @@
 test_cppflags = \
     -std=gnu++11 \
 
+libBionicStandardTests_src_files_target := \
+    libdl_test.cpp \
+
 libBionicStandardTests_src_files := \
     arpa_inet_test.cpp \
     buffer_tests.cpp \
@@ -103,7 +106,9 @@
     sys_sysinfo_test.cpp \
     sys_time_test.cpp \
     sys_types_test.cpp \
+    sys_uio_test.cpp \
     sys_vfs_test.cpp \
+    sys_xattr_test.cpp \
     system_properties_test.cpp \
     time_test.cpp \
     uchar_test.cpp \
@@ -269,6 +274,7 @@
     dlext_test.cpp \
     __cxa_thread_atexit_test.cpp \
     dlfcn_test.cpp \
+    pthread_dlfcn_test.cpp \
 
 bionic-unit-tests_cflags := $(test_cflags)
 
@@ -346,6 +352,7 @@
     atexit_test.cpp \
     dlfcn_test.cpp \
     dl_test.cpp \
+    pthread_dlfcn_test.cpp \
 
 bionic-unit-tests-glibc_shared_libraries := \
     libdl_preempt_test_1 \
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 56a8f6f..f901708 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -214,7 +214,7 @@
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
 
-  void* handle = dlopen((lib_path + "!libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
+  void* handle = dlopen((lib_path + "!/libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
   int (*fn)(void);
@@ -226,7 +226,7 @@
 }
 
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
-  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!libdir";
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
 
   typedef void (*fn_t)(const char*);
   fn_t android_update_LD_LIBRARY_PATH =
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 6b1f109..3c9b8e3 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -71,30 +71,102 @@
   void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
-  // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
   void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
   ASSERT_TRUE(symbol == nullptr);
   ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
 
   typedef int* (*fn_t)();
-  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
 
-  ASSERT_TRUE(fn != nullptr) << dlerror();
-
-  int* ptr = fn();
+  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
   ASSERT_TRUE(ptr != nullptr) << dlerror();
   ASSERT_EQ(42, *ptr);
 
+  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
+
+  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+  ASSERT_TRUE(ptr != nullptr) << dlerror();
+  ASSERT_EQ(44, *ptr);
+
+  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
+
+  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+  ASSERT_TRUE(ptr != nullptr) << dlerror();
+  ASSERT_EQ(43, *ptr);
+
+  dlclose(handle);
+}
+
+TEST(dlfcn, dlsym_from_sofile_with_preload) {
+  void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(preload != nullptr) << dlerror();
+
+  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
+  ASSERT_TRUE(symbol == nullptr);
+  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
+
+  typedef int* (*fn_t)();
+  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
+
+  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
+  ASSERT_TRUE(ptr != nullptr) << dlerror();
+  ASSERT_EQ(42, *ptr);
+
+  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
+
+  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+  ASSERT_TRUE(ptr != nullptr) << dlerror();
+  ASSERT_EQ(44, *ptr);
+
+  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
+
+  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+  ASSERT_TRUE(ptr != nullptr) << dlerror();
+  ASSERT_EQ(43, *ptr);
+
+  dlclose(handle);
+  dlclose(preload);
+}
+
+TEST(dlfcn, dlsym_handle_global_sym) {
+  // check that we do not look into global group
+  // when looking up symbol by handle
+  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
+  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
+  void* sym = dlsym(handle, "getRandomNumber");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
+
+  sym = dlsym(handle, "DlSymTestFunction");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
   dlclose(handle);
 }
 
 TEST(dlfcn, dlsym_with_dependencies) {
   void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   dlerror();
   // This symbol is in DT_NEEDED library.
   void* sym = dlsym(handle, "getRandomNumber");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr) << dlerror();
   int (*fn)(void);
   fn = reinterpret_cast<int (*)(void)>(sym);
   EXPECT_EQ(4, fn());
@@ -526,6 +598,15 @@
   // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
   void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
   ASSERT_EQ(sym, sym_after_dlclose);
+
+  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
+  // shared libraries after symbol was not found in the main executable
+  // and dependent libraries.
+  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
+  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym != nullptr) << dlerror();
+
+  dlclose(handle_for_main_executable);
 }
 
 // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
diff --git a/tests/libdl_test.cpp b/tests/libdl_test.cpp
new file mode 100644
index 0000000..b162edc
--- /dev/null
+++ b/tests/libdl_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <android/api-level.h>
+
+extern "C" uint32_t android_get_application_target_sdk_version();
+extern "C" void android_set_application_target_sdk_version(uint32_t target);
+
+TEST(libdl, application_sdk_versions_smoke) {
+  // Check initial values
+  ASSERT_EQ(static_cast<uint32_t>(__ANDROID_API__), android_get_application_target_sdk_version());
+
+  android_set_application_target_sdk_version(20U);
+  ASSERT_EQ(20U, android_get_application_target_sdk_version());
+
+  android_set_application_target_sdk_version(22U);
+  ASSERT_EQ(22U, android_get_application_target_sdk_version());
+}
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index c432c2e..a5ef622 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -355,10 +355,7 @@
 # -----------------------------------------------------------------------------
 libdl_test_df_1_global_src_files := dl_df_1_global.cpp
 libdl_test_df_1_global_ldflags := -Wl,-z,global
-# TODO (dimitry): x86* toolchain does not support -z global - switch to bfd
-ifeq ($(filter $(TARGET_ARCH),x86 x86_64),$(TARGET_ARCH))
-libdl_test_df_1_global_ldflags_target := -fuse-ld=bfd
-endif
+
 # TODO (dimitry): host ld.gold does not yet support -z global
 # remove this line once it is updated.
 libdl_test_df_1_global_ldflags_host := -fuse-ld=bfd
@@ -385,11 +382,34 @@
 # -----------------------------------------------------------------------------
 # Library to check RTLD_LOCAL with dlsym in 'this'
 # -----------------------------------------------------------------------------
-libtest_dlsym_from_this_src_files := dlsym_from_this.cpp
+libtest_dlsym_from_this_src_files := dlsym_from_this_symbol.cpp
+
+libtest_dlsym_from_this_shared_libraries_target := libdl
+libtest_dlsym_from_this_shared_libraries := libtest_dlsym_from_this_child
 
 module := libtest_dlsym_from_this
-libtest_dlsym_from_this_shared_libraries_target := libdl
+include $(LOCAL_PATH)/Android.build.testlib.mk
 
+# -----------------------------------------------------------------------------
+libtest_dlsym_from_this_child_src_files := dlsym_from_this_functions.cpp
+
+libtest_dlsym_from_this_child_shared_libraries := libtest_dlsym_from_this_grandchild
+
+module := libtest_dlsym_from_this_child
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+libtest_dlsym_from_this_grandchild_src_files := dlsym_from_this_symbol2.cpp
+
+module := libtest_dlsym_from_this_grandchild
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+# Empty library
+# -----------------------------------------------------------------------------
+libtest_empty_src_files := empty.cpp
+
+module := libtest_empty
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
 # -----------------------------------------------------------------------------
diff --git a/tests/libs/dlsym_from_this_functions.cpp b/tests/libs/dlsym_from_this_functions.cpp
new file mode 100644
index 0000000..1f357e0
--- /dev/null
+++ b/tests/libs/dlsym_from_this_functions.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int test_dlsym_symbol;
+
+int test_dlsym_symbol = -1;
+
+extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() {
+  dlerror();
+  int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol"));
+  // TODO: remove this once b/20049306 is fixed
+  if (result == nullptr) {
+    printf("Cannot find the answer\n");
+  }
+  return result;
+}
+
+extern "C" int* lookup_dlsym_symbol2_using_RTLD_DEFAULT() {
+  dlerror();
+  int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol2"));
+  // TODO: remove this once b/20049306 is fixed
+  if (result == nullptr) {
+    printf("Cannot find the answer\n");
+  }
+  return result;
+}
+
+extern "C" int* lookup_dlsym_symbol_using_RTLD_NEXT() {
+  dlerror();
+  int* result = static_cast<int*>(dlsym(RTLD_NEXT, "test_dlsym_symbol"));
+  // TODO: remove this once b/20049306 is fixed
+  if (result == nullptr) {
+    printf("Cannot find the answer\n");
+  }
+  return result;
+}
+
diff --git a/tests/libs/dlsym_from_this.cpp b/tests/libs/dlsym_from_this_symbol.cpp
similarity index 60%
rename from tests/libs/dlsym_from_this.cpp
rename to tests/libs/dlsym_from_this_symbol.cpp
index b5215c9..c3ec255 100644
--- a/tests/libs/dlsym_from_this.cpp
+++ b/tests/libs/dlsym_from_this_symbol.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,18 +13,5 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <dlfcn.h>
-#include <stdio.h>
 
 int test_dlsym_symbol = 42;
-
-extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() {
-  dlerror();
-  int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol"));
-  // TODO: remove this once b/20049306 is fixed
-  if (result == nullptr) {
-    printf("Cannot find the answer\n");
-  }
-  return result;
-}
-
diff --git a/tests/libs/dlsym_from_this_symbol2.cpp b/tests/libs/dlsym_from_this_symbol2.cpp
new file mode 100644
index 0000000..20da1d5
--- /dev/null
+++ b/tests/libs/dlsym_from_this_symbol2.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+int test_dlsym_symbol = 43;
+int test_dlsym_symbol2 = 44;
diff --git a/tests/pthread_dlfcn_test.cpp b/tests/pthread_dlfcn_test.cpp
new file mode 100644
index 0000000..5e8b206
--- /dev/null
+++ b/tests/pthread_dlfcn_test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <gtest/gtest.h>
+
+#include <dlfcn.h>
+
+static int g_atfork_prepare_calls = 0;
+static void AtForkPrepare1() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 1; }
+static void AtForkPrepare2() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 2; }
+static void AtForkPrepare3() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 3; }
+static void AtForkPrepare4() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 4; }
+
+static int g_atfork_parent_calls = 0;
+static void AtForkParent1() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 1; }
+static void AtForkParent2() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 2; }
+static void AtForkParent3() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 3; }
+static void AtForkParent4() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 4; }
+
+static int g_atfork_child_calls = 0;
+static void AtForkChild1() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 1; }
+static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 2; }
+static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
+static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
+
+TEST(pthread, pthread_atfork_with_dlclose) {
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
+
+  void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  // the library registers 2 additional atfork handlers in a constructor
+  ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
+  ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));
+
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));
+
+  int pid = fork();
+
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  if (pid == 0) {
+    ASSERT_EQ(1234, g_atfork_child_calls);
+    _exit(0);
+  }
+
+  ASSERT_EQ(1234, g_atfork_parent_calls);
+  ASSERT_EQ(4321, g_atfork_prepare_calls);
+
+  EXPECT_EQ(0, dlclose(handle));
+  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
+
+  int status;
+  ASSERT_EQ(pid, waitpid(pid, &status, 0));
+
+  pid = fork();
+
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  if (pid == 0) {
+    ASSERT_EQ(14, g_atfork_child_calls);
+    _exit(0);
+  }
+
+  ASSERT_EQ(14, g_atfork_parent_calls);
+  ASSERT_EQ(41, g_atfork_prepare_calls);
+
+  ASSERT_EQ(pid, waitpid(pid, &status, 0));
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index cb5e818..8ae28d8 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -16,7 +16,6 @@
 
 #include <gtest/gtest.h>
 
-#include <dlfcn.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
@@ -459,42 +458,6 @@
   ASSERT_EQ(ESRCH, pthread_detach(dead_thread));
 }
 
-TEST(pthread, pthread_detach_no_leak) {
-  size_t initial_bytes = 0;
-  // Run this loop more than once since the first loop causes some memory
-  // to be allocated permenantly. Run an extra loop to help catch any subtle
-  // memory leaks.
-  for (size_t loop = 0; loop < 3; loop++) {
-    // Set the initial bytes on the second loop since the memory in use
-    // should have stabilized.
-    if (loop == 1) {
-      initial_bytes = mallinfo().uordblks;
-    }
-
-    pthread_attr_t attr;
-    ASSERT_EQ(0, pthread_attr_init(&attr));
-    ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
-
-    std::vector<pthread_t> threads;
-    for (size_t i = 0; i < 32; ++i) {
-      pthread_t t;
-      ASSERT_EQ(0, pthread_create(&t, &attr, IdFn, NULL));
-      threads.push_back(t);
-    }
-
-    sleep(1);
-
-    for (size_t i = 0; i < 32; ++i) {
-      ASSERT_EQ(0, pthread_detach(threads[i])) << i;
-    }
-  }
-
-  size_t final_bytes = mallinfo().uordblks;
-  int leaked_bytes = (final_bytes - initial_bytes);
-
-  ASSERT_EQ(0, leaked_bytes);
-}
-
 TEST(pthread, pthread_getcpuclockid__clock_gettime) {
   SpinFunctionHelper spinhelper;
 
@@ -1019,62 +982,6 @@
   ASSERT_EQ(pid, waitpid(pid, &status, 0));
 }
 
-static void AtForkPrepare3() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 3; }
-static void AtForkPrepare4() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 4; }
-
-static void AtForkParent3() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 3; }
-static void AtForkParent4() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 4; }
-
-static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
-static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
-
-TEST(pthread, pthread_atfork_with_dlclose) {
-  ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
-
-  void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
-  ASSERT_TRUE(handle != nullptr) << dlerror();
-  typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
-  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
-  ASSERT_TRUE(fn != nullptr) << dlerror();
-  // the library registers 2 additional atfork handlers in a constructor
-  ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
-  ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));
-
-  ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));
-
-  int pid = fork();
-
-  ASSERT_NE(-1, pid) << strerror(errno);
-
-  if (pid == 0) {
-    ASSERT_EQ(1234, g_atfork_child_calls);
-    _exit(0);
-  }
-
-  ASSERT_EQ(1234, g_atfork_parent_calls);
-  ASSERT_EQ(4321, g_atfork_prepare_calls);
-
-  EXPECT_EQ(0, dlclose(handle));
-  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
-
-  int status;
-  ASSERT_EQ(pid, waitpid(pid, &status, 0));
-
-  pid = fork();
-
-  ASSERT_NE(-1, pid) << strerror(errno);
-
-  if (pid == 0) {
-    ASSERT_EQ(14, g_atfork_child_calls);
-    _exit(0);
-  }
-
-  ASSERT_EQ(14, g_atfork_parent_calls);
-  ASSERT_EQ(41, g_atfork_prepare_calls);
-
-  ASSERT_EQ(pid, waitpid(pid, &status, 0));
-}
-
 TEST(pthread, pthread_attr_getscope) {
   pthread_attr_t attr;
   ASSERT_EQ(0, pthread_attr_init(&attr));
@@ -1630,3 +1537,37 @@
   GTEST_LOG_(INFO) << "This test tests bionic implementation details.";
 #endif
 }
+
+TEST(pthread, pthread_mutex_lock_null_32) {
+#if defined(__BIONIC__) && !defined(__LP64__)
+  ASSERT_EQ(EINVAL, pthread_mutex_lock(NULL));
+#else
+  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+#endif
+}
+
+TEST(pthread, pthread_mutex_unlock_null_32) {
+#if defined(__BIONIC__) && !defined(__LP64__)
+  ASSERT_EQ(EINVAL, pthread_mutex_unlock(NULL));
+#else
+  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+#endif
+}
+
+TEST_F(pthread_DeathTest, pthread_mutex_lock_null_64) {
+#if defined(__BIONIC__) && defined(__LP64__)
+  pthread_mutex_t* null_value = nullptr;
+  ASSERT_EXIT(pthread_mutex_lock(null_value), testing::KilledBySignal(SIGSEGV), "");
+#else
+  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+#endif
+}
+
+TEST_F(pthread_DeathTest, pthread_mutex_unlock_null_64) {
+#if defined(__BIONIC__) && defined(__LP64__)
+  pthread_mutex_t* null_value = nullptr;
+  ASSERT_EXIT(pthread_mutex_unlock(null_value), testing::KilledBySignal(SIGSEGV), "");
+#else
+  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+#endif
+}
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
new file mode 100644
index 0000000..c7af8a7
--- /dev/null
+++ b/tests/sys_uio_test.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/uio.h>
+
+TEST(sys_uio, process_vm_readv_ESRCH) {
+  ASSERT_EQ(0, process_vm_readv(0, nullptr, 0, nullptr, 0, 0));
+}
+
+TEST(sys_uio, process_vm_writev_ESRCH) {
+  ASSERT_EQ(0, process_vm_writev(0, nullptr, 0, nullptr, 0, 0));
+}
diff --git a/tests/sys_xattr_test.cpp b/tests/sys_xattr_test.cpp
new file mode 100644
index 0000000..1842682
--- /dev/null
+++ b/tests/sys_xattr_test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/xattr.h>
+
+#include "TemporaryFile.h"
+
+TEST(sys_xattr, setxattr) {
+  TemporaryFile tf;
+  char buf[10];
+  ASSERT_EQ(0, setxattr(tf.filename, "user.foo", "bar", 4, 0));
+  ASSERT_EQ(4, getxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+  ASSERT_STREQ("bar", buf);
+  buf[0] = '\0';
+  ASSERT_EQ(4, lgetxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+  ASSERT_STREQ("bar", buf);
+}
+
+TEST(sys_xattr, fsetxattr) {
+  TemporaryFile tf;
+  char buf[10];
+  ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "bar", 4, 0));
+  ASSERT_EQ(4, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+  ASSERT_STREQ("bar", buf);
+}
+
+TEST(sys_xattr, fsetxattr_zerobuf) {
+  TemporaryFile tf;
+  char buf[10];
+  ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "", 0, 0));
+  ASSERT_EQ(0, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+}
+
+TEST(sys_xattr, fsetxattr_toosmallbuf) {
+  TemporaryFile tf;
+  char buf[10];
+  ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "01234567890123456789", 21, 0));
+  ASSERT_EQ(-1, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+  ASSERT_EQ(ERANGE, errno);
+}
+
+TEST(sys_xattr, fsetxattr_invalidfd) {
+  char buf[10];
+  errno = 0;
+  ASSERT_EQ(-1, fsetxattr(65535, "user.foo", "0123", 5, 0));
+  ASSERT_EQ(EBADF, errno);
+  errno = 0;
+  ASSERT_EQ(-1, fgetxattr(65535, "user.foo", buf, sizeof(buf)));
+  ASSERT_EQ(EBADF, errno);
+}
+
+TEST(sys_xattr, fsetxattr_with_opath) {
+  TemporaryFile tf;
+  int fd = open(tf.filename, O_PATH);
+  ASSERT_NE(-1, fd);
+
+  int res = fsetxattr(fd, "user.foo", "bar", 4, 0);
+#if defined(__BIONIC__)
+  char buf[10];
+  ASSERT_EQ(0, res);
+  ASSERT_EQ(4, fgetxattr(fd, "user.foo", buf, sizeof(buf)));
+  ASSERT_STREQ("bar", buf);
+#else
+  ASSERT_EQ(-1, res);
+  ASSERT_EQ(EBADF, errno);
+#endif
+}
+
+TEST(sys_xattr, fsetxattr_with_opath_toosmall) {
+  TemporaryFile tf;
+  int fd = open(tf.filename, O_PATH);
+  ASSERT_NE(-1, fd);
+
+  int res = fsetxattr(fd, "user.foo", "01234567890123456789", 21, 0);
+#if defined(__BIONIC__)
+  char buf[10];
+  ASSERT_EQ(0, res);
+  ASSERT_EQ(-1, fgetxattr(fd, "user.foo", buf, sizeof(buf)));
+  ASSERT_EQ(ERANGE, errno);
+#else
+  ASSERT_EQ(-1, res);
+  ASSERT_EQ(EBADF, errno);
+#endif
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index f54a461..79c16d7 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -176,6 +176,13 @@
   ASSERT_EQ(123, sb.st_size);
 }
 
+TEST(unistd, ftruncate_negative) {
+  TemporaryFile tf;
+  errno = 0;
+  ASSERT_EQ(-1, ftruncate(tf.fd, -123));
+  ASSERT_EQ(EINVAL, errno);
+}
+
 static bool g_pause_test_flag = false;
 static void PauseTestSignalHandler(int) {
   g_pause_test_flag = true;
diff --git a/tools/relocation_packer/Android.mk b/tools/relocation_packer/Android.mk
index 75dba71..4e2fd97 100644
--- a/tools/relocation_packer/Android.mk
+++ b/tools/relocation_packer/Android.mk
@@ -14,6 +14,7 @@
 # limitations under the License.
 #
 
+ifeq ($(HOST_OS),linux)
 common_cppflags := -Wall -Wextra -Wunused -Werror -Wold-style-cast
 
 LOCAL_PATH := $(call my-dir)
@@ -95,3 +96,5 @@
 $(eval $(call copy-test-library,elf_file_unittest_relocs_arm32_packed.so))
 $(eval $(call copy-test-library,elf_file_unittest_relocs_arm64.so))
 $(eval $(call copy-test-library,elf_file_unittest_relocs_arm64_packed.so))
+
+endif
diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc
index c8ddde6..102d614 100644
--- a/tools/relocation_packer/src/elf_file.cc
+++ b/tools/relocation_packer/src/elf_file.cc
@@ -37,11 +37,13 @@
 static constexpr uint32_t SHT_ANDROID_REL = SHT_LOOS + 1;
 static constexpr uint32_t SHT_ANDROID_RELA = SHT_LOOS + 2;
 
+static const size_t kPageSize = 4096;
+
 // Alignment to preserve, in bytes.  This must be at least as large as the
 // largest d_align and sh_addralign values found in the loaded file.
 // Out of caution for RELRO page alignment, we preserve to a complete target
 // page.  See http://www.airs.com/blog/archives/189.
-static constexpr size_t kPreserveAlignment = 4096;
+static const size_t kPreserveAlignment = kPageSize;
 
 // Get section data.  Checks that the section has exactly one data entry,
 // so that the section size and the data size are the same.  True in
@@ -310,6 +312,13 @@
   for (size_t i = 0; i < count; ++i) {
     typename ELF::Phdr* program_header = &program_headers[i];
 
+    // Do not adjust PT_GNU_STACK - it confuses gdb and results
+    // in incorrect unwinding if the executable is stripped after
+    // packing.
+    if (program_header->p_type == PT_GNU_STACK) {
+      continue;
+    }
+
     if (program_header->p_offset > hole_start) {
       // The hole start is past this segment, so adjust offset.
       program_header->p_offset += hole_size;
@@ -318,9 +327,13 @@
     } else {
       program_header->p_vaddr -= hole_size;
       program_header->p_paddr -= hole_size;
+      if (program_header->p_align > kPageSize) {
+        program_header->p_align = kPageSize;
+      }
       VLOG(1) << "phdr[" << i
               << "] p_vaddr adjusted to "<< program_header->p_vaddr
-              << "; p_paddr adjusted to "<< program_header->p_paddr;
+              << "; p_paddr adjusted to "<< program_header->p_paddr
+              << "; p_align adjusted to "<< program_header->p_align;
     }
   }
 }
@@ -466,6 +479,16 @@
               << " d_val adjusted to " << dynamic->d_un.d_val;
     }
 
+    // Special case: DT_MIPS_RLD_MAP2 stores the difference between dynamic
+    // entry address and the address of the _r_debug (used by GDB)
+    // since the dynamic section and target address are on the
+    // different sides of the hole it needs to be adjusted accordingly
+    if (tag == DT_MIPS_RLD_MAP2) {
+      dynamic->d_un.d_val += hole_size;
+      VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag
+              << " d_val adjusted to " << dynamic->d_un.d_val;
+    }
+
     // Ignore DT_RELCOUNT and DT_RELACOUNT: (1) nobody uses them and
     // technically (2) the relative relocation count is not changed.
 
diff --git a/tools/relocation_packer/src/elf_traits.h b/tools/relocation_packer/src/elf_traits.h
index 41b06c8..1c938fa 100644
--- a/tools/relocation_packer/src/elf_traits.h
+++ b/tools/relocation_packer/src/elf_traits.h
@@ -10,6 +10,10 @@
 #include "elf.h"
 #include "libelf.h"
 
+#if !defined(DT_MIPS_RLD_MAP2)
+#define DT_MIPS_RLD_MAP2 0x70000035
+#endif
+
 // ELF is a traits structure used to provide convenient aliases for
 // 32/64 bit Elf types and functions, depending on the target file.
 
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
index a2b0039..ed85ce1 100755
--- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
Binary files differ