am 1d76f1cc: Merge "add a fortified implementation of realpath" am: c2e2a9ddec
am: 81a308542e

* commit '81a308542e281a0ceeed52746993423f6f867a27':
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..9b7478c
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,15 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+ContinuationIndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 841ad16..9421e26 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -48,6 +48,11 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libc_*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libc_*)
 
+# Required due to the replacement of a symlink with a shared library
+# (commit b952f42bef69e5c in frameworks/native).
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib/libGLES*)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib64/libGLES*)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/README.md b/README.md
index 79bb72a..5f5cc5c 100644
--- a/README.md
+++ b/README.md
@@ -169,9 +169,10 @@
 Updating tzdata
 ---------------
 
-This is fully automated:
+This is fully automated (and these days handled by the libcore team, because
+they own icu, and that needs to be updated in sync with bionic):
 
-  1. Run update-tzdata.py.
+  1. Run update-tzdata.py in external/icu/tools/.
 
 
 Verifying changes
@@ -194,14 +195,15 @@
 ### Device tests
 
     $ mma
+    $ adb remount
     $ adb sync
     $ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
     $ adb shell \
         /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
     # Only for 64-bit targets
-    $ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
+    $ adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests64
     $ adb shell \
-        /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static64
+        /data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static64
 
 ### Host tests
 
@@ -256,18 +258,33 @@
 The coverage report is now available at `covreport/index.html`.
 
 
-LP32 ABI bugs
--------------
+Attaching GDB to the tests
+--------------------------
+
+Bionic's test runner will run each test in its own process by default to prevent
+tests failures from impacting other tests. This also has the added benefit of
+running them in parallel, so they are much faster.
+
+However, this also makes it difficult to run the tests under GDB. To prevent
+each test from being forked, run the tests with the flag `--no-isolate`.
+
+
+32-bit ABI bugs
+---------------
 
 This probably belongs in the NDK documentation rather than here, but these
-are the known ABI bugs in LP32:
+are the known ABI bugs in the 32-bit ABI:
 
- * `time_t` is 32-bit. <http://b/5819737>
+ * `time_t` is 32-bit. <http://b/5819737>. In the 64-bit ABI, time_t is
+   64-bit.
 
- * `off_t` is 32-bit. There is `off64_t`, but no `_FILE_OFFSET_BITS` support.
-   Many of the `off64_t` functions are missing in older releases, and
-   stdio uses 32-bit offsets, so there's no way to fully implement
-   `_FILE_OFFSET_BITS`.
+ * `off_t` is 32-bit. There is `off64_t`, and in newer releases there is
+   almost-complete support for `_FILE_OFFSET_BITS`. Unfortunately our stdio
+   implementation uses 32-bit offsets and -- worse -- function pointers to
+   functions that use 32-bit offsets, so there's no good way to implement
+   the last few pieces <http://b/24807045>. In the 64-bit ABI, off_t is
+   off64_t.
 
  * `sigset_t` is too small on ARM and x86 (but correct on MIPS), so support
-   for real-time signals is broken. <http://b/5828899>
+   for real-time signals is broken. <http://b/5828899> In the 64-bit ABI,
+   `sigset_t` is the correct size for every architecture.
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
index e1580fe..20742bd 100644
--- a/benchmarks/Android.mk
+++ b/benchmarks/Android.mk
@@ -29,7 +29,6 @@
     -Wunused \
 
 benchmark_cppflags := \
-    -std=gnu++11 \
 
 benchmarklib_src_files := \
     Benchmark.cpp \
diff --git a/benchmarks/Benchmark.cpp b/benchmarks/Benchmark.cpp
index ea6000f..a7ab682 100644
--- a/benchmarks/Benchmark.cpp
+++ b/benchmarks/Benchmark.cpp
@@ -24,7 +24,7 @@
 #include <string>
 #include <vector>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 #include <benchmark/Benchmark.h>
 
diff --git a/benchmarks/math_benchmark.cpp b/benchmarks/math_benchmark.cpp
index 4de28d1..ed5b56c 100644
--- a/benchmarks/math_benchmark.cpp
+++ b/benchmarks/math_benchmark.cpp
@@ -65,6 +65,50 @@
   StopBenchmarkTiming();
 }
 
+BENCHMARK_WITH_ARG(BM_math_isfinite_macro, double)->AT_COMMON_VALS;
+void BM_math_isfinite_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += isfinite(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+#if defined(__BIONIC__)
+#define test_isfinite __isfinite
+#else
+#define test_isfinite __finite
+#endif
+BENCHMARK_WITH_ARG(BM_math_isfinite, double)->AT_COMMON_VALS;
+void BM_math_isfinite::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += test_isfinite(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_isinf_macro, double)->AT_COMMON_VALS;
+void BM_math_isinf_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += isinf(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
 BENCHMARK_WITH_ARG(BM_math_isinf, double)->AT_COMMON_VALS;
 void BM_math_isinf::Run(int iters, double value) {
   StartBenchmarkTiming();
@@ -78,6 +122,60 @@
   StopBenchmarkTiming();
 }
 
+BENCHMARK_WITH_ARG(BM_math_isnan_macro, double)->AT_COMMON_VALS;
+void BM_math_isnan_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += isnan(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_isnan, double)->AT_COMMON_VALS;
+void BM_math_isnan::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += (isnan)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_isnormal_macro, double)->AT_COMMON_VALS;
+void BM_math_isnormal_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += isnormal(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+#if defined(__BIONIC__)
+BENCHMARK_WITH_ARG(BM_math_isnormal, double)->AT_COMMON_VALS;
+void BM_math_isnormal::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += (__isnormal)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+#endif
+
 BENCHMARK_NO_ARG(BM_math_sin_fast);
 void BM_math_sin_fast::Run(int iters) {
   StartBenchmarkTiming();
@@ -134,3 +232,55 @@
 
   StopBenchmarkTiming();
 }
+
+BENCHMARK_WITH_ARG(BM_math_signbit_macro, double)->AT_COMMON_VALS;
+void BM_math_signbit_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += signbit(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_signbit, double)->AT_COMMON_VALS;
+void BM_math_signbit::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += (__signbit)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_fabs_macro, double)->AT_COMMON_VALS;
+void BM_math_fabs_macro::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += fabs(v);
+  }
+
+  StopBenchmarkTiming();
+}
+
+BENCHMARK_WITH_ARG(BM_math_fabs, double)->AT_COMMON_VALS;
+void BM_math_fabs::Run(int iters, double value) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = value;
+  for (int i = 0; i < iters; ++i) {
+    d += (fabs)(v);
+  }
+
+  StopBenchmarkTiming();
+}
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 342e561..69e01a9 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -16,6 +16,7 @@
 
 #include <stdio.h>
 #include <stdio_ext.h>
+#include <stdlib.h>
 
 #include <benchmark/Benchmark.h>
 
@@ -73,7 +74,7 @@
   for (int i = 0; i < iters; ++i) {
     FILE* fp = fopen("/proc/version", "re");
     if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
-    fgets(buf, sizeof(buf), fp);
+    if (fgets(buf, sizeof(buf), fp) == nullptr) abort();
     fclose(fp);
   }
 }
diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
index 6688bbc..1b0d08d 100644
--- a/benchmarks/time_benchmark.cpp
+++ b/benchmarks/time_benchmark.cpp
@@ -17,6 +17,7 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <time.h>
+#include <unistd.h>
 
 #include <benchmark/Benchmark.h>
 
diff --git a/benchmarks/utils.cpp b/benchmarks/utils.cpp
index 863b9db..8bbd20a 100644
--- a/benchmarks/utils.cpp
+++ b/benchmarks/utils.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "utils.h"
+
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -21,7 +23,7 @@
 
 #include <string>
 
-#include "utils.h"
+#include <android-base/stringprintf.h>
 
 int Round(int n) {
   int base = 1;
@@ -72,10 +74,7 @@
       break;
     }
   }
-  char* s = NULL;
-  asprintf(&s, "%s%" PRId64 "%s", (negative_number ? "-" : ""),
-           count / kAmountPerUnit[i], kUnitStrings[i]);
-  std::string result(s);
-  free(s);
-  return result;
+  return android::base::StringPrintf("%s%" PRId64 "%s",
+                                     negative_number ? "-" : "",
+                                     count / kAmountPerUnit[i], kUnitStrings[i]);
 }
diff --git a/libc/Android.bp b/libc/Android.bp
new file mode 100644
index 0000000..dd9bb6e
--- /dev/null
+++ b/libc/Android.bp
@@ -0,0 +1,2160 @@
+// Define the common source files for all the libc instances
+// =========================================================
+libc_common_src_files = [
+    "bionic/bindresvport.c",
+    "bionic/ether_aton.c",
+    "bionic/ether_ntoa.c",
+    "bionic/fts.c",
+    "bionic/getpriority.c",
+    "bionic/if_indextoname.c",
+    "bionic/if_nametoindex.c",
+    "bionic/initgroups.c",
+    "bionic/isatty.c",
+    "bionic/memmem.c",
+    "bionic/pututline.c",
+    "bionic/sched_cpualloc.c",
+    "bionic/sched_cpucount.c",
+    "bionic/sigblock.c",
+    "bionic/siginterrupt.c",
+    "bionic/sigsetmask.c",
+    "bionic/system_properties_compat.c",
+    "stdio/findfp.c",
+    "stdio/fread.c",
+    "stdio/refill.c",
+    "stdio/snprintf.c",
+    "stdio/sprintf.c",
+    "stdio/stdio.c",
+    "stdio/stdio_ext.cpp",
+    "stdlib/atexit.c",
+    "stdlib/exit.c",
+
+    // Fortify implementations of libc functions.
+    "bionic/__FD_chk.cpp",
+    "bionic/__fgets_chk.cpp",
+    "bionic/__fread_chk.cpp",
+    "bionic/__fwrite_chk.cpp",
+    "bionic/__getcwd_chk.cpp",
+    "bionic/__memchr_chk.cpp",
+    "bionic/__memmove_chk.cpp",
+    "bionic/__memrchr_chk.cpp",
+    "bionic/__poll_chk.cpp",
+    "bionic/__pread64_chk.cpp",
+    "bionic/__pread_chk.cpp",
+    "bionic/__pwrite64_chk.cpp",
+    "bionic/__pwrite_chk.cpp",
+    "bionic/__read_chk.cpp",
+    "bionic/__readlink_chk.cpp",
+    "bionic/__readlinkat_chk.cpp",
+    "bionic/__recvfrom_chk.cpp",
+    "bionic/__stpcpy_chk.cpp",
+    "bionic/__stpncpy_chk.cpp",
+    "bionic/__strchr_chk.cpp",
+    "bionic/__strlcat_chk.cpp",
+    "bionic/__strlcpy_chk.cpp",
+    "bionic/__strlen_chk.cpp",
+    "bionic/__strncat_chk.cpp",
+    "bionic/__strncpy_chk.cpp",
+    "bionic/__strrchr_chk.cpp",
+    "bionic/__umask_chk.cpp",
+    "bionic/__vsnprintf_chk.cpp",
+    "bionic/__vsprintf_chk.cpp",
+    "bionic/__write_chk.cpp",
+]
+
+// Various kinds of cruft.
+// ========================================================
+libc_common_src_files += [
+    "bionic/ndk_cruft.cpp",
+]
+
+libc_common_src_files_32 = [
+    "bionic/legacy_32_bit_support.cpp",
+    "bionic/time64.c",
+]
+
+// Define some common cflags
+// ========================================================
+cc_defaults {
+    name: "libc_defaults",
+    cflags: [
+        "-D_LIBC=1",
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+
+        // Try to catch typical 32-bit assumptions that break with 64-bit pointers.
+        "-Werror=pointer-to-int-cast",
+        "-Werror=int-to-pointer-cast",
+        "-Werror=type-limits",
+        "-Werror",
+    ],
+    // TODO: split out the asflags.
+    asflags: [
+        "-D_LIBC=1",
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+
+        // Try to catch typical 32-bit assumptions that break with 64-bit pointers.
+        "-Werror=pointer-to-int-cast",
+        "-Werror=int-to-pointer-cast",
+        "-Werror=type-limits",
+        "-Werror",
+    ],
+    conlyflags: ["-std=gnu99"],
+    cppflags: [],
+
+    product_variables: {
+        device_uses_jemalloc: {
+            cflags: ["-DUSE_JEMALLOC"],
+            include_dirs: ["external/jemalloc/include"],
+        },
+        device_uses_dlmalloc: {
+            cflags: ["-DUSE_DLMALLOC"],
+        },
+    },
+    // Clang/llvm has incompatible long double (fp128) for x86_64.
+    // https://llvm.org/bugs/show_bug.cgi?id=23897
+    arch: {
+        x86_64: {
+            clang: false,
+        },
+    },
+
+    stl: "none",
+    system_shared_libs: [],
+    sanitize: ["never"],
+    native_coverage: false,
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true)
+//libc_common_cflags += ["-DDEBUG"]
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
+
+// ========================================================
+// libc_stack_protector.a - stack protector code
+// ========================================================
+//
+// The stack protector code needs to be compiled
+// with -fno-stack-protector, since it modifies the
+// stack canary.
+
+cc_library_static {
+
+    srcs: ["bionic/__stack_chk_fail.cpp"],
+    defaults: ["libc_defaults"],
+    cflags: ["-fno-stack-protector"],
+    name: "libc_stack_protector",
+}
+
+// ========================================================
+// libc_tzcode.a - upstream 'tzcode' code
+// ========================================================
+
+cc_library_static {
+
+    defaults: ["libc_defaults"],
+    srcs: [
+        "tzcode/asctime.c",
+        "tzcode/difftime.c",
+        "tzcode/localtime.c",
+        "tzcode/strftime.c",
+        "tzcode/strptime.c",
+        "upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one.
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-Wno-unused-parameter",
+        // Don't use ridiculous amounts of stack.
+        "-DALL_STATE",
+        // Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
+        "-DSTD_INSPIRED",
+        // Obviously, we want to be thread-safe.
+        "-DTHREAD_SAFE",
+        // The name of the tm_gmtoff field in our struct tm.
+        "-DTM_GMTOFF=tm_gmtoff",
+        // Where we store our tzdata.
+        "-DTZDIR=\\\"/system/usr/share/zoneinfo\\\"",
+        // Include timezone and daylight globals.
+        "-DUSG_COMPAT=1",
+        // Use the empty string (instead of "   ") as the timezone abbreviation
+        // fallback.
+        "-DWILDABBR=\\\"\\\"",
+        "-DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU",
+        "-Dlint",
+    ],
+
+    local_include_dirs: ["tzcode/"],
+    name: "libc_tzcode",
+}
+
+// ========================================================
+// libc_dns.a - modified NetBSD DNS code
+// ========================================================
+
+cc_library_static {
+
+    defaults: ["libc_defaults"],
+    srcs: [
+        "dns/net/gethnamaddr.c",
+        "dns/net/getservbyname.c",
+        "dns/net/getservbyport.c",
+        "dns/net/getaddrinfo.c",
+        "dns/net/getnameinfo.c",
+        "dns/net/sethostent.c",
+        "dns/net/getservent.c",
+        "dns/net/nsdispatch.c",
+        "dns/net/base64.c",
+        "dns/resolv/res_state.c",
+        "dns/resolv/res_init.c",
+        "dns/resolv/res_mkquery.c",
+        "dns/resolv/res_data.c",
+        "dns/resolv/res_debug.c",
+        "dns/resolv/herror.c",
+        "dns/resolv/res_cache.c",
+        "dns/resolv/res_query.c",
+        "dns/resolv/res_comp.c",
+        "dns/resolv/res_send.c",
+        "dns/nameser/ns_name.c",
+        "dns/nameser/ns_print.c",
+        "dns/nameser/ns_parse.c",
+        "dns/nameser/ns_ttl.c",
+        "dns/nameser/ns_netint.c",
+        "dns/nameser/ns_samedomain.c",
+
+        "upstream-netbsd/lib/libc/isc/ev_streams.c",
+        "upstream-netbsd/lib/libc/isc/ev_timers.c",
+        "upstream-netbsd/lib/libc/resolv/mtctxres.c",
+        // We use the OpenBSD res_random.
+        "upstream-openbsd/lib/libc/net/res_random.c",
+    ],
+
+    cflags: [
+        "-Dres_randomid=__res_randomid",
+        "-DANDROID_CHANGES",
+        "-DINET6",
+        "-fvisibility=hidden",
+        "-Wno-unused-parameter",
+        "-include netbsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "dns/include",
+        "private",
+        "upstream-netbsd/lib/libc/include",
+        "upstream-netbsd/android/include",
+    ],
+
+    name: "libc_dns",
+}
+
+// ========================================================
+// libc_freebsd.a - upstream FreeBSD C library code
+// ========================================================
+//
+// These files are built with the freebsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "upstream-freebsd/lib/libc/gen/ldexp.c",
+        "upstream-freebsd/lib/libc/gen/sleep.c",
+        "upstream-freebsd/lib/libc/gen/usleep.c",
+        "upstream-freebsd/lib/libc/stdlib/getopt_long.c",
+        "upstream-freebsd/lib/libc/stdlib/qsort.c",
+        "upstream-freebsd/lib/libc/stdlib/quick_exit.c",
+        "upstream-freebsd/lib/libc/stdlib/realpath.c",
+        "upstream-freebsd/lib/libc/string/wcpcpy.c",
+        "upstream-freebsd/lib/libc/string/wcpncpy.c",
+        "upstream-freebsd/lib/libc/string/wcscasecmp.c",
+        "upstream-freebsd/lib/libc/string/wcscat.c",
+        "upstream-freebsd/lib/libc/string/wcschr.c",
+        "upstream-freebsd/lib/libc/string/wcscmp.c",
+        "upstream-freebsd/lib/libc/string/wcscpy.c",
+        "upstream-freebsd/lib/libc/string/wcscspn.c",
+        "upstream-freebsd/lib/libc/string/wcsdup.c",
+        "upstream-freebsd/lib/libc/string/wcslcat.c",
+        "upstream-freebsd/lib/libc/string/wcslen.c",
+        "upstream-freebsd/lib/libc/string/wcsncasecmp.c",
+        "upstream-freebsd/lib/libc/string/wcsncat.c",
+        "upstream-freebsd/lib/libc/string/wcsncmp.c",
+        "upstream-freebsd/lib/libc/string/wcsncpy.c",
+        "upstream-freebsd/lib/libc/string/wcsnlen.c",
+        "upstream-freebsd/lib/libc/string/wcspbrk.c",
+        "upstream-freebsd/lib/libc/string/wcsrchr.c",
+        "upstream-freebsd/lib/libc/string/wcsspn.c",
+        "upstream-freebsd/lib/libc/string/wcstok.c",
+        "upstream-freebsd/lib/libc/string/wmemchr.c",
+        "upstream-freebsd/lib/libc/string/wmemcmp.c",
+        "upstream-freebsd/lib/libc/string/wmemset.c",
+        "upstream-freebsd/lib/libc/string/wmemmove.c",
+    ],
+    arch: {
+        arm64: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wmemmove.c",
+            ],
+        },
+        x86: {
+            exclude_srcs: [
+                "upstream-freebsd/lib/libc/string/wcschr.c",
+                "upstream-freebsd/lib/libc/string/wcscmp.c",
+                "upstream-freebsd/lib/libc/string/wcslen.c",
+                "upstream-freebsd/lib/libc/string/wcsrchr.c",
+            ],
+            atom: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wmemcmp.c",
+                ],
+            },
+            ssse3: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wcscat.c",
+                    "upstream-freebsd/lib/libc/string/wcscpy.c",
+                ],
+            },
+            sse4: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wmemcmp.c",
+                ],
+            },
+        },
+    },
+
+    cflags: [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-include freebsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "upstream-freebsd/android/include",
+    ],
+
+    name: "libc_freebsd",
+}
+
+// ========================================================
+// libc_netbsd.a - upstream NetBSD C library code
+// ========================================================
+//
+// These files are built with the netbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+
+    defaults: ["libc_defaults"],
+    srcs: [
+        "upstream-netbsd/common/lib/libc/stdlib/random.c",
+        "upstream-netbsd/lib/libc/gen/ftw.c",
+        "upstream-netbsd/lib/libc/gen/nftw.c",
+        "upstream-netbsd/lib/libc/gen/nice.c",
+        "upstream-netbsd/lib/libc/gen/popen.c",
+        "upstream-netbsd/lib/libc/gen/psignal.c",
+        "upstream-netbsd/lib/libc/gen/utime.c",
+        "upstream-netbsd/lib/libc/gen/utmp.c",
+        "upstream-netbsd/lib/libc/inet/nsap_addr.c",
+        "upstream-netbsd/lib/libc/regex/regcomp.c",
+        "upstream-netbsd/lib/libc/regex/regerror.c",
+        "upstream-netbsd/lib/libc/regex/regexec.c",
+        "upstream-netbsd/lib/libc/regex/regfree.c",
+        "upstream-netbsd/lib/libc/stdlib/bsearch.c",
+        "upstream-netbsd/lib/libc/stdlib/div.c",
+        "upstream-netbsd/lib/libc/stdlib/drand48.c",
+        "upstream-netbsd/lib/libc/stdlib/erand48.c",
+        "upstream-netbsd/lib/libc/stdlib/jrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/lcong48.c",
+        "upstream-netbsd/lib/libc/stdlib/ldiv.c",
+        "upstream-netbsd/lib/libc/stdlib/lldiv.c",
+        "upstream-netbsd/lib/libc/stdlib/lrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/mrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/nrand48.c",
+        "upstream-netbsd/lib/libc/stdlib/_rand48.c",
+        "upstream-netbsd/lib/libc/stdlib/rand_r.c",
+        "upstream-netbsd/lib/libc/stdlib/reallocarr.c",
+        "upstream-netbsd/lib/libc/stdlib/seed48.c",
+        "upstream-netbsd/lib/libc/stdlib/srand48.c",
+        "upstream-netbsd/lib/libc/string/memccpy.c",
+        "upstream-netbsd/lib/libc/string/strcasestr.c",
+        "upstream-netbsd/lib/libc/string/strcoll.c",
+        "upstream-netbsd/lib/libc/string/strxfrm.c",
+    ],
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["upstream-netbsd/common/lib/libc/hash/sha1/sha1.c"],
+        },
+    },
+    cflags: [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-DPOSIX_MISTAKE",
+        "-include netbsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "upstream-netbsd/android/include",
+        "upstream-netbsd/lib/libc/include",
+    ],
+
+    name: "libc_netbsd",
+}
+
+// ========================================================
+// libc_openbsd_ndk.a - upstream OpenBSD C library code
+// that can be safely included in the libc_ndk.a (doesn't
+// contain any troublesome global data or constructors).
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    name: "libc_openbsd_ndk",
+    defaults: ["libc_defaults"],
+    srcs: [
+        "upstream-openbsd/lib/libc/compat-43/killpg.c",
+        "upstream-openbsd/lib/libc/gen/alarm.c",
+        "upstream-openbsd/lib/libc/gen/ctype_.c",
+        "upstream-openbsd/lib/libc/gen/daemon.c",
+        "upstream-openbsd/lib/libc/gen/err.c",
+        "upstream-openbsd/lib/libc/gen/errx.c",
+        "upstream-openbsd/lib/libc/gen/exec.c",
+        "upstream-openbsd/lib/libc/gen/fnmatch.c",
+        "upstream-openbsd/lib/libc/gen/ftok.c",
+        "upstream-openbsd/lib/libc/gen/getprogname.c",
+        "upstream-openbsd/lib/libc/gen/isctype.c",
+        "upstream-openbsd/lib/libc/gen/setprogname.c",
+        "upstream-openbsd/lib/libc/gen/time.c",
+        "upstream-openbsd/lib/libc/gen/tolower_.c",
+        "upstream-openbsd/lib/libc/gen/toupper_.c",
+        "upstream-openbsd/lib/libc/gen/verr.c",
+        "upstream-openbsd/lib/libc/gen/verrx.c",
+        "upstream-openbsd/lib/libc/gen/vwarn.c",
+        "upstream-openbsd/lib/libc/gen/vwarnx.c",
+        "upstream-openbsd/lib/libc/gen/warn.c",
+        "upstream-openbsd/lib/libc/gen/warnx.c",
+        "upstream-openbsd/lib/libc/locale/btowc.c",
+        "upstream-openbsd/lib/libc/locale/mbrlen.c",
+        "upstream-openbsd/lib/libc/locale/mbstowcs.c",
+        "upstream-openbsd/lib/libc/locale/mbtowc.c",
+        "upstream-openbsd/lib/libc/locale/wcscoll.c",
+        "upstream-openbsd/lib/libc/locale/wcstod.c",
+        "upstream-openbsd/lib/libc/locale/wcstof.c",
+        "upstream-openbsd/lib/libc/locale/wcstoimax.c",
+        "upstream-openbsd/lib/libc/locale/wcstol.c",
+        "upstream-openbsd/lib/libc/locale/wcstold.c",
+        "upstream-openbsd/lib/libc/locale/wcstoll.c",
+        "upstream-openbsd/lib/libc/locale/wcstombs.c",
+        "upstream-openbsd/lib/libc/locale/wcstoul.c",
+        "upstream-openbsd/lib/libc/locale/wcstoull.c",
+        "upstream-openbsd/lib/libc/locale/wcstoumax.c",
+        "upstream-openbsd/lib/libc/locale/wcsxfrm.c",
+        "upstream-openbsd/lib/libc/locale/wctob.c",
+        "upstream-openbsd/lib/libc/locale/wctomb.c",
+        "upstream-openbsd/lib/libc/net/htonl.c",
+        "upstream-openbsd/lib/libc/net/htons.c",
+        "upstream-openbsd/lib/libc/net/inet_lnaof.c",
+        "upstream-openbsd/lib/libc/net/inet_makeaddr.c",
+        "upstream-openbsd/lib/libc/net/inet_netof.c",
+        "upstream-openbsd/lib/libc/net/inet_ntoa.c",
+        "upstream-openbsd/lib/libc/net/inet_ntop.c",
+        "upstream-openbsd/lib/libc/net/inet_pton.c",
+        "upstream-openbsd/lib/libc/net/ntohl.c",
+        "upstream-openbsd/lib/libc/net/ntohs.c",
+        "upstream-openbsd/lib/libc/stdio/asprintf.c",
+        "upstream-openbsd/lib/libc/stdio/clrerr.c",
+        "upstream-openbsd/lib/libc/stdio/dprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fclose.c",
+        "upstream-openbsd/lib/libc/stdio/fdopen.c",
+        "upstream-openbsd/lib/libc/stdio/feof.c",
+        "upstream-openbsd/lib/libc/stdio/ferror.c",
+        "upstream-openbsd/lib/libc/stdio/fflush.c",
+        "upstream-openbsd/lib/libc/stdio/fgetc.c",
+        "upstream-openbsd/lib/libc/stdio/fgetln.c",
+        "upstream-openbsd/lib/libc/stdio/fgetpos.c",
+        "upstream-openbsd/lib/libc/stdio/fgets.c",
+        "upstream-openbsd/lib/libc/stdio/fgetwc.c",
+        "upstream-openbsd/lib/libc/stdio/fgetws.c",
+        "upstream-openbsd/lib/libc/stdio/fileno.c",
+        "upstream-openbsd/lib/libc/stdio/flags.c",
+        "upstream-openbsd/lib/libc/stdio/fmemopen.c",
+        "upstream-openbsd/lib/libc/stdio/fopen.c",
+        "upstream-openbsd/lib/libc/stdio/fprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fpurge.c",
+        "upstream-openbsd/lib/libc/stdio/fputc.c",
+        "upstream-openbsd/lib/libc/stdio/fputs.c",
+        "upstream-openbsd/lib/libc/stdio/fputwc.c",
+        "upstream-openbsd/lib/libc/stdio/fputws.c",
+        "upstream-openbsd/lib/libc/stdio/freopen.c",
+        "upstream-openbsd/lib/libc/stdio/fscanf.c",
+        "upstream-openbsd/lib/libc/stdio/fseek.c",
+        "upstream-openbsd/lib/libc/stdio/fsetpos.c",
+        "upstream-openbsd/lib/libc/stdio/ftell.c",
+        "upstream-openbsd/lib/libc/stdio/funopen.c",
+        "upstream-openbsd/lib/libc/stdio/fvwrite.c",
+        "upstream-openbsd/lib/libc/stdio/fwalk.c",
+        "upstream-openbsd/lib/libc/stdio/fwide.c",
+        "upstream-openbsd/lib/libc/stdio/fwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/fwrite.c",
+        "upstream-openbsd/lib/libc/stdio/fwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/getc.c",
+        "upstream-openbsd/lib/libc/stdio/getchar.c",
+        "upstream-openbsd/lib/libc/stdio/getdelim.c",
+        "upstream-openbsd/lib/libc/stdio/getline.c",
+        "upstream-openbsd/lib/libc/stdio/gets.c",
+        "upstream-openbsd/lib/libc/stdio/getwc.c",
+        "upstream-openbsd/lib/libc/stdio/getwchar.c",
+        "upstream-openbsd/lib/libc/stdio/makebuf.c",
+        "upstream-openbsd/lib/libc/stdio/mktemp.c",
+        "upstream-openbsd/lib/libc/stdio/open_memstream.c",
+        "upstream-openbsd/lib/libc/stdio/open_wmemstream.c",
+        "upstream-openbsd/lib/libc/stdio/perror.c",
+        "upstream-openbsd/lib/libc/stdio/printf.c",
+        "upstream-openbsd/lib/libc/stdio/putc.c",
+        "upstream-openbsd/lib/libc/stdio/putchar.c",
+        "upstream-openbsd/lib/libc/stdio/puts.c",
+        "upstream-openbsd/lib/libc/stdio/putwc.c",
+        "upstream-openbsd/lib/libc/stdio/putwchar.c",
+        "upstream-openbsd/lib/libc/stdio/remove.c",
+        "upstream-openbsd/lib/libc/stdio/rewind.c",
+        "upstream-openbsd/lib/libc/stdio/rget.c",
+        "upstream-openbsd/lib/libc/stdio/scanf.c",
+        "upstream-openbsd/lib/libc/stdio/setbuf.c",
+        "upstream-openbsd/lib/libc/stdio/setbuffer.c",
+        "upstream-openbsd/lib/libc/stdio/setvbuf.c",
+        "upstream-openbsd/lib/libc/stdio/sscanf.c",
+        "upstream-openbsd/lib/libc/stdio/swprintf.c",
+        "upstream-openbsd/lib/libc/stdio/swscanf.c",
+        "upstream-openbsd/lib/libc/stdio/tempnam.c",
+        "upstream-openbsd/lib/libc/stdio/tmpnam.c",
+        "upstream-openbsd/lib/libc/stdio/ungetc.c",
+        "upstream-openbsd/lib/libc/stdio/ungetwc.c",
+        "upstream-openbsd/lib/libc/stdio/vasprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vdprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vfwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vfwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vsnprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vsprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vsscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vswprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vswscanf.c",
+        "upstream-openbsd/lib/libc/stdio/vwprintf.c",
+        "upstream-openbsd/lib/libc/stdio/vwscanf.c",
+        "upstream-openbsd/lib/libc/stdio/wbuf.c",
+        "upstream-openbsd/lib/libc/stdio/wprintf.c",
+        "upstream-openbsd/lib/libc/stdio/wscanf.c",
+        "upstream-openbsd/lib/libc/stdio/wsetup.c",
+        "upstream-openbsd/lib/libc/stdlib/abs.c",
+        "upstream-openbsd/lib/libc/stdlib/atoi.c",
+        "upstream-openbsd/lib/libc/stdlib/atol.c",
+        "upstream-openbsd/lib/libc/stdlib/atoll.c",
+        "upstream-openbsd/lib/libc/stdlib/getenv.c",
+        "upstream-openbsd/lib/libc/stdlib/insque.c",
+        "upstream-openbsd/lib/libc/stdlib/imaxabs.c",
+        "upstream-openbsd/lib/libc/stdlib/imaxdiv.c",
+        "upstream-openbsd/lib/libc/stdlib/labs.c",
+        "upstream-openbsd/lib/libc/stdlib/llabs.c",
+        "upstream-openbsd/lib/libc/stdlib/lsearch.c",
+        "upstream-openbsd/lib/libc/stdlib/reallocarray.c",
+        "upstream-openbsd/lib/libc/stdlib/remque.c",
+        "upstream-openbsd/lib/libc/stdlib/setenv.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoimax.c",
+        "upstream-openbsd/lib/libc/stdlib/strtol.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoll.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoul.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoull.c",
+        "upstream-openbsd/lib/libc/stdlib/strtoumax.c",
+        "upstream-openbsd/lib/libc/stdlib/system.c",
+        "upstream-openbsd/lib/libc/stdlib/tfind.c",
+        "upstream-openbsd/lib/libc/stdlib/tsearch.c",
+        "upstream-openbsd/lib/libc/string/strcasecmp.c",
+        "upstream-openbsd/lib/libc/string/strcspn.c",
+        "upstream-openbsd/lib/libc/string/strdup.c",
+        "upstream-openbsd/lib/libc/string/strndup.c",
+        "upstream-openbsd/lib/libc/string/strpbrk.c",
+        "upstream-openbsd/lib/libc/string/strsep.c",
+        "upstream-openbsd/lib/libc/string/strspn.c",
+        "upstream-openbsd/lib/libc/string/strstr.c",
+        "upstream-openbsd/lib/libc/string/strtok.c",
+        "upstream-openbsd/lib/libc/string/wmemcpy.c",
+        "upstream-openbsd/lib/libc/string/wcslcpy.c",
+        "upstream-openbsd/lib/libc/string/wcsstr.c",
+        "upstream-openbsd/lib/libc/string/wcswidth.c",
+    ],
+
+    cflags: [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-Wno-unused-parameter",
+        "-include openbsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "private",
+        "stdio",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+        "upstream-openbsd/lib/libc/gdtoa/",
+    ],
+}
+
+// ========================================================
+// libc_openbsd.a - upstream OpenBSD C library code
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        // These two depend on getentropy_linux.c, which isn't in libc_ndk.a.
+        "upstream-openbsd/lib/libc/crypt/arc4random.c",
+        "upstream-openbsd/lib/libc/crypt/arc4random_uniform.c",
+
+        // May be overriden by per-arch optimized versions
+        "upstream-openbsd/lib/libc/string/memchr.c",
+        "upstream-openbsd/lib/libc/string/memmove.c",
+        "upstream-openbsd/lib/libc/string/memrchr.c",
+        "upstream-openbsd/lib/libc/string/stpcpy.c",
+        "upstream-openbsd/lib/libc/string/stpncpy.c",
+        "upstream-openbsd/lib/libc/string/strcat.c",
+        "upstream-openbsd/lib/libc/string/strcpy.c",
+        "upstream-openbsd/lib/libc/string/strlcat.c",
+        "upstream-openbsd/lib/libc/string/strlcpy.c",
+        "upstream-openbsd/lib/libc/string/strncat.c",
+        "upstream-openbsd/lib/libc/string/strncmp.c",
+        "upstream-openbsd/lib/libc/string/strncpy.c",
+    ],
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["upstream-openbsd/lib/libc/stdio/putw.c"],
+        },
+    },
+
+    arch: {
+        arm: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+            ],
+            cortex_a7: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a53: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a53_a57: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a8: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a9: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a15: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            denver: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            krait: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+        },
+        arm64: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memchr.c",
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+            ],
+        },
+
+        x86: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memchr.c",
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/memrchr.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
+            ],
+            ssse3: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/strlcat.c",
+                    "upstream-openbsd/lib/libc/string/strlcpy.c",
+                    "upstream-openbsd/lib/libc/string/strncat.c",
+                ],
+            },
+        },
+
+        x86_64: {
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
+                "upstream-openbsd/lib/libc/string/strncat.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
+            ],
+        },
+    },
+
+    cflags: [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-Wno-unused-parameter",
+        "-include openbsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "private",
+        "stdio",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+        "upstream-openbsd/lib/libc/gdtoa/",
+    ],
+
+    name: "libc_openbsd",
+}
+
+// ========================================================
+// libc_gdtoa.a - upstream OpenBSD C library gdtoa code
+// ========================================================
+//
+// These files are built with the openbsd-compat.h header file
+// automatically included.
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "upstream-openbsd/android/gdtoa_support.cpp",
+        "upstream-openbsd/lib/libc/gdtoa/dmisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/dtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/gdtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/gethex.c",
+        "upstream-openbsd/lib/libc/gdtoa/gmisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/hd_init.c",
+        "upstream-openbsd/lib/libc/gdtoa/hdtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/hexnan.c",
+        "upstream-openbsd/lib/libc/gdtoa/ldtoa.c",
+        "upstream-openbsd/lib/libc/gdtoa/misc.c",
+        "upstream-openbsd/lib/libc/gdtoa/smisc.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtod.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtodg.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtof.c",
+        "upstream-openbsd/lib/libc/gdtoa/strtord.c",
+        "upstream-openbsd/lib/libc/gdtoa/sum.c",
+        "upstream-openbsd/lib/libc/gdtoa/ulp.c",
+    ],
+    multilib: {
+        lib64: {
+            srcs: ["upstream-openbsd/lib/libc/gdtoa/strtorQ.c"],
+        },
+    },
+
+    cflags: [
+        "-Wno-sign-compare",
+        "-Wno-uninitialized",
+        "-fvisibility=hidden",
+        "-include openbsd-compat.h",
+    ],
+
+    local_include_dirs: [
+        "private",
+        "upstream-openbsd/android/include",
+        "upstream-openbsd/lib/libc/include",
+    ],
+
+    name: "libc_gdtoa",
+}
+
+// ========================================================
+// libc_bionic.a - home-grown C library code
+// ========================================================
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        // The following implementations depend on pthread data, so we can't
+        // include them in libc_ndk.a.
+        "bionic/__cxa_thread_atexit_impl.cpp",
+        "bionic/fork.cpp",
+
+        // The data that backs getauxval is initialized in the libc init
+        // functions which are invoked by the linker. If this file is included
+        // in libc_ndk.a, only one of the copies of the global data will be
+        // initialized, resulting in nullptr dereferences.
+        "bionic/getauxval.cpp",
+
+        // These four require getauxval, which isn't available on older
+        // platforms.
+        "bionic/getentropy_linux.c",
+        "bionic/sysconf.cpp",
+        "bionic/vdso.cpp",
+        "bionic/setjmp_cookie.cpp",
+
+        "bionic/__memcpy_chk.cpp",
+        "bionic/__memset_chk.cpp",
+        "bionic/__strcat_chk.cpp",
+        "bionic/__strcpy_chk.cpp",
+        "bionic/strchr.cpp",
+        "bionic/strnlen.c",
+        "bionic/strrchr.cpp",
+    ],
+    cflags: ["-Wframe-larger-than=2048"],
+
+    arch: {
+        arm: {
+            srcs: [
+                "arch-arm/bionic/abort_arm.S",
+                "arch-arm/bionic/atomics_arm.c",
+                "arch-arm/bionic/__bionic_clone.S",
+                "arch-arm/bionic/_exit_with_stack_teardown.S",
+                "arch-arm/bionic/libgcc_compat.c",
+                "arch-arm/bionic/popcount_tab.c",
+                "arch-arm/bionic/__restore.S",
+                "arch-arm/bionic/setjmp.S",
+                "arch-arm/bionic/syscall.S",
+                "arch-arm/bionic/vfork.S",
+
+                "arch-arm/generic/bionic/memcmp.S",
+                "arch-arm/generic/bionic/memcpy.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+            ],
+            exclude_srcs: [
+                "bionic/__memcpy_chk.cpp",
+                "bionic/__memset_chk.cpp",
+            ],
+            cortex_a7: {
+                srcs: [
+                    "arch-arm/cortex-a7/bionic/memset.S",
+
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a53: {
+                srcs: [
+                    "arch-arm/cortex-a53/bionic/memcpy.S",
+                    "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+
+                    "arch-arm/cortex-a7/bionic/memset.S",
+
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a53_a57: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a8: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a9: {
+                srcs: [
+                    "arch-arm/cortex-a9/bionic/memcpy.S",
+                    "arch-arm/cortex-a9/bionic/memset.S",
+                    "arch-arm/cortex-a9/bionic/stpcpy.S",
+                    "arch-arm/cortex-a9/bionic/strcat.S",
+                    "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a9/bionic/strcmp.S",
+                    "arch-arm/cortex-a9/bionic/strcpy.S",
+                    "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a9/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a15: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            denver: {
+                srcs: [
+                    "arch-arm/denver/bionic/memcpy.S",
+                    "arch-arm/denver/bionic/memmove.S",
+                    "arch-arm/denver/bionic/memset.S",
+                    "arch-arm/denver/bionic/__strcat_chk.S",
+                    "arch-arm/denver/bionic/__strcpy_chk.S",
+
+                    // Use cortex-a15 versions of strcat/strcpy/strlen.
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            krait: {
+                srcs: [
+                    "arch-arm/krait/bionic/memcpy.S",
+                    "arch-arm/krait/bionic/memset.S",
+                    "arch-arm/krait/bionic/strcmp.S",
+                    "arch-arm/krait/bionic/__strcat_chk.S",
+                    "arch-arm/krait/bionic/__strcpy_chk.S",
+
+                    // Use cortex-a15 versions of strcat/strcpy/strlen.
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+
+        },
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/__bionic_clone.S",
+                "arch-arm64/bionic/_exit_with_stack_teardown.S",
+                "arch-arm64/bionic/setjmp.S",
+                "arch-arm64/bionic/__set_tls.c",
+                "arch-arm64/bionic/syscall.S",
+                "arch-arm64/bionic/vfork.S",
+
+                "arch-arm64/generic/bionic/memchr.S",
+                "arch-arm64/generic/bionic/memcmp.S",
+                "arch-arm64/generic/bionic/memcpy.S",
+                "arch-arm64/generic/bionic/memmove.S",
+                "arch-arm64/generic/bionic/memset.S",
+                "arch-arm64/generic/bionic/stpcpy.S",
+                "arch-arm64/generic/bionic/strchr.S",
+                "arch-arm64/generic/bionic/strcmp.S",
+                "arch-arm64/generic/bionic/strcpy.S",
+                "arch-arm64/generic/bionic/strlen.S",
+                "arch-arm64/generic/bionic/strncmp.S",
+                "arch-arm64/generic/bionic/strnlen.S",
+                "arch-arm64/generic/bionic/wmemmove.S",
+            ],
+            exclude_srcs: [
+                "bionic/__memcpy_chk.cpp",
+                "bionic/strchr.cpp",
+                "bionic/strnlen.c",
+            ],
+            denver64: {
+                srcs: [
+                    "arch-arm64/denver64/bionic/memcpy.S",
+                    "arch-arm64/denver64/bionic/memset.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm64/generic/bionic/memcpy.S",
+                    "arch-arm64/generic/bionic/memset.S",
+                ],
+            },
+        },
+
+        mips: {
+            srcs: [
+                "arch-mips/bionic/__bionic_clone.S",
+                "arch-mips/bionic/bzero.S",
+                "arch-mips/bionic/cacheflush.cpp",
+                "arch-mips/bionic/_exit_with_stack_teardown.S",
+                "arch-mips/bionic/setjmp.S",
+                "arch-mips/bionic/syscall.S",
+                "arch-mips/bionic/vfork.S",
+
+                "arch-mips/string/memcmp.c",
+                "arch-mips/string/memcpy.S",
+                "arch-mips/string/memset.S",
+                "arch-mips/string/strcmp.S",
+                "arch-mips/string/strlen.c",
+            ],
+            rev6: {
+                srcs: [
+                    "arch-mips/string/mips_strlen.c",
+                ],
+                exclude_srcs: [
+                    "arch-mips/string/strlen.c",
+                ],
+            },
+        },
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/__bionic_clone.S",
+                "arch-mips64/bionic/_exit_with_stack_teardown.S",
+                "arch-mips64/bionic/setjmp.S",
+                "arch-mips64/bionic/syscall.S",
+                "arch-mips64/bionic/vfork.S",
+                "arch-mips64/bionic/stat.cpp",
+
+                "arch-mips/string/memcmp.c",
+                "arch-mips/string/memcpy.S",
+                "arch-mips/string/memset.S",
+                "arch-mips/string/strcmp.S",
+                "arch-mips/string/strlen.c",
+            ],
+        },
+
+        x86: {
+            srcs: [
+                "arch-x86/bionic/__bionic_clone.S",
+                "arch-x86/bionic/_exit_with_stack_teardown.S",
+                "arch-x86/bionic/libgcc_compat.c",
+                "arch-x86/bionic/__restore.S",
+                "arch-x86/bionic/setjmp.S",
+                "arch-x86/bionic/__set_tls.c",
+                "arch-x86/bionic/syscall.S",
+                "arch-x86/bionic/vfork.S",
+
+                "arch-x86/generic/string/memcmp.S",
+                "arch-x86/generic/string/strcmp.S",
+                "arch-x86/generic/string/strncmp.S",
+                "arch-x86/generic/string/strcat.S",
+                "arch-x86/atom/string/sse2-memchr-atom.S",
+                "arch-x86/atom/string/sse2-memrchr-atom.S",
+                "arch-x86/atom/string/sse2-strchr-atom.S",
+                "arch-x86/atom/string/sse2-strnlen-atom.S",
+                "arch-x86/atom/string/sse2-strrchr-atom.S",
+                "arch-x86/atom/string/sse2-wcschr-atom.S",
+                "arch-x86/atom/string/sse2-wcsrchr-atom.S",
+                "arch-x86/atom/string/sse2-wcslen-atom.S",
+                "arch-x86/atom/string/sse2-wcscmp-atom.S",
+                "arch-x86/silvermont/string/sse2-bcopy-slm.S",
+                "arch-x86/silvermont/string/sse2-bzero-slm.S",
+                "arch-x86/silvermont/string/sse2-memcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-memmove-slm.S",
+                "arch-x86/silvermont/string/sse2-memset-slm.S",
+                "arch-x86/silvermont/string/sse2-stpcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-stpncpy-slm.S",
+                "arch-x86/silvermont/string/sse2-strcpy-slm.S",
+                "arch-x86/silvermont/string/sse2-strlen-slm.S",
+                "arch-x86/silvermont/string/sse2-strncpy-slm.S",
+            ],
+
+            exclude_srcs: [
+                "bionic/strchr.cpp",
+                "bionic/strnlen.c",
+                "bionic/strrchr.cpp",
+            ],
+            atom: {
+                srcs: [
+                    "arch-x86/atom/string/sse2-bzero-atom.S",
+                    "arch-x86/atom/string/sse2-memset-atom.S",
+                    "arch-x86/atom/string/sse2-strlen-atom.S",
+                    "arch-x86/atom/string/ssse3-bcopy-atom.S",
+                    "arch-x86/atom/string/ssse3-memcmp-atom.S",
+                    "arch-x86/atom/string/ssse3-memmove-atom.S",
+                    "arch-x86/atom/string/ssse3-strncpy-atom.S",
+                    "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/memcmp.S",
+                    "arch-x86/silvermont/string/sse2-bcopy-slm.S",
+                    "arch-x86/silvermont/string/sse2-bzero-slm.S",
+                    "arch-x86/silvermont/string/sse2-memcpy-slm.S",
+                    "arch-x86/silvermont/string/sse2-memmove-slm.S",
+                    "arch-x86/silvermont/string/sse2-memset-slm.S",
+                    "arch-x86/silvermont/string/sse2-strcpy-slm.S",
+                    "arch-x86/silvermont/string/sse2-strlen-slm.S",
+                    "arch-x86/silvermont/string/sse2-strncpy-slm.S",
+                ],
+            },
+            ssse3: {
+                srcs: [
+                    "arch-x86/atom/string/ssse3-strncat-atom.S",
+                    "arch-x86/atom/string/ssse3-strlcat-atom.S",
+                    "arch-x86/atom/string/ssse3-strlcpy-atom.S",
+                    "arch-x86/atom/string/ssse3-strcat-atom.S",
+                    "arch-x86/atom/string/ssse3-strcmp-atom.S",
+                    "arch-x86/atom/string/ssse3-strncmp-atom.S",
+                    "arch-x86/atom/string/ssse3-wcscat-atom.S",
+                    "arch-x86/atom/string/ssse3-wcscpy-atom.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/strcmp.S",
+                    "arch-x86/generic/string/strncmp.S",
+                    "arch-x86/generic/string/strcat.S",
+                ],
+            },
+            sse4: {
+                srcs: [
+                    "arch-x86/silvermont/string/sse4-memcmp-slm.S",
+                    "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/memcmp.S",
+                ],
+            },
+        },
+        x86_64: {
+            srcs: [
+                "arch-x86_64/bionic/__bionic_clone.S",
+                "arch-x86_64/bionic/_exit_with_stack_teardown.S",
+                "arch-x86_64/bionic/__restore_rt.S",
+                "arch-x86_64/bionic/setjmp.S",
+                "arch-x86_64/bionic/__set_tls.c",
+                "arch-x86_64/bionic/syscall.S",
+                "arch-x86_64/bionic/vfork.S",
+
+                "arch-x86_64/string/sse2-memcpy-slm.S",
+                "arch-x86_64/string/sse2-memmove-slm.S",
+                "arch-x86_64/string/sse2-memset-slm.S",
+                "arch-x86_64/string/sse2-stpcpy-slm.S",
+                "arch-x86_64/string/sse2-stpncpy-slm.S",
+                "arch-x86_64/string/sse2-strcat-slm.S",
+                "arch-x86_64/string/sse2-strcpy-slm.S",
+                "arch-x86_64/string/sse2-strlcat-slm.S",
+                "arch-x86_64/string/sse2-strlcpy-slm.S",
+                "arch-x86_64/string/sse2-strlen-slm.S",
+                "arch-x86_64/string/sse2-strncat-slm.S",
+                "arch-x86_64/string/sse2-strncpy-slm.S",
+                "arch-x86_64/string/sse4-memcmp-slm.S",
+                "arch-x86_64/string/ssse3-strcmp-slm.S",
+                "arch-x86_64/string/ssse3-strncmp-slm.S",
+            ],
+        },
+    },
+
+    cppflags: ["-Wold-style-cast"],
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_bionic",
+}
+
+// ========================================================
+// libc_bionic_ndk.a- The portions of libc_bionic that can
+// be safely used in libc_ndk.a (no troublesome global data
+// or constructors).
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "bionic/abort.cpp",
+        "bionic/accept.cpp",
+        "bionic/accept4.cpp",
+        "bionic/access.cpp",
+        "bionic/arpa_inet.cpp",
+        "bionic/assert.cpp",
+        "bionic/atof.cpp",
+        "bionic/bionic_systrace.cpp",
+        "bionic/bionic_time_conversions.cpp",
+        "bionic/brk.cpp",
+        "bionic/c16rtomb.cpp",
+        "bionic/c32rtomb.cpp",
+        "bionic/chmod.cpp",
+        "bionic/chown.cpp",
+        "bionic/clearenv.cpp",
+        "bionic/clock.cpp",
+        "bionic/clock_getcpuclockid.cpp",
+        "bionic/clock_nanosleep.cpp",
+        "bionic/clone.cpp",
+        "bionic/close.cpp",
+        "bionic/__cmsg_nxthdr.cpp",
+        "bionic/connect.cpp",
+        "bionic/ctype.cpp",
+        "bionic/dirent.cpp",
+        "bionic/dup2.cpp",
+        "bionic/epoll_create.cpp",
+        "bionic/epoll_pwait.cpp",
+        "bionic/epoll_wait.cpp",
+        "bionic/__errno.cpp",
+        "bionic/error.cpp",
+        "bionic/eventfd_read.cpp",
+        "bionic/eventfd_write.cpp",
+        "bionic/faccessat.cpp",
+        "bionic/fchmod.cpp",
+        "bionic/fchmodat.cpp",
+        "bionic/ffs.cpp",
+        "bionic/fgetxattr.cpp",
+        "bionic/flistxattr.cpp",
+        "bionic/flockfile.cpp",
+        "bionic/fpclassify.cpp",
+        "bionic/fsetxattr.cpp",
+        "bionic/ftruncate.cpp",
+        "bionic/futimens.cpp",
+        "bionic/getcwd.cpp",
+        "bionic/gethostname.cpp",
+        "bionic/getpgrp.cpp",
+        "bionic/getpid.cpp",
+        "bionic/gettid.cpp",
+        "bionic/__gnu_basename.cpp",
+        "bionic/ifaddrs.cpp",
+        "bionic/inotify_init.cpp",
+        "bionic/ioctl.cpp",
+        "bionic/lchown.cpp",
+        "bionic/lfs64_support.cpp",
+        "bionic/__libc_current_sigrtmax.cpp",
+        "bionic/__libc_current_sigrtmin.cpp",
+        "bionic/libc_init_common.cpp",
+        "bionic/libc_logging.cpp",
+        "bionic/libgen.cpp",
+        "bionic/link.cpp",
+        "bionic/locale.cpp",
+        "bionic/lstat.cpp",
+        "bionic/malloc_info.cpp",
+        "bionic/mbrtoc16.cpp",
+        "bionic/mbrtoc32.cpp",
+        "bionic/mbstate.cpp",
+        "bionic/mempcpy.cpp",
+        "bionic/mkdir.cpp",
+        "bionic/mkfifo.cpp",
+        "bionic/mknod.cpp",
+        "bionic/mntent.cpp",
+        "bionic/mremap.cpp",
+        "bionic/NetdClientDispatch.cpp",
+        "bionic/open.cpp",
+        "bionic/pathconf.cpp",
+        "bionic/pause.cpp",
+        "bionic/pipe.cpp",
+        "bionic/poll.cpp",
+        "bionic/posix_fadvise.cpp",
+        "bionic/posix_fallocate.cpp",
+        "bionic/posix_madvise.cpp",
+        "bionic/posix_timers.cpp",
+        "bionic/ptrace.cpp",
+        "bionic/pty.cpp",
+        "bionic/raise.cpp",
+        "bionic/rand.cpp",
+        "bionic/readlink.cpp",
+        "bionic/reboot.cpp",
+        "bionic/recv.cpp",
+        "bionic/rename.cpp",
+        "bionic/rmdir.cpp",
+        "bionic/scandir.cpp",
+        "bionic/sched_getaffinity.cpp",
+        "bionic/sched_getcpu.cpp",
+        "bionic/semaphore.cpp",
+        "bionic/send.cpp",
+        "bionic/setegid.cpp",
+        "bionic/__set_errno.cpp",
+        "bionic/seteuid.cpp",
+        "bionic/setpgrp.cpp",
+        "bionic/sigaction.cpp",
+        "bionic/sigaddset.cpp",
+        "bionic/sigdelset.cpp",
+        "bionic/sigemptyset.cpp",
+        "bionic/sigfillset.cpp",
+        "bionic/sigismember.cpp",
+        "bionic/signal.cpp",
+        "bionic/signalfd.cpp",
+        "bionic/sigpending.cpp",
+        "bionic/sigprocmask.cpp",
+        "bionic/sigqueue.cpp",
+        "bionic/sigsuspend.cpp",
+        "bionic/sigtimedwait.cpp",
+        "bionic/sigwait.cpp",
+        "bionic/sigwaitinfo.cpp",
+        "bionic/socket.cpp",
+        "bionic/stat.cpp",
+        "bionic/statvfs.cpp",
+        "bionic/strchrnul.cpp",
+        "bionic/strerror.cpp",
+        "bionic/strerror_r.cpp",
+        "bionic/strsignal.cpp",
+        "bionic/strtold.cpp",
+        "bionic/stubs.cpp",
+        "bionic/symlink.cpp",
+        "bionic/sysinfo.cpp",
+        "bionic/syslog.cpp",
+        "bionic/sys_siglist.c",
+        "bionic/sys_signame.c",
+        "bionic/system_properties.cpp",
+        "bionic/tdestroy.cpp",
+        "bionic/termios.cpp",
+        "bionic/thread_private.cpp",
+        "bionic/tmpfile.cpp",
+        "bionic/umount.cpp",
+        "bionic/unlink.cpp",
+        "bionic/utimes.cpp",
+        "bionic/wait.cpp",
+        "bionic/wchar.cpp",
+        "bionic/wctype.cpp",
+        "bionic/wmempcpy.cpp",
+    ],
+    cflags: ["-Wframe-larger-than=2048"],
+
+    multilib: {
+        lib32: {
+            // LP32 cruft
+            srcs: ["bionic/mmap.cpp"],
+        },
+    },
+
+    cppflags: ["-Wold-style-cast"],
+    local_include_dirs: ["stdio"],
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_bionic_ndk",
+}
+
+// ========================================================
+// libc_pthread.a - pthreads parts that previously lived in
+// libc_bionic.a. Relocated to their own library because
+// they can't be included in libc_ndk.a (as they layout of
+// pthread_t has changed over the years and has ABI
+// compatibility issues).
+// ========================================================
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "bionic/pthread_atfork.cpp",
+        "bionic/pthread_attr.cpp",
+        "bionic/pthread_barrier.cpp",
+        "bionic/pthread_cond.cpp",
+        "bionic/pthread_create.cpp",
+        "bionic/pthread_detach.cpp",
+        "bionic/pthread_equal.cpp",
+        "bionic/pthread_exit.cpp",
+        "bionic/pthread_getcpuclockid.cpp",
+        "bionic/pthread_getschedparam.cpp",
+        "bionic/pthread_gettid_np.cpp",
+        "bionic/pthread_internal.cpp",
+        "bionic/pthread_join.cpp",
+        "bionic/pthread_key.cpp",
+        "bionic/pthread_kill.cpp",
+        "bionic/pthread_mutex.cpp",
+        "bionic/pthread_once.cpp",
+        "bionic/pthread_rwlock.cpp",
+        "bionic/pthread_self.cpp",
+        "bionic/pthread_setname_np.cpp",
+        "bionic/pthread_setschedparam.cpp",
+        "bionic/pthread_sigmask.cpp",
+        "bionic/pthread_spinlock.cpp",
+    ],
+    cflags: ["-Wframe-larger-than=2048"],
+
+    cppflags: ["-Wold-style-cast"],
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_pthread",
+}
+
+// ========================================================
+// libc_cxa.a - Things traditionally in libstdc++
+// ========================================================
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "bionic/__cxa_guard.cpp",
+        "bionic/__cxa_pure_virtual.cpp",
+        "bionic/new.cpp",
+    ],
+    cflags: ["-fvisibility=hidden"],
+    include_dirs: ["bionic/libstdc++/include"],
+    name: "libc_cxa",
+    clang: true, // GCC refuses to hide new/delete
+
+    // b/17574078: Need to disable coverage until we have a prebuilt libprofile_rt.
+    // Since this is a static library built with clang, it needs to link
+    // libprofile_rt when it is linked into the final binary. Since the final binary
+    // is built with GCC, it won't link libprofile_rt. We can't very easily just add
+    // libprofile_rt to all link lines the way we've done for libgcov because
+    // libprofile_rt isn't prebuilt, and it would be tricky to write a rule that
+    // would make sure libprofile_rt is built.
+    native_coverage: false,
+}
+
+// ========================================================
+// libc_syscalls.a
+// ========================================================
+
+cc_library_static {
+    arch: {
+        arm: {
+            srcs: ["arch-arm/syscalls/**/*.S"],
+        },
+        arm64: {
+            srcs: ["arch-arm64/syscalls/**/*.S"],
+        },
+        mips: {
+            srcs: ["arch-mips/syscalls/**/*.S"],
+        },
+        mips64: {
+            srcs: ["arch-mips64/syscalls/**/*.S"],
+        },
+        x86: {
+            srcs: ["arch-x86/syscalls/**/*.S"],
+        },
+        x86_64: {
+            srcs: ["arch-x86_64/syscalls/**/*.S"],
+        },
+    },
+    name: "libc_syscalls",
+}
+
+// ========================================================
+// libc_aeabi.a
+// This is an LP32 ARM-only library that needs to be built with -fno-builtin
+// to avoid infinite recursion. For the other architectures we just build an
+// empty library to keep this makefile simple.
+// ========================================================
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    arch: {
+        arm: {
+            srcs: ["arch-arm/bionic/__aeabi.c"],
+        },
+    },
+    name: "libc_aeabi",
+    cflags: ["-fno-builtin"],
+}
+
+// ========================================================
+// libc_ndk.a
+// Compatibility library for the NDK. This library contains
+// all the parts of libc that are safe to statically link.
+// We can't safely statically link things that can only run
+// on a certain version of the OS. Examples include
+// anything that talks to netd (a large portion of the DNS
+// code) and anything that is dependent on the layout of a
+// data structure that has changed across releases (such as
+// pthread_t).
+// ========================================================
+
+cc_library_static {
+    name: "libc_ndk",
+    defaults: ["libc_defaults"],
+    srcs: libc_common_src_files + ["bionic/malloc_debug_common.cpp"],
+    multilib: {
+        lib32: {
+            srcs: libc_common_src_files_32,
+        },
+    },
+    arch: {
+        arm: {
+            srcs: [
+                "arch-arm/bionic/exidx_dynamic.c",
+                "arch-common/bionic/crtbegin_so.c",
+                "arch-arm/bionic/atexit_legacy.c",
+                "arch-common/bionic/crtend_so.S",
+            ],
+            whole_static_libs: ["libc_aeabi"],
+        },
+    },
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DLIBC_STATIC",
+    ],
+
+    whole_static_libs: [
+        "libc_bionic_ndk",
+        "libc_cxa",
+        "libc_freebsd",
+        "libc_gdtoa",
+        "libc_malloc",
+        "libc_netbsd",
+        "libc_openbsd_ndk",
+        "libc_stack_protector",
+        "libc_syscalls",
+        "libc_tzcode",
+        "libm",
+    ],
+}
+
+// ========================================================
+// libc_common.a
+// ========================================================
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: libc_common_src_files,
+    multilib: {
+        lib32: {
+            srcs: libc_common_src_files_32,
+        },
+    },
+    name: "libc_common",
+
+    whole_static_libs: [
+        "libc_bionic",
+        "libc_bionic_ndk",
+        "libc_cxa",
+        "libc_dns",
+        "libc_freebsd",
+        "libc_gdtoa",
+        "libc_malloc",
+        "libc_netbsd",
+        "libc_openbsd",
+        "libc_openbsd_ndk",
+        "libc_pthread",
+        "libc_stack_protector",
+        "libc_syscalls",
+        "libc_tzcode",
+    ],
+
+    arch: {
+        arm: {
+            whole_static_libs: ["libc_aeabi"],
+        },
+    },
+}
+
+// ========================================================
+// libc_nomalloc.a
+// ========================================================
+//
+// This is a version of the static C library that does not
+// include malloc. It's useful in situations when the user wants
+// to provide their own malloc implementation, or wants to
+// explicitly disallow the use of malloc, such as in the
+// dynamic linker.
+
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "bionic/dl_iterate_phdr_static.cpp",
+        "bionic/libc_init_static.cpp",
+    ],
+
+    arch: {
+        arm: {
+            srcs: ["arch-arm/bionic/exidx_static.c"],
+        },
+    },
+
+    cflags: ["-DLIBC_STATIC"],
+
+    name: "libc_nomalloc",
+
+    whole_static_libs: ["libc_common"],
+}
+
+// ========================================================
+// libc_malloc.a: the _prefixed_ malloc functions (like dlcalloc).
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    product_variables: {
+        device_uses_jemalloc: {
+            srcs: ["bionic/jemalloc_wrapper.cpp"],
+            whole_static_libs: ["libjemalloc"],
+        },
+        device_uses_dlmalloc: {
+            srcs: ["bionic/dlmalloc.c"],
+        },
+    },
+    cflags: ["-fvisibility=hidden"],
+
+    name: "libc_malloc",
+}
+
+// ========================================================
+// libc.a + libc.so
+// ========================================================
+cc_library {
+    defaults: ["libc_defaults"],
+    name: "libc",
+    product_variables: {
+        platform_sdk_version: {
+            asflags: ["-DPLATFORM_SDK_VERSION=%d"],
+        },
+    },
+    srcs: ["bionic/malloc_debug_common.cpp"],
+    static: {
+        srcs: [
+            "bionic/dl_iterate_phdr_static.cpp",
+            "bionic/libc_init_static.cpp",
+        ],
+        cflags: ["-DLIBC_STATIC"],
+    },
+    shared: {
+        srcs: [
+            "arch-common/bionic/crtbegin_so.c",
+            "arch-common/bionic/crtbrand.S",
+            "bionic/libc_init_dynamic.cpp",
+            "bionic/NetdClient.cpp",
+            "arch-common/bionic/crtend_so.S",
+        ],
+    },
+
+    required: ["tzdata"],
+
+    // Leave the symbols in the shared library so that stack unwinders can produce
+    // meaningful name resolution.
+    strip: "keep_symbols",
+
+    // 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
+    // external; if that were the case, then libc would not pull those symbols from libgcc.a as it
+    // should, instead relying on the external symbols from the dependent libraries.  That would
+    // create a "cloaked" dependency on libgcc.a in libc though the libraries, which is not what
+    // you wanted!
+
+    shared_libs: ["libdl"],
+    whole_static_libs: ["libc_common"],
+
+    // 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.
+    multilib: {
+        lib64: {
+            ldflags: ["-Wl,--exclude-libs,libgcc.a"],
+        },
+    },
+
+    nocrt: true,
+
+    arch: {
+        arm: {
+            //TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.arm.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.arm.brillo.map",
+                },
+            },
+
+            shared: {
+                srcs: ["arch-arm/bionic/exidx_dynamic.c"],
+            },
+            static: {
+                srcs: ["arch-arm/bionic/exidx_static.c"],
+            },
+
+            // special for arm
+            cflags: ["-DCRT_LEGACY_WORKAROUND"],
+            srcs: [
+                "arch-arm/bionic/atexit_legacy.c",
+            ],
+        },
+        arm64: {
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.arm64.map",
+        },
+        mips: {
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.mips.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.mips.brillo.map",
+                },
+            },
+        },
+        mips64: {
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.mips64.map",
+        },
+        x86: {
+            //TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.x86.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.x86.brillo.map",
+                },
+            },
+        },
+        x86_64: {
+            // Don't re-export new/delete and friends, even if the compiler really wants to.
+            version_script: "libc.x86_64.map",
+        },
+    },
+}
+
+// For all builds, except for the -user build we will enable memory
+// allocation checking (including memory leaks, buffer overwrites, etc.)
+// Note that all these checks are also controlled by env. settings
+// that can enable, or disable specific checks. Note also that some of
+// the checks are available only in emulator and are implemeted in
+// libc_malloc_qemu_instrumented.so.
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifneq ($(TARGET_BUILD_VARIANT),user)
+// ========================================================
+// libc_malloc_debug_leak.so
+// ========================================================
+cc_library_shared {
+    defaults: ["libc_defaults"],
+
+    srcs: [
+        "bionic/debug_backtrace.cpp",
+        "bionic/debug_mapinfo.cpp",
+        "bionic/libc_logging.cpp",
+        "bionic/malloc_debug_leak.cpp",
+        "bionic/malloc_debug_check.cpp",
+    ],
+
+    name: "libc_malloc_debug_leak",
+
+    shared_libs: [
+        "libc",
+        "libdl",
+    ],
+    // Only need this for arm since libc++ uses its own unwind code that
+    // doesn't mix with the other default unwind code.
+    arch: {
+        arm: {
+            static_libs: [
+                "libunwind_llvm",
+                "libc++abi",
+            ],
+            ldflags: ["-Wl,--exclude-libs,libunwind_llvm.a"],
+        },
+    },
+    allow_undefined_symbols: true,
+
+    // Don't re-export new/delete and friends, even if the compiler really wants to.
+    version_script: "version_script.txt",
+
+    // Don't install on release build
+    tags: [
+        "eng",
+        "debug",
+    ],
+}
+
+// ========================================================
+// libc_malloc_debug_qemu.so
+// ========================================================
+cc_library_shared {
+    defaults: ["libc_defaults"],
+    cflags: ["-DMALLOC_QEMU_INSTRUMENT"],
+
+    srcs: [
+        "bionic/libc_logging.cpp",
+        "bionic/malloc_debug_qemu.cpp",
+    ],
+
+    name: "libc_malloc_debug_qemu",
+
+    shared_libs: [
+        "libc",
+        "libdl",
+    ],
+
+    // Don't re-export new/delete and friends, even if the compiler really wants to.
+    version_script: "version_script.txt",
+
+    // Don't install on release build
+    tags: [
+        "eng",
+        "debug",
+    ],
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
+//!user
+
+// ========================================================
+// libstdc++.so + libstdc++.a
+// ========================================================
+cc_library {
+    defaults: ["libc_defaults"],
+    include_dirs: ["bionic/libstdc++/include"],
+    srcs: [
+        "bionic/__cxa_guard.cpp",
+        "bionic/__cxa_pure_virtual.cpp",
+        "bionic/new.cpp",
+        "bionic/libc_logging.cpp",
+    ],
+    name: "libstdc++",
+    system_shared_libs: ["libc"],
+
+    //TODO: This is to work around b/24465209. Remove after root cause is fixed
+    arch: {
+        arm: {
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+        x86: {
+            ldflags: ["-Wl,--hash-style=both"],
+        },
+    },
+}
+
+cc_defaults {
+    name: "crt_defaults",
+
+    no_default_compiler_flags: true,
+
+    arch: {
+        arm: {
+            local_include_dirs: ["arch-arm/include"],
+        },
+        arm64: {
+            local_include_dirs: ["arch-arm64/include"],
+        },
+        mips: {
+            local_include_dirs: ["arch-mips/include"],
+        },
+        mips64: {
+            local_include_dirs: ["arch-mips64/include"],
+        },
+        x86: {
+            local_include_dirs: ["arch-x86/include"],
+        },
+        x86_64: {
+            local_include_dirs: ["arch-x86_64/include"],
+        },
+    },
+    clang: false,
+}
+
+cc_defaults {
+    name: "crt_so_defaults",
+
+    arch: {
+        mips: {
+            cflags: ["-fPIC"],
+        },
+        mips64: {
+            cflags: ["-fPIC"],
+        },
+        x86: {
+            cflags: ["-fPIC"],
+        },
+        x86_64: {
+            cflags: ["-fPIC"],
+        },
+    },
+}
+
+// Android.mk:start
+// # crt obj files
+// # ========================================================
+// # crtbrand.c needs <stdint.h> and a #define for the platform SDK version.
+// libc_crt_target_cflags := \
+//    -I$(LOCAL_PATH)/include \
+//    -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) \
+//
+// my_2nd_arch_prefix :=
+// include $(LOCAL_PATH)/arch-$(TARGET_ARCH)/$(TARGET_ARCH).mk
+// include $(LOCAL_PATH)/crt.mk
+// ifdef TARGET_2ND_ARCH
+// my_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX)
+// include $(LOCAL_PATH)/arch-$(TARGET_2ND_ARCH)/$(TARGET_2ND_ARCH).mk
+// include $(LOCAL_PATH)/crt.mk
+// my_2nd_arch_prefix :=
+// endif
+//
+// include $(call all-makefiles-under,$(LOCAL_PATH))
+// Android.mk:end
+cc_object {
+    name: "crtbrand",
+    local_include_dirs: ["include"],
+    product_variables: {
+        platform_sdk_version: {
+            asflags: ["-DPLATFORM_SDK_VERSION=%d"],
+        },
+    },
+    srcs: ["arch-common/bionic/crtbrand.S"],
+
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_so1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin_so.c"],
+
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_so",
+
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
+    deps: [
+        "crtbegin_so1",
+        "crtbrand",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtend_so",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtend_so.S"],
+
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_static1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin.c"],
+
+    arch: {
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips: {
+            srcs: [
+                "arch-mips/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+    },
+
+    defaults: ["crt_defaults"],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_static",
+
+    deps: [
+        "crtbegin_static1",
+        "crtbrand",
+    ],
+    defaults: ["crt_defaults"],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_dynamic1",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtbegin.c"],
+
+    arch: {
+        arm64: {
+            srcs: [
+                "arch-arm64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips: {
+            srcs: [
+                "arch-mips/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+        mips64: {
+            srcs: [
+                "arch-mips64/bionic/crtbegin.c",
+            ],
+            exclude_srcs: [
+                "arch-common/bionic/crtbegin.c",
+            ],
+        },
+    },
+    defaults: ["crt_defaults"],
+}
+
+// Android.mk:ignore
+cc_object {
+    name: "crtbegin_dynamic",
+
+    deps: [
+        "crtbegin_dynamic1",
+        "crtbrand",
+    ],
+    defaults: ["crt_defaults"],
+}
+
+// Android.mk:ignore
+cc_object {
+    // We rename crtend.o to crtend_android.o to avoid a
+    // name clash between gcc and bionic.
+    name: "crtend_android",
+    local_include_dirs: ["include"],
+    srcs: ["arch-common/bionic/crtend.S"],
+
+    defaults: ["crt_defaults"],
+}
diff --git a/libc/Android.mk b/libc/Android.mk
index f0c5e9f..753e946 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -1,6 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 
-bionic_coverage := false
+bionic_coverage ?= false
 
 # Make everything depend on any changes to included makefiles.
 libc_common_additional_dependencies := $(LOCAL_PATH)/Android.mk
@@ -47,7 +47,6 @@
     bionic/if_indextoname.c \
     bionic/if_nametoindex.c \
     bionic/initgroups.c \
-    bionic/ioctl.c \
     bionic/isatty.c \
     bionic/memmem.c \
     bionic/pututline.c \
@@ -59,6 +58,7 @@
     bionic/system_properties_compat.c \
     stdio/findfp.c \
     stdio/fread.c \
+    stdio/refill.c \
     stdio/snprintf.c\
     stdio/sprintf.c \
     stdio/stdio.c \
@@ -70,12 +70,17 @@
 libc_common_src_files += \
     bionic/__FD_chk.cpp \
     bionic/__fgets_chk.cpp \
+    bionic/__fread_chk.cpp \
+    bionic/__fwrite_chk.cpp \
+    bionic/__getcwd_chk.cpp \
     bionic/__memchr_chk.cpp \
     bionic/__memmove_chk.cpp \
     bionic/__memrchr_chk.cpp \
     bionic/__poll_chk.cpp \
     bionic/__pread64_chk.cpp \
     bionic/__pread_chk.cpp \
+    bionic/__pwrite64_chk.cpp \
+    bionic/__pwrite_chk.cpp \
     bionic/__read_chk.cpp \
     bionic/__readlink_chk.cpp \
     bionic/__readlinkat_chk.cpp \
@@ -92,12 +97,14 @@
     bionic/__umask_chk.cpp \
     bionic/__vsnprintf_chk.cpp \
     bionic/__vsprintf_chk.cpp \
+    bionic/__write_chk.cpp
 
 libc_bionic_ndk_src_files := \
     bionic/abort.cpp \
     bionic/accept.cpp \
     bionic/accept4.cpp \
     bionic/access.cpp \
+    bionic/arpa_inet.cpp \
     bionic/assert.cpp \
     bionic/atof.cpp \
     bionic/bionic_systrace.cpp \
@@ -130,6 +137,7 @@
     bionic/fchmodat.cpp \
     bionic/ffs.cpp \
     bionic/fgetxattr.cpp \
+    bionic/flistxattr.cpp \
     bionic/flockfile.cpp \
     bionic/fpclassify.cpp \
     bionic/fsetxattr.cpp \
@@ -141,7 +149,9 @@
     bionic/getpid.cpp \
     bionic/gettid.cpp \
     bionic/__gnu_basename.cpp \
+    bionic/ifaddrs.cpp \
     bionic/inotify_init.cpp \
+    bionic/ioctl.cpp \
     bionic/lchown.cpp \
     bionic/lfs64_support.cpp \
     bionic/__libc_current_sigrtmax.cpp \
@@ -161,6 +171,7 @@
     bionic/mkfifo.cpp \
     bionic/mknod.cpp \
     bionic/mntent.cpp \
+    bionic/mremap.cpp \
     bionic/NetdClientDispatch.cpp \
     bionic/open.cpp \
     bionic/pathconf.cpp \
@@ -207,6 +218,7 @@
     bionic/socket.cpp \
     bionic/stat.cpp \
     bionic/statvfs.cpp \
+    bionic/strchrnul.cpp \
     bionic/strerror.cpp \
     bionic/strerror_r.cpp \
     bionic/strsignal.cpp \
@@ -232,9 +244,11 @@
 
 libc_bionic_src_files :=
 
-# The fork implementation depends on pthread data, so we can't include it in
-# libc_ndk.a.
-libc_bionic_src_files += bionic/fork.cpp
+# The following implementations depend on pthread data, so we can't include
+# them in libc_ndk.a.
+libc_bionic_src_files += \
+    bionic/__cxa_thread_atexit_impl.cpp \
+    bionic/fork.cpp \
 
 # The data that backs getauxval is initialized in the libc init functions which
 # are invoked by the linker. If this file is included in libc_ndk.a, only one of
@@ -242,10 +256,20 @@
 # dereferences.
 libc_bionic_src_files += bionic/getauxval.cpp
 
-# These three require getauxval, which isn't available on older platforms.
+# These four require getauxval, which isn't available on older platforms.
 libc_bionic_src_files += bionic/getentropy_linux.c
 libc_bionic_src_files += bionic/sysconf.cpp
 libc_bionic_src_files += bionic/vdso.cpp
+libc_bionic_src_files += bionic/setjmp_cookie.cpp
+
+libc_bionic_src_files += \
+    bionic/__memcpy_chk.cpp \
+    bionic/__memset_chk.cpp \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+    bionic/strchr.cpp \
+    bionic/strnlen.c \
+    bionic/strrchr.cpp \
 
 libc_cxa_src_files := \
     bionic/__cxa_guard.cpp \
@@ -256,30 +280,33 @@
     upstream-freebsd/lib/libc/gen/ldexp.c \
     upstream-freebsd/lib/libc/gen/sleep.c \
     upstream-freebsd/lib/libc/gen/usleep.c \
-    upstream-freebsd/lib/libc/stdlib/abs.c \
     upstream-freebsd/lib/libc/stdlib/getopt_long.c \
-    upstream-freebsd/lib/libc/stdlib/imaxabs.c \
-    upstream-freebsd/lib/libc/stdlib/imaxdiv.c \
-    upstream-freebsd/lib/libc/stdlib/labs.c \
-    upstream-freebsd/lib/libc/stdlib/llabs.c \
     upstream-freebsd/lib/libc/stdlib/qsort.c \
     upstream-freebsd/lib/libc/stdlib/quick_exit.c \
     upstream-freebsd/lib/libc/stdlib/realpath.c \
     upstream-freebsd/lib/libc/string/wcpcpy.c \
     upstream-freebsd/lib/libc/string/wcpncpy.c \
     upstream-freebsd/lib/libc/string/wcscasecmp.c \
+    upstream-freebsd/lib/libc/string/wcscat.c \
+    upstream-freebsd/lib/libc/string/wcschr.c \
+    upstream-freebsd/lib/libc/string/wcscmp.c \
+    upstream-freebsd/lib/libc/string/wcscpy.c \
     upstream-freebsd/lib/libc/string/wcscspn.c \
     upstream-freebsd/lib/libc/string/wcsdup.c \
     upstream-freebsd/lib/libc/string/wcslcat.c \
+    upstream-freebsd/lib/libc/string/wcslen.c \
     upstream-freebsd/lib/libc/string/wcsncasecmp.c \
     upstream-freebsd/lib/libc/string/wcsncat.c \
     upstream-freebsd/lib/libc/string/wcsncmp.c \
     upstream-freebsd/lib/libc/string/wcsncpy.c \
     upstream-freebsd/lib/libc/string/wcsnlen.c \
     upstream-freebsd/lib/libc/string/wcspbrk.c \
+    upstream-freebsd/lib/libc/string/wcsrchr.c \
     upstream-freebsd/lib/libc/string/wcsspn.c \
     upstream-freebsd/lib/libc/string/wcstok.c \
     upstream-freebsd/lib/libc/string/wmemchr.c \
+    upstream-freebsd/lib/libc/string/wmemcmp.c \
+    upstream-freebsd/lib/libc/string/wmemmove.c \
     upstream-freebsd/lib/libc/string/wmemset.c \
 
 libc_upstream_netbsd_src_files := \
@@ -344,11 +371,25 @@
     $(libc_upstream_openbsd_gdtoa_src_files) \
     upstream-openbsd/lib/libc/gdtoa/strtorQ.c \
 
-# These two depend on getentropy_linux.cpp, which isn't in libc_ndk.a.
+# These two depend on getentropy_linux.c, which isn't in libc_ndk.a.
 libc_upstream_openbsd_src_files := \
     upstream-openbsd/lib/libc/crypt/arc4random.c \
     upstream-openbsd/lib/libc/crypt/arc4random_uniform.c \
 
+libc_upstream_openbsd_src_files += \
+    upstream-openbsd/lib/libc/string/memchr.c \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/memrchr.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/stpncpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+    upstream-openbsd/lib/libc/string/strcpy.c \
+    upstream-openbsd/lib/libc/string/strlcat.c \
+    upstream-openbsd/lib/libc/string/strlcpy.c \
+    upstream-openbsd/lib/libc/string/strncat.c \
+    upstream-openbsd/lib/libc/string/strncmp.c \
+    upstream-openbsd/lib/libc/string/strncpy.c \
+
 libc_upstream_openbsd_ndk_src_files := \
     upstream-openbsd/lib/libc/compat-43/killpg.c \
     upstream-openbsd/lib/libc/gen/alarm.c \
@@ -391,11 +432,9 @@
     upstream-openbsd/lib/libc/locale/wctomb.c \
     upstream-openbsd/lib/libc/net/htonl.c \
     upstream-openbsd/lib/libc/net/htons.c \
-    upstream-openbsd/lib/libc/net/inet_addr.c \
     upstream-openbsd/lib/libc/net/inet_lnaof.c \
     upstream-openbsd/lib/libc/net/inet_makeaddr.c \
     upstream-openbsd/lib/libc/net/inet_netof.c \
-    upstream-openbsd/lib/libc/net/inet_network.c \
     upstream-openbsd/lib/libc/net/inet_ntoa.c \
     upstream-openbsd/lib/libc/net/inet_ntop.c \
     upstream-openbsd/lib/libc/net/inet_pton.c \
@@ -455,7 +494,6 @@
     upstream-openbsd/lib/libc/stdio/puts.c \
     upstream-openbsd/lib/libc/stdio/putwc.c \
     upstream-openbsd/lib/libc/stdio/putwchar.c \
-    upstream-openbsd/lib/libc/stdio/refill.c \
     upstream-openbsd/lib/libc/stdio/remove.c \
     upstream-openbsd/lib/libc/stdio/rewind.c \
     upstream-openbsd/lib/libc/stdio/rget.c \
@@ -489,11 +527,16 @@
     upstream-openbsd/lib/libc/stdio/wprintf.c \
     upstream-openbsd/lib/libc/stdio/wscanf.c \
     upstream-openbsd/lib/libc/stdio/wsetup.c \
+    upstream-openbsd/lib/libc/stdlib/abs.c \
     upstream-openbsd/lib/libc/stdlib/atoi.c \
     upstream-openbsd/lib/libc/stdlib/atol.c \
     upstream-openbsd/lib/libc/stdlib/atoll.c \
     upstream-openbsd/lib/libc/stdlib/getenv.c \
     upstream-openbsd/lib/libc/stdlib/insque.c \
+    upstream-openbsd/lib/libc/stdlib/imaxabs.c \
+    upstream-openbsd/lib/libc/stdlib/imaxdiv.c \
+    upstream-openbsd/lib/libc/stdlib/labs.c \
+    upstream-openbsd/lib/libc/stdlib/llabs.c \
     upstream-openbsd/lib/libc/stdlib/lsearch.c \
     upstream-openbsd/lib/libc/stdlib/reallocarray.c \
     upstream-openbsd/lib/libc/stdlib/remque.c \
@@ -524,6 +567,7 @@
 libc_pthread_src_files := \
     bionic/pthread_atfork.cpp \
     bionic/pthread_attr.cpp \
+    bionic/pthread_barrier.cpp \
     bionic/pthread_cond.cpp \
     bionic/pthread_create.cpp \
     bionic/pthread_detach.cpp \
@@ -543,9 +587,7 @@
     bionic/pthread_setname_np.cpp \
     bionic/pthread_setschedparam.cpp \
     bionic/pthread_sigmask.cpp \
-
-libc_thread_atexit_impl_src_files := \
-    bionic/__cxa_thread_atexit_impl.cpp \
+    bionic/pthread_spinlock.cpp \
 
 libc_arch_static_src_files := \
     bionic/dl_iterate_phdr_static.cpp \
@@ -575,11 +617,19 @@
     -D_LIBC=1 \
     -Wall -Wextra -Wunused \
 
-ifneq ($(TARGET_USES_LOGD),false)
-libc_common_cflags += -DTARGET_USES_LOGD
+use_clang := $(USE_CLANG_PLATFORM_BUILD)
+
+# Clang/llvm has incompatible long double (fp128) for x86_64.
+# https://llvm.org/bugs/show_bug.cgi?id=23897
+ifeq ($(TARGET_ARCH),x86_64)
+  use_clang := false
 endif
 
-use_clang := $(USE_CLANG_PLATFORM_BUILD)
+# b/25291096, Clang/llvm compiled libc.so for mips/mips64 failed to boot.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),mips mips64))
+  use_clang := false
+endif
+
 ifeq ($(use_clang),)
   use_clang := false
 endif
@@ -595,7 +645,7 @@
   libc_common_cflags += -DDEBUG
 endif
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
   libc_common_cflags += -DUSE_DLMALLOC
   libc_malloc_src := bionic/dlmalloc.c
 else
@@ -604,20 +654,12 @@
   libc_common_c_includes += external/jemalloc/include
 endif
 
-# To customize dlmalloc's alignment, set BOARD_MALLOC_ALIGNMENT in
-# the appropriate BoardConfig.mk file.
-#
-ifneq ($(BOARD_MALLOC_ALIGNMENT),)
-  libc_common_cflags += -DMALLOC_ALIGNMENT=$(BOARD_MALLOC_ALIGNMENT)
-endif
-
 # Define some common conlyflags
 libc_common_conlyflags := \
     -std=gnu99
 
 # Define some common cppflags
 libc_common_cppflags := \
-    -std=gnu++11
 
 # Define some common includes
 # ========================================================
@@ -642,13 +684,21 @@
 # libc_stack_protector.a - stack protector code
 # ========================================================
 #
-# The stack protector code needs to be compiled
-# with -fno-stack-protector, since it modifies the
-# stack canary.
+# Code that implements the stack protector (or that runs
+# before TLS has been set up) needs to be compiled with
+# -fno-stack-protector, since it accesses the stack canary
+# TLS slot.
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := bionic/__stack_chk_fail.cpp
+LOCAL_SRC_FILES := \
+    bionic/__libc_init_main_thread.cpp \
+    bionic/__stack_chk_fail.cpp \
+
+LOCAL_SRC_FILES_arm64 := arch-arm64/bionic/__set_tls.c
+LOCAL_SRC_FILES_x86 := arch-x86/bionic/__set_tls.c
+LOCAL_SRC_FILES_x86_64 := arch-x86_64/bionic/__set_tls.c
+
 LOCAL_CFLAGS := $(libc_common_cflags) -fno-stack-protector
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
@@ -658,7 +708,31 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
+LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+
+$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
+include $(BUILD_STATIC_LIBRARY)
+
+
+# libc_init_static.cpp also needs to be built without stack protector,
+# because it's responsible for setting up TLS for static executables.
+# This isn't the case for dynamic executables because the dynamic linker
+# has already set up the main thread's TLS.
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bionic/libc_init_static.cpp
+LOCAL_CFLAGS := $(libc_common_cflags) -fno-stack-protector
+LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
+LOCAL_CPPFLAGS := $(libc_common_cppflags)
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+LOCAL_MODULE := libc_init_static
+LOCAL_CLANG := $(use_clang)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
+LOCAL_CXX_STL := none
+LOCAL_SYSTEM_SHARED_LIBRARIES :=
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -677,17 +751,22 @@
 
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -fvisibility=hidden \
+    -Wno-unused-parameter \
 
 # Don't use ridiculous amounts of stack.
 LOCAL_CFLAGS += -DALL_STATE
 # Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
 LOCAL_CFLAGS += -DSTD_INSPIRED
+# Obviously, we want to be thread-safe.
+LOCAL_CFLAGS += -DTHREAD_SAFE
 # The name of the tm_gmtoff field in our struct tm.
 LOCAL_CFLAGS += -DTM_GMTOFF=tm_gmtoff
 # Where we store our tzdata.
 LOCAL_CFLAGS += -DTZDIR=\"/system/usr/share/zoneinfo\"
 # Include timezone and daylight globals.
 LOCAL_CFLAGS += -DUSG_COMPAT=1
+# Use the empty string (instead of "   ") as the timezone abbreviation fallback.
+LOCAL_CFLAGS += -DWILDABBR=\"\"
 LOCAL_CFLAGS += -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
 LOCAL_CFLAGS += -Dlint
 
@@ -699,7 +778,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -745,7 +824,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -778,11 +857,11 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 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_freebsd_src_files))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES_EXCLUDE,libc_freebsd_src_files_exclude))
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -813,7 +892,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -854,7 +933,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -892,11 +971,12 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 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_openbsd_src_files))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES_EXCLUDE,libc_openbsd_src_files_exclude))
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -930,7 +1010,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -955,11 +1035,12 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 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_EXCLUDE,libc_bionic_src_files_exclude))
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -983,31 +1064,13 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 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_ndk_src_files))
 include $(BUILD_STATIC_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libc_thread_atexit_impl_src_files)
-LOCAL_CFLAGS := $(libc_common_cflags) -Wframe-larger-than=2048
-
-LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
-LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
-LOCAL_C_INCLUDES := $(libc_common_c_includes)
-LOCAL_MODULE := libc_thread_atexit_impl
-# TODO: Clang tries to use __tls_get_addr which is not supported yet
-# remove after it is implemented.
-LOCAL_CLANG := false
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_CXX_STL := none
-LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
-LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
-
-include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
 # libc_pthread.a - pthreads parts that previously lived in
@@ -1031,7 +1094,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 include $(BUILD_STATIC_LIBRARY)
@@ -1055,7 +1118,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 # b/17574078: Need to disable coverage until we have a prebuilt libprofile_rt.
 # Since this is a static library built with clang, it needs to link
 # libprofile_rt when it is linked into the final binary. Since the final binary
@@ -1083,7 +1146,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 include $(BUILD_STATIC_LIBRARY)
@@ -1105,7 +1168,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 include $(BUILD_STATIC_LIBRARY)
@@ -1131,7 +1194,7 @@
 LOCAL_CFLAGS := $(libc_common_cflags) -fvisibility=hidden -O0
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
@@ -1165,7 +1228,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
 LOCAL_CXX_STL := none
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
@@ -1205,7 +1268,6 @@
     libc_pthread \
     libc_stack_protector \
     libc_syscalls \
-    libc_thread_atexit_impl \
     libc_tzcode \
 
 LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
@@ -1215,7 +1277,7 @@
 
 # TODO: split out the asflags.
 LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -1238,7 +1300,6 @@
 
 LOCAL_SRC_FILES := \
     $(libc_arch_static_src_files) \
-    bionic/libc_init_static.cpp
 
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_CFLAGS := $(libc_common_cflags) \
@@ -1250,10 +1311,10 @@
 LOCAL_MODULE := libc_nomalloc
 LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common libc_init_static
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -1276,7 +1337,7 @@
 LOCAL_MODULE := libc_malloc
 LOCAL_CLANG := $(use_clang)
 LOCAL_CXX_STL := none
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
 include $(BUILD_STATIC_LIBRARY)
@@ -1290,7 +1351,6 @@
 LOCAL_SRC_FILES := \
     $(libc_arch_static_src_files) \
     bionic/malloc_debug_common.cpp \
-    bionic/libc_init_static.cpp \
 
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -DLIBC_STATIC \
@@ -1301,15 +1361,15 @@
 LOCAL_MODULE := libc
 LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common libc_init_static
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -1341,7 +1401,15 @@
 LOCAL_REQUIRED_MODULES := tzdata
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(libc_common_additional_dependencies) \
-    $(LOCAL_PATH)/libc.map \
+    $(LOCAL_PATH)/libc.arm.map \
+    $(LOCAL_PATH)/libc.arm64.map \
+    $(LOCAL_PATH)/libc.mips.map \
+    $(LOCAL_PATH)/libc.mips64.map \
+    $(LOCAL_PATH)/libc.x86.map \
+    $(LOCAL_PATH)/libc.x86_64.map \
+    $(LOCAL_PATH)/libc.arm.brillo.map \
+    $(LOCAL_PATH)/libc.mips.brillo.map \
+    $(LOCAL_PATH)/libc.x86.brillo.map \
 
 # Leave the symbols in the shared library so that stack unwinders can produce
 # meaningful name resolution.
@@ -1361,24 +1429,40 @@
 LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
+
 # Don't re-export new/delete and friends, even if the compiler really wants to.
-LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/libc.map
+ifdef BRILLO
+LOCAL_LDFLAGS_arm    += -Wl,--version-script,$(LOCAL_PATH)/libc.arm.brillo.map
+LOCAL_LDFLAGS_mips   += -Wl,--version-script,$(LOCAL_PATH)/libc.mips.brillo.map
+LOCAL_LDFLAGS_x86    += -Wl,--version-script,$(LOCAL_PATH)/libc.x86.brillo.map
+else
+LOCAL_LDFLAGS_arm    += -Wl,--version-script,$(LOCAL_PATH)/libc.arm.map
+LOCAL_LDFLAGS_mips   += -Wl,--version-script,$(LOCAL_PATH)/libc.mips.map
+LOCAL_LDFLAGS_x86    += -Wl,--version-script,$(LOCAL_PATH)/libc.x86.map
+endif
+
+LOCAL_LDFLAGS_arm64  += -Wl,--version-script,$(LOCAL_PATH)/libc.arm64.map
+LOCAL_LDFLAGS_mips64 += -Wl,--version-script,$(LOCAL_PATH)/libc.mips64.map
+LOCAL_LDFLAGS_x86_64 += -Wl,--version-script,$(LOCAL_PATH)/libc.x86_64.map
 
 # 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.
 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=both
-LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
 
 $(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))
@@ -1391,7 +1475,7 @@
 LOCAL_SRC_FILES_arm += \
     arch-arm/bionic/atexit_legacy.c
 
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 include $(BUILD_SHARED_LIBRARY)
@@ -1419,8 +1503,8 @@
     $(libc_common_c_includes) \
 
 LOCAL_SRC_FILES := \
+    bionic/debug_backtrace.cpp \
     bionic/debug_mapinfo.cpp \
-    bionic/debug_stacktrace.cpp \
     bionic/libc_logging.cpp \
     bionic/malloc_debug_leak.cpp \
     bionic/malloc_debug_check.cpp \
@@ -1437,15 +1521,20 @@
 # Only need this for arm since libc++ uses its own unwind code that
 # doesn't mix with the other default unwind code.
 LOCAL_STATIC_LIBRARIES_arm := libunwind_llvm
+LOCAL_LDFLAGS_arm := -Wl,--exclude-libs,libunwind_llvm.a
 LOCAL_STATIC_LIBRARIES += libc++abi
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -1483,9 +1572,13 @@
 # Don't re-export new/delete and friends, even if the compiler really wants to.
 LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
 
+# Unfortunately --exclude-libs clobbers our version script, so we have to
+# prevent the build system from using this flag.
+LOCAL_NO_EXCLUDE_LIBS := true
+
 # Don't install on release build
 LOCAL_MODULE_TAGS := eng debug
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
@@ -1507,7 +1600,7 @@
 LOCAL_CFLAGS := $(libc_common_cflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
@@ -1516,7 +1609,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 include $(BUILD_SHARED_LIBRARY)
 
@@ -1532,7 +1625,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/libc/NOTICE b/libc/NOTICE
index dbe3944..81e9943 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -308,22 +308,6 @@
 -------------------------------------------------------------------
 
 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.
-
--------------------------------------------------------------------
-
-Copyright (C) 2009 The Android Open Source Project
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -3921,35 +3905,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2009
-     MIPS Technologies, Inc., California.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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 David Schultz <das@FreeBSD.org>
 All rights reserved.
 
@@ -4431,6 +4386,64 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2012-2015
+     MIPS Technologies, Inc., California.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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
+     MIPS Technologies, Inc., California.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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 ARM Ltd
 All rights reserved.
 
@@ -4504,6 +4517,35 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2014
+     Imagination Technologies Limited.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the MIPS Technologies, Inc., 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 IMAGINATION TECHNOLOGIES LIMITED ``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 IMAGINATION TECHNOLOGIES LIMITED 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 Theo de Raadt <deraadt@openbsd.org>
 Copyright (c) 2014 Bob Beck <beck@obtuse.com>
 
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 2e2cd11..526b6d0 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -77,7 +77,6 @@
 int     setgroups:setgroups32(int, const gid_t*)   arm,x86
 int     setgroups:setgroups(int, const gid_t*)     arm64,mips,mips64,x86_64
 int     setpgid(pid_t, pid_t)  all
-pid_t   vfork(void)  arm
 int     setregid:setregid32(gid_t, gid_t)  arm,x86
 int     setregid:setregid(gid_t, gid_t)    arm64,mips,mips64,x86_64
 int     chroot(const char*)  all
@@ -95,10 +94,20 @@
 ssize_t     pread64|pread(int, void*, size_t, off_t) arm64,mips64,x86_64
 ssize_t     pwrite64(int, void*, size_t, off64_t) arm,mips,x86
 ssize_t     pwrite64|pwrite(int, void*, size_t, off_t) arm64,mips64,x86_64
+
+# On LP32, preadv/pwritev don't use off64_t --- they use pairs of 32-bit
+# arguments to avoid problems on architectures like ARM where 64-bit arguments
+# must be in a register pair starting with an even-numbered register.
+# See linux/fs/read_write.c and https://lwn.net/Articles/311630/.
+ssize_t     __preadv64:preadv(int, const struct iovec*, int, long, long) arm,mips,x86
+ssize_t     preadv|preadv64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
+ssize_t     __pwritev64:pwritev(int, const struct iovec*, int, long, long) arm,mips,x86
+ssize_t     pwritev|pwritev64(int, const struct iovec*, int, off_t) arm64,mips64,x86_64
+
 int         ___close:close(int)  all
 pid_t       __getpid:getpid()  all
 int         munmap(void*, size_t)  all
-void*       mremap(void*, size_t, size_t, unsigned long)  all
+void*       ___mremap:mremap(void*, size_t, size_t, int, void*)  all
 int         msync(const void*, size_t, int)    all
 int         mprotect(const void*, size_t, int)  all
 int         madvise(void*, size_t, int)  all
@@ -124,7 +133,7 @@
 void        sync(void)  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
+ssize_t     ___flistxattr:flistxattr(int, char*, size_t) all
 int         fremovexattr(int, const char*) all
 
 int __getdents64:getdents64(unsigned int, struct dirent*, unsigned int)   arm,arm64,mips,mips64,x86,x86_64
@@ -333,7 +342,7 @@
 int     __set_thread_area:set_thread_area(void*) x86
 
 # vdso stuff.
-int clock_gettime(clockid_t, timespec*)                 arm,mips,mips64,x86
-int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86_64
-int gettimeofday(timeval*, timezone*)                   arm,mips,mips64,x86
-int __gettimeofday:gettimeofday(timeval*, timezone*)    arm64,x86_64
+int clock_gettime(clockid_t, timespec*)                 arm,mips,mips64
+int __clock_gettime:clock_gettime(clockid_t, timespec*) arm64,x86,x86_64
+int gettimeofday(timeval*, timezone*)                   arm,mips,mips64
+int __gettimeofday:gettimeofday(timeval*, timezone*)    arm64,x86,x86_64
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index d72a160..76f465e 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -1,33 +1,19 @@
 # 32-bit arm.
 
-#
-# Default implementations of functions that are commonly optimized.
-#
-
 libc_bionic_src_files_arm += \
-    bionic/strchr.cpp \
-    bionic/strnlen.c \
-    bionic/strrchr.cpp \
+    arch-arm/generic/bionic/memcmp.S \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
 
-libc_freebsd_src_files_arm += \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-freebsd/lib/libc/string/wcschr.c \
-    upstream-freebsd/lib/libc/string/wcscmp.c \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcslen.c \
-    upstream-freebsd/lib/libc/string/wcsrchr.c \
-    upstream-freebsd/lib/libc/string/wmemcmp.c \
-    upstream-freebsd/lib/libc/string/wmemmove.c \
+libc_bionic_src_files_exclude_arm += \
+    bionic/__memcpy_chk.cpp \
+    bionic/__memset_chk.cpp \
 
-libc_openbsd_src_files_arm += \
-    upstream-openbsd/lib/libc/string/memchr.c \
-    upstream-openbsd/lib/libc/string/memrchr.c \
-    upstream-openbsd/lib/libc/string/stpncpy.c \
-    upstream-openbsd/lib/libc/string/strlcat.c \
-    upstream-openbsd/lib/libc/string/strlcpy.c \
-    upstream-openbsd/lib/libc/string/strncat.c \
-    upstream-openbsd/lib/libc/string/strncmp.c \
-    upstream-openbsd/lib/libc/string/strncpy.c \
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/strcpy.c \
 
 #
 # Inherently architecture-specific code.
@@ -39,9 +25,11 @@
     arch-arm/bionic/__bionic_clone.S \
     arch-arm/bionic/_exit_with_stack_teardown.S \
     arch-arm/bionic/libgcc_compat.c \
+    arch-arm/bionic/popcount_tab.c \
     arch-arm/bionic/__restore.S \
     arch-arm/bionic/setjmp.S \
     arch-arm/bionic/syscall.S \
+    arch-arm/bionic/vfork.S \
 
 libc_arch_static_src_files_arm := arch-arm/bionic/exidx_static.c
 libc_arch_dynamic_src_files_arm := arch-arm/bionic/exidx_dynamic.c
@@ -50,6 +38,7 @@
 ifeq ($(strip $(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)),)
   $(warning TARGET_$(my_2nd_arch_prefix)ARCH is arm, but TARGET_$(my_2nd_arch_prefix)CPU_VARIANT is not defined)
 endif
+ifneq ($(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT),generic)
 cpu_variant_mk := $(LOCAL_PATH)/arch-arm/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT)/$(TARGET_$(my_2nd_arch_prefix)CPU_VARIANT).mk
 ifeq ($(wildcard $(cpu_variant_mk)),)
 $(error "TARGET_$(my_2nd_arch_prefix)CPU_VARIANT not set or set to an unknown value. Possible values are cortex-a7, cortex-a8, cortex-a9, cortex-a15, krait, denver. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.")
@@ -58,6 +47,7 @@
 libc_common_additional_dependencies += $(cpu_variant_mk)
 
 cpu_variant_mk :=
+endif
 
 
 libc_crt_target_cflags_arm := \
diff --git a/libc/arch-arm/bionic/__aeabi.c b/libc/arch-arm/bionic/__aeabi.c
index 254c7a6..1620d45 100644
--- a/libc/arch-arm/bionic/__aeabi.c
+++ b/libc/arch-arm/bionic/__aeabi.c
@@ -51,34 +51,62 @@
  */
 
 int __attribute__((weak))
-__aeabi_atexit(void *object, void (*destructor) (void *), void *dso_handle) {
+__aeabi_atexit_impl(void *object, void (*destructor) (void *), void *dso_handle) {
+    return __cxa_atexit(destructor, object, dso_handle);
+}
+
+int __attribute__((weak))
+__aeabi_atexit_impl2(void *object, void (*destructor) (void *), void *dso_handle) {
     return __cxa_atexit(destructor, object, dso_handle);
 }
 
 
-void __attribute__((weak))
-__aeabi_memcpy8(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy8_impl(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memcpy4(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy4_impl(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memcpy(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy_impl(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy8_impl2(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy4_impl2(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy_impl2(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
 
-void __attribute__((weak)) __aeabi_memmove8(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove8_impl(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memmove4(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove4_impl(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memmove(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove_impl(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove8_impl2(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove4_impl2(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
@@ -87,27 +115,71 @@
  *  This allows __aeabi_memclr to tail-call __aeabi_memset
  */
 
-void __attribute__((weak)) __aeabi_memset8(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
-void __attribute__((weak)) __aeabi_memset4(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
-void __attribute__((weak)) __aeabi_memset(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset_impl(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset8_impl2(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset4_impl2(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset_impl2(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
 
-void __attribute__((weak)) __aeabi_memclr8(void *dest, size_t n) {
-    __aeabi_memset8(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr8_impl(void *dest, size_t n) {
+    __aeabi_memset8_impl(dest, n, 0);
 }
 
-void __attribute__((weak)) __aeabi_memclr4(void *dest, size_t n) {
-    __aeabi_memset4(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) {
+    __aeabi_memset4_impl(dest, n, 0);
 }
 
-void __attribute__((weak)) __aeabi_memclr(void *dest, size_t n) {
-    __aeabi_memset(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) {
+    __aeabi_memset_impl(dest, n, 0);
 }
+
+void __attribute__((weak)) __aeabi_memclr8_impl2(void *dest, size_t n) {
+    __aeabi_memset8_impl(dest, n, 0);
+}
+
+void __attribute__((weak)) __aeabi_memclr4_impl2(void *dest, size_t n) {
+    __aeabi_memset4_impl(dest, n, 0);
+}
+
+void __attribute__((weak)) __aeabi_memclr_impl2(void *dest, size_t n) {
+    __aeabi_memset_impl(dest, n, 0);
+}
+
+#define __AEABI_SYMVERS(fn_name) \
+__asm__(".symver " #fn_name "_impl, " #fn_name "@@LIBC_N"); \
+__asm__(".symver " #fn_name "_impl2, " #fn_name "@LIBC_PRIVATE")
+
+__AEABI_SYMVERS(__aeabi_atexit);
+__AEABI_SYMVERS(__aeabi_memcpy8);
+__AEABI_SYMVERS(__aeabi_memcpy4);
+__AEABI_SYMVERS(__aeabi_memcpy);
+__AEABI_SYMVERS(__aeabi_memmove8);
+__AEABI_SYMVERS(__aeabi_memmove4);
+__AEABI_SYMVERS(__aeabi_memmove);
+__AEABI_SYMVERS(__aeabi_memset8);
+__AEABI_SYMVERS(__aeabi_memset4);
+__AEABI_SYMVERS(__aeabi_memset);
+__AEABI_SYMVERS(__aeabi_memclr8);
+__AEABI_SYMVERS(__aeabi_memclr4);
+__AEABI_SYMVERS(__aeabi_memclr);
+
+#undef __AEABI_SYMVERS
diff --git a/libc/arch-arm/bionic/__restore.S b/libc/arch-arm/bionic/__restore.S
index 9898125..8c1e41d 100644
--- a/libc/arch-arm/bionic/__restore.S
+++ b/libc/arch-arm/bionic/__restore.S
@@ -34,7 +34,9 @@
 // __restore_rt (but covered by the .fnstart/.fnend) so that although they're
 // not inside the functions from objdump's point of view, an unwinder that
 // blindly looks at the previous instruction (but is then smart enough to check
-// the DWARF information to find out where it landed) gets the right answer.
+// the unwind information to find out where it landed) gets the right answer.
+// Make sure not to have both DWARF and ARM unwind information, so only
+// use the ARM unwind information.
 
 // We need to place .fnstart ourselves (but we may as well keep the free .fnend).
 #undef __bionic_asm_custom_entry
@@ -44,18 +46,18 @@
   .save {r0-r15}
   .pad #32
   nop
-ENTRY_PRIVATE(__restore)
+ENTRY_PRIVATE_NO_DWARF(__restore)
   // This function must have exactly this instruction sequence.
   mov r7, #__NR_sigreturn
   swi #0
-END(__restore)
+END_NO_DWARF(__restore)
 
   .fnstart
   .save {r0-r15}
   .pad #160
   nop
-ENTRY_PRIVATE(__restore_rt)
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
   // This function must have exactly this instruction sequence.
   mov r7, #__NR_rt_sigreturn
   swi #0
-END(__restore_rt)
+END_NO_DWARF(__restore_rt)
diff --git a/libc/arch-arm/bionic/exidx_dynamic.c b/libc/arch-arm/bionic/exidx_dynamic.c
index c7b7156..60ac8af 100644
--- a/libc/arch-arm/bionic/exidx_dynamic.c
+++ b/libc/arch-arm/bionic/exidx_dynamic.c
@@ -37,7 +37,13 @@
  * the expectation that libc will define it and call through to
  * a differently-named function in the dynamic linker.
  */
-_Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount)
-{
+_Unwind_Ptr __gnu_Unwind_Find_exidx_impl(_Unwind_Ptr pc, int *pcount) {
     return dl_unwind_find_exidx(pc, pcount);
 }
+
+_Unwind_Ptr __gnu_Unwind_Find_exidx_impl2(_Unwind_Ptr pc, int *pcount) {
+    return dl_unwind_find_exidx(pc, pcount);
+}
+
+__asm__(".symver __gnu_Unwind_Find_exidx_impl,__gnu_Unwind_Find_exidx@LIBC_PRIVATE");
+__asm__(".symver __gnu_Unwind_Find_exidx_impl2,__gnu_Unwind_Find_exidx@@LIBC_N");
diff --git a/libc/arch-arm/bionic/popcount_tab.c b/libc/arch-arm/bionic/popcount_tab.c
new file mode 100644
index 0000000..eb2faa9
--- /dev/null
+++ b/libc/arch-arm/bionic/popcount_tab.c
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+// Export this to maintain ABI compatibilty with libgcc, since compiler-rt
+// doesn't use a table-driven implementation of __popcount.
+const unsigned char __popcount_tab[256] = {
+  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
+  3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4,
+  3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
+  4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
+  3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2,
+  2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
+  4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5,
+  5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,
+  5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index 8220c08..464f7d8 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -51,13 +51,13 @@
 // The internal structure of a jmp_buf is totally private.
 // Current layout (may change in the future):
 //
-// word   name         description
-// 0      magic        magic number
-// 1      sigmask      signal mask (not used with _setjmp / _longjmp)
-// 2      float_base   base of float registers (d8 to d15)
-// 18     float_state  floating-point status and control register
-// 19     core_base    base of core registers (r4 to r14)
-// 30     reserved     reserved entries (room to grow)
+// word   name            description
+// 0      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
+// 1      sigmask         signal mask (not used with _setjmp / _longjmp)
+// 2      float_base      base of float registers (d8 to d15)
+// 18     float_state     floating-point status and control register
+// 19     core_base       base of core registers (r4 to r14)
+// 30     reserved        reserved entries (room to grow)
 // 64
 //
 // NOTE: float_base must be at an even word index, since the
@@ -80,33 +80,82 @@
   b sigsetjmp
 END(_setjmp)
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg
+#if MANGLE_REGISTERS
+  eor r4, r4, \reg
+  eor r5, r5, \reg
+  eor r6, r6, \reg
+  eor r7, r7, \reg
+  eor r8, r8, \reg
+  eor r9, r9, \reg
+  eor r10, r10, \reg
+  eor r11, r11, \reg
+  eor r12, r12, \reg
+  eor r13, r13, \reg
+  eor r14, r14, \reg
+#endif
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
+  stmfd sp!, {r0, lr}
+  .cfi_def_cfa_offset 8
+  .cfi_rel_offset r0, 0
+  .cfi_rel_offset lr, 4
+
+  mov r0, r1
+  bl __bionic_setjmp_cookie_get
+  mov r1, r0
+
+  ldmfd sp, {r0}
+
+  // Save the setjmp cookie for later.
+  bic r2, r1, #1
+  stmfd sp!, {r2}
+  .cfi_adjust_cfa_offset 4
+
+  // Record the setjmp cookie and whether or not we're saving the signal mask.
   str r1, [r0, #(_JB_SIGFLAG * 4)]
 
   // Do we need to save the signal mask?
-  teq r1, #0
+  tst r1, #1
   beq 1f
 
-  // Get current signal mask.
-  stmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 8
-  .cfi_rel_offset r0, 0
-  .cfi_rel_offset r14, 4
-  mov r0, #0
-  bl sigblock
-  mov r1, r0
-  ldmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 0
+  // Align the stack.
+  sub sp, #4
+  .cfi_adjust_cfa_offset 4
 
-  // Save the signal mask.
-  str r1, [r0, #(_JB_SIGMASK * 4)]
+  // Save the current signal mask.
+  add r2, r0, #(_JB_SIGMASK * 4)
+  mov r0, #2 // SIG_SETMASK
+  mov r1, #0
+  bl sigprocmask
+
+  // Unalign the stack.
+  add sp, #4
+  .cfi_adjust_cfa_offset -4
 
 1:
+  ldmfd sp!, {r2}
+  .cfi_adjust_cfa_offset -4
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore r0
+  .cfi_restore lr
+
   // Save core registers.
   add r1, r0, #(_JB_CORE_BASE * 4)
-  stmia r1, {r4-r14}
+  m_mangle_registers r2
+
+  // ARM deprecates using sp in the register list for stmia.
+  stmia r1, {r4-r12, lr}
+  str sp, [r1, #(10 * 4)]
+  m_unmangle_registers r2
 
   // Save floating-point registers.
   add r1, r0, #(_JB_FLOAT_BASE * 4)
@@ -122,29 +171,30 @@
 
 // void siglongjmp(sigjmp_buf env, int value);
 ENTRY(siglongjmp)
-  // Do we need to restore the signal mask?
-  ldr r2, [r0, #(_JB_SIGFLAG * 4)]
-  teq r2, #0
-  beq 1f
-
-  // Restore the signal mask.
-  stmfd sp!, {r0, r1, r14}
+  stmfd sp!, {r0, r1, lr}
   .cfi_def_cfa_offset 12
   .cfi_rel_offset r0, 0
   .cfi_rel_offset r1, 4
-  .cfi_rel_offset r14, 8
-  sub sp, sp, #4 // Align the stack.
-  .cfi_adjust_cfa_offset 4
+  .cfi_rel_offset lr, 8
 
+  // Fetch the signal flag.
+  ldr r1, [r0, #(_JB_SIGFLAG * 4)]
+
+  // Do we need to restore the signal mask?
+  ands r1, r1, #1
+  beq 1f
+
+  // Restore the signal mask.
   ldr r0, [r0, #(_JB_SIGMASK * 4)]
   bl sigsetmask
 
-  add sp, sp, #4 // Unalign the stack.
-  .cfi_adjust_cfa_offset -4
-  ldmfd sp!, {r0, r1, r14}
-  .cfi_def_cfa_offset 0
-
 1:
+  ldmfd sp!, {r0, r1, lr}
+  .cfi_adjust_cfa_offset -12
+  .cfi_restore r0
+  .cfi_restore r1
+  .cfi_restore lr
+
   // Restore floating-point registers.
   add r2, r0, #(_JB_FLOAT_BASE * 4)
   vldmia r2, {d8-d15}
@@ -154,16 +204,27 @@
   fmxr fpscr, r2
 
   // Restore core registers.
+  ldr r3, [r0, #(_JB_SIGFLAG * 4)]
+  bic r3, r3, #1
   add r2, r0, #(_JB_CORE_BASE * 4)
-  ldmia r2, {r4-r14}
 
-  // Validate sp and r14.
-  teq sp, #0
-  teqne r14, #0
-  bleq longjmperror
+  // ARM deprecates using sp in the register list for ldmia.
+  ldmia r2, {r4-r12, lr}
+  ldr sp, [r2, #(10 * 4)]
+  m_unmangle_registers r3
 
-  // Set return value.
-  mov r0, r1
+  // Save the return value/address and check the setjmp cookie.
+  stmfd sp!, {r1, lr}
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset lr, 4
+  mov r0, r3
+  bl __bionic_setjmp_cookie_check
+
+  // Restore return value/address.
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore lr
+
   teq r0, #0
   moveq r0, #1
   bx lr
diff --git a/libc/include/sys/shm.h b/libc/arch-arm/bionic/vfork.S
similarity index 74%
copy from libc/include/sys/shm.h
copy to libc/arch-arm/bionic/vfork.S
index c691c29..1b7cbad 100644
--- a/libc/include/sys/shm.h
+++ b/libc/arch-arm/bionic/vfork.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,21 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+#include <private/bionic_asm.h>
 
-#include <linux/shm.h>
+ENTRY(vfork)
+    // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+    mrc     p15, 0, r3, c13, c0, 3
+    ldr     r3, [r3, #4]
+    mov     r0, #0
+    str     r0, [r3, #12]
 
-#endif /* _SYS_SHM_H_ */
+    mov     ip, r7
+    ldr     r7, =__NR_vfork
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(vfork)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
index a2e9c22..3692f04 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,191 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
-#include <private/libc_events.h>
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "memcpy_base.S"
 
-    .syntax unified
-
-    .thumb
-    .thumb_func
-
-// Get the length of src string, then get the source of the dst string.
-// Check that the two lengths together don't exceed the threshold, then
-// do a memcpy of the data.
-ENTRY(__strcat_chk)
-    pld     [r0, #0]
-    push    {r0, lr}
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-    push    {r4, r5}
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r4, 0
-    .cfi_rel_offset r5, 4
-
-    mov     lr, r2
-
-    // Save the dst register to r5
-    mov     r5, r0
-
-    // Zero out r4
-    eor     r4, r4, r4
-
-    // r1 contains the address of the string to count.
-.L_strlen_start:
-    mov     r0, r1
-    ands    r3, r1, #7
-    beq     .L_mainloop
-
-    // Align to a double word (64 bits).
-    rsb     r3, r3, #8
-    lsls    ip, r3, #31
-    beq     .L_align_to_32
-
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_32:
-    bcc     .L_align_to_64
-    ands    ip, r3, #2
-    beq     .L_align_to_64
-
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-    ldrb    r2, [r1], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_64:
-    tst     r3, #4
-    beq     .L_mainloop
-    ldr     r3, [r1], #4
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-
-    .p2align 2
-.L_mainloop:
-    ldrd    r2, r3, [r1], #8
-
-    pld     [r1, #64]
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_first_register
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-    b       .L_mainloop
-
-.L_update_count_and_finish:
-    sub     r3, r1, r0
-    sub     r3, r3, #1
-    b       .L_finish
-
-.L_zero_in_first_register:
-    sub     r3, r1, r0
-    lsls    r2, ip, #17
-    bne     .L_sub8_and_finish
-    bcs     .L_sub7_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub6_and_finish
-
-    sub     r3, r3, #5
-    b       .L_finish
-
-.L_sub8_and_finish:
-    sub     r3, r3, #8
-    b       .L_finish
-
-.L_sub7_and_finish:
-    sub     r3, r3, #7
-    b       .L_finish
-
-.L_sub6_and_finish:
-    sub     r3, r3, #6
-    b       .L_finish
-
-.L_zero_in_second_register:
-    sub     r3, r1, r0
-    lsls    r2, ip, #17
-    bne     .L_sub4_and_finish
-    bcs     .L_sub3_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub2_and_finish
-
-    sub     r3, r3, #1
-    b       .L_finish
-
-.L_sub4_and_finish:
-    sub     r3, r3, #4
-    b       .L_finish
-
-.L_sub3_and_finish:
-    sub     r3, r3, #3
-    b       .L_finish
-
-.L_sub2_and_finish:
-    sub     r3, r3, #2
-
-.L_finish:
-    cmp     r4, #0
-    bne     .L_strlen_done
-
-    // Time to get the dst string length.
-    mov     r1, r5
-
-    // Save the original source address to r5.
-    mov     r5, r0
-
-    // Save the current length (adding 1 for the terminator).
-    add     r4, r3, #1
-    b       .L_strlen_start
-
-    // r0 holds the pointer to the dst string.
-    // r3 holds the dst string length.
-    // r4 holds the src string length + 1.
-.L_strlen_done:
-    add     r2, r3, r4
-    cmp     r2, lr
-    bhi     __strcat_chk_failed
-
-    // Set up the registers for the memcpy code.
-    mov     r1, r5
-    pld     [r1, #64]
-    mov     r2, r4
-    add     r0, r0, r3
-    pop     {r4, r5}
-END(__strcat_chk)
-
-#define MEMCPY_BASE         __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
-
-#include "memcpy_base.S"
-
-ENTRY_PRIVATE(__strcat_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r4, 0
-    .cfi_rel_offset r5, 4
-
-    ldr     r0, error_message
-    ldr     r1, error_code
-1:
-    add     r0, pc
-    bl      __fortify_chk_fail
-error_code:
-    .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
-error_message:
-    .word   error_string-(1b+4)
-END(__strcat_chk_failed)
-
-    .data
-error_string:
-    .string "strcat: prevented write past end of buffer"
+#include "__strcat_chk_common.S"
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S
new file mode 100644
index 0000000..de66967
--- /dev/null
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk_common.S
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2013 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 <private/bionic_asm.h>
+#include <private/libc_events.h>
+
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of src string, then get the source of the dst string.
+// Check that the two lengths together don't exceed the threshold, then
+// do a memcpy of the data.
+ENTRY(__strcat_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+    push    {r4, r5}
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+
+    mov     lr, r2
+
+    // Save the dst register to r5
+    mov     r5, r0
+
+    // Zero out r4
+    eor     r4, r4, r4
+
+    // r1 contains the address of the string to count.
+.L_strlen_start:
+    mov     r0, r1
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r1], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r1], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r1], #8
+
+    pld     [r1, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r1, r0
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_zero_in_first_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_finish
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_finish
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_finish
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_finish
+
+.L_zero_in_second_register:
+    sub     r3, r1, r0
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_finish
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_finish
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_finish
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_finish:
+    cmp     r4, #0
+    bne     .L_strlen_done
+
+    // Time to get the dst string length.
+    mov     r1, r5
+
+    // Save the original source address to r5.
+    mov     r5, r0
+
+    // Save the current length (adding 1 for the terminator).
+    add     r4, r3, #1
+    b       .L_strlen_start
+
+    // r0 holds the pointer to the dst string.
+    // r3 holds the dst string length.
+    // r4 holds the src string length + 1.
+.L_strlen_done:
+    add     r2, r3, r4
+    cmp     r2, lr
+    bhi     .L_strcat_chk_failed
+
+    // Set up the registers for the memcpy code.
+    mov     r1, r5
+    pld     [r1, #64]
+    mov     r2, r4
+    add     r0, r0, r3
+    pop     {r4, r5}
+    .cfi_adjust_cfa_offset -8
+    .cfi_restore r4
+    .cfi_restore r5
+
+#include MEMCPY_BASE
+
+    // Undo the above cfi directives
+    .cfi_adjust_cfa_offset 8
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+.L_strcat_chk_failed:
+    ldr     r0, error_message
+    ldr     r1, error_code
+1:
+    add     r0, pc
+    bl      __fortify_chk_fail
+error_code:
+    .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
+error_message:
+    .word   error_string-(1b+4)
+END(__strcat_chk)
+
+    .data
+error_string:
+    .string "strcat: prevented write past end of buffer"
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
index db76686..d8cb3d9 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,155 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
-#include <private/libc_events.h>
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "memcpy_base.S"
 
-    .syntax unified
-
-    .thumb
-    .thumb_func
-
-// Get the length of the source string first, then do a memcpy of the data
-// instead of a strcpy.
-ENTRY(__strcpy_chk)
-    pld     [r0, #0]
-    push    {r0, lr}
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-
-    mov     lr, r2
-    mov     r0, r1
-
-    ands    r3, r1, #7
-    beq     .L_mainloop
-
-    // Align to a double word (64 bits).
-    rsb     r3, r3, #8
-    lsls    ip, r3, #31
-    beq     .L_align_to_32
-
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_32:
-    bcc     .L_align_to_64
-    ands    ip, r3, #2
-    beq     .L_align_to_64
-
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-    ldrb    r2, [r0], #1
-    cbz     r2, .L_update_count_and_finish
-
-.L_align_to_64:
-    tst     r3, #4
-    beq     .L_mainloop
-    ldr     r3, [r0], #4
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-
-    .p2align 2
-.L_mainloop:
-    ldrd    r2, r3, [r0], #8
-
-    pld     [r0, #64]
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_first_register
-
-    sub     ip, r3, #0x01010101
-    bic     ip, ip, r3
-    ands    ip, ip, #0x80808080
-    bne     .L_zero_in_second_register
-    b       .L_mainloop
-
-.L_update_count_and_finish:
-    sub     r3, r0, r1
-    sub     r3, r3, #1
-    b       .L_check_size
-
-.L_zero_in_first_register:
-    sub     r3, r0, r1
-    lsls    r2, ip, #17
-    bne     .L_sub8_and_finish
-    bcs     .L_sub7_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub6_and_finish
-
-    sub     r3, r3, #5
-    b       .L_check_size
-
-.L_sub8_and_finish:
-    sub     r3, r3, #8
-    b       .L_check_size
-
-.L_sub7_and_finish:
-    sub     r3, r3, #7
-    b       .L_check_size
-
-.L_sub6_and_finish:
-    sub     r3, r3, #6
-    b       .L_check_size
-
-.L_zero_in_second_register:
-    sub     r3, r0, r1
-    lsls    r2, ip, #17
-    bne     .L_sub4_and_finish
-    bcs     .L_sub3_and_finish
-    lsls    ip, ip, #1
-    bne     .L_sub2_and_finish
-
-    sub     r3, r3, #1
-    b       .L_check_size
-
-.L_sub4_and_finish:
-    sub     r3, r3, #4
-    b       .L_check_size
-
-.L_sub3_and_finish:
-    sub     r3, r3, #3
-    b       .L_check_size
-
-.L_sub2_and_finish:
-    sub     r3, r3, #2
-
-.L_check_size:
-    pld     [r1, #0]
-    pld     [r1, #64]
-    ldr     r0, [sp]
-    cmp     r3, lr
-    bhs     __strcpy_chk_failed
-
-    // Add 1 for copy length to get the string terminator.
-    add     r2, r3, #1
-END(__strcpy_chk)
-
-#define MEMCPY_BASE         __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
-#include "memcpy_base.S"
-
-ENTRY_PRIVATE(__strcpy_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-
-    ldr     r0, error_message
-    ldr     r1, error_code
-1:
-    add     r0, pc
-    bl      __fortify_chk_fail
-error_code:
-    .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
-error_message:
-    .word   error_string-(1b+4)
-END(__strcpy_chk_failed)
-
-    .data
-error_string:
-    .string "strcpy: prevented write past end of buffer"
+#include "__strcpy_chk_common.S"
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S
new file mode 100644
index 0000000..69ebcb4
--- /dev/null
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk_common.S
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 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 <private/bionic_asm.h>
+#include <private/libc_events.h>
+
+    .syntax unified
+
+    .thumb
+    .thumb_func
+
+// Get the length of the source string first, then do a memcpy of the data
+// instead of a strcpy.
+ENTRY(__strcpy_chk)
+    pld     [r0, #0]
+    push    {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
+    mov     lr, r2
+    mov     r0, r1
+
+    ands    r3, r1, #7
+    beq     .L_mainloop
+
+    // Align to a double word (64 bits).
+    rsb     r3, r3, #8
+    lsls    ip, r3, #31
+    beq     .L_align_to_32
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_32:
+    bcc     .L_align_to_64
+    ands    ip, r3, #2
+    beq     .L_align_to_64
+
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+    ldrb    r2, [r0], #1
+    cbz     r2, .L_update_count_and_finish
+
+.L_align_to_64:
+    tst     r3, #4
+    beq     .L_mainloop
+    ldr     r3, [r0], #4
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+
+    .p2align 2
+.L_mainloop:
+    ldrd    r2, r3, [r0], #8
+
+    pld     [r0, #64]
+
+    sub     ip, r2, #0x01010101
+    bic     ip, ip, r2
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_first_register
+
+    sub     ip, r3, #0x01010101
+    bic     ip, ip, r3
+    ands    ip, ip, #0x80808080
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
+
+.L_update_count_and_finish:
+    sub     r3, r0, r1
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_zero_in_first_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub8_and_finish
+    bcs     .L_sub7_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub6_and_finish
+
+    sub     r3, r3, #5
+    b       .L_check_size
+
+.L_sub8_and_finish:
+    sub     r3, r3, #8
+    b       .L_check_size
+
+.L_sub7_and_finish:
+    sub     r3, r3, #7
+    b       .L_check_size
+
+.L_sub6_and_finish:
+    sub     r3, r3, #6
+    b       .L_check_size
+
+.L_zero_in_second_register:
+    sub     r3, r0, r1
+    lsls    r2, ip, #17
+    bne     .L_sub4_and_finish
+    bcs     .L_sub3_and_finish
+    lsls    ip, ip, #1
+    bne     .L_sub2_and_finish
+
+    sub     r3, r3, #1
+    b       .L_check_size
+
+.L_sub4_and_finish:
+    sub     r3, r3, #4
+    b       .L_check_size
+
+.L_sub3_and_finish:
+    sub     r3, r3, #3
+    b       .L_check_size
+
+.L_sub2_and_finish:
+    sub     r3, r3, #2
+
+.L_check_size:
+    pld     [r1, #0]
+    pld     [r1, #64]
+    ldr     r0, [sp]
+    cmp     r3, lr
+    bhs     .L_strcpy_chk_failed
+
+    // Add 1 for copy length to get the string terminator.
+    add     r2, r3, #1
+
+#include MEMCPY_BASE
+
+.L_strcpy_chk_failed:
+    ldr     r0, error_message
+    ldr     r1, error_code
+1:
+    add     r0, pc
+    bl      __fortify_chk_fail
+error_code:
+    .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
+error_message:
+    .word   error_string-(1b+4)
+END(__strcpy_chk)
+
+    .data
+error_string:
+    .string "strcpy: prevented write past end of buffer"
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 410b663..537f3de 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,79 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/*
- * Copyright (c) 2013 ARM Ltd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the company may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
 
-// Prototype: void *memcpy (void *dst, const void *src, size_t count).
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "memcpy_base.S"
 
-#include <private/bionic_asm.h>
-#include <private/libc_events.h>
-
-        .text
-        .syntax unified
-        .fpu    neon
-
-ENTRY(__memcpy_chk)
-        cmp     r2, r3
-        bhi     __memcpy_chk_fail
-
-        // Fall through to memcpy...
-END(__memcpy_chk)
-
-ENTRY(memcpy)
-        pld     [r1, #64]
-        push    {r0, lr}
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
-END(memcpy)
-
-#define MEMCPY_BASE         __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
-#include "memcpy_base.S"
-
-ENTRY_PRIVATE(__memcpy_chk_fail)
-        // Preserve lr for backtrace.
-        push    {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        ldr     r0, error_message
-        ldr     r1, error_code
-1:
-        add     r0, pc
-        bl      __fortify_chk_fail
-error_code:
-        .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
-error_message:
-        .word   error_string-(1b+8)
-END(__memcpy_chk_fail)
-
-        .data
-error_string:
-        .string "memcpy: prevented write past end of buffer"
+#include "memcpy_common.S"
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
index 2a73852..aac737d 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
@@ -53,11 +53,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-ENTRY_PRIVATE(MEMCPY_BASE)
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
-
+.L_memcpy_base:
         // Assumes that n >= 0, and dst, src are valid pointers.
         // For any sizes less than 832 use the neon code that doesn't
         // care about the src alignment. This avoids any checks
@@ -168,12 +164,6 @@
         eor     r3, r0, r1
         ands    r3, r3, #0x3
         bne     .L_copy_unknown_alignment
-END(MEMCPY_BASE)
-
-ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
 
         // To try and improve performance, stack layout changed,
         // i.e., not keeping the stack looking like users expect
@@ -185,7 +175,7 @@
         strd    r6, r7, [sp, #-8]!
         .cfi_adjust_cfa_offset 8
         .cfi_rel_offset r6, 0
-        .cfi_rel_offset r7, 0
+        .cfi_rel_offset r7, 4
         strd    r8, r9, [sp, #-8]!
         .cfi_adjust_cfa_offset 8
         .cfi_rel_offset r8, 0
@@ -291,10 +281,28 @@
 
         // Restore registers: optimized pop {r0, pc}
         ldrd    r8, r9, [sp], #8
+        .cfi_adjust_cfa_offset -8
+        .cfi_restore r8
+        .cfi_restore r9
         ldrd    r6, r7, [sp], #8
+        .cfi_adjust_cfa_offset -8
+        .cfi_restore r6
+        .cfi_restore r7
         ldrd    r4, r5, [sp], #8
+        .cfi_adjust_cfa_offset -8
+        .cfi_restore r4
+        .cfi_restore r5
         pop     {r0, pc}
 
+        // Put the cfi directives back for the below instructions.
+        .cfi_adjust_cfa_offset 24
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
+        .cfi_rel_offset r6, 8
+        .cfi_rel_offset r7, 12
+        .cfi_rel_offset r8, 16
+        .cfi_rel_offset r9, 20
+
 .L_dst_not_word_aligned:
         // Align dst to word.
         rsb     ip, ip, #4
@@ -315,4 +323,12 @@
 
         // Src is guaranteed to be at least word aligned by this point.
         b       .L_word_aligned
-END(MEMCPY_BASE_ALIGNED)
+
+        // Undo any cfi directives from above.
+        .cfi_adjust_cfa_offset -24
+        .cfi_restore r4
+        .cfi_restore r5
+        .cfi_restore r6
+        .cfi_restore r7
+        .cfi_restore r8
+        .cfi_restore r9
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_common.S b/libc/arch-arm/cortex-a15/bionic/memcpy_common.S
new file mode 100644
index 0000000..464fb46
--- /dev/null
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy_common.S
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2013 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <private/bionic_asm.h>
+#include <private/libc_events.h>
+
+        .text
+        .syntax unified
+        .fpu    neon
+
+ENTRY(__memcpy_chk)
+        cmp     r2, r3
+        bhi     .L_memcpy_chk_fail
+
+        // Fall through to memcpy...
+END(__memcpy_chk)
+
+// Prototype: void *memcpy (void *dst, const void *src, size_t count).
+ENTRY(memcpy)
+        pld     [r1, #64]
+        push    {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
+#include MEMCPY_BASE
+
+        // Undo the cfi instructions from above.
+        .cfi_def_cfa_offset 0
+        .cfi_restore r0
+        .cfi_restore lr
+.L_memcpy_chk_fail:
+        // Preserve lr for backtrace.
+        push    {lr}
+        .cfi_adjust_cfa_offset 4
+        .cfi_rel_offset lr, 0
+
+        ldr     r0, error_message
+        ldr     r1, error_code
+1:
+        add     r0, pc
+        bl      __fortify_chk_fail
+error_code:
+        .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
+error_message:
+        .word   error_string-(1b+8)
+END(memcpy)
+
+        .data
+error_string:
+        .string "memcpy: prevented write past end of buffer"
diff --git a/libc/arch-arm/cortex-a15/bionic/strcat.S b/libc/arch-arm/cortex-a15/bionic/strcat.S
index b95be94..157cc9f 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcat.S
@@ -70,7 +70,7 @@
 
     .macro m_scan_byte
     ldrb    r3, [r0]
-    cbz     r3, strcat_r0_scan_done
+    cbz     r3, .L_strcat_r0_scan_done
     add     r0, #1
     .endm // m_scan_byte
 
@@ -84,10 +84,10 @@
     // Quick check to see if src is empty.
     ldrb    r2, [r1]
     pld     [r1, #0]
-    cbnz    r2, strcat_continue
+    cbnz    r2, .L_strcat_continue
     bx      lr
 
-strcat_continue:
+.L_strcat_continue:
     // To speed up really small dst strings, unroll checking the first 4 bytes.
     m_push
     m_scan_byte
@@ -96,95 +96,102 @@
     m_scan_byte
 
     ands    r3, r0, #7
-    beq     strcat_mainloop
+    beq     .L_strcat_mainloop
 
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcat_align_to_32
+    beq     .L_strcat_align_to_32
 
     ldrb    r5, [r0]
-    cbz     r5, strcat_r0_scan_done
+    cbz     r5, .L_strcat_r0_scan_done
     add     r0, r0, #1
 
-strcat_align_to_32:
-    bcc     strcat_align_to_64
+.L_strcat_align_to_32:
+    bcc     .L_strcat_align_to_64
 
     ldrb    r2, [r0]
-    cbz     r2, strcat_r0_scan_done
+    cbz     r2, .L_strcat_r0_scan_done
     add     r0, r0, #1
     ldrb    r4, [r0]
-    cbz     r4, strcat_r0_scan_done
+    cbz     r4, .L_strcat_r0_scan_done
     add     r0, r0, #1
 
-strcat_align_to_64:
+.L_strcat_align_to_64:
     tst     r3, #4
-    beq     strcat_mainloop
+    beq     .L_strcat_mainloop
     ldr     r3, [r0], #4
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .L_strcat_zero_in_second_register
+    b       .L_strcat_mainloop
 
-strcat_r0_scan_done:
+.L_strcat_r0_scan_done:
     // For short copies, hard-code checking the first 8 bytes since this
     // new code doesn't win until after about 8 bytes.
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
+    m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r5, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish
+    m_copy_byte reg=r5, cmd=cbnz, label=.L_strcpy_continue
 
-strcpy_finish:
+.L_strcpy_finish:
     m_pop
 
-strcpy_continue:
+.L_strcpy_continue:
     ands    r3, r0, #7
-    beq     strcpy_check_src_align
+    beq     .L_strcpy_check_src_align
 
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcpy_align_to_32
+    beq     .L_strcpy_align_to_32
 
     ldrb    r2, [r1], #1
     strb    r2, [r0], #1
-    cbz     r2, strcpy_complete
+    cbz     r2, .L_strcpy_complete
 
-strcpy_align_to_32:
-    bcc     strcpy_align_to_64
+.L_strcpy_align_to_32:
+    bcc     .L_strcpy_align_to_64
 
     ldrb    r2, [r1], #1
     strb    r2, [r0], #1
-    cbz     r2, strcpy_complete
+    cbz     r2, .L_strcpy_complete
     ldrb    r2, [r1], #1
     strb    r2, [r0], #1
-    cbz     r2, strcpy_complete
+    cbz     r2, .L_strcpy_complete
 
-strcpy_align_to_64:
+.L_strcpy_align_to_64:
     tst     r3, #4
-    beq     strcpy_check_src_align
-    ldr     r2, [r1], #4
+    beq     .L_strcpy_check_src_align
+    // Read one byte at a time since we don't know the src alignment
+    // and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .L_strcpy_complete
 
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
-    str     r2, [r0], #4
-
-strcpy_check_src_align:
+.L_strcpy_check_src_align:
     // At this point dst is aligned to a double word, check if src
     // is also aligned to a double word.
     ands    r3, r1, #7
-    bne     strcpy_unaligned_copy
+    bne     .L_strcpy_unaligned_copy
 
     .p2align 2
-strcpy_mainloop:
+.L_strcpy_mainloop:
     ldrd    r2, r3, [r1], #8
 
     pld     [r1, #64]
@@ -192,128 +199,128 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_mainloop
+    b       .L_strcpy_mainloop
 
-strcpy_complete:
+.L_strcpy_complete:
     m_pop
 
-strcpy_zero_in_first_register:
+.L_strcpy_zero_in_first_register:
     lsls    lr, ip, #17
-    bne     strcpy_copy1byte
-    bcs     strcpy_copy2bytes
+    bne     .L_strcpy_copy1byte
+    bcs     .L_strcpy_copy2bytes
     lsls    ip, ip, #1
-    bne     strcpy_copy3bytes
+    bne     .L_strcpy_copy3bytes
 
-strcpy_copy4bytes:
+.L_strcpy_copy4bytes:
     // Copy 4 bytes to the destiniation.
     str     r2, [r0]
     m_pop
 
-strcpy_copy1byte:
+.L_strcpy_copy1byte:
     strb    r2, [r0]
     m_pop
 
-strcpy_copy2bytes:
+.L_strcpy_copy2bytes:
     strh    r2, [r0]
     m_pop
 
-strcpy_copy3bytes:
+.L_strcpy_copy3bytes:
     strh    r2, [r0], #2
     lsr     r2, #16
     strb    r2, [r0]
     m_pop
 
-strcpy_zero_in_second_register:
+.L_strcpy_zero_in_second_register:
     lsls    lr, ip, #17
-    bne     strcpy_copy5bytes
-    bcs     strcpy_copy6bytes
+    bne     .L_strcpy_copy5bytes
+    bcs     .L_strcpy_copy6bytes
     lsls    ip, ip, #1
-    bne     strcpy_copy7bytes
+    bne     .L_strcpy_copy7bytes
 
     // Copy 8 bytes to the destination.
     strd    r2, r3, [r0]
     m_pop
 
-strcpy_copy5bytes:
+.L_strcpy_copy5bytes:
     str     r2, [r0], #4
     strb    r3, [r0]
     m_pop
 
-strcpy_copy6bytes:
+.L_strcpy_copy6bytes:
     str     r2, [r0], #4
     strh    r3, [r0]
     m_pop
 
-strcpy_copy7bytes:
+.L_strcpy_copy7bytes:
     str     r2, [r0], #4
     strh    r3, [r0], #2
     lsr     r3, #16
     strb    r3, [r0]
     m_pop
 
-strcpy_unaligned_copy:
+.L_strcpy_unaligned_copy:
     // Dst is aligned to a double word, while src is at an unknown alignment.
     // There are 7 different versions of the unaligned copy code
     // to prevent overreading the src. The mainloop of every single version
     // will store 64 bits per loop. The difference is how much of src can
     // be read without potentially crossing a page boundary.
     tbb     [pc, r3]
-strcpy_unaligned_branchtable:
+.L_strcpy_unaligned_branchtable:
     .byte 0
-    .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign7 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign6 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign5 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign4 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign3 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign2 - .L_strcpy_unaligned_branchtable)/2)
+    .byte ((.L_strcpy_unalign1 - .L_strcpy_unaligned_branchtable)/2)
 
     .p2align 2
     // Can read 7 bytes before possibly crossing a page.
-strcpy_unalign7:
+.L_strcpy_unalign7:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     ldrb    r3, [r1]
-    cbz     r3, strcpy_unalign7_copy5bytes
+    cbz     r3, .L_strcpy_unalign7_copy5bytes
     ldrb    r4, [r1, #1]
-    cbz     r4, strcpy_unalign7_copy6bytes
+    cbz     r4, .L_strcpy_unalign7_copy6bytes
     ldrb    r5, [r1, #2]
-    cbz     r5, strcpy_unalign7_copy7bytes
+    cbz     r5, .L_strcpy_unalign7_copy7bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     lsrs    ip, r3, #24
     strd    r2, r3, [r0], #8
-    beq     strcpy_unalign_return
-    b       strcpy_unalign7
+    beq     .L_strcpy_unalign_return
+    b       .L_strcpy_unalign7
 
-strcpy_unalign7_copy5bytes:
+.L_strcpy_unalign7_copy5bytes:
     str     r2, [r0], #4
     strb    r3, [r0]
-strcpy_unalign_return:
+.L_strcpy_unalign_return:
     m_pop
 
-strcpy_unalign7_copy6bytes:
+.L_strcpy_unalign7_copy6bytes:
     str     r2, [r0], #4
     strb    r3, [r0], #1
     strb    r4, [r0], #1
     m_pop
 
-strcpy_unalign7_copy7bytes:
+.L_strcpy_unalign7_copy7bytes:
     str     r2, [r0], #4
     strb    r3, [r0], #1
     strb    r4, [r0], #1
@@ -322,41 +329,41 @@
 
     .p2align 2
     // Can read 6 bytes before possibly crossing a page.
-strcpy_unalign6:
+.L_strcpy_unalign6:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .L_strcpy_unalign_copy5bytes
     ldrb    r5, [r1, #1]
-    cbz     r5, strcpy_unalign_copy6bytes
+    cbz     r5, .L_strcpy_unalign_copy6bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r3, #0xff0000
-    beq     strcpy_copy7bytes
+    beq     .L_strcpy_copy7bytes
     lsrs    ip, r3, #24
     strd    r2, r3, [r0], #8
-    beq     strcpy_unalign_return
-    b       strcpy_unalign6
+    beq     .L_strcpy_unalign_return
+    b       .L_strcpy_unalign6
 
     .p2align 2
     // Can read 5 bytes before possibly crossing a page.
-strcpy_unalign5:
+.L_strcpy_unalign5:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .L_strcpy_unalign_copy5bytes
 
     ldr     r3, [r1], #4
 
@@ -365,17 +372,17 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_unalign5
+    b       .L_strcpy_unalign5
 
-strcpy_unalign_copy5bytes:
+.L_strcpy_unalign_copy5bytes:
     str     r2, [r0], #4
     strb    r4, [r0]
     m_pop
 
-strcpy_unalign_copy6bytes:
+.L_strcpy_unalign_copy6bytes:
     str     r2, [r0], #4
     strb    r4, [r0], #1
     strb    r5, [r0]
@@ -383,13 +390,13 @@
 
     .p2align 2
     // Can read 4 bytes before possibly crossing a page.
-strcpy_unalign4:
+.L_strcpy_unalign4:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
@@ -397,20 +404,20 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_unalign4
+    b       .L_strcpy_unalign4
 
     .p2align 2
     // Can read 3 bytes before possibly crossing a page.
-strcpy_unalign3:
+.L_strcpy_unalign3:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign3_copy1byte
+    cbz     r2, .L_strcpy_unalign3_copy1byte
     ldrb    r3, [r1, #1]
-    cbz     r3, strcpy_unalign3_copy2bytes
+    cbz     r3, .L_strcpy_unalign3_copy2bytes
     ldrb    r4, [r1, #2]
-    cbz     r4, strcpy_unalign3_copy3bytes
+    cbz     r4, .L_strcpy_unalign3_copy3bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -418,26 +425,26 @@
     pld     [r1, #64]
 
     lsrs    lr, r2, #24
-    beq     strcpy_copy4bytes
+    beq     .L_strcpy_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_unalign3
+    b       .L_strcpy_unalign3
 
-strcpy_unalign3_copy1byte:
+.L_strcpy_unalign3_copy1byte:
     strb    r2, [r0]
     m_pop
 
-strcpy_unalign3_copy2bytes:
+.L_strcpy_unalign3_copy2bytes:
     strb    r2, [r0], #1
     strb    r3, [r0]
     m_pop
 
-strcpy_unalign3_copy3bytes:
+.L_strcpy_unalign3_copy3bytes:
     strb    r2, [r0], #1
     strb    r3, [r0], #1
     strb    r4, [r0]
@@ -445,34 +452,34 @@
 
     .p2align 2
     // Can read 2 bytes before possibly crossing a page.
-strcpy_unalign2:
+.L_strcpy_unalign2:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .L_strcpy_unalign_copy1byte
     ldrb    r4, [r1, #1]
-    cbz     r4, strcpy_unalign_copy2bytes
+    cbz     r4, .L_strcpy_unalign_copy2bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r2, #0xff0000
-    beq     strcpy_copy3bytes
+    beq     .L_strcpy_copy3bytes
     lsrs    ip, r2, #24
-    beq     strcpy_copy4bytes
+    beq     .L_strcpy_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_unalign2
+    b       .L_strcpy_unalign2
 
     .p2align 2
     // Can read 1 byte before possibly crossing a page.
-strcpy_unalign1:
+.L_strcpy_unalign1:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .L_strcpy_unalign_copy1byte
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -482,27 +489,27 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .L_strcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .L_strcpy_zero_in_second_register
 
     strd    r2, r3, [r0], #8
-    b       strcpy_unalign1
+    b       .L_strcpy_unalign1
 
-strcpy_unalign_copy1byte:
+.L_strcpy_unalign_copy1byte:
     strb    r2, [r0]
     m_pop
 
-strcpy_unalign_copy2bytes:
+.L_strcpy_unalign_copy2bytes:
     strb    r2, [r0], #1
     strb    r4, [r0]
     m_pop
 
     .p2align 2
-strcat_mainloop:
+.L_strcat_mainloop:
     ldrd    r2, r3, [r0], #8
 
     pld     [r0, #64]
@@ -510,59 +517,59 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_first_register
+    bne     .L_strcat_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .L_strcat_zero_in_second_register
+    b       .L_strcat_mainloop
 
-strcat_zero_in_first_register:
+.L_strcat_zero_in_first_register:
     // Prefetch the src now, it's going to be used soon.
     pld     [r1, #0]
     lsls    lr, ip, #17
-    bne     strcat_sub8
-    bcs     strcat_sub7
+    bne     .L_strcat_sub8
+    bcs     .L_strcat_sub7
     lsls    ip, ip, #1
-    bne     strcat_sub6
+    bne     .L_strcat_sub6
 
     sub     r0, r0, #5
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub8:
+.L_strcat_sub8:
     sub     r0, r0, #8
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub7:
+.L_strcat_sub7:
     sub     r0, r0, #7
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub6:
+.L_strcat_sub6:
     sub     r0, r0, #6
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_zero_in_second_register:
+.L_strcat_zero_in_second_register:
     // Prefetch the src now, it's going to be used soon.
     pld     [r1, #0]
     lsls    lr, ip, #17
-    bne     strcat_sub4
-    bcs     strcat_sub3
+    bne     .L_strcat_sub4
+    bcs     .L_strcat_sub3
     lsls    ip, ip, #1
-    bne     strcat_sub2
+    bne     .L_strcat_sub2
 
     sub     r0, r0, #1
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub4:
+.L_strcat_sub4:
     sub     r0, r0, #4
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub3:
+.L_strcat_sub3:
     sub     r0, r0, #3
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 
-strcat_sub2:
+.L_strcat_sub2:
     sub     r0, r0, #2
-    b       strcat_r0_scan_done
+    b       .L_strcat_r0_scan_done
 END(strcat)
diff --git a/libc/arch-arm/cortex-a15/bionic/string_copy.S b/libc/arch-arm/cortex-a15/bionic/string_copy.S
index 20f0e91..92d1c98 100644
--- a/libc/arch-arm/cortex-a15/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a15/bionic/string_copy.S
@@ -149,13 +149,20 @@
 .Lstringcopy_align_to_64:
     tst     r3, #4
     beq     .Lstringcopy_check_src_align
-    ldr     r2, [r1], #4
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .Lstringcopy_zero_in_first_register
-    str     r2, [r0], #4
+    // Read one byte at a time since we don't have any idea about the alignment
+    // of the source and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
 
 .Lstringcopy_check_src_align:
     // At this point dst is aligned to a double word, check if src
diff --git a/libc/arch-arm/cortex-a15/bionic/strlen.S b/libc/arch-arm/cortex-a15/bionic/strlen.S
index 9a0ce62..4fd6284 100644
--- a/libc/arch-arm/cortex-a15/bionic/strlen.S
+++ b/libc/arch-arm/cortex-a15/bionic/strlen.S
@@ -65,38 +65,38 @@
     mov     r1, r0
 
     ands    r3, r0, #7
-    beq     mainloop
+    beq     .L_mainloop
 
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     align_to_32
+    beq     .L_align_to_32
 
     ldrb    r2, [r1], #1
-    cbz     r2, update_count_and_return
+    cbz     r2, .L_update_count_and_return
 
-align_to_32:
-    bcc     align_to_64
+.L_align_to_32:
+    bcc     .L_align_to_64
     ands    ip, r3, #2
-    beq     align_to_64
+    beq     .L_align_to_64
 
     ldrb    r2, [r1], #1
-    cbz     r2, update_count_and_return
+    cbz     r2, .L_update_count_and_return
     ldrb    r2, [r1], #1
-    cbz     r2, update_count_and_return
+    cbz     r2, .L_update_count_and_return
 
-align_to_64:
+.L_align_to_64:
     tst     r3, #4
-    beq     mainloop
+    beq     .L_mainloop
     ldr     r3, [r1], #4
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     zero_in_second_register
+    bne     .L_zero_in_second_register
 
     .p2align 2
-mainloop:
+.L_mainloop:
     ldrd    r2, r3, [r1], #8
 
     pld     [r1, #64]
@@ -104,62 +104,62 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     zero_in_first_register
+    bne     .L_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     zero_in_second_register
-    b       mainloop
+    bne     .L_zero_in_second_register
+    b       .L_mainloop
 
-update_count_and_return:
+.L_update_count_and_return:
     sub     r0, r1, r0
     sub     r0, r0, #1
     bx      lr
 
-zero_in_first_register:
+.L_zero_in_first_register:
     sub     r0, r1, r0
     lsls    r3, ip, #17
-    bne     sub8_and_return
-    bcs     sub7_and_return
+    bne     .L_sub8_and_return
+    bcs     .L_sub7_and_return
     lsls    ip, ip, #1
-    bne     sub6_and_return
+    bne     .L_sub6_and_return
 
     sub     r0, r0, #5
     bx      lr
 
-sub8_and_return:
+.L_sub8_and_return:
     sub     r0, r0, #8
     bx      lr
 
-sub7_and_return:
+.L_sub7_and_return:
     sub     r0, r0, #7
     bx      lr
 
-sub6_and_return:
+.L_sub6_and_return:
     sub     r0, r0, #6
     bx      lr
 
-zero_in_second_register:
+.L_zero_in_second_register:
     sub     r0, r1, r0
     lsls    r3, ip, #17
-    bne     sub4_and_return
-    bcs     sub3_and_return
+    bne     .L_sub4_and_return
+    bcs     .L_sub3_and_return
     lsls    ip, ip, #1
-    bne     sub2_and_return
+    bne     .L_sub2_and_return
 
     sub     r0, r0, #1
     bx      lr
 
-sub4_and_return:
+.L_sub4_and_return:
     sub     r0, r0, #4
     bx      lr
 
-sub3_and_return:
+.L_sub3_and_return:
     sub     r0, r0, #3
     bx      lr
 
-sub2_and_return:
+.L_sub2_and_return:
     sub     r0, r0, #2
     bx      lr
 END(strlen)
diff --git a/libc/arch-arm/cortex-a15/cortex-a15.mk b/libc/arch-arm/cortex-a15/cortex-a15.mk
index 6fa3270..20202a7 100644
--- a/libc/arch-arm/cortex-a15/cortex-a15.mk
+++ b/libc/arch-arm/cortex-a15/cortex-a15.mk
@@ -1,3 +1,17 @@
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
 libc_bionic_src_files_arm += \
     arch-arm/cortex-a15/bionic/memcpy.S \
     arch-arm/cortex-a15/bionic/memset.S \
@@ -10,7 +24,4 @@
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
-    arch-arm/generic/bionic/memcmp.S \
-
-libc_bionic_src_files_arm += \
     arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk b/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk
new file mode 100644
index 0000000..6455d04
--- /dev/null
+++ b/libc/arch-arm/cortex-a53.a57/cortex-a53.a57.mk
@@ -0,0 +1,32 @@
+# This file represents the best optimized routines that are the middle
+# ground when running on a big/little system that is cortex-a57/cortex-a53.
+# The cortex-a7 optimized routines, and the cortex-a53 optimized routines
+# decrease performance on cortex-a57 processors by as much as 20%.
+
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a15/bionic/memcpy.S \
+    arch-arm/cortex-a15/bionic/memset.S \
+    arch-arm/cortex-a15/bionic/stpcpy.S \
+    arch-arm/cortex-a15/bionic/strcat.S \
+    arch-arm/cortex-a15/bionic/__strcat_chk.S \
+    arch-arm/cortex-a15/bionic/strcmp.S \
+    arch-arm/cortex-a15/bionic/strcpy.S \
+    arch-arm/cortex-a15/bionic/__strcpy_chk.S \
+    arch-arm/cortex-a15/bionic/strlen.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/denver/bionic/memmove.S \
diff --git a/libc/include/sys/shm.h b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
similarity index 84%
copy from libc/include/sys/shm.h
copy to libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
index c691c29..c5bc98a 100644
--- a/libc/include/sys/shm.h
+++ b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
 
-#include <linux/shm.h>
-
-#endif /* _SYS_SHM_H_ */
+#include "arch-arm/cortex-a15/bionic/__strcat_chk_common.S"
diff --git a/libc/include/sys/shm.h b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
similarity index 84%
copy from libc/include/sys/shm.h
copy to libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
index c691c29..1f8945d 100644
--- a/libc/include/sys/shm.h
+++ b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
 
-#include <linux/shm.h>
-
-#endif /* _SYS_SHM_H_ */
+#include "arch-arm/cortex-a15/bionic/__strcpy_chk_common.S"
diff --git a/libc/include/sys/shm.h b/libc/arch-arm/cortex-a53/bionic/memcpy.S
similarity index 85%
rename from libc/include/sys/shm.h
rename to libc/arch-arm/cortex-a53/bionic/memcpy.S
index c691c29..664f574 100644
--- a/libc/include/sys/shm.h
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+// Indicate which memcpy base file to include.
+#define MEMCPY_BASE "arch-arm/cortex-a53/bionic/memcpy_base.S"
 
-#include <linux/shm.h>
-
-#endif /* _SYS_SHM_H_ */
+#include "arch-arm/cortex-a15/bionic/memcpy_common.S"
diff --git a/libc/arch-arm/cortex-a53/bionic/memcpy_base.S b/libc/arch-arm/cortex-a53/bionic/memcpy_base.S
new file mode 100644
index 0000000..2749fc8
--- /dev/null
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy_base.S
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2013 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.L_memcpy_base:
+        // Assumes that n >= 0, and dst, src are valid pointers.
+        cmp     r2, #16
+        blo     .L_copy_less_than_16_unknown_align
+
+.L_copy_unknown_alignment:
+        // Unknown alignment of src and dst.
+        // Assumes that the first few bytes have already been prefetched.
+
+        // Align destination to 128 bits. The mainloop store instructions
+        // require this alignment or they will throw an exception.
+        rsb         r3, r0, #0
+        ands        r3, r3, #0xF
+        beq         2f
+
+        // Copy up to 15 bytes (count in r3).
+        sub         r2, r2, r3
+        movs        ip, r3, lsl #31
+
+        itt         mi
+        ldrbmi      lr, [r1], #1
+        strbmi      lr, [r0], #1
+        itttt       cs
+        ldrbcs      ip, [r1], #1
+        ldrbcs      lr, [r1], #1
+        strbcs      ip, [r0], #1
+        strbcs      lr, [r0], #1
+
+        movs        ip, r3, lsl #29
+        bge         1f
+        // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after.
+        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
+        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
+1:      bcc         2f
+        // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after.
+        vld1.8      {d0}, [r1]!
+        vst1.8      {d0}, [r0, :64]!
+
+2:      // Make sure we have at least 64 bytes to copy.
+        subs        r2, r2, #64
+        blo         2f
+
+1:      // The main loop copies 64 bytes at a time.
+        vld1.8      {d0  - d3},   [r1]!
+        vld1.8      {d4  - d7},   [r1]!
+        subs        r2, r2, #64
+        vstmia      r0!, {d0 - d7}
+        pld         [r1, #(64*10)]
+        bhs         1b
+
+2:      // Fix-up the remaining count and make sure we have >= 32 bytes left.
+        adds        r2, r2, #32
+        blo         3f
+
+        // 32 bytes. These cache lines were already preloaded.
+        vld1.8      {d0 - d3},  [r1]!
+        sub         r2, r2, #32
+        vst1.8      {d0 - d3},  [r0, :128]!
+3:      // Less than 32 left.
+        add         r2, r2, #32
+        tst         r2, #0x10
+        beq         .L_copy_less_than_16_unknown_align
+        // Copies 16 bytes, destination 128 bits aligned.
+        vld1.8      {d0, d1}, [r1]!
+        vst1.8      {d0, d1}, [r0, :128]!
+
+.L_copy_less_than_16_unknown_align:
+        // Copy up to 15 bytes (count in r2).
+        movs        ip, r2, lsl #29
+        bcc         1f
+        vld1.8      {d0}, [r1]!
+        vst1.8      {d0}, [r0]!
+1:      bge         2f
+        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
+        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0]!
+
+2:      // Copy 0 to 4 bytes.
+        lsls        r2, r2, #31
+        itt         ne
+        ldrbne      lr, [r1], #1
+        strbne      lr, [r0], #1
+        itttt       cs
+        ldrbcs      ip, [r1], #1
+        ldrbcs      lr, [r1]
+        strbcs      ip, [r0], #1
+        strbcs      lr, [r0]
+
+        pop         {r0, pc}
diff --git a/libc/arch-arm/cortex-a53/cortex-a53.mk b/libc/arch-arm/cortex-a53/cortex-a53.mk
index b5c337c..9b431ae 100644
--- a/libc/arch-arm/cortex-a53/cortex-a53.mk
+++ b/libc/arch-arm/cortex-a53/cortex-a53.mk
@@ -1 +1,31 @@
-include bionic/libc/arch-arm/cortex-a7/cortex-a7.mk
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a53/bionic/memcpy.S \
+    arch-arm/cortex-a53/bionic/__strcat_chk.S \
+    arch-arm/cortex-a53/bionic/__strcpy_chk.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a7/bionic/memset.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a15/bionic/stpcpy.S \
+    arch-arm/cortex-a15/bionic/strcat.S \
+    arch-arm/cortex-a15/bionic/strcmp.S \
+    arch-arm/cortex-a15/bionic/strcpy.S \
+    arch-arm/cortex-a15/bionic/strlen.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/cortex-a7/bionic/memset.S b/libc/arch-arm/cortex-a7/bionic/memset.S
new file mode 100644
index 0000000..6365b06
--- /dev/null
+++ b/libc/arch-arm/cortex-a7/bionic/memset.S
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 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 <machine/cpu-features.h>
+#include <private/bionic_asm.h>
+#include <private/libc_events.h>
+
+        /*
+         * Optimized memset() for ARM.
+         *
+         * memset() returns its first argument.
+         */
+
+        .fpu        neon
+        .syntax     unified
+
+ENTRY(__memset_chk)
+        cmp         r2, r3
+        bls         .L_done
+
+        // Preserve lr for backtrace.
+        push        {lr}
+        .cfi_def_cfa_offset 4
+        .cfi_rel_offset lr, 0
+
+        ldr         r0, error_message
+        ldr         r1, error_code
+1:
+        add         r0, pc
+        bl          __fortify_chk_fail
+error_code:
+        .word       BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW
+error_message:
+        .word       error_string-(1b+8)
+END(__memset_chk)
+
+ENTRY(bzero)
+        mov         r2, r1
+        mov         r1, #0
+.L_done:
+        // Fall through to memset...
+END(bzero)
+
+ENTRY(memset)
+        mov         r3, r0
+        // At this point only d0, d1 are going to be used below.
+        vdup.8      q0, r1
+        cmp         r2, #16
+        blo         .L_set_less_than_16_unknown_align
+
+.L_check_alignment:
+        // Align destination to a double word to avoid the store crossing
+        // a cache line boundary.
+        ands        ip, r3, #7
+        bne         .L_do_double_word_align
+
+.L_double_word_aligned:
+        // Duplicate since the less than 64 can use d2, d3.
+        vmov        q1, q0
+        subs        r2, #64
+        blo         .L_set_less_than_64
+
+        // Duplicate the copy value so that we can store 64 bytes at a time.
+        vmov        q2, q0
+        vmov        q3, q0
+
+1:      // Main loop stores 64 bytes at a time.
+        subs        r2, #64
+        vstmia      r3!, {d0 - d7}
+        bge         1b
+
+.L_set_less_than_64:
+        // Restore r2 to the count of bytes left to set.
+        add         r2, #64
+        lsls        ip, r2, #27
+        bcc         .L_set_less_than_32
+        // Set 32 bytes.
+        vstmia      r3!, {d0 - d3}
+
+.L_set_less_than_32:
+        bpl         .L_set_less_than_16
+        // Set 16 bytes.
+        vstmia      r3!, {d0, d1}
+
+.L_set_less_than_16:
+        // Less than 16 bytes to set.
+        lsls        ip, r2, #29
+        bcc         .L_set_less_than_8
+
+        // Set 8 bytes.
+        vstmia      r3!, {d0}
+
+.L_set_less_than_8:
+        bpl         .L_set_less_than_4
+        // Set 4 bytes
+        vst1.32     {d0[0]}, [r3]!
+
+.L_set_less_than_4:
+        lsls        ip, r2, #31
+        it          ne
+        strbne      r1, [r3], #1
+        itt         cs
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3]
+        bx          lr
+
+.L_do_double_word_align:
+        rsb         ip, ip, #8
+        sub         r2, r2, ip
+
+        // Do this comparison now, otherwise we'll need to save a
+        // register to the stack since we've used all available
+        // registers.
+        cmp         ip, #4
+        blo         1f
+
+        // Need to do a four byte copy.
+        movs        ip, ip, lsl #31
+        it          mi
+        strbmi      r1, [r3], #1
+        itt         cs
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3], #1
+        vst1.32     {d0[0]}, [r3]!
+        b           .L_double_word_aligned
+
+1:
+        // No four byte copy.
+        movs        ip, ip, lsl #31
+        it          mi
+        strbmi      r1, [r3], #1
+        itt         cs
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3], #1
+        b           .L_double_word_aligned
+
+.L_set_less_than_16_unknown_align:
+        // Set up to 15 bytes.
+        movs        ip, r2, lsl #29
+        bcc         1f
+        vst1.8      {d0}, [r3]!
+1:      bge         2f
+        vst1.32     {d0[0]}, [r3]!
+2:      movs        ip, r2, lsl #31
+        it          mi
+        strbmi      r1, [r3], #1
+        itt         cs
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3], #1
+        bx          lr
+END(memset)
+
+        .data
+error_string:
+        .string     "memset: prevented write past end of buffer"
diff --git a/libc/arch-arm/cortex-a7/cortex-a7.mk b/libc/arch-arm/cortex-a7/cortex-a7.mk
index 9af03d9..f570d0f 100644
--- a/libc/arch-arm/cortex-a7/cortex-a7.mk
+++ b/libc/arch-arm/cortex-a7/cortex-a7.mk
@@ -1 +1,29 @@
-include bionic/libc/arch-arm/cortex-a15/cortex-a15.mk
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a7/bionic/memset.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/cortex-a15/bionic/memcpy.S \
+    arch-arm/cortex-a15/bionic/stpcpy.S \
+    arch-arm/cortex-a15/bionic/strcat.S \
+    arch-arm/cortex-a15/bionic/__strcat_chk.S \
+    arch-arm/cortex-a15/bionic/strcmp.S \
+    arch-arm/cortex-a15/bionic/strcpy.S \
+    arch-arm/cortex-a15/bionic/__strcpy_chk.S \
+    arch-arm/cortex-a15/bionic/strlen.S \
+
+libc_bionic_src_files_arm += \
+    arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
index 5e81305..966b9b3 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
@@ -44,7 +44,7 @@
         /* check if buffers are aligned. If so, run arm-only version */
         eor         r3, r0, r1
         ands        r3, r3, #0x3
-        beq         __memcpy_base_aligned
+        beq         MEMCPY_BASE_ALIGNED
 
         /* Check the upper size limit for Neon unaligned memory access in memcpy */
         cmp         r2, #224
@@ -133,8 +133,7 @@
         strbcs      ip, [r0], #1
         strbcs      lr, [r0], #1
 
-        ldmfd       sp!, {r0, lr}
-        bx          lr
+        ldmfd       sp!, {r0, pc}
 END(MEMCPY_BASE)
 
 ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED)
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index 8ee6ac2..b39fcc4 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -69,12 +69,9 @@
 ENTRY(memset)
         // The neon memset only wins for less than 132.
         cmp         r2, #132
-        bhi         __memset_large_copy
+        bhi         .L_memset_large_copy
 
-        stmfd       sp!, {r0}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset r0, 0
-
+        mov         r3, r0
         vdup.8      q0, r1
 
         /* make sure we have at least 32 bytes to write */
@@ -84,7 +81,7 @@
 
 1:      /* The main loop writes 32 bytes at a time */
         subs        r2, r2, #32
-        vst1.8      {d0 - d3}, [r0]!
+        vst1.8      {d0 - d3}, [r3]!
         bhs         1b
 
 2:      /* less than 32 left */
@@ -93,22 +90,20 @@
         beq         3f
 
         // writes 16 bytes, 128-bits aligned
-        vst1.8      {d0, d1}, [r0]!
+        vst1.8      {d0, d1}, [r3]!
 3:      /* write up to 15-bytes (count in r2) */
         movs        ip, r2, lsl #29
         bcc         1f
-        vst1.8      {d0}, [r0]!
+        vst1.8      {d0}, [r3]!
 1:      bge         2f
-        vst1.32     {d0[0]}, [r0]!
+        vst1.32     {d0[0]}, [r3]!
 2:      movs        ip, r2, lsl #31
-        strbmi      r1, [r0], #1
-        strbcs      r1, [r0], #1
-        strbcs      r1, [r0], #1
-        ldmfd       sp!, {r0}
+        strbmi      r1, [r3], #1
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3], #1
         bx          lr
-END(memset)
 
-ENTRY_PRIVATE(__memset_large_copy)
+.L_memset_large_copy:
         /* compute the offset to align the destination
          * offset = (4-(src&3))&3 = -src & 3
          */
@@ -136,8 +131,7 @@
         strbcs      r1, [r0], #1
         strbmi      r1, [r0], #1
         subs        r2, r2, r3
-        popls       {r0, r4-r7, lr}   /* return */
-        bxls        lr
+        popls       {r0, r4-r7, pc}   /* return */
 
         /* align the destination to a cache-line */
         mov         r12, r1
@@ -180,9 +174,8 @@
         strhmi      r1, [r0], #2
         movs        r2, r2, lsl #2
         strbcs      r1, [r0]
-        ldmfd       sp!, {r0, r4-r7, lr}
-        bx          lr
-END(__memset_large_copy)
+        ldmfd       sp!, {r0, r4-r7, pc}
+END(memset)
 
         .data
 error_string:
diff --git a/libc/arch-arm/cortex-a9/bionic/strcat.S b/libc/arch-arm/cortex-a9/bionic/strcat.S
index f5a855e..9077a74 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcat.S
@@ -70,7 +70,7 @@
 
     .macro m_scan_byte
     ldrb    r3, [r0]
-    cbz     r3, strcat_r0_scan_done
+    cbz     r3, .Lstrcat_r0_scan_done
     add     r0, #1
     .endm // m_scan_byte
 
@@ -84,10 +84,10 @@
     // Quick check to see if src is empty.
     ldrb        r2, [r1]
     pld         [r1, #0]
-    cbnz        r2, strcat_continue
+    cbnz        r2, .Lstrcat_continue
     bx          lr
 
-strcat_continue:
+.Lstrcat_continue:
     // To speed up really small dst strings, unroll checking the first 4 bytes.
     m_push
     m_scan_byte
@@ -96,10 +96,10 @@
     m_scan_byte
 
     ands    r3, r0, #7
-    bne     strcat_align_src
+    bne     .Lstrcat_align_src
 
     .p2align 2
-strcat_mainloop:
+.Lstrcat_mainloop:
     ldmia   r0!, {r2, r3}
 
     pld     [r0, #64]
@@ -107,28 +107,28 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_first_register
+    bne     .Lstrcat_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .Lstrcat_zero_in_second_register
+    b       .Lstrcat_mainloop
 
-strcat_zero_in_first_register:
+.Lstrcat_zero_in_first_register:
     sub     r0, r0, #4
 
-strcat_zero_in_second_register:
+.Lstrcat_zero_in_second_register:
     // Check for zero in byte 0.
     tst     ip, #0x80
     it      ne
     subne   r0, r0, #4
-    bne     strcat_r0_scan_done
+    bne     .Lstrcat_r0_scan_done
     // Check for zero in byte 1.
     tst     ip, #0x8000
     it      ne
     subne   r0, r0, #3
-    bne     strcat_r0_scan_done
+    bne     .Lstrcat_r0_scan_done
     // Check for zero in byte 2.
     tst     ip, #0x800000
     it      ne
@@ -137,33 +137,33 @@
     // Zero is in byte 3.
     subeq   r0, r0, #1
 
-strcat_r0_scan_done:
+.Lstrcat_r0_scan_done:
     // Unroll the first 8 bytes that will be copied.
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r2, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r3, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r4, cmd=cbz, label=strcpy_finish
-    m_copy_byte reg=r5, cmd=cbnz, label=strcpy_continue
+    m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish
+    m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue
 
-strcpy_finish:
+.Lstrcpy_finish:
     m_ret   inst=pop
 
-strcpy_continue:
+.Lstrcpy_continue:
     pld     [r1, #0]
     ands    r3, r0, #7
-    bne     strcpy_align_dst
+    bne     .Lstrcpy_align_dst
 
-strcpy_check_src_align:
+.Lstrcpy_check_src_align:
     // At this point dst is aligned to a double word, check if src
     // is also aligned to a double word.
     ands    r3, r1, #7
-    bne     strcpy_unaligned_copy
+    bne     .Lstrcpy_unaligned_copy
 
     .p2align 2
-strcpy_mainloop:
+.Lstrcpy_mainloop:
     ldmia   r1!, {r2, r3}
 
     pld     [r1, #64]
@@ -171,17 +171,17 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_mainloop
+    b       .Lstrcpy_mainloop
 
-strcpy_zero_in_first_register:
+.Lstrcpy_zero_in_first_register:
     lsls    lr, ip, #17
     itt     ne
     strbne  r2, [r0]
@@ -198,7 +198,7 @@
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_zero_in_second_register:
+.Lstrcpy_zero_in_second_register:
     lsls    lr, ip, #17
     ittt    ne
     stmiane r0!, {r2}
@@ -218,18 +218,18 @@
     strb    r4, [r0]
     m_ret   inst=pop
 
-strcpy_align_dst:
+.Lstrcpy_align_dst:
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcpy_align_to_32
+    beq     .Lstrcpy_align_to_32
 
     ldrb    r2, [r1], #1
     strb    r2, [r0], #1
-    cbz     r2, strcpy_complete
+    cbz     r2, .Lstrcpy_complete
 
-strcpy_align_to_32:
-    bcc     strcpy_align_to_64
+.Lstrcpy_align_to_32:
+    bcc     .Lstrcpy_align_to_64
 
     ldrb    r4, [r1], #1
     strb    r4, [r0], #1
@@ -242,76 +242,83 @@
     it      eq
     m_ret   inst=popeq
 
-strcpy_align_to_64:
+.Lstrcpy_align_to_64:
     tst     r3, #4
-    beq     strcpy_check_src_align
-    ldr     r2, [r1], #4
+    beq     .Lstrcpy_check_src_align
+    // Read one byte at a time since we don't know the src alignment
+    // and we don't want to read into a different page.
+    ldrb    r4, [r1], #1
+    strb    r4, [r0], #1
+    cbz     r4, .Lstrcpy_complete
+    ldrb    r5, [r1], #1
+    strb    r5, [r0], #1
+    cbz     r5, .Lstrcpy_complete
+    ldrb    r4, [r1], #1
+    strb    r4, [r0], #1
+    cbz     r4, .Lstrcpy_complete
+    ldrb    r5, [r1], #1
+    strb    r5, [r0], #1
+    cbz     r5, .Lstrcpy_complete
+    b       .Lstrcpy_check_src_align
 
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
-    stmia   r0!, {r2}
-    b       strcpy_check_src_align
-
-strcpy_complete:
+.Lstrcpy_complete:
     m_ret   inst=pop
 
-strcpy_unaligned_copy:
+.Lstrcpy_unaligned_copy:
     // Dst is aligned to a double word, while src is at an unknown alignment.
     // There are 7 different versions of the unaligned copy code
     // to prevent overreading the src. The mainloop of every single version
     // will store 64 bits per loop. The difference is how much of src can
     // be read without potentially crossing a page boundary.
     tbb     [pc, r3]
-strcpy_unaligned_branchtable:
+.Lstrcpy_unaligned_branchtable:
     .byte 0
-    .byte ((strcpy_unalign7 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign6 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign5 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign4 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign3 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign2 - strcpy_unaligned_branchtable)/2)
-    .byte ((strcpy_unalign1 - strcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2)
+    .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2)
 
     .p2align 2
     // Can read 7 bytes before possibly crossing a page.
-strcpy_unalign7:
+.Lstrcpy_unalign7:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r3, [r1]
-    cbz     r3, strcpy_unalign7_copy5bytes
+    cbz     r3, .Lstrcpy_unalign7_copy5bytes
     ldrb    r4, [r1, #1]
-    cbz     r4, strcpy_unalign7_copy6bytes
+    cbz     r4, .Lstrcpy_unalign7_copy6bytes
     ldrb    r5, [r1, #2]
-    cbz     r5, strcpy_unalign7_copy7bytes
+    cbz     r5, .Lstrcpy_unalign7_copy7bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     lsrs    ip, r3, #24
     stmia   r0!, {r2, r3}
-    beq     strcpy_unalign_return
-    b       strcpy_unalign7
+    beq     .Lstrcpy_unalign_return
+    b       .Lstrcpy_unalign7
 
-strcpy_unalign7_copy5bytes:
+.Lstrcpy_unalign7_copy5bytes:
     stmia   r0!, {r2}
     strb    r3, [r0]
-strcpy_unalign_return:
+.Lstrcpy_unalign_return:
     m_ret   inst=pop
 
-strcpy_unalign7_copy6bytes:
+.Lstrcpy_unalign7_copy6bytes:
     stmia   r0!, {r2}
     strb    r3, [r0], #1
     strb    r4, [r0], #1
     m_ret   inst=pop
 
-strcpy_unalign7_copy7bytes:
+.Lstrcpy_unalign7_copy7bytes:
     stmia   r0!, {r2}
     strb    r3, [r0], #1
     strb    r4, [r0], #1
@@ -320,30 +327,30 @@
 
     .p2align 2
     // Can read 6 bytes before possibly crossing a page.
-strcpy_unalign6:
+.Lstrcpy_unalign6:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .Lstrcpy_unalign_copy5bytes
     ldrb    r5, [r1, #1]
-    cbz     r5, strcpy_unalign_copy6bytes
+    cbz     r5, .Lstrcpy_unalign_copy6bytes
 
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r3, #0xff0000
-    beq     strcpy_unalign6_copy7bytes
+    beq     .Lstrcpy_unalign6_copy7bytes
     lsrs    ip, r3, #24
     stmia   r0!, {r2, r3}
-    beq     strcpy_unalign_return
-    b       strcpy_unalign6
+    beq     .Lstrcpy_unalign_return
+    b       .Lstrcpy_unalign6
 
-strcpy_unalign6_copy7bytes:
+.Lstrcpy_unalign6_copy7bytes:
     stmia   r0!, {r2}
     strh    r3, [r0], #2
     lsr     r3, #16
@@ -352,16 +359,16 @@
 
     .p2align 2
     // Can read 5 bytes before possibly crossing a page.
-strcpy_unalign5:
+.Lstrcpy_unalign5:
     ldr     r2, [r1], #4
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldrb    r4, [r1]
-    cbz     r4, strcpy_unalign_copy5bytes
+    cbz     r4, .Lstrcpy_unalign_copy5bytes
 
     ldr     r3, [r1], #4
 
@@ -370,17 +377,17 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign5
+    b       .Lstrcpy_unalign5
 
-strcpy_unalign_copy5bytes:
+.Lstrcpy_unalign_copy5bytes:
     stmia   r0!, {r2}
     strb    r4, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy6bytes:
+.Lstrcpy_unalign_copy6bytes:
     stmia   r0!, {r2}
     strb    r4, [r0], #1
     strb    r5, [r0]
@@ -388,13 +395,13 @@
 
     .p2align 2
     // Can read 4 bytes before possibly crossing a page.
-strcpy_unalign4:
+.Lstrcpy_unalign4:
     ldmia   r1!, {r2}
 
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     ldmia   r1!, {r3}
     pld     [r1, #64]
@@ -402,20 +409,20 @@
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign4
+    b       .Lstrcpy_unalign4
 
     .p2align 2
     // Can read 3 bytes before possibly crossing a page.
-strcpy_unalign3:
+.Lstrcpy_unalign3:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign3_copy1byte
+    cbz     r2, .Lstrcpy_unalign3_copy1byte
     ldrb    r3, [r1, #1]
-    cbz     r3, strcpy_unalign3_copy2bytes
+    cbz     r3, .Lstrcpy_unalign3_copy2bytes
     ldrb    r4, [r1, #2]
-    cbz     r4, strcpy_unalign3_copy3bytes
+    cbz     r4, .Lstrcpy_unalign3_copy3bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -423,26 +430,26 @@
     pld     [r1, #64]
 
     lsrs    lr, r2, #24
-    beq     strcpy_unalign_copy4bytes
+    beq     .Lstrcpy_unalign_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign3
+    b       .Lstrcpy_unalign3
 
-strcpy_unalign3_copy1byte:
+.Lstrcpy_unalign3_copy1byte:
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign3_copy2bytes:
+.Lstrcpy_unalign3_copy2bytes:
     strb    r2, [r0], #1
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_unalign3_copy3bytes:
+.Lstrcpy_unalign3_copy3bytes:
     strb    r2, [r0], #1
     strb    r3, [r0], #1
     strb    r4, [r0]
@@ -450,34 +457,34 @@
 
     .p2align 2
     // Can read 2 bytes before possibly crossing a page.
-strcpy_unalign2:
+.Lstrcpy_unalign2:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .Lstrcpy_unalign_copy1byte
     ldrb    r3, [r1, #1]
-    cbz     r3, strcpy_unalign_copy2bytes
+    cbz     r3, .Lstrcpy_unalign_copy2bytes
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
     pld     [r1, #64]
 
     tst     r2, #0xff0000
-    beq     strcpy_unalign_copy3bytes
+    beq     .Lstrcpy_unalign_copy3bytes
     lsrs    ip, r2, #24
-    beq     strcpy_unalign_copy4bytes
+    beq     .Lstrcpy_unalign_copy4bytes
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign2
+    b       .Lstrcpy_unalign2
 
     .p2align 2
     // Can read 1 byte before possibly crossing a page.
-strcpy_unalign1:
+.Lstrcpy_unalign1:
     ldrb    r2, [r1]
-    cbz     r2, strcpy_unalign_copy1byte
+    cbz     r2, .Lstrcpy_unalign_copy1byte
 
     ldr     r2, [r1], #4
     ldr     r3, [r1], #4
@@ -487,62 +494,62 @@
     sub     ip, r2, #0x01010101
     bic     ip, ip, r2
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_first_register
+    bne     .Lstrcpy_zero_in_first_register
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcpy_zero_in_second_register
+    bne     .Lstrcpy_zero_in_second_register
 
     stmia   r0!, {r2, r3}
-    b       strcpy_unalign1
+    b       .Lstrcpy_unalign1
 
-strcpy_unalign_copy1byte:
+.Lstrcpy_unalign_copy1byte:
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy2bytes:
+.Lstrcpy_unalign_copy2bytes:
     strb    r2, [r0], #1
     strb    r3, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy3bytes:
+.Lstrcpy_unalign_copy3bytes:
     strh    r2, [r0], #2
     lsr     r2, #16
     strb    r2, [r0]
     m_ret   inst=pop
 
-strcpy_unalign_copy4bytes:
+.Lstrcpy_unalign_copy4bytes:
     stmia   r0, {r2}
     m_ret   inst=pop
 
-strcat_align_src:
+.Lstrcat_align_src:
     // Align to a double word (64 bits).
     rsb     r3, r3, #8
     lsls    ip, r3, #31
-    beq     strcat_align_to_32
+    beq     .Lstrcat_align_to_32
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
 
-strcat_align_to_32:
-    bcc     strcat_align_to_64
+.Lstrcat_align_to_32:
+    bcc     .Lstrcat_align_to_64
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
     ldrb    r2, [r0], #1
-    cbz     r2, strcat_r0_update
+    cbz     r2, .Lstrcat_r0_update
 
-strcat_align_to_64:
+.Lstrcat_align_to_64:
     tst     r3, #4
-    beq     strcat_mainloop
+    beq     .Lstrcat_mainloop
     ldr     r3, [r0], #4
 
     sub     ip, r3, #0x01010101
     bic     ip, ip, r3
     ands    ip, ip, #0x80808080
-    bne     strcat_zero_in_second_register
-    b       strcat_mainloop
+    bne     .Lstrcat_zero_in_second_register
+    b       .Lstrcat_mainloop
 
-strcat_r0_update:
+.Lstrcat_r0_update:
     sub     r0, r0, #1
-    b strcat_r0_scan_done
+    b .Lstrcat_r0_scan_done
 END(strcat)
diff --git a/libc/arch-arm/cortex-a9/bionic/string_copy.S b/libc/arch-arm/cortex-a9/bionic/string_copy.S
index caf5a11..642db0f 100644
--- a/libc/arch-arm/cortex-a9/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a9/bionic/string_copy.S
@@ -244,13 +244,20 @@
 .Lstringcopy_align_to_64:
     tst     r3, #4
     beq     .Lstringcopy_check_src_align
-    ldr     r2, [r1], #4
-
-    sub     ip, r2, #0x01010101
-    bic     ip, ip, r2
-    ands    ip, ip, #0x80808080
-    bne     .Lstringcopy_zero_in_first_register
-    stmia   r0!, {r2}
+    // Read one byte at a time since we don't have any idea about the alignment
+    // of the source and we don't want to read into a different page.
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
+    ldrb    r2, [r1], #1
+    strb    r2, [r0], #1
+    cbz     r2, .Lstringcopy_complete
     b       .Lstringcopy_check_src_align
 
 .Lstringcopy_complete:
diff --git a/libc/arch-arm/cortex-a9/cortex-a9.mk b/libc/arch-arm/cortex-a9/cortex-a9.mk
index 7b38de1..8a26d6b 100644
--- a/libc/arch-arm/cortex-a9/cortex-a9.mk
+++ b/libc/arch-arm/cortex-a9/cortex-a9.mk
@@ -1,3 +1,18 @@
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+    upstream-openbsd/lib/libc/string/strcpy.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
 libc_bionic_src_files_arm += \
     arch-arm/cortex-a9/bionic/memcpy.S \
     arch-arm/cortex-a9/bionic/memset.S \
@@ -10,7 +25,4 @@
     arch-arm/cortex-a9/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
-    arch-arm/generic/bionic/memcmp.S \
-
-libc_bionic_src_files_arm += \
     arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/denver/denver.mk b/libc/arch-arm/denver/denver.mk
index 5fddf95..f167991 100644
--- a/libc/arch-arm/denver/denver.mk
+++ b/libc/arch-arm/denver/denver.mk
@@ -1,5 +1,18 @@
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
 libc_bionic_src_files_arm += \
-    arch-arm/generic/bionic/memcmp.S \
     arch-arm/denver/bionic/memcpy.S \
     arch-arm/denver/bionic/memmove.S \
     arch-arm/denver/bionic/memset.S \
diff --git a/libc/arch-arm/generic/bionic/memcmp.S b/libc/arch-arm/generic/bionic/memcmp.S
index c78dbd4..6643d55 100644
--- a/libc/arch-arm/generic/bionic/memcmp.S
+++ b/libc/arch-arm/generic/bionic/memcmp.S
@@ -221,8 +221,7 @@
         bne         8b
 
 9:      /* restore registers and return */
-        ldmfd       sp!, {r4, lr}
-        bx          lr
+        ldmfd       sp!, {r4, pc}
 
 10:     /* process less than 12 bytes */
         cmp         r2, #0
diff --git a/libc/arch-arm/generic/bionic/memcpy.S b/libc/arch-arm/generic/bionic/memcpy.S
index ea5a399..65cba4c 100644
--- a/libc/arch-arm/generic/bionic/memcpy.S
+++ b/libc/arch-arm/generic/bionic/memcpy.S
@@ -194,8 +194,7 @@
 
         /* we're done! restore everything and return */
 1:      ldmfd       sp!, {r5-r11}
-        ldmfd       sp!, {r0, r4, lr}
-        bx          lr
+        ldmfd       sp!, {r0, r4, pc}
 
         /********************************************************************/
 
@@ -385,8 +384,7 @@
 
         /* we're done! restore sp and spilled registers and return */
         add         sp,  sp, #28
-        ldmfd       sp!, {r0, r4, lr}
-        bx          lr
+        ldmfd       sp!, {r0, r4, pc}
 END(memcpy)
 
         // Only reached when the __memcpy_chk check fails.
diff --git a/libc/arch-arm/generic/bionic/memset.S b/libc/arch-arm/generic/bionic/memset.S
index d17a9c4..b8eabbf 100644
--- a/libc/arch-arm/generic/bionic/memset.S
+++ b/libc/arch-arm/generic/bionic/memset.S
@@ -82,8 +82,7 @@
         strbcs      r1, [r0], #1
         strbmi      r1, [r0], #1
         subs        r2, r2, r3
-        popls       {r0, r4-r7, lr}    /* return */
-        bxls        lr
+        popls       {r0, r4-r7, pc}    /* return */
 
         /* align the destination to a cache-line */
         mov         r12, r1
@@ -126,8 +125,7 @@
         strhmi      r1, [r0], #2
         movs        r2, r2, lsl #2
         strbcs      r1, [r0]
-        ldmfd       sp!, {r0, r4-r7, lr}
-        bx          lr
+        ldmfd       sp!, {r0, r4-r7, pc}
 END(memset)
 
         .data
diff --git a/libc/arch-arm/generic/generic.mk b/libc/arch-arm/generic/generic.mk
deleted file mode 100644
index e49d6d2..0000000
--- a/libc/arch-arm/generic/generic.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-libc_bionic_src_files_arm += \
-    arch-arm/generic/bionic/memcmp.S \
-    arch-arm/generic/bionic/memcpy.S \
-    arch-arm/generic/bionic/memset.S \
-    arch-arm/generic/bionic/strcmp.S \
-    arch-arm/generic/bionic/strcpy.S \
-    arch-arm/generic/bionic/strlen.c \
-    bionic/__strcat_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-
-libc_openbsd_src_files_arm += \
-    upstream-openbsd/lib/libc/string/memmove.c \
-    upstream-openbsd/lib/libc/string/stpcpy.c \
-    upstream-openbsd/lib/libc/string/strcat.c \
diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S
index 246f159..1a39c5b 100644
--- a/libc/arch-arm/krait/bionic/__strcat_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 ENTRY(__strcat_chk)
     pld     [r0, #0]
     push    {r0, lr}
-    .cfi_def_cfa_offset 8
+    .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
     push    {r4, r5}
@@ -177,7 +177,7 @@
 .L_strlen_done:
     add     r2, r3, r4
     cmp     r2, lr
-    bhi     __strcat_chk_failed
+    bhi     .L_strcat_chk_failed
 
     // Set up the registers for the memcpy code.
     mov     r1, r5
@@ -185,20 +185,17 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-END(__strcat_chk)
+    .cfi_adjust_cfa_offset -8
+    .cfi_restore r4
+    .cfi_restore r5
 
-#define MEMCPY_BASE         __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__strcat_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
+    // Undo the above cfi directives.
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-
+.L_strcat_chk_failed:
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -208,7 +205,7 @@
     .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
 error_message:
     .word   error_string-(1b+4)
-END(__strcat_chk_failed)
+END(__strcat_chk)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S
index db76686..00202f3 100644
--- a/libc/arch-arm/krait/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 ENTRY(__strcpy_chk)
     pld     [r0, #0]
     push    {r0, lr}
-    .cfi_def_cfa_offset 8
+    .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
 
@@ -149,21 +149,14 @@
     pld     [r1, #64]
     ldr     r0, [sp]
     cmp     r3, lr
-    bhs     __strcpy_chk_failed
+    bhs     .L_strcpy_chk_failed
 
     // Add 1 for copy length to get the string terminator.
     add     r2, r3, #1
-END(__strcpy_chk)
 
-#define MEMCPY_BASE         __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__strcpy_chk_failed)
-    .cfi_def_cfa_offset 8
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset lr, 4
-
+.L_strcpy_chk_failed:
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -173,7 +166,7 @@
     .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
 error_message:
     .word   error_string-(1b+4)
-END(__strcpy_chk_failed)
+END(__strcpy_chk)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index 9ff46a8..5d27b57 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -45,7 +45,7 @@
 
 ENTRY(__memcpy_chk)
         cmp         r2, r3
-        bhi         __memcpy_chk_fail
+        bhi         .L_memcpy_chk_fail
 
         // Fall through to memcpy...
 END(__memcpy_chk)
@@ -53,19 +53,20 @@
 ENTRY(memcpy)
         pld     [r1, #64]
         stmfd   sp!, {r0, lr}
-        .cfi_def_cfa_offset 8
+        .cfi_adjust_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
-END(memcpy)
 
-#define MEMCPY_BASE         __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
 #include "memcpy_base.S"
 
-ENTRY_PRIVATE(__memcpy_chk_fail)
+        // Undo the cfi directives from above.
+        .cfi_adjust_cfa_offset -8
+        .cfi_restore r0
+        .cfi_restore lr
+.L_memcpy_chk_fail:
         // Preserve lr for backtrace.
         push    {lr}
-        .cfi_def_cfa_offset 4
+        .cfi_adjust_cfa_offset 4
         .cfi_rel_offset lr, 0
 
         ldr     r0, error_message
@@ -77,7 +78,7 @@
         .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
 error_message:
         .word   error_string-(1b+4)
-END(__memcpy_chk_fail)
+END(memcpy)
 
         .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S
index 035dcf1..76c5a84 100644
--- a/libc/arch-arm/krait/bionic/memcpy_base.S
+++ b/libc/arch-arm/krait/bionic/memcpy_base.S
@@ -1,123 +1,191 @@
-/*
- * Copyright (C) 2013 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-2013 The Linux Foundation. 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 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 code assumes it is running on a processor that supports all arm v7
- * instructions, that supports neon instructions, and that has a 32 byte
- * cache line.
- */
+ 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 HOLDER 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.
+  ***************************************************************************/
 
-// Assumes neon instructions and a cache line size of 32 bytes.
+/* Assumes neon instructions and a cache line size of 64 bytes. */
 
-ENTRY_PRIVATE(MEMCPY_BASE)
-        .cfi_def_cfa_offset 8
-        .cfi_rel_offset r0, 0
-        .cfi_rel_offset lr, 4
+#include <machine/cpu-features.h>
+#include <machine/asm.h>
 
-        /* do we have at least 16-bytes to copy (needed for alignment below) */
-        cmp         r2, #16
-        blo         5f
+#define PLDOFFS	(10)
+#define PLDTHRESH (PLDOFFS)
+#define BBTHRESH (4096/64)
+#define PLDSIZE (64)
 
-        /* align destination to cache-line for the write-buffer */
-        rsb         r3, r0, #0
-        ands        r3, r3, #0xF
-        beq         2f
+#if (PLDOFFS < 1)
+#error Routine does not support offsets less than 1
+#endif
 
-        /* copy up to 15-bytes (count in r3) */
-        sub         r2, r2, r3
-        movs        ip, r3, lsl #31
-        itt         mi
-        ldrbmi      lr, [r1], #1
-        strbmi      lr, [r0], #1
-        itttt       cs
-        ldrbcs      ip, [r1], #1
-        ldrbcs      lr, [r1], #1
-        strbcs      ip, [r0], #1
-        strbcs      lr, [r0], #1
-        movs        ip, r3, lsl #29
-        bge         1f
-        // copies 4 bytes, destination 32-bits aligned
-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
-1:      bcc         2f
-        // copies 8 bytes, destination 64-bits aligned
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0, :64]!
+#if (PLDTHRESH < PLDOFFS)
+#error PLD threshold must be greater than or equal to the PLD offset
+#endif
 
-2:      /* make sure we have at least 64 bytes to copy */
-        subs        r2, r2, #64
-        blo         2f
+	.text
+	.fpu    neon
 
-1:      /* The main loop copies 64 bytes at a time */
-        vld1.8      {d0  - d3},   [r1]!
-        vld1.8      {d4  - d7},   [r1]!
-        pld         [r1, #(32*8)]
-        subs        r2, r2, #64
-        vst1.8      {d0  - d3},   [r0, :128]!
-        vst1.8      {d4  - d7},   [r0, :128]!
-        bhs         1b
+.L_memcpy_base:
+	cmp	r2, #4
+	blt	.L_neon_lt4
+	cmp	r2, #16
+	blt	.L_neon_lt16
+	cmp	r2, #32
+	blt	.L_neon_16
+	cmp	r2, #64
+	blt	.L_neon_copy_32_a
 
-2:      /* fix-up the remaining count and make sure we have >= 32 bytes left */
-        adds        r2, r2, #32
-        blo         4f
+	mov	r12, r2, lsr #6
+	cmp	r12, #PLDTHRESH
+	ble	.L_neon_copy_64_loop_nopld
 
-        /* Copy 32 bytes. These cache lines were already preloaded */
-        vld1.8      {d0 - d3},  [r1]!
-        sub         r2, r2, #32
-        vst1.8      {d0 - d3},  [r0, :128]!
+	push	{r9, r10}
+	.cfi_adjust_cfa_offset 8
+	.cfi_rel_offset r9, 0
+	.cfi_rel_offset r10, 4
 
-4:      /* less than 32 left */
-        add         r2, r2, #32
-        tst         r2, #0x10
-        beq         5f
-        // copies 16 bytes, 128-bits aligned
-        vld1.8      {d0, d1}, [r1]!
-        vst1.8      {d0, d1}, [r0, :128]!
+	cmp	r12, #BBTHRESH
+	ble	.L_neon_prime_pump
 
-5:      /* copy up to 15-bytes (count in r2) */
-        movs        ip, r2, lsl #29
-        bcc         1f
-        vld1.8      {d0}, [r1]!
-        vst1.8      {d0}, [r0]!
-1:      bge         2f
-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0]!
-2:      movs        ip, r2, lsl #31
-        itt         mi
-        ldrbmi      r3, [r1], #1
-        strbmi      r3, [r0], #1
-        itttt       cs
-        ldrbcs      ip, [r1], #1
-        ldrbcs      lr, [r1], #1
-        strbcs      ip, [r0], #1
-        strbcs      lr, [r0], #1
+	add	lr, r0, #0x400
+	add	r9, r1, #(PLDOFFS*PLDSIZE)
+	sub	lr, lr, r9
+	lsl	lr, lr, #21
+	lsr	lr, lr, #21
+	add	lr, lr, #(PLDOFFS*PLDSIZE)
+	cmp	r12, lr, lsr #6
+	ble	.L_neon_prime_pump
 
-        ldmfd       sp!, {r0, lr}
-        bx          lr
-END(MEMCPY_BASE)
+	itt	gt
+	movgt	r9, #(PLDOFFS)
+	rsbsgt	r9, r9, lr, lsr #6
+	ble	.L_neon_prime_pump
+
+	add	r10, r1, lr
+	bic	r10, #0x3F
+
+	sub	r12, r12, lr, lsr #6
+
+	cmp	r9, r12
+	itee	le
+	suble	r12, r12, r9
+	movgt	r9, r12
+	movgt	r12, #0
+
+	pld	[r1, #((PLDOFFS-1)*PLDSIZE)]
+.L_neon_copy_64_loop_outer_doublepld:
+	pld	[r1, #((PLDOFFS)*PLDSIZE)]
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	ldr	r3, [r10]
+	subs	r9, r9, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_outer_doublepld
+	cmp	r12, #0
+	beq	.L_neon_pop_before_nopld
+
+	cmp	r12, #(512*1024/64)
+	blt	.L_neon_copy_64_loop_outer
+
+.L_neon_copy_64_loop_ddr:
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	pld	[r10]
+	subs	r12, r12, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_ddr
+	b	.L_neon_pop_before_nopld
+
+.L_neon_prime_pump:
+	mov	lr, #(PLDOFFS*PLDSIZE)
+	add	r10, r1, #(PLDOFFS*PLDSIZE)
+	bic	r10, #0x3F
+	sub	r12, r12, #PLDOFFS
+	ldr	r3, [r10, #(-1*PLDSIZE)]
+
+.L_neon_copy_64_loop_outer:
+	vld1.32	{q0, q1}, [r1]!
+	vld1.32	{q2, q3}, [r1]!
+	ldr	r3, [r10]
+	subs	r12, r12, #1
+	vst1.32	{q0, q1}, [r0]!
+	vst1.32	{q2, q3}, [r0]!
+	add	r10, #64
+	bne	.L_neon_copy_64_loop_outer
+
+.L_neon_pop_before_nopld:
+	mov	r12, lr, lsr #6
+	pop	{r9, r10}
+	.cfi_adjust_cfa_offset -8
+	.cfi_restore r9
+	.cfi_restore r10
+
+.L_neon_copy_64_loop_nopld:
+	vld1.32	{q8, q9}, [r1]!
+	vld1.32	{q10, q11}, [r1]!
+	subs	r12, r12, #1
+	vst1.32	{q8, q9}, [r0]!
+	vst1.32	{q10, q11}, [r0]!
+	bne	.L_neon_copy_64_loop_nopld
+	ands	r2, r2, #0x3f
+	beq	.L_neon_exit
+
+.L_neon_copy_32_a:
+	movs	r3, r2, lsl #27
+	bcc	.L_neon_16
+	vld1.32	{q0,q1}, [r1]!
+	vst1.32	{q0,q1}, [r0]!
+
+.L_neon_16:
+	bpl	.L_neon_lt16
+	vld1.32	{q8}, [r1]!
+	vst1.32	{q8}, [r0]!
+	ands	r2, r2, #0x0f
+	beq	.L_neon_exit
+
+.L_neon_lt16:
+	movs	r3, r2, lsl #29
+	bcc	1f
+	vld1.8	{d0}, [r1]!
+	vst1.8	{d0}, [r0]!
+1:
+	bge	.L_neon_lt4
+	vld4.8	{d0[0], d1[0], d2[0], d3[0]}, [r1]!
+	vst4.8	{d0[0], d1[0], d2[0], d3[0]}, [r0]!
+
+.L_neon_lt4:
+	movs	r2, r2, lsl #31
+	itt	cs
+	ldrhcs	r3, [r1], #2
+	strhcs	r3, [r0], #2
+	itt	mi
+	ldrbmi	r3, [r1]
+	strbmi	r3, [r0]
+
+.L_neon_exit:
+	pop	{r0, pc}
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index a4fbe17..ae05965 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -69,10 +69,7 @@
 
 /* memset() returns its first argument.  */
 ENTRY(memset)
-        stmfd       sp!, {r0}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset r0, 0
-
+        mov         r3, r0
         vdup.8      q0, r1
 
         /* make sure we have at least 32 bytes to write */
@@ -82,7 +79,7 @@
 
 1:      /* The main loop writes 32 bytes at a time */
         subs        r2, r2, #32
-        vst1.8      {d0 - d3}, [r0]!
+        vst1.8      {d0 - d3}, [r3]!
         bhs         1b
 
 2:      /* less than 32 left */
@@ -91,18 +88,17 @@
         beq         3f
 
         // writes 16 bytes, 128-bits aligned
-        vst1.8      {d0, d1}, [r0]!
+        vst1.8      {d0, d1}, [r3]!
 3:      /* write up to 15-bytes (count in r2) */
         movs        ip, r2, lsl #29
         bcc         1f
-        vst1.8      {d0}, [r0]!
+        vst1.8      {d0}, [r3]!
 1:      bge         2f
-        vst1.32     {d0[0]}, [r0]!
+        vst1.32     {d0[0]}, [r3]!
 2:      movs        ip, r2, lsl #31
-        strbmi      r1, [r0], #1
-        strbcs      r1, [r0], #1
-        strbcs      r1, [r0], #1
-        ldmfd       sp!, {r0}
+        strbmi      r1, [r3], #1
+        strbcs      r1, [r3], #1
+        strbcs      r1, [r3], #1
         bx          lr
 END(memset)
 
diff --git a/libc/arch-arm/krait/krait.mk b/libc/arch-arm/krait/krait.mk
index 88b4d66..f8e3452 100644
--- a/libc/arch-arm/krait/krait.mk
+++ b/libc/arch-arm/krait/krait.mk
@@ -1,3 +1,18 @@
+libc_openbsd_src_files_exclude_arm += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+
+libc_bionic_src_files_exclude_arm += \
+    arch-arm/generic/bionic/memcpy.S \
+    arch-arm/generic/bionic/memset.S \
+    arch-arm/generic/bionic/strcmp.S \
+    arch-arm/generic/bionic/strcpy.S \
+    arch-arm/generic/bionic/strlen.c \
+    bionic/__strcat_chk.cpp \
+    bionic/__strcpy_chk.cpp \
+
 libc_bionic_src_files_arm += \
     arch-arm/krait/bionic/memcpy.S \
     arch-arm/krait/bionic/memset.S \
@@ -13,7 +28,4 @@
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
-    arch-arm/generic/bionic/memcmp.S \
-
-libc_bionic_src_files_arm += \
     arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/syscalls/flistxattr.S b/libc/arch-arm/syscalls/___flistxattr.S
similarity index 81%
rename from libc/arch-arm/syscalls/flistxattr.S
rename to libc/arch-arm/syscalls/___flistxattr.S
index ee09295..8ae8b7e 100644
--- a/libc/arch-arm/syscalls/flistxattr.S
+++ b/libc/arch-arm/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     mov     ip, r7
     ldr     r7, =__NR_flistxattr
     swi     #0
@@ -11,4 +11,5 @@
     bxls    lr
     neg     r0, r0
     b       __set_errno_internal
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-arm/syscalls/___mremap.S b/libc/arch-arm/syscalls/___mremap.S
new file mode 100644
index 0000000..ade8d78
--- /dev/null
+++ b/libc/arch-arm/syscalls/___mremap.S
@@ -0,0 +1,23 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(___mremap)
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_mremap
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-arm/syscalls/__preadv64.S b/libc/arch-arm/syscalls/__preadv64.S
new file mode 100644
index 0000000..19eaaa5
--- /dev/null
+++ b/libc/arch-arm/syscalls/__preadv64.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__preadv64)
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_preadv
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(__preadv64)
diff --git a/libc/arch-arm/syscalls/__pwritev64.S b/libc/arch-arm/syscalls/__pwritev64.S
new file mode 100644
index 0000000..afcbe40
--- /dev/null
+++ b/libc/arch-arm/syscalls/__pwritev64.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__pwritev64)
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_pwritev
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(__pwritev64)
diff --git a/libc/arch-arm/syscalls/mremap.S b/libc/arch-arm/syscalls/mremap.S
deleted file mode 100644
index 505ea3c..0000000
--- a/libc/arch-arm/syscalls/mremap.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(mremap)
-    mov     ip, r7
-    ldr     r7, =__NR_mremap
-    swi     #0
-    mov     r7, ip
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno_internal
-END(mremap)
diff --git a/libc/arch-arm/syscalls/vfork.S b/libc/arch-arm/syscalls/vfork.S
deleted file mode 100644
index 5f4cb3d..0000000
--- a/libc/arch-arm/syscalls/vfork.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(vfork)
-    mov     ip, r7
-    ldr     r7, =__NR_vfork
-    swi     #0
-    mov     r7, ip
-    cmn     r0, #(MAX_ERRNO + 1)
-    bxls    lr
-    neg     r0, r0
-    b       __set_errno_internal
-END(vfork)
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index 470a038..9a76072 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -1,32 +1,38 @@
 # 64-bit arm.
 
 #
-# Default implementations of functions that are commonly optimized.
+# Generic arm64 optimizations, may be overriden by CPU variants.
 #
 
 libc_bionic_src_files_arm64 += \
-    bionic/__memset_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-    bionic/__strcat_chk.cpp \
-    bionic/strrchr.cpp \
+    arch-arm64/generic/bionic/memchr.S \
+    arch-arm64/generic/bionic/memcmp.S \
+    arch-arm64/generic/bionic/memcpy.S \
+    arch-arm64/generic/bionic/memmove.S \
+    arch-arm64/generic/bionic/memset.S \
+    arch-arm64/generic/bionic/stpcpy.S \
+    arch-arm64/generic/bionic/strchr.S \
+    arch-arm64/generic/bionic/strcmp.S \
+    arch-arm64/generic/bionic/strcpy.S \
+    arch-arm64/generic/bionic/strlen.S \
+    arch-arm64/generic/bionic/strncmp.S \
+    arch-arm64/generic/bionic/strnlen.S \
+    arch-arm64/generic/bionic/wmemmove.S \
 
-libc_freebsd_src_files_arm64 += \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-freebsd/lib/libc/string/wcschr.c \
-    upstream-freebsd/lib/libc/string/wcscmp.c \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcslen.c \
-    upstream-freebsd/lib/libc/string/wcsrchr.c \
-    upstream-freebsd/lib/libc/string/wmemcmp.c \
+libc_bionic_src_files_exclude_arm64 += \
+    bionic/__memcpy_chk.cpp \
+    bionic/strchr.cpp \
+    bionic/strnlen.c \
 
-libc_openbsd_src_files_arm64 += \
-    upstream-openbsd/lib/libc/string/memrchr.c \
-    upstream-openbsd/lib/libc/string/stpncpy.c \
-    upstream-openbsd/lib/libc/string/strcat.c \
-    upstream-openbsd/lib/libc/string/strlcat.c \
-    upstream-openbsd/lib/libc/string/strlcpy.c \
-    upstream-openbsd/lib/libc/string/strncat.c \
-    upstream-openbsd/lib/libc/string/strncpy.c \
+libc_freebsd_src_files_exclude_arm64 += \
+    upstream-freebsd/lib/libc/string/wmemmove.c \
+
+libc_openbsd_src_files_exclude_arm64 += \
+    upstream-openbsd/lib/libc/string/memchr.c \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/strcpy.c \
+    upstream-openbsd/lib/libc/string/strncmp.c \
 
 #
 # Inherently architecture-specific code.
@@ -36,7 +42,6 @@
     arch-arm64/bionic/__bionic_clone.S \
     arch-arm64/bionic/_exit_with_stack_teardown.S \
     arch-arm64/bionic/setjmp.S \
-    arch-arm64/bionic/__set_tls.c \
     arch-arm64/bionic/syscall.S \
     arch-arm64/bionic/vfork.S \
 
@@ -54,6 +59,7 @@
 ifeq ($(strip $(TARGET_CPU_VARIANT)),)
   $(warning TARGET_ARCH is arm64, but TARGET_CPU_VARIANT is not defined)
 endif
+ifneq ($(TARGET_CPU_VARIANT),generic)
 cpu_variant_mk := $(LOCAL_PATH)/arch-arm64/$(TARGET_CPU_VARIANT)/$(TARGET_CPU_VARIANT).mk
 ifeq ($(wildcard $(cpu_variant_mk)),)
 $(error "TARGET_CPU_VARIANT not set or set to an unknown value. Possible values are generic, denver64. Use generic for devices that do not have a CPU similar to any of the supported cpu variants.")
@@ -62,3 +68,4 @@
 libc_common_additional_dependencies += $(cpu_variant_mk)
 
 cpu_variant_mk :=
+endif
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index ba0a226..c06a671 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -52,6 +52,29 @@
 #define _JB_D10_D11     (_JB_D12_D13 + 2)
 #define _JB_D8_D9       (_JB_D10_D11 + 2)
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg, sp_reg
+#if MANGLE_REGISTERS
+  eor x19, x19, \reg
+  eor x20, x20, \reg
+  eor x21, x21, \reg
+  eor x22, x22, \reg
+  eor x23, x23, \reg
+  eor x24, x24, \reg
+  eor x25, x25, \reg
+  eor x26, x26, \reg
+  eor x27, x27, \reg
+  eor x28, x28, \reg
+  eor x29, x29, \reg
+  eor x30, x30, \reg
+  eor \sp_reg, \sp_reg, \reg
+#endif
+.endm
+
+.macro m_unmangle_registers reg, sp_reg
+  m_mangle_registers \reg, sp_reg=\sp_reg
+.endm
+
 ENTRY(setjmp)
   mov w1, #1
   b sigsetjmp
@@ -64,23 +87,47 @@
 
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
-  str w1, [x0, #(_JB_SIGFLAG * 8)]
+  stp x0, x30, [sp, #-16]!
+  .cfi_def_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x30, 8
+
+  // Get the cookie and store it along with the signal flag.
+  mov x0, x1
+  bl __bionic_setjmp_cookie_get
+  mov x1, x0
+  ldr x0, [sp, #0]
+  str x1, [x0, #(_JB_SIGFLAG * 8)]
 
   // Do we need to save the signal mask?
-  cbz w1, 1f
+  tbz w1, #0, 1f
+
+  // Save the cookie for later.
+  stp x1, xzr, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
 
   // Save current signal mask.
-  stp x0, x30, [sp, #-16]!
   // The 'how' argument is ignored if new_mask is NULL.
   mov x1, #0 // NULL.
   add x2, x0, #(_JB_SIGMASK * 8) // old_mask.
   bl sigprocmask
-  ldp x0, x30, [sp], #16
+
+  ldp x1, xzr, [sp], #16
+  .cfi_adjust_cfa_offset -16
 
 1:
+  // Restore original x0 and lr.
+  ldp x0, x30, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x30
+
+  // Mask off the signal flag bit.
+  bic x1, x1, #1
+
   // Save core registers.
   mov x10, sp
+  m_mangle_registers x1, sp_reg=x10
   stp x30, x10, [x0, #(_JB_X30_SP  * 8)]
   stp x28, x29, [x0, #(_JB_X28_X29 * 8)]
   stp x26, x27, [x0, #(_JB_X26_X27 * 8)]
@@ -88,6 +135,7 @@
   stp x22, x23, [x0, #(_JB_X22_X23 * 8)]
   stp x20, x21, [x0, #(_JB_X20_X21 * 8)]
   str x19,      [x0, #(_JB_X19     * 8)]
+  m_unmangle_registers x1, sp_reg=x10
 
   // Save floating point registers.
   stp d14, d15, [x0, #(_JB_D14_D15 * 8)]
@@ -102,30 +150,60 @@
 // void siglongjmp(sigjmp_buf env, int value);
 ENTRY(siglongjmp)
   // Do we need to restore the signal mask?
-  ldr w9, [x0, #(_JB_SIGFLAG * 8)]
-  cbz w9, 1f
+  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
+  tbz w2, #0, 1f
+
+  stp x0, x30, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x30, 8
 
   // Restore signal mask.
-  stp x0, x30, [sp, #-16]!
   mov x19, x1 // Save 'value'.
+
   mov x2, x0
   mov x0, #2 // SIG_SETMASK
   add x1, x2, #(_JB_SIGMASK * 8) // new_mask.
   mov x2, #0 // NULL.
   bl sigprocmask
   mov x1, x19 // Restore 'value'.
-  ldp x0, x30, [sp], #16
 
+  // Restore original x0 and lr.
+  ldp x0, x30, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x30
+
+  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
 1:
   // Restore core registers.
+  bic x2, x2, #1
   ldp x30, x10, [x0, #(_JB_X30_SP  * 8)]
-  mov sp, x10
   ldp x28, x29, [x0, #(_JB_X28_X29 * 8)]
   ldp x26, x27, [x0, #(_JB_X26_X27 * 8)]
   ldp x24, x25, [x0, #(_JB_X24_X25 * 8)]
   ldp x22, x23, [x0, #(_JB_X22_X23 * 8)]
   ldp x20, x21, [x0, #(_JB_X20_X21 * 8)]
   ldr x19,      [x0, #(_JB_X19     * 8)]
+  m_unmangle_registers x2, sp_reg=x10
+  mov sp, x10
+
+  stp x0, x1, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x1, 8
+  stp x30, xzr, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x30, 0
+  ldr x0, [x0, #(_JB_SIGFLAG * 8)]
+  bl __bionic_setjmp_cookie_check
+  ldp x30, xzr, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x30
+  ldp x0, x1, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x1
 
   // Restore floating point registers.
   ldp d14, d15, [x0, #(_JB_D14_D15 * 8)]
@@ -133,13 +211,6 @@
   ldp d10, d11, [x0, #(_JB_D10_D11 * 8)]
   ldp d8,  d9,  [x0, #(_JB_D8_D9   * 8)]
 
-  // Validate sp (sp mod 16 = 0) and lr (lr mod 4 = 0).
-  tst x30, #3
-  b.ne longjmperror
-  mov x10, sp
-  tst x10, #15
-  b.ne longjmperror
-
   // Set return value.
   cmp w1, wzr
   csinc w0, w1, wzr, ne
diff --git a/libc/arch-arm64/bionic/vfork.S b/libc/arch-arm64/bionic/vfork.S
index b6a672d..92fa333 100644
--- a/libc/arch-arm64/bionic/vfork.S
+++ b/libc/arch-arm64/bionic/vfork.S
@@ -31,6 +31,11 @@
 #include <linux/sched.h>
 
 ENTRY(vfork)
+    // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+    mrs     x0, tpidr_el0
+    ldr     x0, [x0, #8]
+    str     wzr, [x0, #20]
+
     mov     x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD)
     mov     x1, xzr
     mov     x2, xzr
diff --git a/libc/arch-arm64/cortex-a53/cortex-a53.mk b/libc/arch-arm64/cortex-a53/cortex-a53.mk
index 676e886..e69de29 100644
--- a/libc/arch-arm64/cortex-a53/cortex-a53.mk
+++ b/libc/arch-arm64/cortex-a53/cortex-a53.mk
@@ -1 +0,0 @@
-include bionic/libc/arch-arm64/generic/generic.mk
diff --git a/libc/arch-arm64/denver64/denver64.mk b/libc/arch-arm64/denver64/denver64.mk
index d619c11..703af45 100644
--- a/libc/arch-arm64/denver64/denver64.mk
+++ b/libc/arch-arm64/denver64/denver64.mk
@@ -1,14 +1,7 @@
 libc_bionic_src_files_arm64 += \
-    arch-arm64/generic/bionic/memchr.S \
-    arch-arm64/generic/bionic/memcmp.S \
     arch-arm64/denver64/bionic/memcpy.S \
-    arch-arm64/generic/bionic/memmove.S \
     arch-arm64/denver64/bionic/memset.S \
-    arch-arm64/generic/bionic/stpcpy.S \
-    arch-arm64/generic/bionic/strchr.S \
-    arch-arm64/generic/bionic/strcmp.S \
-    arch-arm64/generic/bionic/strcpy.S \
-    arch-arm64/generic/bionic/strlen.S \
-    arch-arm64/generic/bionic/strncmp.S \
-    arch-arm64/generic/bionic/strnlen.S \
-    arch-arm64/generic/bionic/wmemmove.S
+
+libc_bionic_src_files_exclude_arm64 += \
+    arch-arm64/generic/bionic/memcpy.S \
+    arch-arm64/generic/bionic/memset.S \
diff --git a/libc/arch-arm64/generic/bionic/memmove.S b/libc/arch-arm64/generic/bionic/memmove.S
index 8b366a3..739ce49 100644
--- a/libc/arch-arm64/generic/bionic/memmove.S
+++ b/libc/arch-arm64/generic/bionic/memmove.S
@@ -35,10 +35,6 @@
 #include <private/bionic_asm.h>
 
 /* Parameters and result.  */
-#ifdef BCOPY
-#define origdstin	x1
-#define origsrc	x0
-#endif
 #define dstin	x0
 #define src	x1
 #define count	x2
@@ -59,13 +55,7 @@
 #define D_l	x13
 #define D_h	x14
 
-#ifdef BCOPY
-ENTRY(bcopy)
-	/* Swap src and dst so that a branch to memcpy doesn't cause issues. */
-	mov	tmp1, origsrc
-	mov	origsrc, origdstin
-	mov	origdstin, tmp1
-#elif defined(WMEMMOVE)
+#if defined(WMEMMOVE)
 ENTRY(wmemmove)
 	lsl	count, count, #2
 #else
@@ -332,9 +322,7 @@
 	tst	count, #0x3f
 	b.ne	.Ltail63down
 	ret
-#ifdef BCOPY
-END(bcopy)
-#elif defined(WMEMMOVE)
+#if defined(WMEMMOVE)
 END(wmemmove)
 #else
 END(memmove)
diff --git a/libc/arch-arm64/generic/generic.mk b/libc/arch-arm64/generic/generic.mk
deleted file mode 100644
index 1b595aa..0000000
--- a/libc/arch-arm64/generic/generic.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-libc_bionic_src_files_arm64 += \
-    arch-arm64/generic/bionic/memchr.S \
-    arch-arm64/generic/bionic/memcmp.S \
-    arch-arm64/generic/bionic/memcpy.S \
-    arch-arm64/generic/bionic/memmove.S \
-    arch-arm64/generic/bionic/memset.S \
-    arch-arm64/generic/bionic/stpcpy.S \
-    arch-arm64/generic/bionic/strchr.S \
-    arch-arm64/generic/bionic/strcmp.S \
-    arch-arm64/generic/bionic/strcpy.S \
-    arch-arm64/generic/bionic/strlen.S \
-    arch-arm64/generic/bionic/strncmp.S \
-    arch-arm64/generic/bionic/strnlen.S \
-    arch-arm64/generic/bionic/wmemmove.S
diff --git a/libc/arch-arm64/syscalls/flistxattr.S b/libc/arch-arm64/syscalls/___flistxattr.S
similarity index 78%
rename from libc/arch-arm64/syscalls/flistxattr.S
rename to libc/arch-arm64/syscalls/___flistxattr.S
index 8921bb4..02c8478 100644
--- a/libc/arch-arm64/syscalls/flistxattr.S
+++ b/libc/arch-arm64/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     mov     x8, __NR_flistxattr
     svc     #0
 
@@ -11,4 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-arm64/syscalls/mremap.S b/libc/arch-arm64/syscalls/___mremap.S
similarity index 81%
rename from libc/arch-arm64/syscalls/mremap.S
rename to libc/arch-arm64/syscalls/___mremap.S
index 69b91d6..aeb93bc 100644
--- a/libc/arch-arm64/syscalls/mremap.S
+++ b/libc/arch-arm64/syscalls/___mremap.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(___mremap)
     mov     x8, __NR_mremap
     svc     #0
 
@@ -11,4 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(mremap)
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-arm64/syscalls/mremap.S b/libc/arch-arm64/syscalls/preadv.S
similarity index 69%
copy from libc/arch-arm64/syscalls/mremap.S
copy to libc/arch-arm64/syscalls/preadv.S
index 69b91d6..cb8300d 100644
--- a/libc/arch-arm64/syscalls/mremap.S
+++ b/libc/arch-arm64/syscalls/preadv.S
@@ -2,8 +2,8 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
-    mov     x8, __NR_mremap
+ENTRY(preadv)
+    mov     x8, __NR_preadv
     svc     #0
 
     cmn     x0, #(MAX_ERRNO + 1)
@@ -11,4 +11,6 @@
     b.hi    __set_errno_internal
 
     ret
-END(mremap)
+END(preadv)
+
+ALIAS_SYMBOL(preadv64, preadv)
diff --git a/libc/arch-arm64/syscalls/mremap.S b/libc/arch-arm64/syscalls/pwritev.S
similarity index 68%
copy from libc/arch-arm64/syscalls/mremap.S
copy to libc/arch-arm64/syscalls/pwritev.S
index 69b91d6..621466a 100644
--- a/libc/arch-arm64/syscalls/mremap.S
+++ b/libc/arch-arm64/syscalls/pwritev.S
@@ -2,8 +2,8 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
-    mov     x8, __NR_mremap
+ENTRY(pwritev)
+    mov     x8, __NR_pwritev
     svc     #0
 
     cmn     x0, #(MAX_ERRNO + 1)
@@ -11,4 +11,6 @@
     b.hi    __set_errno_internal
 
     ret
-END(mremap)
+END(pwritev)
+
+ALIAS_SYMBOL(pwritev64, pwritev)
diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S
index 3ef0f11..73002e8 100644
--- a/libc/arch-mips/bionic/setjmp.S
+++ b/libc/arch-mips/bionic/setjmp.S
@@ -132,10 +132,9 @@
 /*     	field:		byte offset:	size:						*/
 /*     	dynam filler	(0*4)		   0-4 bytes of rounddown filler, DON'T TOUCH!!
 						often overlays user storage!!		*/
-#define	SC_MAGIC_OFFSET	(1*4)		/* 4 bytes, identify jmpbuf, first actual field */
-#define	SC_FLAG_OFFSET	(2*4)		/* 4 bytes, savesigs flag */
-#define	SC_FPSR_OFFSET	(3*4)		/* 4 bytes, floating point control/status reg */
+#define	SC_FPSR_OFFSET	(1*4)		/* 4 bytes, floating point control/status reg */
 /* following fields are 8-byte aligned */
+#define	SC_FLAG_OFFSET	(2*4)		/* 8 bytes, cookie and savesigs flag, first actual field  */
 #define	SC_MASK_OFFSET	(4*4)		/* 16 bytes, mips32/mips64 version of sigset_t */
 #define	SC_SPARE_OFFSET	(8*4)		/* 8 bytes, reserved for future uses */
 
@@ -166,6 +165,16 @@
 #error _JBLEN is too small
 #endif
 
+.macro m_mangle_reg_and_store reg, cookie, temp, offset
+	xor	\temp, \reg, \cookie
+	REG_S	\temp, \offset
+.endm
+
+.macro m_unmangle_reg_and_load reg, cookie, temp, offset
+	REG_L	\temp, \offset
+	xor	\reg, \temp, \cookie
+.endm
+
 /*
  *
  *  GPOFF and FRAMESIZE must be the same for all setjmp/longjmp routines
@@ -190,36 +199,46 @@
 	li	t0, ~7
 	and	a0, t0				# round jmpbuf addr DOWN to 8-byte boundary
 #endif
-	sw	a1, SC_FLAG_OFFSET(a0)		# save savesigs flag
-	beqz	a1, 1f				# do saving of signal mask?
-
 	REG_S	ra, RAOFF(sp)			# spill state
 	REG_S	a0, A0OFF(sp)
+
+	# get the cookie and store it along with the signal flag.
+	move	a0, a1
+	jal	__bionic_setjmp_cookie_get
+	REG_L	a0, A0OFF(sp)
+
+	REG_S	v0, SC_FLAG_OFFSET(a0)		# save cookie and savesigs flag
+	andi	t0, v0, 1			# extract savesigs flag
+
+	beqz	t0, 1f				# do saving of signal mask?
+
 	# call sigprocmask(int how ignored, sigset_t* null, sigset_t* SC_MASK(a0)):
 	LA	a2, SC_MASK_OFFSET(a0)		# gets current signal mask
 	li	a0, 0				# how; ignored when new mask is null
 	li	a1, 0				# null new mask
 	jal	sigprocmask			# get current signal mask
 	REG_L	a0, A0OFF(sp)
-	REG_L	ra, RAOFF(sp)
 1:
-	li	v0, 0xACEDBADE			# sigcontext magic number
-	sw	v0, SC_MAGIC_OFFSET(a0)
+	REG_L	gp, GPOFF(sp)			# restore spills
+	REG_L	ra, RAOFF(sp)
+	REG_L	t0, SC_FLAG_OFFSET(a0)		# move cookie to temp reg
+
 	# callee-saved long-sized regs:
-	REG_S	ra, SC_REGS+0*REGSZ(a0)
-	REG_S	s0, SC_REGS+1*REGSZ(a0)
-	REG_S	s1, SC_REGS+2*REGSZ(a0)
-	REG_S	s2, SC_REGS+3*REGSZ(a0)
-	REG_S	s3, SC_REGS+4*REGSZ(a0)
-	REG_S	s4, SC_REGS+5*REGSZ(a0)
-	REG_S	s5, SC_REGS+6*REGSZ(a0)
-	REG_S	s6, SC_REGS+7*REGSZ(a0)
-	REG_S	s7, SC_REGS+8*REGSZ(a0)
-	REG_S	s8, SC_REGS+9*REGSZ(a0)
-	REG_L	v0, GPOFF(sp)
-	REG_S	v0, SC_REGS+10*REGSZ(a0)	# save gp
-	PTR_ADDU v0, sp, FRAMESZ
-	REG_S	v0, SC_REGS+11*REGSZ(a0)	# save orig sp
+	PTR_ADDU v1, sp, FRAMESZ		# save orig sp
+
+	# m_mangle_reg_and_store reg, cookie, temp, offset
+	m_mangle_reg_and_store	ra, t0, t1, SC_REGS+0*REGSZ(a0)
+	m_mangle_reg_and_store	s0, t0, t2, SC_REGS+1*REGSZ(a0)
+	m_mangle_reg_and_store	s1, t0, t3, SC_REGS+2*REGSZ(a0)
+	m_mangle_reg_and_store	s2, t0, t1, SC_REGS+3*REGSZ(a0)
+	m_mangle_reg_and_store	s3, t0, t2, SC_REGS+4*REGSZ(a0)
+	m_mangle_reg_and_store	s4, t0, t3, SC_REGS+5*REGSZ(a0)
+	m_mangle_reg_and_store	s5, t0, t1, SC_REGS+6*REGSZ(a0)
+	m_mangle_reg_and_store	s6, t0, t2, SC_REGS+7*REGSZ(a0)
+	m_mangle_reg_and_store	s7, t0, t3, SC_REGS+8*REGSZ(a0)
+	m_mangle_reg_and_store	s8, t0, t1, SC_REGS+9*REGSZ(a0)
+	m_mangle_reg_and_store	gp, t0, t2, SC_REGS+10*REGSZ(a0)
+	m_mangle_reg_and_store	v1, t0, t3, SC_REGS+11*REGSZ(a0)
 
 	cfc1	v0, $31
 
@@ -288,36 +307,41 @@
 	li	t0, ~7
 	and	a0, t0				# round jmpbuf addr DOWN to 8-byte boundary
 #endif
-	lw	v0, SC_MAGIC_OFFSET(a0)
-	li	t0, 0xACEDBADE
-	bne	v0, t0, longjmp_botch		# jump if error
 
-	lw	t0, SC_FLAG_OFFSET(a0)		# get savesigs flag
+	move	s1, a1				# temp spill
+	move	s0, a0
+
+	# extract savesigs flag
+	REG_L	s2, SC_FLAG_OFFSET(s0)
+	andi	t0, s2, 1
 	beqz	t0, 1f				# restore signal mask?
 
-	REG_S	a1, A1OFF(sp)			# temp spill
-	REG_S	a0, A0OFF(sp)
-        # call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null):
-	LA	a1, SC_MASK_OFFSET(a0)		# signals being restored
+	# call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null):
+	LA	a1, SC_MASK_OFFSET(s0)		# signals being restored
 	li	a0, 3				# mips SIG_SETMASK
 	li	a2, 0				# null
 	jal	sigprocmask			# restore signal mask
-	REG_L	a0, A0OFF(sp)
-	REG_L	a1, A1OFF(sp)
 1:
+	move	t0, s2				# get cookie to temp reg
+	move	a1, s1
+	move	a0, s0
+
 	# callee-saved long-sized regs:
-	REG_L	ra, SC_REGS+0*REGSZ(a0)
-	REG_L	s0, SC_REGS+1*REGSZ(a0)
-	REG_L	s1, SC_REGS+2*REGSZ(a0)
-	REG_L	s2, SC_REGS+3*REGSZ(a0)
-	REG_L	s3, SC_REGS+4*REGSZ(a0)
-	REG_L	s4, SC_REGS+5*REGSZ(a0)
-	REG_L	s5, SC_REGS+6*REGSZ(a0)
-	REG_L	s6, SC_REGS+7*REGSZ(a0)
-	REG_L	s7, SC_REGS+8*REGSZ(a0)
-	REG_L	s8, SC_REGS+9*REGSZ(a0)
-	REG_L	gp, SC_REGS+10*REGSZ(a0)
-	REG_L	sp, SC_REGS+11*REGSZ(a0)
+
+	# m_unmangle_reg_and_load reg, cookie, temp, offset
+	# don't restore gp yet, old value is needed for cookie_check call
+	m_unmangle_reg_and_load ra, t0, t1, SC_REGS+0*REGSZ(a0)
+	m_unmangle_reg_and_load s0, t0, t2, SC_REGS+1*REGSZ(a0)
+	m_unmangle_reg_and_load s1, t0, t3, SC_REGS+2*REGSZ(a0)
+	m_unmangle_reg_and_load s2, t0, t1, SC_REGS+3*REGSZ(a0)
+	m_unmangle_reg_and_load s3, t0, t2, SC_REGS+4*REGSZ(a0)
+	m_unmangle_reg_and_load s4, t0, t3, SC_REGS+5*REGSZ(a0)
+	m_unmangle_reg_and_load s5, t0, t1, SC_REGS+6*REGSZ(a0)
+	m_unmangle_reg_and_load s6, t0, t2, SC_REGS+7*REGSZ(a0)
+	m_unmangle_reg_and_load s7, t0, t3, SC_REGS+8*REGSZ(a0)
+	m_unmangle_reg_and_load s8, t0, t1, SC_REGS+9*REGSZ(a0)
+	m_unmangle_reg_and_load v1, t0, t2, SC_REGS+10*REGSZ(a0)
+	m_unmangle_reg_and_load sp, t0, t3, SC_REGS+11*REGSZ(a0)
 
 	lw	v0, SC_FPSR_OFFSET(a0)
 	ctc1	v0, $31			# restore old fr mode before fp values
@@ -341,15 +365,22 @@
 	l.d	$f28, SC_FPREGS+4*REGSZ_FP(a0)
 	l.d	$f30, SC_FPREGS+5*REGSZ_FP(a0)
 #endif
-	bne	a1, zero, 1f
-	li	a1, 1			# never return 0!
-1:
-	move	v0, a1
-	j	ra			# return to setjmp call site
 
-longjmp_botch:
-	jal	longjmperror
-	jal	abort
+	# check cookie
+	PTR_SUBU sp, FRAMESZ
+	REG_S	v1, GPOFF(sp)
+	REG_S	ra, RAOFF(sp)
+	REG_S	a1, A1OFF(sp)
+	move	a0, t0
+	jal	__bionic_setjmp_cookie_check
+	REG_L	gp, GPOFF(sp)
+	REG_L	ra, RAOFF(sp)
+	REG_L	a1, A1OFF(sp)
+	PTR_ADDU sp, FRAMESZ
+
+	sltiu	t0, a1, 1		# never return 0!
+	xor	v0, a1, t0
+	j	ra			# return to setjmp call site
 END(siglongjmp)
 
 ALIAS_SYMBOL(longjmp, siglongjmp)
diff --git a/libc/arch-mips/bionic/vfork.S b/libc/arch-mips/bionic/vfork.S
index 1849624..7ccf70b 100644
--- a/libc/arch-mips/bionic/vfork.S
+++ b/libc/arch-mips/bionic/vfork.S
@@ -37,6 +37,14 @@
 	.set	noreorder
 	.cpload	t9
 
+	// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+	.set	push
+	.set	mips32r2
+	rdhwr	v0, $29			// v0 = tls; kernel trap on mips32r1
+	.set	pop
+	lw	v0, REGSZ*1(v0)		// v0 = v0[TLS_SLOT_THREAD_ID ie 1]
+	sw	$0, REGSZ*2+4(v0)	// v0->cached_pid_ = 0
+
 	li	a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
 	li	a1, 0
 	li	a2, 0
diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk
index 05e7198..b184abb 100644
--- a/libc/arch-mips/mips.mk
+++ b/libc/arch-mips/mips.mk
@@ -1,45 +1,10 @@
 # 32-bit mips.
 
-#
-# Default implementations of functions that are commonly optimized.
-#
-
 libc_bionic_src_files_mips += \
     arch-mips/string/memcmp.c \
     arch-mips/string/memcpy.S \
     arch-mips/string/memset.S \
     arch-mips/string/strcmp.S \
-    bionic/__memcpy_chk.cpp \
-    bionic/__memset_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-    bionic/__strcat_chk.cpp \
-    bionic/strchr.cpp \
-    bionic/strnlen.c \
-    bionic/strrchr.cpp \
-
-libc_freebsd_src_files_mips += \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-freebsd/lib/libc/string/wcschr.c \
-    upstream-freebsd/lib/libc/string/wcscmp.c \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcslen.c \
-    upstream-freebsd/lib/libc/string/wcsrchr.c \
-    upstream-freebsd/lib/libc/string/wmemcmp.c \
-    upstream-freebsd/lib/libc/string/wmemmove.c \
-
-libc_openbsd_src_files_mips += \
-    upstream-openbsd/lib/libc/string/memchr.c \
-    upstream-openbsd/lib/libc/string/memmove.c \
-    upstream-openbsd/lib/libc/string/memrchr.c \
-    upstream-openbsd/lib/libc/string/stpcpy.c \
-    upstream-openbsd/lib/libc/string/stpncpy.c \
-    upstream-openbsd/lib/libc/string/strcat.c \
-    upstream-openbsd/lib/libc/string/strcpy.c \
-    upstream-openbsd/lib/libc/string/strlcat.c \
-    upstream-openbsd/lib/libc/string/strlcpy.c \
-    upstream-openbsd/lib/libc/string/strncat.c \
-    upstream-openbsd/lib/libc/string/strncmp.c \
-    upstream-openbsd/lib/libc/string/strncpy.c \
 
 #
 # Inherently architecture-specific code.
diff --git a/libc/arch-mips/syscalls/flistxattr.S b/libc/arch-mips/syscalls/___flistxattr.S
similarity index 81%
rename from libc/arch-mips/syscalls/flistxattr.S
rename to libc/arch-mips/syscalls/___flistxattr.S
index 0b71532..5a4a53d 100644
--- a/libc/arch-mips/syscalls/flistxattr.S
+++ b/libc/arch-mips/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     .set noreorder
     .cpload t9
     li v0, __NR_flistxattr
@@ -16,4 +16,5 @@
     j t9
     nop
     .set reorder
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-mips/syscalls/mremap.S b/libc/arch-mips/syscalls/___mremap.S
similarity index 84%
rename from libc/arch-mips/syscalls/mremap.S
rename to libc/arch-mips/syscalls/___mremap.S
index 7cbb94e..82e2eb3 100644
--- a/libc/arch-mips/syscalls/mremap.S
+++ b/libc/arch-mips/syscalls/___mremap.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(___mremap)
     .set noreorder
     .cpload t9
     li v0, __NR_mremap
@@ -16,4 +16,5 @@
     j t9
     nop
     .set reorder
-END(mremap)
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-mips/syscalls/mremap.S b/libc/arch-mips/syscalls/__preadv64.S
similarity index 80%
copy from libc/arch-mips/syscalls/mremap.S
copy to libc/arch-mips/syscalls/__preadv64.S
index 7cbb94e..a46b869 100644
--- a/libc/arch-mips/syscalls/mremap.S
+++ b/libc/arch-mips/syscalls/__preadv64.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(__preadv64)
     .set noreorder
     .cpload t9
-    li v0, __NR_mremap
+    li v0, __NR_preadv
     syscall
     bnez a3, 1f
     move a0, v0
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(mremap)
+END(__preadv64)
diff --git a/libc/arch-mips/syscalls/mremap.S b/libc/arch-mips/syscalls/__pwritev64.S
similarity index 80%
copy from libc/arch-mips/syscalls/mremap.S
copy to libc/arch-mips/syscalls/__pwritev64.S
index 7cbb94e..1222942 100644
--- a/libc/arch-mips/syscalls/mremap.S
+++ b/libc/arch-mips/syscalls/__pwritev64.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(__pwritev64)
     .set noreorder
     .cpload t9
-    li v0, __NR_mremap
+    li v0, __NR_pwritev
     syscall
     bnez a3, 1f
     move a0, v0
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(mremap)
+END(__pwritev64)
diff --git a/libc/arch-mips64/bionic/vfork.S b/libc/arch-mips64/bionic/vfork.S
index d180a8c..e0a39ed 100644
--- a/libc/arch-mips64/bionic/vfork.S
+++ b/libc/arch-mips64/bionic/vfork.S
@@ -46,6 +46,12 @@
 	PTR_SUBU sp, FRAMESZ
 #endif
 	SETUP_GP64(a5, vfork)
+
+	// __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+	rdhwr	v0, $29			// v0 = tls
+	REG_L	v0, REGSZ*1(v0)		// v0 = v0[TLS_SLOT_THREAD_ID ie 1]
+	sw	$0, REGSZ*2+4(v0)	// v0->cached_pid_ = 0
+
 	LI	a0, (CLONE_VM | CLONE_VFORK | SIGCHLD)
 	move	a1, $0
 	move	a2, $0
diff --git a/libc/arch-mips64/mips64.mk b/libc/arch-mips64/mips64.mk
index 7757385..20ee639 100644
--- a/libc/arch-mips64/mips64.mk
+++ b/libc/arch-mips64/mips64.mk
@@ -1,46 +1,11 @@
 # 64-bit mips.
 
-#
-# Default implementations of functions that are commonly optimized.
-#
-
 libc_bionic_src_files_mips64 += \
     arch-mips/string/memcmp.c \
     arch-mips/string/memcpy.S \
     arch-mips/string/memset.S \
     arch-mips/string/strcmp.S \
     arch-mips/string/strlen.c \
-    bionic/__memcpy_chk.cpp \
-    bionic/__memset_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-    bionic/__strcat_chk.cpp \
-    bionic/strchr.cpp \
-    bionic/strnlen.c \
-    bionic/strrchr.cpp \
-
-libc_freebsd_src_files_mips64 += \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-freebsd/lib/libc/string/wcschr.c \
-    upstream-freebsd/lib/libc/string/wcscmp.c \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcslen.c \
-    upstream-freebsd/lib/libc/string/wcsrchr.c \
-    upstream-freebsd/lib/libc/string/wmemcmp.c \
-    upstream-freebsd/lib/libc/string/wmemmove.c \
-
-libc_openbsd_src_files_mips64 += \
-    upstream-openbsd/lib/libc/string/memchr.c \
-    upstream-openbsd/lib/libc/string/memmove.c \
-    upstream-openbsd/lib/libc/string/memrchr.c \
-    upstream-openbsd/lib/libc/string/stpcpy.c \
-    upstream-openbsd/lib/libc/string/stpncpy.c \
-    upstream-openbsd/lib/libc/string/strcat.c \
-    upstream-openbsd/lib/libc/string/strcpy.c \
-    upstream-openbsd/lib/libc/string/strlcat.c \
-    upstream-openbsd/lib/libc/string/strlcpy.c \
-    upstream-openbsd/lib/libc/string/strncat.c \
-    upstream-openbsd/lib/libc/string/strncmp.c \
-    upstream-openbsd/lib/libc/string/strncpy.c \
 
 #
 # Inherently architecture-specific code.
diff --git a/libc/arch-mips64/syscalls/flistxattr.S b/libc/arch-mips64/syscalls/___flistxattr.S
similarity index 85%
rename from libc/arch-mips64/syscalls/flistxattr.S
rename to libc/arch-mips64/syscalls/___flistxattr.S
index 1d5b1b0..586bcf7 100644
--- a/libc/arch-mips64/syscalls/flistxattr.S
+++ b/libc/arch-mips64/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     .set push
     .set noreorder
     li v0, __NR_flistxattr
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-mips64/syscalls/mremap.S b/libc/arch-mips64/syscalls/___mremap.S
similarity index 87%
rename from libc/arch-mips64/syscalls/mremap.S
rename to libc/arch-mips64/syscalls/___mremap.S
index cf7f1de..5004d50 100644
--- a/libc/arch-mips64/syscalls/mremap.S
+++ b/libc/arch-mips64/syscalls/___mremap.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(___mremap)
     .set push
     .set noreorder
     li v0, __NR_mremap
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(mremap)
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-mips64/syscalls/mremap.S b/libc/arch-mips64/syscalls/preadv.S
similarity index 80%
copy from libc/arch-mips64/syscalls/mremap.S
copy to libc/arch-mips64/syscalls/preadv.S
index cf7f1de..df43a8d 100644
--- a/libc/arch-mips64/syscalls/mremap.S
+++ b/libc/arch-mips64/syscalls/preadv.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(preadv)
     .set push
     .set noreorder
-    li v0, __NR_mremap
+    li v0, __NR_preadv
     syscall
     bnez a3, 1f
     move a0, v0
@@ -22,4 +22,6 @@
     j t9
     move ra, t0
     .set pop
-END(mremap)
+END(preadv)
+
+ALIAS_SYMBOL(preadv64, preadv)
diff --git a/libc/arch-mips64/syscalls/mremap.S b/libc/arch-mips64/syscalls/pwritev.S
similarity index 79%
copy from libc/arch-mips64/syscalls/mremap.S
copy to libc/arch-mips64/syscalls/pwritev.S
index cf7f1de..f55cec0 100644
--- a/libc/arch-mips64/syscalls/mremap.S
+++ b/libc/arch-mips64/syscalls/pwritev.S
@@ -2,10 +2,10 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(pwritev)
     .set push
     .set noreorder
-    li v0, __NR_mremap
+    li v0, __NR_pwritev
     syscall
     bnez a3, 1f
     move a0, v0
@@ -22,4 +22,6 @@
     j t9
     move ra, t0
     .set pop
-END(mremap)
+END(pwritev)
+
+ALIAS_SYMBOL(pwritev64, pwritev)
diff --git a/libc/arch-x86/atom/atom.mk b/libc/arch-x86/atom/atom.mk
index 3f28fb2..1afabac 100644
--- a/libc/arch-x86/atom/atom.mk
+++ b/libc/arch-x86/atom/atom.mk
@@ -1,32 +1,27 @@
 libc_bionic_src_files_x86 += \
     arch-x86/atom/string/sse2-bzero-atom.S \
-    arch-x86/atom/string/sse2-memchr-atom.S \
-    arch-x86/atom/string/sse2-memrchr-atom.S \
     arch-x86/atom/string/sse2-memset-atom.S \
-    arch-x86/atom/string/sse2-strchr-atom.S \
     arch-x86/atom/string/sse2-strlen-atom.S \
-    arch-x86/atom/string/sse2-strnlen-atom.S \
-    arch-x86/atom/string/sse2-strrchr-atom.S \
-    arch-x86/atom/string/sse2-wcschr-atom.S \
-    arch-x86/atom/string/sse2-wcsrchr-atom.S \
-    arch-x86/atom/string/sse2-wcslen-atom.S \
-    arch-x86/atom/string/sse2-wcscmp-atom.S \
     arch-x86/atom/string/ssse3-bcopy-atom.S \
     arch-x86/atom/string/ssse3-memcmp-atom.S \
     arch-x86/atom/string/ssse3-memcpy-atom.S \
     arch-x86/atom/string/ssse3-memmove-atom.S \
-    arch-x86/atom/string/ssse3-strcat-atom.S \
-    arch-x86/atom/string/ssse3-strcmp-atom.S \
     arch-x86/atom/string/ssse3-strcpy-atom.S \
-    arch-x86/atom/string/ssse3-strlcat-atom.S \
-    arch-x86/atom/string/ssse3-strlcpy-atom.S \
-    arch-x86/atom/string/ssse3-strncat-atom.S \
-    arch-x86/atom/string/ssse3-strncmp-atom.S \
     arch-x86/atom/string/ssse3-strncpy-atom.S \
-    arch-x86/atom/string/ssse3-wcscat-atom.S \
-    arch-x86/atom/string/ssse3-wcscpy-atom.S \
     arch-x86/atom/string/ssse3-wmemcmp-atom.S
 
-libc_bionic_src_files_x86 += \
-    arch-x86/silvermont/string/sse2-stpcpy-slm.S \
-    arch-x86/silvermont/string/sse2-stpncpy-slm.S
+libc_bionic_src_files_exclude_x86 += \
+    arch-x86/generic/string/memcmp.S \
+
+libc_bionic_src_files_exclude_x86 += \
+    arch-x86/silvermont/string/sse2-bcopy-slm.S \
+    arch-x86/silvermont/string/sse2-bzero-slm.S \
+    arch-x86/silvermont/string/sse2-memcpy-slm.S \
+    arch-x86/silvermont/string/sse2-memmove-slm.S \
+    arch-x86/silvermont/string/sse2-memset-slm.S \
+    arch-x86/silvermont/string/sse2-strcpy-slm.S \
+    arch-x86/silvermont/string/sse2-strlen-slm.S \
+    arch-x86/silvermont/string/sse2-strncpy-slm.S \
+
+libc_freebsd_src_files_exclude_x86 += \
+    upstream-freebsd/lib/libc/string/wmemcmp.c \
diff --git a/libc/arch-x86/bionic/setjmp.S b/libc/arch-x86/bionic/setjmp.S
index 18ad810..86e6e3c 100644
--- a/libc/arch-x86/bionic/setjmp.S
+++ b/libc/arch-x86/bionic/setjmp.S
@@ -41,30 +41,49 @@
 #define _JB_SIGMASK 6
 #define _JB_SIGFLAG 7
 
+.macro m_mangle_registers reg
+  xorl \reg,%edx
+  xorl \reg,%ebx
+  xorl \reg,%esp
+  xorl \reg,%ebp
+  xorl \reg,%esi
+  xorl \reg,%edi
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
 ENTRY(setjmp)
   movl 4(%esp),%ecx
-  movl $1,(_JB_SIGFLAG * 4)(%ecx)
-  jmp .L_sigsetjmp_signal_mask
+  mov $1,%eax
+  jmp .L_sigsetjmp
 END(setjmp)
 
 ENTRY(_setjmp)
   movl 4(%esp),%ecx
-  movl $0,(_JB_SIGFLAG * 4)(%ecx)
-  jmp .L_sigsetjmp_no_signal_mask
+  movl $0,%eax
+  jmp .L_sigsetjmp
 END(_setjmp)
 
 ENTRY(sigsetjmp)
   movl 4(%esp),%ecx
   movl 8(%esp),%eax
 
-  // Record whether or not the signal mask is valid.
+.L_sigsetjmp:
+  PIC_PROLOGUE
+  pushl %eax
+  call PIC_PLT(__bionic_setjmp_cookie_get)
+  addl $4,%esp
+  PIC_EPILOGUE
+
+  // Record the setjmp cookie and whether or not we're saving the signal mask.
   movl %eax,(_JB_SIGFLAG * 4)(%ecx)
 
   // Do we need to save the signal mask?
-  testl %eax,%eax
+  testl $1,%eax
   jz 1f
 
-.L_sigsetjmp_signal_mask:
   // Get the current signal mask.
   PIC_PROLOGUE
   pushl $0
@@ -76,16 +95,21 @@
   movl 4(%esp),%ecx
   movl %eax,(_JB_SIGMASK * 4)(%ecx)
 
-.L_sigsetjmp_no_signal_mask:
 1:
+  // Fetch the setjmp cookie and clear the signal flag bit.
+  movl (_JB_SIGFLAG * 4)(%ecx),%eax
+  andl $-2,%eax
+
   // Save the callee-save registers.
   movl 0(%esp),%edx
+  m_mangle_registers %eax
   movl %edx,(_JB_EDX * 4)(%ecx)
   movl %ebx,(_JB_EBX * 4)(%ecx)
   movl %esp,(_JB_ESP * 4)(%ecx)
   movl %ebp,(_JB_EBP * 4)(%ecx)
   movl %esi,(_JB_ESI * 4)(%ecx)
   movl %edi,(_JB_EDI * 4)(%ecx)
+  m_unmangle_registers %eax
 
   xorl %eax,%eax
   ret
@@ -94,7 +118,8 @@
 ENTRY(siglongjmp)
   // Do we have a signal mask to restore?
   movl 4(%esp),%edx
-  cmpl $0,(_JB_SIGFLAG * 4)(%edx)
+  movl (_JB_SIGFLAG * 4)(%edx), %eax
+  testl $1,%eax
   jz 1f
 
   // Restore the signal mask.
@@ -108,12 +133,31 @@
   // Restore the callee-save registers.
   movl 4(%esp),%edx
   movl 8(%esp),%eax
-  movl (_JB_EDX * 4)(%edx),%ecx
-  movl (_JB_EBX * 4)(%edx),%ebx
-  movl (_JB_ESP * 4)(%edx),%esp
-  movl (_JB_EBP * 4)(%edx),%ebp
-  movl (_JB_ESI * 4)(%edx),%esi
-  movl (_JB_EDI * 4)(%edx),%edi
+
+  movl (_JB_SIGFLAG * 4)(%edx),%ecx
+  andl $-2,%ecx
+
+  movl %ecx,%ebx
+  movl %ecx,%esp
+  movl %ecx,%ebp
+  movl %ecx,%esi
+  movl %ecx,%edi
+  xorl (_JB_EDX * 4)(%edx),%ecx
+  xorl (_JB_EBX * 4)(%edx),%ebx
+  xorl (_JB_ESP * 4)(%edx),%esp
+  xorl (_JB_EBP * 4)(%edx),%ebp
+  xorl (_JB_ESI * 4)(%edx),%esi
+  xorl (_JB_EDI * 4)(%edx),%edi
+
+  PIC_PROLOGUE
+  pushl %eax
+  pushl %ecx
+  pushl (_JB_SIGFLAG * 4)(%edx)
+  call PIC_PLT(__bionic_setjmp_cookie_check)
+  addl $4,%esp
+  popl %ecx
+  popl %eax
+  PIC_EPILOGUE
 
   testl %eax,%eax
   jnz 2f
diff --git a/libc/arch-x86/bionic/vfork.S b/libc/arch-x86/bionic/vfork.S
index ca7af0f..5c71b8d 100644
--- a/libc/arch-x86/bionic/vfork.S
+++ b/libc/arch-x86/bionic/vfork.S
@@ -34,6 +34,12 @@
   popl    %ecx  // Grab the return address.
   .cfi_adjust_cfa_offset 4
   .cfi_rel_offset ecx, 0
+
+  // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+  movl    %gs:0, %eax
+  movl    4(%eax), %eax
+  movl    $0, 12(%eax)
+
   movl    $__NR_vfork, %eax
   int     $0x80
   cmpl    $-MAX_ERRNO, %eax
diff --git a/libc/arch-x86/generic/generic.mk b/libc/arch-x86/generic/generic.mk
deleted file mode 100644
index 4aee5dc..0000000
--- a/libc/arch-x86/generic/generic.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-libc_bionic_src_files_x86 += \
-    arch-x86/atom/string/sse2-memchr-atom.S \
-    arch-x86/atom/string/sse2-memrchr-atom.S \
-    arch-x86/atom/string/sse2-strchr-atom.S \
-    arch-x86/atom/string/sse2-strnlen-atom.S \
-    arch-x86/atom/string/sse2-strrchr-atom.S \
-    arch-x86/atom/string/sse2-wcschr-atom.S \
-    arch-x86/atom/string/sse2-wcsrchr-atom.S \
-    arch-x86/atom/string/sse2-wcslen-atom.S \
-    arch-x86/atom/string/sse2-wcscmp-atom.S \
-    arch-x86/silvermont/string/sse2-bcopy-slm.S \
-    arch-x86/silvermont/string/sse2-bzero-slm.S \
-    arch-x86/silvermont/string/sse2-memcpy-slm.S \
-    arch-x86/silvermont/string/sse2-memmove-slm.S \
-    arch-x86/silvermont/string/sse2-memset-slm.S \
-    arch-x86/silvermont/string/sse2-stpcpy-slm.S \
-    arch-x86/silvermont/string/sse2-stpncpy-slm.S \
-    arch-x86/silvermont/string/sse2-strcpy-slm.S \
-    arch-x86/silvermont/string/sse2-strlen-slm.S \
-    arch-x86/silvermont/string/sse2-strncpy-slm.S
-
-ifeq ($(ARCH_X86_HAVE_SSSE3),true)
-libc_bionic_src_files_x86 += \
-    arch-x86/atom/string/ssse3-strncat-atom.S \
-    arch-x86/atom/string/ssse3-strlcat-atom.S \
-    arch-x86/atom/string/ssse3-strlcpy-atom.S \
-    arch-x86/atom/string/ssse3-strcmp-atom.S \
-    arch-x86/atom/string/ssse3-strncmp-atom.S \
-    arch-x86/atom/string/ssse3-strcat-atom.S \
-    arch-x86/atom/string/ssse3-wcscat-atom.S \
-    arch-x86/atom/string/ssse3-wcscpy-atom.S
-else
-libc_bionic_src_files_x86 += \
-    arch-x86/generic/string/strcmp.S \
-    arch-x86/generic/string/strncmp.S \
-    arch-x86/generic/string/strcat.S \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-openbsd/lib/libc/string/strlcat.c \
-    upstream-openbsd/lib/libc/string/strlcpy.c \
-    upstream-openbsd/lib/libc/string/strncat.c
-endif
-
-ifeq ($(ARCH_X86_HAVE_SSE4),true)
- libc_bionic_src_files_x86 += \
-    arch-x86/silvermont/string/sse4-memcmp-slm.S \
-    arch-x86/silvermont/string/sse4-wmemcmp-slm.S
-else
-libc_bionic_src_files_x86 += \
-    arch-x86/generic/string/memcmp.S \
-    upstream-freebsd/lib/libc/string/wmemcmp.c
-endif
diff --git a/libc/arch-x86/silvermont/silvermont.mk b/libc/arch-x86/silvermont/silvermont.mk
index 176bee3..e69de29 100644
--- a/libc/arch-x86/silvermont/silvermont.mk
+++ b/libc/arch-x86/silvermont/silvermont.mk
@@ -1,32 +0,0 @@
-libc_bionic_src_files_x86 += \
-    arch-x86/silvermont/string/sse2-bcopy-slm.S \
-    arch-x86/silvermont/string/sse2-bzero-slm.S \
-    arch-x86/silvermont/string/sse2-memcpy-slm.S \
-    arch-x86/silvermont/string/sse2-memmove-slm.S \
-    arch-x86/silvermont/string/sse2-memset-slm.S \
-    arch-x86/silvermont/string/sse2-stpcpy-slm.S \
-    arch-x86/silvermont/string/sse2-stpncpy-slm.S \
-    arch-x86/silvermont/string/sse2-strcpy-slm.S \
-    arch-x86/silvermont/string/sse2-strlen-slm.S \
-    arch-x86/silvermont/string/sse2-strncpy-slm.S \
-    arch-x86/silvermont/string/sse4-memcmp-slm.S \
-    arch-x86/silvermont/string/sse4-wmemcmp-slm.S
-
-libc_bionic_src_files_x86 += \
-    arch-x86/atom/string/sse2-memchr-atom.S \
-    arch-x86/atom/string/sse2-memrchr-atom.S \
-    arch-x86/atom/string/sse2-strchr-atom.S \
-    arch-x86/atom/string/sse2-strrchr-atom.S \
-    arch-x86/atom/string/sse2-strnlen-atom.S \
-    arch-x86/atom/string/sse2-wcschr-atom.S \
-    arch-x86/atom/string/sse2-wcsrchr-atom.S \
-    arch-x86/atom/string/sse2-wcslen-atom.S \
-    arch-x86/atom/string/sse2-wcscmp-atom.S \
-    arch-x86/atom/string/ssse3-strncat-atom.S \
-    arch-x86/atom/string/ssse3-strlcat-atom.S \
-    arch-x86/atom/string/ssse3-strlcpy-atom.S \
-    arch-x86/atom/string/ssse3-strcmp-atom.S \
-    arch-x86/atom/string/ssse3-strncmp-atom.S \
-    arch-x86/atom/string/ssse3-strcat-atom.S \
-    arch-x86/atom/string/ssse3-wcscat-atom.S \
-    arch-x86/atom/string/ssse3-wcscpy-atom.S
diff --git a/libc/arch-x86/syscalls/flistxattr.S b/libc/arch-x86/syscalls/___flistxattr.S
similarity index 90%
rename from libc/arch-x86/syscalls/flistxattr.S
rename to libc/arch-x86/syscalls/___flistxattr.S
index fc81a37..a67967b 100644
--- a/libc/arch-x86/syscalls/flistxattr.S
+++ b/libc/arch-x86/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -28,4 +28,5 @@
     popl    %ecx
     popl    %ebx
     ret
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-x86/syscalls/mremap.S b/libc/arch-x86/syscalls/___mremap.S
similarity index 69%
rename from libc/arch-x86/syscalls/mremap.S
rename to libc/arch-x86/syscalls/___mremap.S
index 869ef5d..e5e9c54 100644
--- a/libc/arch-x86/syscalls/mremap.S
+++ b/libc/arch-x86/syscalls/___mremap.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(___mremap)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -15,10 +15,14 @@
     pushl   %esi
     .cfi_adjust_cfa_offset 4
     .cfi_rel_offset esi, 0
-    mov     20(%esp), %ebx
-    mov     24(%esp), %ecx
-    mov     28(%esp), %edx
-    mov     32(%esp), %esi
+    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_mremap, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
@@ -28,9 +32,11 @@
     call    __set_errno_internal
     addl    $4, %esp
 1:
+    popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
     popl    %ebx
     ret
-END(mremap)
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-x86/syscalls/clock_gettime.S b/libc/arch-x86/syscalls/__clock_gettime.S
similarity index 92%
rename from libc/arch-x86/syscalls/clock_gettime.S
rename to libc/arch-x86/syscalls/__clock_gettime.S
index 0875cfb..61eadc8 100644
--- a/libc/arch-x86/syscalls/clock_gettime.S
+++ b/libc/arch-x86/syscalls/__clock_gettime.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(clock_gettime)
+ENTRY(__clock_gettime)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -23,4 +23,4 @@
     popl    %ecx
     popl    %ebx
     ret
-END(clock_gettime)
+END(__clock_gettime)
diff --git a/libc/arch-x86/syscalls/gettimeofday.S b/libc/arch-x86/syscalls/__gettimeofday.S
similarity index 92%
rename from libc/arch-x86/syscalls/gettimeofday.S
rename to libc/arch-x86/syscalls/__gettimeofday.S
index a508c14..90f3f91 100644
--- a/libc/arch-x86/syscalls/gettimeofday.S
+++ b/libc/arch-x86/syscalls/__gettimeofday.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(gettimeofday)
+ENTRY(__gettimeofday)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -23,4 +23,4 @@
     popl    %ecx
     popl    %ebx
     ret
-END(gettimeofday)
+END(__gettimeofday)
diff --git a/libc/arch-x86/syscalls/mremap.S b/libc/arch-x86/syscalls/__preadv64.S
similarity index 67%
copy from libc/arch-x86/syscalls/mremap.S
copy to libc/arch-x86/syscalls/__preadv64.S
index 869ef5d..3ce4fc3 100644
--- a/libc/arch-x86/syscalls/mremap.S
+++ b/libc/arch-x86/syscalls/__preadv64.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(__preadv64)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -15,11 +15,15 @@
     pushl   %esi
     .cfi_adjust_cfa_offset 4
     .cfi_rel_offset esi, 0
-    mov     20(%esp), %ebx
-    mov     24(%esp), %ecx
-    mov     28(%esp), %edx
-    mov     32(%esp), %esi
-    movl    $__NR_mremap, %eax
+    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_preadv, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
     jb      1f
@@ -28,9 +32,10 @@
     call    __set_errno_internal
     addl    $4, %esp
 1:
+    popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
     popl    %ebx
     ret
-END(mremap)
+END(__preadv64)
diff --git a/libc/arch-x86/syscalls/mremap.S b/libc/arch-x86/syscalls/__pwritev64.S
similarity index 67%
copy from libc/arch-x86/syscalls/mremap.S
copy to libc/arch-x86/syscalls/__pwritev64.S
index 869ef5d..2ce5b0e 100644
--- a/libc/arch-x86/syscalls/mremap.S
+++ b/libc/arch-x86/syscalls/__pwritev64.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(__pwritev64)
     pushl   %ebx
     .cfi_def_cfa_offset 8
     .cfi_rel_offset ebx, 0
@@ -15,11 +15,15 @@
     pushl   %esi
     .cfi_adjust_cfa_offset 4
     .cfi_rel_offset esi, 0
-    mov     20(%esp), %ebx
-    mov     24(%esp), %ecx
-    mov     28(%esp), %edx
-    mov     32(%esp), %esi
-    movl    $__NR_mremap, %eax
+    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_pwritev, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
     jb      1f
@@ -28,9 +32,10 @@
     call    __set_errno_internal
     addl    $4, %esp
 1:
+    popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
     popl    %ebx
     ret
-END(mremap)
+END(__pwritev64)
diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk
index e5d70a9..1d717aa 100644
--- a/libc/arch-x86/x86.mk
+++ b/libc/arch-x86/x86.mk
@@ -1,17 +1,103 @@
 # 32-bit x86.
 
 #
-# Default implementations of functions that are commonly optimized.
+# Generic x86 optimizations, may be overriden by CPU variants.
 #
 
-libc_common_src_files_x86 += \
-    bionic/__memcpy_chk.cpp \
-    bionic/__memset_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-    bionic/__strcat_chk.cpp \
+libc_bionic_src_files_x86 += \
+    arch-x86/atom/string/sse2-memchr-atom.S \
+    arch-x86/atom/string/sse2-memrchr-atom.S \
+    arch-x86/atom/string/sse2-strchr-atom.S \
+    arch-x86/atom/string/sse2-strnlen-atom.S \
+    arch-x86/atom/string/sse2-strrchr-atom.S \
+    arch-x86/atom/string/sse2-wcschr-atom.S \
+    arch-x86/atom/string/sse2-wcsrchr-atom.S \
+    arch-x86/atom/string/sse2-wcslen-atom.S \
+    arch-x86/atom/string/sse2-wcscmp-atom.S \
+    arch-x86/silvermont/string/sse2-bcopy-slm.S \
+    arch-x86/silvermont/string/sse2-bzero-slm.S \
+    arch-x86/silvermont/string/sse2-memcpy-slm.S \
+    arch-x86/silvermont/string/sse2-memmove-slm.S \
+    arch-x86/silvermont/string/sse2-memset-slm.S \
+    arch-x86/silvermont/string/sse2-stpcpy-slm.S \
+    arch-x86/silvermont/string/sse2-stpncpy-slm.S \
+    arch-x86/silvermont/string/sse2-strcpy-slm.S \
+    arch-x86/silvermont/string/sse2-strlen-slm.S \
+    arch-x86/silvermont/string/sse2-strncpy-slm.S
 
-libc_freebsd_src_files_x86 += \
-    upstream-freebsd/lib/libc/string/wmemmove.c \
+libc_bionic_src_files_x86 += \
+    arch-x86/generic/string/memcmp.S \
+    arch-x86/generic/string/strcmp.S \
+    arch-x86/generic/string/strncmp.S \
+    arch-x86/generic/string/strcat.S
+
+ifeq ($(ARCH_X86_HAVE_SSSE3),true)
+libc_bionic_src_files_x86 += \
+    arch-x86/atom/string/ssse3-strncat-atom.S \
+    arch-x86/atom/string/ssse3-strlcat-atom.S \
+    arch-x86/atom/string/ssse3-strlcpy-atom.S \
+    arch-x86/atom/string/ssse3-strcmp-atom.S \
+    arch-x86/atom/string/ssse3-strncmp-atom.S \
+    arch-x86/atom/string/ssse3-strcat-atom.S \
+    arch-x86/atom/string/ssse3-wcscat-atom.S \
+    arch-x86/atom/string/ssse3-wcscpy-atom.S
+libc_bionic_src_files_exclude_x86 += \
+    arch-x86/generic/string/strcmp.S \
+    arch-x86/generic/string/strncmp.S \
+    arch-x86/generic/string/strcat.S
+endif
+
+ifeq ($(ARCH_X86_HAVE_SSE4),true)
+libc_bionic_src_files_x86 += \
+    arch-x86/silvermont/string/sse4-memcmp-slm.S \
+    arch-x86/silvermont/string/sse4-wmemcmp-slm.S
+libc_bionic_src_files_exclude_x86 += \
+    arch-x86/generic/string/memcmp.S
+endif
+
+#
+# Remove default implementations that we have optimized versions of.
+#
+
+libc_freebsd_src_files_exclude_x86 += \
+    upstream-freebsd/lib/libc/string/wcschr.c \
+    upstream-freebsd/lib/libc/string/wcscmp.c \
+    upstream-freebsd/lib/libc/string/wcslen.c \
+    upstream-freebsd/lib/libc/string/wcsrchr.c \
+
+ifeq ($(ARCH_X86_HAVE_SSSE3),true)
+libc_freebsd_src_files_exclude_x86 += \
+    upstream-freebsd/lib/libc/string/wcscat.c \
+    upstream-freebsd/lib/libc/string/wcscpy.c
+endif
+
+ifeq ($(ARCH_X86_HAVE_SSE4),true)
+libc_freebsd_src_files_exclude_x86 += \
+    upstream-freebsd/lib/libc/string/wmemcmp.c
+endif
+
+libc_openbsd_src_files_exclude_x86 += \
+    upstream-openbsd/lib/libc/string/memchr.c \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/memrchr.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/stpncpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+    upstream-openbsd/lib/libc/string/strcpy.c \
+    upstream-openbsd/lib/libc/string/strncmp.c \
+    upstream-openbsd/lib/libc/string/strncpy.c \
+
+ifeq ($(ARCH_X86_HAVE_SSSE3),true)
+libc_openbsd_src_files_exclude_x86 += \
+    upstream-openbsd/lib/libc/string/strlcat.c \
+    upstream-openbsd/lib/libc/string/strlcpy.c \
+    upstream-openbsd/lib/libc/string/strncat.c
+endif
+
+libc_bionic_src_files_exclude_x86 += \
+    bionic/strchr.cpp \
+    bionic/strnlen.c \
+    bionic/strrchr.cpp \
 
 #
 # Inherently architecture-specific functions.
@@ -23,19 +109,20 @@
     arch-x86/bionic/libgcc_compat.c \
     arch-x86/bionic/__restore.S \
     arch-x86/bionic/setjmp.S \
-    arch-x86/bionic/__set_tls.c \
     arch-x86/bionic/syscall.S \
     arch-x86/bionic/vfork.S \
 
 ## ARCH variant specific source files
 arch_variant_mk := $(LOCAL_PATH)/arch-x86/$(TARGET_ARCH_VARIANT)/$(TARGET_ARCH_VARIANT).mk
 ifeq ($(wildcard $(arch_variant_mk)),)
-    arch_variant_mk := $(LOCAL_PATH)/arch-x86/generic/generic.mk
+    arch_variant_mk :=
 endif
+ifneq ($(arch_variant_mk),)
 include $(arch_variant_mk)
 libc_common_additional_dependencies += $(arch_variant_mk)
 
 arch_variant_mk :=
+endif
 
 libc_crt_target_cflags_x86 := \
     -m32 \
diff --git a/libc/arch-x86_64/bionic/setjmp.S b/libc/arch-x86_64/bionic/setjmp.S
index 5559f54..56ebb07 100644
--- a/libc/arch-x86_64/bionic/setjmp.S
+++ b/libc/arch-x86_64/bionic/setjmp.S
@@ -50,6 +50,25 @@
 #define _JB_SIGMASK 9
 #define _JB_SIGMASK_RT 10 // sigprocmask will write here too.
 
+#define MANGLE_REGISTERS 1
+.macro m_mangle_registers reg
+#if MANGLE_REGISTERS
+  xorq \reg,%rbx
+  xorq \reg,%rbp
+  xorq \reg,%r12
+  xorq \reg,%r13
+  xorq \reg,%r14
+  xorq \reg,%r15
+  xorq \reg,%rsp
+  xorq \reg,%r11
+#endif
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
+
 ENTRY(setjmp)
   movl $1,%esi
   jmp PIC_PLT(sigsetjmp)
@@ -62,11 +81,17 @@
 
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
-  movl %esi,(_JB_SIGFLAG * 8)(%rdi)
+  pushq %rdi
+  movq %rsi,%rdi
+  call PIC_PLT(__bionic_setjmp_cookie_get)
+  popq %rdi
+
+  // Record setjmp cookie and whether or not we're saving the signal mask.
+  movq %rax,(_JB_SIGFLAG * 8)(%rdi)
+  pushq %rax
 
   // Do we need to save the signal mask?
-  testl %esi,%esi
+  testq $1,%rax
   jz 2f
 
   // Save current signal mask.
@@ -79,7 +104,10 @@
 
 2:
   // Save the callee-save registers.
+  popq %rax
+  andq $-2,%rax
   movq (%rsp),%r11
+  m_mangle_registers %rax
   movq %rbx,(_JB_RBX * 8)(%rdi)
   movq %rbp,(_JB_RBP * 8)(%rdi)
   movq %r12,(_JB_R12 * 8)(%rdi)
@@ -88,6 +116,7 @@
   movq %r15,(_JB_R15 * 8)(%rdi)
   movq %rsp,(_JB_RSP * 8)(%rdi)
   movq %r11,(_JB_PC  * 8)(%rdi)
+  m_unmangle_registers %rax
 
   xorl %eax,%eax
   ret
@@ -99,7 +128,9 @@
   pushq %rsi // Push 'value'.
 
   // Do we need to restore the signal mask?
-  cmpl $0,(_JB_SIGFLAG * 8)(%rdi)
+  movq (_JB_SIGFLAG * 8)(%rdi), %rdi
+  pushq %rdi // Push cookie
+  testq $1, %rdi
   jz 2f
 
   // Restore the signal mask.
@@ -109,6 +140,10 @@
   call PIC_PLT(sigprocmask)
 
 2:
+  // Fetch the setjmp cookie and clear the signal flag bit.
+  popq %rcx
+  andq $-2, %rcx
+
   popq %rax // Pop 'value'.
 
   // Restore the callee-save registers.
@@ -120,7 +155,17 @@
   movq (_JB_RSP * 8)(%r12),%rsp
   movq (_JB_PC  * 8)(%r12),%r11
   movq (_JB_R12 * 8)(%r12),%r12
+  m_unmangle_registers %rcx
 
+  // Check the cookie.
+  pushq %rax
+  pushq %r11
+  movq %rcx, %rdi
+  call PIC_PLT(__bionic_setjmp_cookie_check)
+  popq %r11
+  popq %rax
+
+  // Return 1 if value is 0.
   testl %eax,%eax
   jnz 1f
   incl %eax
diff --git a/libc/arch-x86_64/bionic/vfork.S b/libc/arch-x86_64/bionic/vfork.S
index 129f1db..3b32c66 100644
--- a/libc/arch-x86_64/bionic/vfork.S
+++ b/libc/arch-x86_64/bionic/vfork.S
@@ -32,6 +32,12 @@
 
 ENTRY(vfork)
   popq    %rdi  // Grab the return address.
+
+  // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
+  mov    %fs:0, %rax
+  mov    8(%rax), %rax
+  movl   $0, 20(%rax)
+
   movl    $__NR_vfork, %eax
   syscall
   pushq   %rdi  // Restore the return address.
diff --git a/libc/arch-x86_64/string/sse2-memmove-slm.S b/libc/arch-x86_64/string/sse2-memmove-slm.S
index 0dbffad..6a5afd6 100644
--- a/libc/arch-x86_64/string/sse2-memmove-slm.S
+++ b/libc/arch-x86_64/string/sse2-memmove-slm.S
@@ -91,9 +91,6 @@
 	.section .text.sse2,"ax",@progbits
 ENTRY (MEMMOVE)
 	ENTRANCE
-#ifdef USE_AS_BCOPY
-	xchg	%rsi, %rdi
-#endif
 	mov	%rdi, %rax
 
 /* Check whether we should copy backward or forward.  */
diff --git a/libc/arch-x86_64/syscalls/flistxattr.S b/libc/arch-x86_64/syscalls/___flistxattr.S
similarity index 80%
rename from libc/arch-x86_64/syscalls/flistxattr.S
rename to libc/arch-x86_64/syscalls/___flistxattr.S
index aa02db1..b4695cc 100644
--- a/libc/arch-x86_64/syscalls/flistxattr.S
+++ b/libc/arch-x86_64/syscalls/___flistxattr.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(flistxattr)
+ENTRY(___flistxattr)
     movl    $__NR_flistxattr, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
@@ -12,4 +12,5 @@
     call    __set_errno_internal
 1:
     ret
-END(flistxattr)
+END(___flistxattr)
+.hidden ___flistxattr
diff --git a/libc/arch-x86_64/syscalls/mremap.S b/libc/arch-x86_64/syscalls/___mremap.S
similarity index 84%
rename from libc/arch-x86_64/syscalls/mremap.S
rename to libc/arch-x86_64/syscalls/___mremap.S
index a6042cb..cc6dee9 100644
--- a/libc/arch-x86_64/syscalls/mremap.S
+++ b/libc/arch-x86_64/syscalls/___mremap.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(___mremap)
     movq    %rcx, %r10
     movl    $__NR_mremap, %eax
     syscall
@@ -13,4 +13,5 @@
     call    __set_errno_internal
 1:
     ret
-END(mremap)
+END(___mremap)
+.hidden ___mremap
diff --git a/libc/arch-x86_64/syscalls/mremap.S b/libc/arch-x86_64/syscalls/preadv.S
similarity index 73%
copy from libc/arch-x86_64/syscalls/mremap.S
copy to libc/arch-x86_64/syscalls/preadv.S
index a6042cb..7771a44 100644
--- a/libc/arch-x86_64/syscalls/mremap.S
+++ b/libc/arch-x86_64/syscalls/preadv.S
@@ -2,9 +2,9 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(preadv)
     movq    %rcx, %r10
-    movl    $__NR_mremap, %eax
+    movl    $__NR_preadv, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
     jb      1f
@@ -13,4 +13,6 @@
     call    __set_errno_internal
 1:
     ret
-END(mremap)
+END(preadv)
+
+ALIAS_SYMBOL(preadv64, preadv)
diff --git a/libc/arch-x86_64/syscalls/mremap.S b/libc/arch-x86_64/syscalls/pwritev.S
similarity index 72%
copy from libc/arch-x86_64/syscalls/mremap.S
copy to libc/arch-x86_64/syscalls/pwritev.S
index a6042cb..d3bd8fa 100644
--- a/libc/arch-x86_64/syscalls/mremap.S
+++ b/libc/arch-x86_64/syscalls/pwritev.S
@@ -2,9 +2,9 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(mremap)
+ENTRY(pwritev)
     movq    %rcx, %r10
-    movl    $__NR_mremap, %eax
+    movl    $__NR_pwritev, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
     jb      1f
@@ -13,4 +13,6 @@
     call    __set_errno_internal
 1:
     ret
-END(mremap)
+END(pwritev)
+
+ALIAS_SYMBOL(pwritev64, pwritev)
diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk
index 06d3185..ce06217 100644
--- a/libc/arch-x86_64/x86_64.mk
+++ b/libc/arch-x86_64/x86_64.mk
@@ -1,31 +1,20 @@
 # 64-bit x86.
 
 #
-# Default implementations of functions that are commonly optimized.
+# Remove default implementations that we have optimized versions of.
 #
 
-libc_bionic_src_files_x86_64 += \
-    bionic/__memcpy_chk.cpp \
-    bionic/__memset_chk.cpp \
-    bionic/__strcpy_chk.cpp \
-    bionic/__strcat_chk.cpp \
-    bionic/strchr.cpp \
-    bionic/strnlen.c \
-    bionic/strrchr.cpp \
-
-libc_freebsd_src_files_x86_64 += \
-    upstream-freebsd/lib/libc/string/wcscat.c \
-    upstream-freebsd/lib/libc/string/wcschr.c \
-    upstream-freebsd/lib/libc/string/wcscmp.c \
-    upstream-freebsd/lib/libc/string/wcscpy.c \
-    upstream-freebsd/lib/libc/string/wcslen.c \
-    upstream-freebsd/lib/libc/string/wcsrchr.c \
-    upstream-freebsd/lib/libc/string/wmemcmp.c \
-    upstream-freebsd/lib/libc/string/wmemmove.c \
-
-libc_openbsd_src_files_x86_64 += \
-    upstream-openbsd/lib/libc/string/memchr.c \
-    upstream-openbsd/lib/libc/string/memrchr.c \
+libc_openbsd_src_files_exclude_x86_64 += \
+    upstream-openbsd/lib/libc/string/memmove.c \
+    upstream-openbsd/lib/libc/string/stpcpy.c \
+    upstream-openbsd/lib/libc/string/stpncpy.c \
+    upstream-openbsd/lib/libc/string/strcat.c \
+    upstream-openbsd/lib/libc/string/strcpy.c \
+    upstream-openbsd/lib/libc/string/strlcat.c \
+    upstream-openbsd/lib/libc/string/strlcpy.c \
+    upstream-openbsd/lib/libc/string/strncat.c \
+    upstream-openbsd/lib/libc/string/strncmp.c \
+    upstream-openbsd/lib/libc/string/strncpy.c \
 
 #
 # Inherently architecture-specific code.
@@ -36,7 +25,6 @@
     arch-x86_64/bionic/_exit_with_stack_teardown.S \
     arch-x86_64/bionic/__restore_rt.S \
     arch-x86_64/bionic/setjmp.S \
-    arch-x86_64/bionic/__set_tls.c \
     arch-x86_64/bionic/syscall.S \
     arch-x86_64/bionic/vfork.S \
 
diff --git a/libc/bionic/__cxa_guard.cpp b/libc/bionic/__cxa_guard.cpp
index 5b34b58..97284d5 100644
--- a/libc/bionic/__cxa_guard.cpp
+++ b/libc/bionic/__cxa_guard.cpp
@@ -109,7 +109,7 @@
       }
     }
 
-    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, NULL);
+    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, false, nullptr);
     old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
   }
 }
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 0e427d3..6284b12 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -15,32 +15,34 @@
  */
 #include <sys/cdefs.h>
 
-struct thread_local_dtor {
+#include "pthread_internal.h"
+
+class thread_local_dtor {
+ public:
   void (*func) (void *);
   void *arg;
   void *dso_handle; // unused...
   thread_local_dtor* next;
 };
 
-static __thread thread_local_dtor* thread_local_dtors = nullptr;
-
 extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
   thread_local_dtor* dtor = new thread_local_dtor();
 
   dtor->func = func;
   dtor->arg = arg;
   dtor->dso_handle = dso_handle;
-  dtor->next = thread_local_dtors;
 
-  thread_local_dtors = dtor;
-
+  pthread_internal_t* thread = __get_thread();
+  dtor->next = thread->thread_local_dtors;
+  thread->thread_local_dtors = dtor;
   return 0;
 }
 
 extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() {
-  while (thread_local_dtors != nullptr) {
-    thread_local_dtor* current = thread_local_dtors;
-    thread_local_dtors = current->next;
+  pthread_internal_t* thread = __get_thread();
+  while (thread->thread_local_dtors != nullptr) {
+    thread_local_dtor* current = thread->thread_local_dtors;
+    thread->thread_local_dtors = current->next;
 
     current->func(current->arg);
     delete current;
diff --git a/libc/private/bionic_time.h b/libc/bionic/__fread_chk.cpp
similarity index 68%
copy from libc/private/bionic_time.h
copy to libc/bionic/__fread_chk.cpp
index 030dcfd..afc8d90 100644
--- a/libc/private/bionic_time.h
+++ b/libc/bionic/__fread_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,23 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _BIONIC_TIME_H
-#define _BIONIC_TIME_H
 
-#include <time.h>
+#undef _FORTIFY_SOURCE
+#include <stdio.h>
 #include <sys/cdefs.h>
+#include "private/libc_logging.h"
 
-__BEGIN_DECLS
+extern "C" size_t __fread_chk(void * __restrict buf, size_t size, size_t count,
+                              FILE * __restrict stream, size_t buf_size) {
+  size_t total;
+  if (__predict_false(__size_mul_overflow(size, count, &total))) {
+    // overflow: trigger the error path in fread
+    return fread(buf, size, count, stream);
+  }
 
-// We can't remove this (and this file) until we fix MtpUtils.cpp.
-time_t mktime_tz(struct tm* const, char const*);
+  if (__predict_false(total > buf_size)) {
+    __fortify_chk_fail("fread: prevented write past end of buffer", 0);
+  }
 
-__END_DECLS
-
-#endif /* _BIONIC_TIME_H */
+  return fread(buf, size, count, stream);
+}
diff --git a/libc/bionic/debug_stacktrace.h b/libc/bionic/__fwrite_chk.cpp
similarity index 68%
copy from libc/bionic/debug_stacktrace.h
copy to libc/bionic/__fwrite_chk.cpp
index 2cf8636..2af13d6 100644
--- a/libc/bionic/debug_stacktrace.h
+++ b/libc/bionic/__fwrite_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,22 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_STACKTRACE_H
-#define DEBUG_STACKTRACE_H
-
-#include <stdint.h>
+#undef _FORTIFY_SOURCE
+#include <stdio.h>
 #include <sys/cdefs.h>
+#include "private/libc_logging.h"
 
-__LIBC_HIDDEN__ void backtrace_startup();
-__LIBC_HIDDEN__ void backtrace_shutdown();
-__LIBC_HIDDEN__ int get_backtrace(uintptr_t* stack_frames, size_t max_depth);
-__LIBC_HIDDEN__ void log_backtrace(uintptr_t* stack_frames, size_t frame_count);
+extern "C" size_t __fwrite_chk(const void * __restrict buf, size_t size, size_t count,
+                               FILE * __restrict stream, size_t buf_size) {
+  size_t total;
+  if (__predict_false(__size_mul_overflow(size, count, &total))) {
+    // overflow: trigger the error path in fwrite
+    return fwrite(buf, size, count, stream);
+  }
 
-#endif /* DEBUG_STACKTRACE_H */
+  if (__predict_false(total > buf_size)) {
+    __fortify_chk_fail("fwrite: prevented read past end of buffer", 0);
+  }
+
+  return fwrite(buf, size, count, stream);
+}
diff --git a/libc/bionic/ioctl.c b/libc/bionic/__getcwd_chk.cpp
similarity index 79%
copy from libc/bionic/ioctl.c
copy to libc/bionic/__getcwd_chk.cpp
index 6dd95d0..b53ab5c 100644
--- a/libc/bionic/ioctl.c
+++ b/libc/bionic/__getcwd_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,19 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <stdarg.h>
 
-extern int __ioctl(int, int, void *);
+#undef _FORTIFY_SOURCE
 
-int ioctl(int fd, int request, ...)
-{
-    va_list ap;
-    void * arg;
+#include <unistd.h>
+#include "private/libc_logging.h"
 
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
-    va_end(ap);
+extern char* __getcwd_chk(char* buf, size_t len, size_t buflen) {
+  if (__predict_false(len > buflen)) {
+    __fortify_chk_fail("getcwd: prevented write past end of buffer", 0);
+  }
 
-    return __ioctl(fd, request, arg);
+  return getcwd(buf, len);
 }
-
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
new file mode 100644
index 0000000..e1445cb
--- /dev/null
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libc_init_common.h"
+
+#include "private/bionic_auxv.h"
+#include "private/bionic_globals.h"
+#include "private/KernelArgumentBlock.h"
+#include "pthread_internal.h"
+
+extern "C" int __set_tls(void* ptr);
+extern "C" int __set_tid_address(int* tid_address);
+
+// Setup for the main thread. For dynamic executables, this is called by the
+// linker _before_ libc is mapped in memory. This means that all writes to
+// globals from this function will apply to linker-private copies and will not
+// be visible from libc later on.
+//
+// Note: this function creates a pthread_internal_t for the initial thread and
+// stores the pointer in TLS, but does not add it to pthread's thread list. This
+// has to be done later from libc itself (see __libc_init_common).
+//
+// This is in a file by itself because it needs to be built with
+// -fno-stack-protector because it's responsible for setting up the main
+// thread's TLS (which stack protector relies on).
+
+void __libc_init_main_thread(KernelArgumentBlock& args) {
+  __libc_auxv = args.auxv;
+
+  static pthread_internal_t main_thread;
+
+  // The -fstack-protector implementation uses TLS, so make sure that's
+  // set up before we call any function that might get a stack check inserted.
+  __set_tls(main_thread.tls);
+
+  // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
+  // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
+  main_thread.tid = __set_tid_address(&main_thread.tid);
+  main_thread.set_cached_pid(main_thread.tid);
+
+  // We don't want to free the main thread's stack even when the main thread exits
+  // because things like environment variables with global scope live on it.
+  // We also can't free the pthread_internal_t itself, since that lives on the main
+  // thread's stack rather than on the heap.
+  // The main thread has no mmap allocated space for stack or pthread_internal_t.
+  main_thread.mmap_size = 0;
+  pthread_attr_init(&main_thread.attr);
+  main_thread.attr.guard_size = 0; // The main thread has no guard page.
+  main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked.
+  // TODO: the main thread's sched_policy and sched_priority need to be queried.
+
+  __init_thread(&main_thread);
+  __init_tls(&main_thread);
+
+  // Store a pointer to the kernel argument block in a TLS slot to be
+  // picked up by the libc constructor.
+  main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
+
+  __init_alternate_signal_stack(&main_thread);
+}
diff --git a/libc/bionic/ioctl.c b/libc/bionic/__pwrite64_chk.cpp
similarity index 71%
copy from libc/bionic/ioctl.c
copy to libc/bionic/__pwrite64_chk.cpp
index 6dd95d0..e488ca1 100644
--- a/libc/bionic/ioctl.c
+++ b/libc/bionic/__pwrite64_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,19 +25,20 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <stdarg.h>
 
-extern int __ioctl(int, int, void *);
+#undef _FORTIFY_SOURCE
+#include <unistd.h>
+#include "private/libc_logging.h"
 
-int ioctl(int fd, int request, ...)
-{
-    va_list ap;
-    void * arg;
+extern "C" ssize_t __pwrite64_chk(int fd, const void* buf, size_t count, off64_t offset,
+                                  size_t buf_size) {
+  if (__predict_false(count > buf_size)) {
+    __fortify_chk_fail("pwrite64: prevented read past end of buffer", 0);
+  }
 
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
-    va_end(ap);
+  if (__predict_false(count > SSIZE_MAX)) {
+    __fortify_chk_fail("pwrite64: count > SSIZE_MAX", 0);
+  }
 
-    return __ioctl(fd, request, arg);
+  return pwrite64(fd, buf, count, offset);
 }
-
diff --git a/libc/bionic/ioctl.c b/libc/bionic/__pwrite_chk.cpp
similarity index 71%
copy from libc/bionic/ioctl.c
copy to libc/bionic/__pwrite_chk.cpp
index 6dd95d0..a889ef6 100644
--- a/libc/bionic/ioctl.c
+++ b/libc/bionic/__pwrite_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,19 +25,20 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <stdarg.h>
 
-extern int __ioctl(int, int, void *);
+#undef _FORTIFY_SOURCE
+#include <unistd.h>
+#include "private/libc_logging.h"
 
-int ioctl(int fd, int request, ...)
-{
-    va_list ap;
-    void * arg;
+extern "C" ssize_t __pwrite_chk(int fd, const void* buf, size_t count, off_t offset,
+                                size_t buf_size) {
+  if (__predict_false(count > buf_size)) {
+    __fortify_chk_fail("pwrite: prevented read past end of buffer", 0);
+  }
 
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
-    va_end(ap);
+  if (__predict_false(count > SSIZE_MAX)) {
+    __fortify_chk_fail("pwrite: count > SSIZE_MAX", 0);
+  }
 
-    return __ioctl(fd, request, arg);
+  return pwrite(fd, buf, count, offset);
 }
-
diff --git a/libc/bionic/__set_errno.cpp b/libc/bionic/__set_errno.cpp
index 30df350..9ef0047 100644
--- a/libc/bionic/__set_errno.cpp
+++ b/libc/bionic/__set_errno.cpp
@@ -36,20 +36,13 @@
 // system these are the same size, but on a 64-bit system they're not.
 // 'long' gives us 32-bit on 32-bit systems, 64-bit on 64-bit systems.
 
-// __set_errno was mistakenly exposed in <errno.h> in the 32-bit NDK.
-// We need the extra level of indirection so that the .hidden directives
-// in the system call stubs don't cause __set_errno to be hidden, breaking
-// old NDK apps.
+// Since __set_errno was mistakenly exposed in <errno.h> in the 32-bit
+// NDK, use a differently named internal function for the system call
+// stubs. This avoids having the stubs .hidden directives accidentally
+// hide __set_errno for old NDK apps.
 
 // This one is for internal use only and used by both LP32 and LP64 assembler.
 extern "C" __LIBC_HIDDEN__ long __set_errno_internal(int n) {
   errno = n;
   return -1;
 }
-
-// This one exists for the LP32 NDK and is not present at all in LP64.
-#if !defined(__LP64__)
-extern "C" long __set_errno(int n) {
-  return __set_errno_internal(n);
-}
-#endif
diff --git a/libc/include/sys/shm.h b/libc/bionic/__write_chk.cpp
similarity index 73%
copy from libc/include/sys/shm.h
copy to libc/bionic/__write_chk.cpp
index c691c29..cbd247a 100644
--- a/libc/include/sys/shm.h
+++ b/libc/bionic/__write_chk.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,18 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+#undef _FORTIFY_SOURCE
+#include <unistd.h>
+#include "private/libc_logging.h"
 
-#include <linux/shm.h>
+extern "C" ssize_t __write_chk(int fd, const void* buf, size_t count, size_t buf_size) {
+  if (__predict_false(count > buf_size)) {
+    __fortify_chk_fail("write: prevented read past end of buffer", 0);
+  }
 
-#endif /* _SYS_SHM_H_ */
+  if (__predict_false(count > SSIZE_MAX)) {
+    __fortify_chk_fail("write: count > SSIZE_MAX", 0);
+  }
+
+  return write(fd, buf, count);
+}
diff --git a/libc/bionic/arpa_inet.cpp b/libc/bionic/arpa_inet.cpp
new file mode 100644
index 0000000..9d4afe3
--- /dev/null
+++ b/libc/bionic/arpa_inet.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "private/ErrnoRestorer.h"
+
+// The difference between inet_network(3) and inet_addr(3) is that
+// inet_network uses host order and inet_addr network order.
+in_addr_t inet_network(const char* cp) {
+  in_addr_t network_order = inet_addr(cp);
+  return ntohl(network_order);
+}
+
+in_addr_t inet_addr(const char* cp) {
+  in_addr addr;
+  return inet_aton(cp, &addr) ? addr.s_addr : INADDR_NONE;
+}
+
+int inet_aton(const char* cp, in_addr* addr) {
+  ErrnoRestorer errno_restorer;
+
+  unsigned long parts[4];
+  size_t i;
+  for (i = 0; i < 4; ++i) {
+    char* end;
+    errno = 0;
+    parts[i] = strtoul(cp, &end, 0);
+    if (errno != 0 || end == cp || (*end != '.' && *end != '\0')) return 0;
+    if (*end == '\0') break;
+    cp = end + 1;
+  }
+
+  uint32_t result = 0;
+  if (i == 0) {
+    // a (a 32-bit).
+    if (parts[0] > 0xffffffff) return 0;
+    result = parts[0];
+  } else if (i == 1) {
+    // a.b (b 24-bit).
+    if (parts[0] > 0xff || parts[1] > 0xffffff) return 0;
+    result = (parts[0] << 24) | parts[1];
+  } else if (i == 2) {
+    // a.b.c (c 16-bit).
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff) return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | parts[2];
+  } else if (i == 3) {
+    // a.b.c.d (d 8-bit).
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
+  } else {
+    return 0;
+  }
+
+  if (addr != nullptr) addr->s_addr = htonl(result);
+  return 1;
+}
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index 103aa8f..b522b10 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -34,27 +34,25 @@
 
 static Lock g_lock;
 static const prop_info* g_pinfo;
-static uint32_t g_serial = -1;
+static uint32_t g_property_serial = -1;
+static uint32_t g_property_area_serial = -1;
 static uint64_t g_tags;
 static int g_trace_marker_fd = -1;
 
 static bool should_trace() {
   bool result = false;
   g_lock.lock();
-  // If g_pinfo is null, this means that systrace hasn't been run and it's safe to
-  // assume that no trace writing will need to take place.  However, to avoid running
-  // this costly find check each time, we set it to a non-tracing value so that next
-  // time, it will just check the serial to see if the value has been changed.
-  // this function also deals with the bootup case, during which the call to property
-  // set will fail if the property server hasn't yet started.
-  if (g_pinfo == NULL) {
+  // debug.atrace.tags.enableflags is set to a safe non-tracing value during property
+  // space initialization, so it should only be null in two cases, if there are
+  // insufficient permissions for this process to access the property, in which
+  // case an audit will be logged, and during boot before the property server has
+  // been started, in which case we store the global property_area serial to prevent
+  // the costly find operation until we see a changed property_area.
+  if (!g_pinfo && g_property_area_serial != __system_property_area_serial()) {
+    g_property_area_serial = __system_property_area_serial();
     g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
-    if (g_pinfo == NULL) {
-      __system_property_set(SYSTRACE_PROPERTY_NAME, "0");
-      g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
-    }
   }
-  if (g_pinfo != NULL) {
+  if (g_pinfo) {
     // Find out which tags have been enabled on the command line and set
     // the value of tags accordingly.  If the value of the property changes,
     // the serial will also change, so the costly system_property_read function
@@ -62,11 +60,11 @@
     // first.  The values within pinfo may change, but its location is guaranteed
     // not to move.
     uint32_t cur_serial = __system_property_serial(g_pinfo);
-    if (cur_serial != g_serial) {
-      g_serial = cur_serial;
+    if (cur_serial != g_property_serial) {
+      g_property_serial = cur_serial;
       char value[PROP_VALUE_MAX];
       __system_property_read(g_pinfo, 0, value);
-      g_tags = strtoull(value, NULL, 0);
+      g_tags = strtoull(value, nullptr, 0);
     }
     result = ((g_tags & ATRACE_TAG_BIONIC) != 0);
   }
diff --git a/libc/bionic/bionic_time_conversions.cpp b/libc/bionic/bionic_time_conversions.cpp
index 75e8d49..f3ca46a 100644
--- a/libc/bionic/bionic_time_conversions.cpp
+++ b/libc/bionic/bionic_time_conversions.cpp
@@ -52,18 +52,12 @@
   tv.tv_usec = ts.tv_nsec / 1000;
 }
 
-// Initializes 'ts' with the difference between 'abs_ts' and the current time
-// according to 'clock'. Returns false if abstime already expired, true otherwise.
-bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
-  clock_gettime(clock, &ts);
-  ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
-  ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
-  if (ts.tv_nsec < 0) {
-    ts.tv_sec--;
-    ts.tv_nsec += NS_PER_S;
+void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts, clockid_t clock) {
+  clock_gettime(clock, &abs_ts);
+  abs_ts.tv_sec += ts.tv_sec;
+  abs_ts.tv_nsec += ts.tv_nsec;
+  if (abs_ts.tv_nsec >= NS_PER_S) {
+    abs_ts.tv_nsec -= NS_PER_S;
+    abs_ts.tv_sec++;
   }
-  if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
-    return false;
-  }
-  return true;
 }
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_backtrace.cpp
similarity index 81%
rename from libc/bionic/debug_stacktrace.cpp
rename to libc/bionic/debug_backtrace.cpp
index 71e876b..de3ce08 100644
--- a/libc/bionic/debug_stacktrace.cpp
+++ b/libc/bionic/debug_backtrace.cpp
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#include "debug_stacktrace.h"
+#include "debug_backtrace.h"
 
 #include <dlfcn.h>
 #include <inttypes.h>
@@ -85,23 +85,37 @@
     return _URC_NO_REASON;
   }
 
-#if defined(__arm__)
-  /*
-   * The instruction pointer is pointing at the instruction after the bl(x), and
-   * the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB
-   * in PC). So we need to do a quick check here to find out if the previous
-   * instruction is a Thumb-mode BLX(2). If so subtract 2 otherwise 4 from PC.
-   */
+  // The instruction pointer is pointing at the instruction after the return
+  // call on all architectures.
+  // Modify the pc to point at the real function.
   if (ip != 0) {
-    short* ptr = reinterpret_cast<short*>(ip);
-    // Thumb BLX(2)
-    if ((*(ptr-1) & 0xff80) == 0x4780) {
-      ip -= 2;
-    } else {
-      ip -= 4;
+#if defined(__arm__)
+    // If the ip is suspiciously low, do nothing to avoid a segfault trying
+    // to access this memory.
+    if (ip >= 4096) {
+      // Check bits [15:11] of the first halfword assuming the instruction
+      // is 32 bits long. If the bits are any of these values, then our
+      // assumption was correct:
+      //  b11101
+      //  b11110
+      //  b11111
+      // Otherwise, this is a 16 bit instruction.
+      uint16_t value = (*reinterpret_cast<uint16_t*>(ip - 2)) >> 11;
+      if (value == 0x1f || value == 0x1e || value == 0x1d) {
+        ip -= 4;
+      } else {
+        ip -= 2;
+      }
     }
-  }
+#elif defined(__aarch64__)
+    // All instructions are 4 bytes long, skip back one instruction.
+    ip -= 4;
+#elif defined(__i386__) || defined(__x86_64__)
+    // It's difficult to decode exactly where the previous instruction is,
+    // so subtract 1 to estimate where the instruction lives.
+    ip--;
 #endif
+  }
 
   state->frames[state->frame_count++] = ip;
   return (state->frame_count >= state->max_depth) ? _URC_END_OF_STACK : _URC_NO_REASON;
diff --git a/libc/bionic/debug_stacktrace.h b/libc/bionic/debug_backtrace.h
similarity index 94%
rename from libc/bionic/debug_stacktrace.h
rename to libc/bionic/debug_backtrace.h
index 2cf8636..adc9d1d 100644
--- a/libc/bionic/debug_stacktrace.h
+++ b/libc/bionic/debug_backtrace.h
@@ -26,8 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_STACKTRACE_H
-#define DEBUG_STACKTRACE_H
+#ifndef DEBUG_BACKTRACE_H
+#define DEBUG_BACKTRACE_H
 
 #include <stdint.h>
 #include <sys/cdefs.h>
@@ -37,4 +37,4 @@
 __LIBC_HIDDEN__ int get_backtrace(uintptr_t* stack_frames, size_t max_depth);
 __LIBC_HIDDEN__ void log_backtrace(uintptr_t* stack_frames, size_t frame_count);
 
-#endif /* DEBUG_STACKTRACE_H */
+#endif /* DEBUG_BACKTRACE_H */
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index de72cb2..6fb8ebe 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -50,14 +50,11 @@
   uintptr_t offset;
   char permissions[4];
   int name_pos;
-  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
+  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
              &end, permissions, &offset, &name_pos) < 2) {
     return NULL;
   }
 
-  while (isspace(line[name_pos])) {
-    name_pos += 1;
-  }
   const char* name = line + name_pos;
   size_t name_len = strlen(name);
   if (name_len && name[name_len - 1] == '\n') {
diff --git a/libc/include/sys/shm.h b/libc/bionic/flistxattr.cpp
similarity index 60%
copy from libc/include/sys/shm.h
copy to libc/bionic/flistxattr.cpp
index c691c29..05a96d2 100644
--- a/libc/include/sys/shm.h
+++ b/libc/bionic/flistxattr.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,34 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
 
-#include <linux/shm.h>
+extern "C" ssize_t ___flistxattr(int, char*, size_t);
 
-#endif /* _SYS_SHM_H_ */
+ssize_t flistxattr(int fd, char *list, size_t size) {
+  int saved_errno = errno;
+  ssize_t result = ___flistxattr(fd, list, 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 listxattr(buf, list, size);
+}
diff --git a/libc/bionic/flockfile.cpp b/libc/bionic/flockfile.cpp
index b73907cb..db53828 100644
--- a/libc/bionic/flockfile.cpp
+++ b/libc/bionic/flockfile.cpp
@@ -36,23 +36,15 @@
 // struct __sfileext (see fileext.h).
 
 void flockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_lock(&_FLOCK(fp));
   }
 }
 
 int ftrylockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
   // The specification for ftrylockfile() says it returns 0 on success,
   // or non-zero on error. So return an errno code directly on error.
-  if (fp == NULL) {
+  if (fp == nullptr) {
     return EINVAL;
   }
 
@@ -60,11 +52,7 @@
 }
 
 void funlockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_unlock(&_FLOCK(fp));
   }
 }
diff --git a/libc/bionic/getcwd.cpp b/libc/bionic/getcwd.cpp
index a8bbcf3..bcd6a57 100644
--- a/libc/bionic/getcwd.cpp
+++ b/libc/bionic/getcwd.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#undef _FORTIFY_SOURCE
 #include <errno.h>
 #include <malloc.h>
 #include <string.h>
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
new file mode 100644
index 0000000..c869420
--- /dev/null
+++ b/libc/bionic/ifaddrs.cpp
@@ -0,0 +1,241 @@
+/*
+ * 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 <ifaddrs.h>
+
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// The public ifaddrs struct is full of pointers. Rather than track several
+// different allocations, we use a maximally-sized structure with the public
+// part at offset 0, and pointers into its hidden tail.
+struct ifaddrs_storage {
+  // Must come first, so that `ifaddrs_storage` is-a `ifaddrs`.
+  ifaddrs ifa;
+
+  // The interface index, so we can match RTM_NEWADDR messages with
+  // earlier RTM_NEWLINK messages (to copy the interface flags).
+  int interface_index;
+
+  // Storage for the pointers in `ifa`.
+  sockaddr_storage addr;
+  sockaddr_storage netmask;
+  sockaddr_storage ifa_ifu;
+  char name[IFNAMSIZ + 1];
+
+  ifaddrs_storage(ifaddrs** list) {
+    memset(this, 0, sizeof(*this));
+
+    // push_front onto `list`.
+    ifa.ifa_next = *list;
+    *list = reinterpret_cast<ifaddrs*>(this);
+  }
+
+  // Netlink gives us the address family in the header, and the
+  // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
+  // stitch the two bits together into the sockaddr that's part of
+  // our portable interface.
+  void SetAddress(int family, const void* data, size_t byteCount) {
+      addr.ss_family = family;
+      memcpy(SockaddrBytes(family, &addr), data, byteCount);
+      ifa.ifa_addr = reinterpret_cast<sockaddr*>(&addr);
+  }
+
+  void SetBroadcastAddress(int family, const void* data, size_t byteCount) {
+      ifa_ifu.ss_family = family;
+      memcpy(SockaddrBytes(family, &ifa_ifu), data, byteCount);
+      ifa.ifa_dstaddr = reinterpret_cast<sockaddr*>(&ifa_ifu);
+  }
+
+  // Netlink gives us the prefix length as a bit count. We need to turn
+  // that into a BSD-compatible netmask represented by a sockaddr*.
+  void SetNetmask(int family, size_t prefix_length) {
+      // ...and work out the netmask from the prefix length.
+      netmask.ss_family = family;
+      uint8_t* dst = SockaddrBytes(family, &netmask);
+      memset(dst, 0xff, prefix_length / 8);
+      if ((prefix_length % 8) != 0) {
+        dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8)));
+      }
+      ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask);
+  }
+
+ private:
+  // Returns a pointer to the first byte in the address data (which is
+  // stored in network byte order).
+  uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) {
+    if (family == AF_INET) {
+      sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
+      return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
+    } else if (family == AF_INET6) {
+      sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
+      return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
+    }
+    return nullptr;
+  }
+};
+
+#if !defined(__clang__)
+// GCC gets confused by NLMSG_DATA and doesn't realize that the old-style
+// cast is from a system header and should be ignored.
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) {
+  if (hdr->nlmsg_type == RTM_NEWLINK) {
+    ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr));
+
+    // Create a new ifaddr entry, and set the interface index and flags.
+    ifaddrs_storage* new_addr = new ifaddrs_storage(out);
+    new_addr->interface_index = ifi->ifi_index;
+    new_addr->ifa.ifa_flags = ifi->ifi_flags;
+
+    // Go through the various bits of information and find the name.
+    rtattr* rta = IFLA_RTA(ifi);
+    size_t rta_len = IFLA_PAYLOAD(hdr);
+    while (RTA_OK(rta, rta_len)) {
+      if (rta->rta_type == IFLA_IFNAME) {
+        if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
+          memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
+          new_addr->ifa.ifa_name = new_addr->name;
+        }
+      }
+      rta = RTA_NEXT(rta, rta_len);
+    }
+  } else if (hdr->nlmsg_type == RTM_NEWADDR) {
+    ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
+
+    // We should already know about this from an RTM_NEWLINK message.
+    ifaddrs_storage* addr = reinterpret_cast<ifaddrs_storage*>(*out);
+    while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) {
+      addr = reinterpret_cast<ifaddrs_storage*>(addr->ifa.ifa_next);
+    }
+    // If this is an unknown interface, ignore whatever we're being told about it.
+    if (addr == nullptr) return;
+
+    // Create a new ifaddr entry and copy what we already know.
+    ifaddrs_storage* new_addr = new ifaddrs_storage(out);
+    // We can just copy the name rather than look for IFA_LABEL.
+    strcpy(new_addr->name, addr->name);
+    new_addr->ifa.ifa_name = new_addr->name;
+    new_addr->ifa.ifa_flags = addr->ifa.ifa_flags;
+    new_addr->interface_index = addr->interface_index;
+
+    // Go through the various bits of information and find the address
+    // and any broadcast/destination address.
+    rtattr* rta = IFA_RTA(msg);
+    size_t rta_len = IFA_PAYLOAD(hdr);
+    while (RTA_OK(rta, rta_len)) {
+      if (rta->rta_type == IFA_ADDRESS) {
+        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
+          addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+          addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
+        }
+      } else if (rta->rta_type == IFA_BROADCAST) {
+        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
+          addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+        }
+      }
+      rta = RTA_NEXT(rta, rta_len);
+    }
+  }
+}
+
+static bool __send_netlink_request(int fd, int type) {
+  struct NetlinkMessage {
+    nlmsghdr hdr;
+    rtgenmsg msg;
+  } request;
+  memset(&request, 0, sizeof(request));
+  request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+  request.hdr.nlmsg_type = type;
+  request.hdr.nlmsg_len = sizeof(request);
+  request.msg.rtgen_family = AF_UNSPEC; // All families.
+  return (TEMP_FAILURE_RETRY(send(fd, &request, sizeof(request), 0)) == sizeof(request));
+}
+
+static bool __read_netlink_responses(int fd, ifaddrs** out, char* buf, size_t buf_len) {
+  ssize_t bytes_read;
+  // Read through all the responses, handing interesting ones to __handle_netlink_response.
+  while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd, buf, buf_len, 0))) > 0) {
+    nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buf);
+    for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
+      if (hdr->nlmsg_type == NLMSG_DONE) return true;
+      if (hdr->nlmsg_type == NLMSG_ERROR) return false;
+      __handle_netlink_response(out, hdr);
+    }
+  }
+  // We only get here if recv fails before we see a NLMSG_DONE.
+  return false;
+}
+
+int getifaddrs(ifaddrs** out) {
+  // Make cleanup easy.
+  *out = nullptr;
+
+  // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE),
+  // but that's a bit too large to go on the stack.
+  size_t buf_len = 8192;
+  char* buf = new char[buf_len];
+  if (buf == nullptr) return -1;
+
+  // Open the netlink socket and ask for all the links and addresses.
+  int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
+  bool okay = fd != -1 &&
+      __send_netlink_request(fd, RTM_GETLINK) && __read_netlink_responses(fd, out, buf, buf_len) &&
+      __send_netlink_request(fd, RTM_GETADDR) && __read_netlink_responses(fd, out, buf, buf_len);
+
+  if (!okay) {
+    freeifaddrs(*out);
+    // Ensure that callers crash if they forget to check for success.
+    *out = nullptr;
+  }
+  {
+    int saved_errno = errno;
+    close(fd);
+    delete[] buf;
+    errno = saved_errno;
+  }
+  return okay ? 0 : -1;
+}
+
+void freeifaddrs(ifaddrs* list) {
+  while (list != nullptr) {
+    ifaddrs* current = list;
+    list = list->ifa_next;
+    free(current);
+  }
+}
diff --git a/libc/bionic/ioctl.c b/libc/bionic/ioctl.cpp
similarity index 85%
rename from libc/bionic/ioctl.c
rename to libc/bionic/ioctl.cpp
index 6dd95d0..db85132 100644
--- a/libc/bionic/ioctl.c
+++ b/libc/bionic/ioctl.cpp
@@ -25,19 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#include <sys/ioctl.h>
 #include <stdarg.h>
 
-extern int __ioctl(int, int, void *);
+extern "C" int __ioctl(int, int, void *);
 
-int ioctl(int fd, int request, ...)
-{
-    va_list ap;
-    void * arg;
-
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
-    va_end(ap);
-
-    return __ioctl(fd, request, arg);
+int ioctl(int fd, int request, ...) {
+  va_list ap;
+  va_start(ap, request);
+  void* arg = va_arg(ap, void*);
+  va_end(ap);
+  return __ioctl(fd, request, arg);
 }
-
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index a107664..f2bb37d 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -33,6 +33,7 @@
 #include <stdarg.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 #include <sys/vfs.h>
 #include <unistd.h>
 
@@ -43,6 +44,8 @@
 // System calls we need.
 extern "C" int __fcntl64(int, int, void*);
 extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int);
+extern "C" int __preadv64(int, const struct iovec*, int, long, long);
+extern "C" int __pwritev64(int, const struct iovec*, int, long, long);
 
 // For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
 int fcntl(int fd, int cmd, ...) {
@@ -77,6 +80,23 @@
   return pwrite64(fd, buf, byte_count, static_cast<off64_t>(offset));
 }
 
+// On LP32, there is no off_t preadv/pwritev, and even the 64-bit preadv/pwritev
+// don't use off64_t (see SYSCALLS.TXT for more). Here, this means that we need
+// to implement all four functions because the two system calls don't match any
+// of the userspace functions. Unlike llseek, the pair is split lo-hi, not hi-lo.
+ssize_t preadv(int fd, const struct iovec* ios, int count, off_t offset) {
+  return __preadv64(fd, ios, count, offset, 0);
+}
+ssize_t preadv64(int fd, const struct iovec* ios, int count, off64_t offset) {
+  return __preadv64(fd, ios, count, offset, offset >> 32);
+}
+ssize_t pwritev(int fd, const struct iovec* ios, int count, off_t offset) {
+  return __pwritev64(fd, ios, count, offset, 0);
+}
+ssize_t pwritev64(int fd, const struct iovec* ios, int count, off64_t offset) {
+  return __pwritev64(fd, ios, count, offset, offset >> 32);
+}
+
 // There is no fallocate for 32-bit off_t, so we need to widen and call fallocate64.
 int fallocate(int fd, int mode, off_t offset, off_t length) {
   return fallocate64(fd, mode, static_cast<off64_t>(offset), static_cast<off64_t>(length));
@@ -91,3 +111,22 @@
 int setrlimit64(int resource, const rlimit64* limits64) {
   return prlimit64(0, resource, limits64, NULL);
 }
+
+// There is no prlimit system call, so we need to use prlimit64.
+int prlimit(pid_t pid, int resource, const rlimit* n32, rlimit* o32) {
+  rlimit64 n64;
+  if (n32 != nullptr) {
+    n64.rlim_cur = (n32->rlim_cur == RLIM_INFINITY) ? RLIM64_INFINITY : n32->rlim_cur;
+    n64.rlim_max = (n32->rlim_max == RLIM_INFINITY) ? RLIM64_INFINITY : n32->rlim_max;
+  }
+
+  rlimit64 o64;
+  int result = prlimit64(pid, resource,
+                         (n32 != nullptr) ? &n64 : nullptr,
+                         (o32 != nullptr) ? &o64 : nullptr);
+  if (result != -1 && o32 != nullptr) {
+    o32->rlim_cur = (o64.rlim_cur == RLIM64_INFINITY) ? RLIM_INFINITY : o64.rlim_cur;
+    o32->rlim_max = (o64.rlim_max == RLIM64_INFINITY) ? RLIM_INFINITY : o64.rlim_max;
+  }
+  return result;
+}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index bd71628..532dab9 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -42,18 +42,18 @@
 #include <unistd.h>
 
 #include "private/bionic_auxv.h"
+#include "private/bionic_globals.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 #include "private/libc_logging.h"
+#include "private/WriteProtected.h"
 #include "pthread_internal.h"
 
 extern "C" abort_msg_t** __abort_message_ptr;
 extern "C" int __system_properties_init(void);
-extern "C" int __set_tls(void* ptr);
-extern "C" int __set_tid_address(int* tid_address);
 
-__LIBC_HIDDEN__ void __libc_init_vdso();
+__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
 
 // Not public, but well-known in the BSDs.
 const char* __progname;
@@ -64,51 +64,22 @@
 // Declared in "private/bionic_ssp.h".
 uintptr_t __stack_chk_guard = 0;
 
-/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
- * in memory. Beware: all writes to libc globals from this function will
- * apply to linker-private copies and will not be visible from libc later on.
- *
- * Note: this function creates a pthread_internal_t for the initial thread and
- * stores the pointer in TLS, but does not add it to pthread's thread list. This
- * has to be done later from libc itself (see __libc_init_common).
- *
- * This function also stores a pointer to the kernel argument block in a TLS slot to be
- * picked up by the libc constructor.
- */
-void __libc_init_tls(KernelArgumentBlock& args) {
+void __libc_init_globals(KernelArgumentBlock& args) {
+  // Initialize libc globals that are needed in both the linker and in libc.
+  // In dynamic binaries, this is run at least twice for different copies of the
+  // globals, once for the linker's copy and once for the one in libc.so.
   __libc_auxv = args.auxv;
-
-  static pthread_internal_t main_thread;
-
-  // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
-  // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
-  main_thread.tid = __set_tid_address(&main_thread.tid);
-  main_thread.set_cached_pid(main_thread.tid);
-
-  // We don't want to free the main thread's stack even when the main thread exits
-  // because things like environment variables with global scope live on it.
-  // We also can't free the pthread_internal_t itself, since that lives on the main
-  // thread's stack rather than on the heap.
-  // The main thread has no mmap allocated space for stack or pthread_internal_t.
-  main_thread.mmap_size = 0;
-  pthread_attr_init(&main_thread.attr);
-  main_thread.attr.guard_size = 0; // The main thread has no guard page.
-  main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked.
-  // TODO: the main thread's sched_policy and sched_priority need to be queried.
-
-  __init_thread(&main_thread);
-  __init_tls(&main_thread);
-  __set_tls(main_thread.tls);
-  main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
-
-  __init_alternate_signal_stack(&main_thread);
+  __libc_globals.initialize();
+  __libc_globals.mutate([&args](libc_globals* globals) {
+    __libc_init_vdso(globals, args);
+    __libc_init_setjmp_cookie(globals, args);
+  });
 }
 
 void __libc_init_common(KernelArgumentBlock& args) {
   // Initialize various globals.
   environ = args.envp;
   errno = 0;
-  __libc_auxv = args.auxv;
   __progname = args.argv[0] ? args.argv[0] : "<unknown>";
   __abort_message_ptr = args.abort_message_ptr;
 
@@ -120,8 +91,6 @@
   __pthread_internal_add(main_thread);
 
   __system_properties_init(); // Requires 'environ'.
-
-  __libc_init_vdso();
 }
 
 __noreturn static void __early_abort(int line) {
@@ -234,39 +203,42 @@
 }
 
 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
+  // None of these should be allowed when the AT_SECURE auxv
+  // flag is set. This flag is set to inform userspace that a
+  // security transition has occurred, for example, as a result
+  // of executing a setuid program or the result of an SELinux
+  // security transition.
+  static constexpr const char* 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",
   };
-  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
-    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
+  for (const auto& unsafe_variable_name : UNSAFE_VARIABLE_NAMES) {
+    if (env_match(name, unsafe_variable_name) != nullptr) {
       return true;
     }
   }
@@ -319,7 +291,7 @@
 
   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
+    // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
     __nullify_closed_stdio();
 
     __sanitize_environment_variables(args.envp);
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 673ad5b..5066652 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -51,6 +51,9 @@
 #if defined(__cplusplus)
 
 class KernelArgumentBlock;
+
+__LIBC_HIDDEN__ void __libc_init_globals(KernelArgumentBlock& args);
+
 __LIBC_HIDDEN__ void __libc_init_common(KernelArgumentBlock& args);
 
 __LIBC_HIDDEN__ void __libc_init_AT_SECURE(KernelArgumentBlock& args);
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 78125f9..97d9e39 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 /*
  * libc_init_dynamic.c
  *
@@ -50,11 +51,11 @@
 #include <elf.h>
 #include "libc_init_common.h"
 
+#include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 
 extern "C" {
-  extern void malloc_debug_init(void);
   extern void malloc_debug_fini(void);
   extern void netdClientInit(void);
   extern int __cxa_atexit(void (*)(void *), void *, void *);
@@ -74,10 +75,11 @@
   // __libc_init_common() will change the TLS area so the old one won't be accessible anyway.
   *args_slot = NULL;
 
+  __libc_init_globals(*args);
   __libc_init_common(*args);
 
   // Hooks for various libraries to let them know that we're starting up.
-  malloc_debug_init();
+  __libc_globals.mutate(__libc_init_malloc);
   netdClientInit();
 }
 
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 7794fbe..3cda1a2 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -25,17 +25,6 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/*
- * libc_init_static.c
- *
- * The program startup function __libc_init() defined here is
- * used for static executables only (i.e. those that don't depend
- * on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S
- * which is directly invoked by the kernel when the program is launched.
- *
- * The 'structors' parameter contains pointers to various initializer
- * arrays that must be run before the program's 'main' routine is launched.
- */
 
 #include <elf.h>
 #include <errno.h>
@@ -49,16 +38,10 @@
 #include "libc_init_common.h"
 #include "pthread_internal.h"
 
+#include "private/bionic_page.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 
-// Returns the address of the page containing address 'x'.
-#define PAGE_START(x)  ((x) & PAGE_MASK)
-
-// Returns the address of the next page after address 'x', unless 'x' is
-// itself at the start of a page.
-#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
-
 extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
 
 static void call_array(void(**list)()) {
@@ -85,12 +68,24 @@
   }
 }
 
+// The program startup function __libc_init() defined here is
+// used for static executables only (i.e. those that don't depend
+// on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S
+// which is directly invoked by the kernel when the program is launched.
+//
+// The 'structors' parameter contains pointers to various initializer
+// arrays that must be run before the program's 'main' routine is launched.
+
 __noreturn void __libc_init(void* raw_args,
                             void (*onexit)(void) __unused,
                             int (*slingshot)(int, char**, char**),
                             structors_array_t const * const structors) {
   KernelArgumentBlock args(raw_args);
-  __libc_init_tls(args);
+  __libc_init_main_thread(args);
+
+  // Initializing the globals requires TLS to be available for errno.
+  __libc_init_globals(args);
+
   __libc_init_AT_SECURE(args);
   __libc_init_common(args);
 
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index cb0b334..67bb052 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -31,6 +31,7 @@
 
 #include <android/set_abort_message.h>
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
@@ -46,6 +47,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 static pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
 
 __LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
@@ -448,7 +452,6 @@
   return result;
 }
 
-#ifdef TARGET_USES_LOGD
 static int __libc_open_log_socket() {
   // ToDo: Ideally we want this to fail if the gid of the current
   // process is AID_LOGD, but will have to wait until we have
@@ -482,14 +485,70 @@
   return log_fd;
 }
 
+struct cache {
+  const prop_info* pinfo;
+  uint32_t serial;
+  char c;
+};
+
+static void refresh_cache(struct cache *cache, const char *key)
+{
+  if (!cache->pinfo) {
+    cache->pinfo = __system_property_find(key);
+    if (!cache->pinfo) {
+      return;
+    }
+  }
+  uint32_t serial = __system_property_serial(cache->pinfo);
+  if (serial == cache->serial) {
+    return;
+  }
+  cache->serial = serial;
+
+  char buf[PROP_VALUE_MAX];
+  __system_property_read(cache->pinfo, 0, buf);
+  cache->c = buf[0];
+}
+
+// Timestamp state generally remains constant, since a change is
+// rare, we can accept a trylock failure gracefully.
+static pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER;
+
+static clockid_t __android_log_clockid()
+{
+  static struct cache r_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
+  static struct cache p_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
+  char c;
+
+  if (pthread_mutex_trylock(&lock_clockid)) {
+    // We are willing to accept some race in this context
+    if (!(c = p_time_cache.c)) {
+      c = r_time_cache.c;
+    }
+  } else {
+    static uint32_t serial;
+    uint32_t current_serial = __system_property_area_serial();
+    if (current_serial != serial) {
+      refresh_cache(&r_time_cache, "ro.logd.timestamp");
+      refresh_cache(&p_time_cache, "persist.logd.timestamp");
+      serial = current_serial;
+    }
+    if (!(c = p_time_cache.c)) {
+      c = r_time_cache.c;
+    }
+
+    pthread_mutex_unlock(&lock_clockid);
+  }
+
+  return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+}
+
 struct log_time { // Wire format
   uint32_t tv_sec;
   uint32_t tv_nsec;
 };
-#endif
 
 static int __libc_write_log(int priority, const char* tag, const char* msg) {
-#ifdef TARGET_USES_LOGD
   int main_log_fd = __libc_open_log_socket();
   if (main_log_fd == -1) {
     // Try stderr instead.
@@ -504,7 +563,7 @@
   vec[1].iov_base = &tid;
   vec[1].iov_len = sizeof(tid);
   timespec ts;
-  clock_gettime(CLOCK_REALTIME, &ts);
+  clock_gettime(__android_log_clockid(), &ts);
   log_time realtime_ts;
   realtime_ts.tv_sec = ts.tv_sec;
   realtime_ts.tv_nsec = ts.tv_nsec;
@@ -517,24 +576,6 @@
   vec[4].iov_len = strlen(tag) + 1;
   vec[5].iov_base = const_cast<char*>(msg);
   vec[5].iov_len = strlen(msg) + 1;
-#else
-  int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
-  if (main_log_fd == -1) {
-    if (errno == ENOTDIR) {
-      // /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead.
-      return __libc_write_stderr(tag, msg);
-    }
-    return -1;
-  }
-
-  iovec vec[3];
-  vec[0].iov_base = &priority;
-  vec[0].iov_len = 1;
-  vec[1].iov_base = const_cast<char*>(tag);
-  vec[1].iov_len = strlen(tag) + 1;
-  vec[2].iov_base = const_cast<char*>(msg);
-  vec[2].iov_len = strlen(msg) + 1;
-#endif
 
   int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
   close(main_log_fd);
@@ -557,7 +598,6 @@
 }
 
 static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
-#ifdef TARGET_USES_LOGD
   iovec vec[6];
   char log_id = LOG_ID_EVENTS;
   vec[0].iov_base = &log_id;
@@ -566,7 +606,7 @@
   vec[1].iov_base = &tid;
   vec[1].iov_len = sizeof(tid);
   timespec ts;
-  clock_gettime(CLOCK_REALTIME, &ts);
+  clock_gettime(__android_log_clockid(), &ts);
   log_time realtime_ts;
   realtime_ts.tv_sec = ts.tv_sec;
   realtime_ts.tv_nsec = ts.tv_nsec;
@@ -581,17 +621,6 @@
   vec[5].iov_len = len;
 
   int event_log_fd = __libc_open_log_socket();
-#else
-  iovec vec[3];
-  vec[0].iov_base = &tag;
-  vec[0].iov_len = sizeof(tag);
-  vec[1].iov_base = &type;
-  vec[1].iov_len = sizeof(type);
-  vec[2].iov_base = const_cast<void*>(payload);
-  vec[2].iov_len = len;
-
-  int event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY));
-#endif
 
   if (event_log_fd == -1) {
     return -1;
diff --git a/libc/bionic/libgen.cpp b/libc/bionic/libgen.cpp
index 2f29d7b..c415c0f 100644
--- a/libc/bionic/libgen.cpp
+++ b/libc/bionic/libgen.cpp
@@ -39,7 +39,7 @@
 static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_tls_buffer;
 static ThreadLocalBuffer<char, MAXPATHLEN> g_dirname_tls_buffer;
 
-__LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
+static int __basename_r(const char* path, char* buffer, size_t buffer_size) {
   const char* startp = NULL;
   const char* endp = NULL;
   int len;
@@ -91,7 +91,12 @@
   return result;
 }
 
-__LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_size) {
+// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable.
+__LIBC32_LEGACY_PUBLIC__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
+  return __basename_r(path, buffer, buffer_size);
+}
+
+static int __dirname_r(const char* path, char* buffer, size_t buffer_size) {
   const char* endp = NULL;
   int len;
   int result;
@@ -150,14 +155,19 @@
   return result;
 }
 
+// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable.
+__LIBC32_LEGACY_PUBLIC__ int dirname_r(const char* path, char* buffer, size_t buffer_size) {
+  return __dirname_r(path, buffer, buffer_size);
+}
+
 char* basename(const char* path) {
   char* buf = g_basename_tls_buffer.get();
-  int rc = basename_r(path, buf, g_basename_tls_buffer.size());
+  int rc = __basename_r(path, buf, g_basename_tls_buffer.size());
   return (rc < 0) ? NULL : buf;
 }
 
 char* dirname(const char* path) {
   char* buf = g_dirname_tls_buffer.get();
-  int rc = dirname_r(path, buf, g_dirname_tls_buffer.size());
+  int rc = __dirname_r(path, buf, g_dirname_tls_buffer.size());
   return (rc < 0) ? NULL : buf;
 }
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index dee03fa..07186ce 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -47,7 +47,7 @@
 #include <unwind.h>
 
 #include "debug_mapinfo.h"
-#include "debug_stacktrace.h"
+#include "debug_backtrace.h"
 #include "malloc_debug_backtrace.h"
 #include "malloc_debug_common.h"
 #include "malloc_debug_disable.h"
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index ee796c6..9f7f3ba 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -44,6 +44,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "private/bionic_globals.h"
 #include "private/ScopedPthreadMutexLocker.h"
 
 #if defined(USE_JEMALLOC)
@@ -56,33 +57,29 @@
 #error "Either one of USE_DLMALLOC or USE_JEMALLOC must be defined."
 #endif
 
+static constexpr MallocDebug __libc_malloc_default_dispatch
+  __attribute__((unused)) = {
+    Malloc(calloc),
+    Malloc(free),
+    Malloc(mallinfo),
+    Malloc(malloc),
+    Malloc(malloc_usable_size),
+    Malloc(memalign),
+    Malloc(posix_memalign),
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+    Malloc(pvalloc),
+#endif
+    Malloc(realloc),
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+    Malloc(valloc),
+#endif
+  };
+
 // In a VM process, this is set to 1 after fork()ing out of zygote.
 int gMallocLeakZygoteChild = 0;
 
 static HashTable g_hash_table;
 
-// Support for malloc debugging.
-// Table for dispatching malloc calls, initialized with default dispatchers.
-static const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) = {
-  Malloc(calloc),
-  Malloc(free),
-  Malloc(mallinfo),
-  Malloc(malloc),
-  Malloc(malloc_usable_size),
-  Malloc(memalign),
-  Malloc(posix_memalign),
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-  Malloc(pvalloc),
-#endif
-  Malloc(realloc),
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-  Malloc(valloc),
-#endif
-};
-
-// Selector of dispatch table to use for dispatching malloc calls.
-static const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
-
 // Handle to shared library where actual memory allocation is implemented.
 // This library is loaded and memory allocation calls are redirected there
 // when libc.debug.malloc environment variable contains value other than
@@ -244,46 +241,87 @@
 // Allocation functions
 // =============================================================================
 extern "C" void* calloc(size_t n_elements, size_t elem_size) {
-  return __libc_malloc_dispatch->calloc(n_elements, elem_size);
+  auto _calloc = __libc_globals->malloc_dispatch.calloc;
+  if (__predict_false(_calloc != nullptr)) {
+    return _calloc(n_elements, elem_size);
+  }
+  return Malloc(calloc)(n_elements, elem_size);
 }
 
 extern "C" void free(void* mem) {
-  __libc_malloc_dispatch->free(mem);
+  auto _free = __libc_globals->malloc_dispatch.free;
+  if (__predict_false(_free != nullptr)) {
+    _free(mem);
+  } else {
+    Malloc(free)(mem);
+  }
 }
 
 extern "C" struct mallinfo mallinfo() {
-  return __libc_malloc_dispatch->mallinfo();
+  auto _mallinfo = __libc_globals->malloc_dispatch.mallinfo;
+  if (__predict_false(_mallinfo != nullptr)) {
+    return _mallinfo();
+  }
+  return Malloc(mallinfo)();
 }
 
 extern "C" void* malloc(size_t bytes) {
-  return __libc_malloc_dispatch->malloc(bytes);
+  auto _malloc = __libc_globals->malloc_dispatch.malloc;
+  if (__predict_false(_malloc != nullptr)) {
+    return _malloc(bytes);
+  }
+  return Malloc(malloc)(bytes);
 }
 
 extern "C" size_t malloc_usable_size(const void* mem) {
-  return __libc_malloc_dispatch->malloc_usable_size(mem);
+  auto _malloc_usable_size = __libc_globals->malloc_dispatch.malloc_usable_size;
+  if (__predict_false(_malloc_usable_size != nullptr)) {
+    return _malloc_usable_size(mem);
+  }
+  return Malloc(malloc_usable_size)(mem);
 }
 
 extern "C" void* memalign(size_t alignment, size_t bytes) {
-  return __libc_malloc_dispatch->memalign(alignment, bytes);
+  auto _memalign = __libc_globals->malloc_dispatch.memalign;
+  if (__predict_false(_memalign != nullptr)) {
+    return _memalign(alignment, bytes);
+  }
+  return Malloc(memalign)(alignment, bytes);
 }
 
 extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
-  return __libc_malloc_dispatch->posix_memalign(memptr, alignment, size);
+  auto _posix_memalign = __libc_globals->malloc_dispatch.posix_memalign;
+  if (__predict_false(_posix_memalign != nullptr)) {
+    return _posix_memalign(memptr, alignment, size);
+  }
+  return Malloc(posix_memalign)(memptr, alignment, size);
 }
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* pvalloc(size_t bytes) {
-  return __libc_malloc_dispatch->pvalloc(bytes);
+  auto _pvalloc = __libc_globals->malloc_dispatch.pvalloc;
+  if (__predict_false(_pvalloc != nullptr)) {
+    return _pvalloc(bytes);
+  }
+  return Malloc(pvalloc)(bytes);
 }
 #endif
 
-extern "C" void* realloc(void* oldMem, size_t bytes) {
-  return __libc_malloc_dispatch->realloc(oldMem, bytes);
+extern "C" void* realloc(void* old_mem, size_t bytes) {
+  auto _realloc = __libc_globals->malloc_dispatch.realloc;
+  if (__predict_false(_realloc != nullptr)) {
+    return _realloc(old_mem, bytes);
+  }
+  return Malloc(realloc)(old_mem, bytes);
 }
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* valloc(size_t bytes) {
-  return __libc_malloc_dispatch->valloc(bytes);
+  auto _valloc = __libc_globals->malloc_dispatch.valloc;
+  if (__predict_false(_valloc != nullptr)) {
+    return _valloc(bytes);
+  }
+  return Malloc(valloc)(bytes);
 }
 #endif
 
@@ -326,7 +364,7 @@
 }
 
 // Initializes memory allocation framework once per process.
-static void malloc_init_impl() {
+static void malloc_init_impl(libc_globals* globals) {
   const char* so_name = NULL;
   MallocDebugInit malloc_debug_initialize = NULL;
   unsigned int qemu_running = 0;
@@ -442,7 +480,7 @@
 
   // No need to init the dispatch table because we can only get
   // here if debug level is 1, 5, 10, or 20.
-  static MallocDebug malloc_dispatch_table __attribute__((aligned(32)));
+  MallocDebug malloc_dispatch_table;
   switch (g_malloc_debug_level) {
     case 1:
       InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak");
@@ -480,24 +518,25 @@
               getprogname(), g_malloc_debug_level);
     dlclose(malloc_impl_handle);
   } else {
-    __libc_malloc_dispatch = &malloc_dispatch_table;
+    globals->malloc_dispatch = malloc_dispatch_table;
     libc_malloc_impl_handle = malloc_impl_handle;
   }
 }
 
 static void malloc_fini_impl() {
-  // Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
-  // And it doesn't do that until its atexit handler is run, and we run first!
-  // It's great that other unclosed FILE*s show up as malloc leaks, but we need to manually
-  // clean up the standard streams ourselves.
-  fclose(stdin);
-  fclose(stdout);
-  fclose(stderr);
-
   if (libc_malloc_impl_handle != NULL) {
     MallocDebugFini malloc_debug_finalize =
       reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle, "malloc_debug_finalize"));
     if (malloc_debug_finalize != NULL) {
+      // Our BSD stdio implementation doesn't close the standard streams,
+      // it only flushes them. And it doesn't do that until its atexit
+      // handler is run, and we run first! It's great that other unclosed
+      // FILE*s show up as malloc leaks, but we need to manually clean up
+      // the standard streams ourselves.
+      fclose(stdin);
+      fclose(stdout);
+      fclose(stderr);
+
       malloc_debug_finalize(g_malloc_debug_level);
     }
   }
@@ -506,15 +545,12 @@
 #endif  // !LIBC_STATIC
 
 // Initializes memory allocation framework.
-// This routine is called from __libc_init routines implemented
-// in libc_init_static.c and libc_init_dynamic.c files.
-extern "C" __LIBC_HIDDEN__ void malloc_debug_init() {
+// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
+__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
+  (void)globals;
 #if !defined(LIBC_STATIC)
-  static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
-  if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
-    error_log("Unable to initialize malloc_debug component.");
-  }
-#endif  // !LIBC_STATIC
+  malloc_init_impl(globals);
+#endif
 }
 
 extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() {
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
index 5c73da3..f8745da 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 
 #include "private/bionic_config.h"
+#include "private/bionic_malloc_dispatch.h"
 #include "private/libc_logging.h"
 
 #define HASHTABLE_SIZE      1543
@@ -72,39 +73,6 @@
     HashEntry* slots[HASHTABLE_SIZE];
 };
 
-/* Entry in malloc dispatch table. */
-typedef void* (*MallocDebugCalloc)(size_t, size_t);
-typedef void (*MallocDebugFree)(void*);
-typedef struct mallinfo (*MallocDebugMallinfo)();
-typedef void* (*MallocDebugMalloc)(size_t);
-typedef size_t (*MallocDebugMallocUsableSize)(const void*);
-typedef void* (*MallocDebugMemalign)(size_t, size_t);
-typedef int (*MallocDebugPosixMemalign)(void**, size_t, size_t);
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-typedef void* (*MallocDebugPvalloc)(size_t);
-#endif
-typedef void* (*MallocDebugRealloc)(void*, size_t);
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-typedef void* (*MallocDebugValloc)(size_t);
-#endif
-
-struct MallocDebug {
-  MallocDebugCalloc calloc;
-  MallocDebugFree free;
-  MallocDebugMallinfo mallinfo;
-  MallocDebugMalloc malloc;
-  MallocDebugMallocUsableSize malloc_usable_size;
-  MallocDebugMemalign memalign;
-  MallocDebugPosixMemalign posix_memalign;
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-  MallocDebugPvalloc pvalloc;
-#endif
-  MallocDebugRealloc realloc;
-#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-  MallocDebugValloc valloc;
-#endif
-};
-
 typedef bool (*MallocDebugInit)(HashTable*, const MallocDebug*);
 typedef void (*MallocDebugFini)(int);
 
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 6a46667..1ffbee2 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -46,7 +46,7 @@
 #include <unistd.h>
 #include <unwind.h>
 
-#include "debug_stacktrace.h"
+#include "debug_backtrace.h"
 #include "malloc_debug_backtrace.h"
 #include "malloc_debug_common.h"
 #include "malloc_debug_disable.h"
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index fa40b35..b01cef2 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -612,7 +612,7 @@
         error_log("Unable to open /dev/qemu_trace");
         return false;
     } else {
-        qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        qtrace = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
         close(fd);
 
         if (qtrace == MAP_FAILED) {
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index 8f25a89..57a8cdf 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -27,9 +27,11 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
+#include "private/bionic_macros.h"
 #include "private/ErrnoRestorer.h"
 
 // mmap2(2) is like mmap(2), but the offset is in 4096-byte blocks, not bytes.
@@ -45,10 +47,21 @@
     return MAP_FAILED;
   }
 
-  bool is_private_anonymous = (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) != 0;
+  // prevent allocations large enough for `end - start` to overflow
+  size_t rounded = BIONIC_ALIGN(size, PAGE_SIZE);
+  if (rounded < size || rounded > PTRDIFF_MAX) {
+    errno = ENOMEM;
+    return MAP_FAILED;
+  }
+
+  bool is_private_anonymous =
+      (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
+  bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
+
   void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
 
-  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE && is_private_anonymous) {
+  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
+      is_private_anonymous && !is_stack_or_grows_down) {
     ErrnoRestorer errno_restorer;
     int rc = madvise(result, size, MADV_MERGEABLE);
     if (rc == -1 && errno == EINVAL) {
diff --git a/libc/bionic/ioctl.c b/libc/bionic/mremap.cpp
similarity index 61%
copy from libc/bionic/ioctl.c
copy to libc/bionic/mremap.cpp
index 6dd95d0..6653d43 100644
--- a/libc/bionic/ioctl.c
+++ b/libc/bionic/mremap.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,19 +25,33 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#include <errno.h>
+#include <sys/mman.h>
 #include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
 
-extern int __ioctl(int, int, void *);
+#include "private/bionic_macros.h"
 
-int ioctl(int fd, int request, ...)
-{
+extern "C" void* ___mremap(void*, size_t, size_t, int, void*);
+
+void* mremap(void* old_address, size_t old_size, size_t new_size, int flags, ...) {
+  // prevent allocations large enough for `end - start` to overflow
+  size_t rounded = BIONIC_ALIGN(new_size, PAGE_SIZE);
+  if (rounded < new_size || rounded > PTRDIFF_MAX) {
+    errno = ENOMEM;
+    return MAP_FAILED;
+  }
+
+  void* new_address = nullptr;
+  // The optional argument is only valid if the MREMAP_FIXED flag is set,
+  // so we assume it's not present otherwise.
+  if ((flags & MREMAP_FIXED) != 0) {
     va_list ap;
-    void * arg;
-
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
+    va_start(ap, flags);
+    new_address = va_arg(ap, void*);
     va_end(ap);
-
-    return __ioctl(fd, request, arg);
+  }
+  return ___mremap(old_address, old_size, new_size, flags, new_address);
 }
-
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index b299684..dfd0e68 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -47,34 +47,34 @@
 
 #include "private/libc_logging.h"
 
-// The part is only for 32-bit targets.
-#if !defined(__LP64__)
+extern "C" {
+
+// Brillo and LP64 don't need to support any legacy cruft.
+#if !defined(__BRILLO__) && !defined(__LP64__)
 
 // These were accidentally declared in <unistd.h> because we stupidly used to inline
 // getpagesize() and __getpageshift(). Needed for backwards compatibility with old NDK apps.
-extern "C" {
-  unsigned int __page_size = PAGE_SIZE;
-  unsigned int __page_shift = 12;
-}
+unsigned int __page_size = PAGE_SIZE;
+unsigned int __page_shift = 12;
 
 // TODO: remove this backward compatibility hack (for jb-mr1 strace binaries).
-extern "C" pid_t __wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
+pid_t __wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
   return wait4(pid, status, options, rusage);
 }
 
 // TODO: does anything still need this?
-extern "C" int __open() {
+int __open() {
   abort();
 }
 
 // TODO: does anything still need this?
-extern "C" void** __get_tls() {
+void** __get_tls() {
 #include "private/__get_tls.h"
   return __get_tls();
 }
 
 // This non-standard function was in our <string.h> for some reason.
-extern "C" void memswap(void* m1, void* m2, size_t n) {
+void memswap(void* m1, void* m2, size_t n) {
   char* p = reinterpret_cast<char*>(m1);
   char* p_end = p + n;
   char* q = reinterpret_cast<char*>(m2);
@@ -87,13 +87,13 @@
   }
 }
 
-extern "C" int pthread_attr_setstackaddr(pthread_attr_t*, void*) {
+int pthread_attr_setstackaddr(pthread_attr_t*, void*) {
   // This was removed from POSIX.1-2008, and is not implemented on bionic.
   // Needed for ABI compatibility with the NDK.
   return ENOSYS;
 }
 
-extern "C" int pthread_attr_getstackaddr(const pthread_attr_t* attr, void** stack_addr) {
+int pthread_attr_getstackaddr(const pthread_attr_t* attr, void** stack_addr) {
   // This was removed from POSIX.1-2008.
   // Needed for ABI compatibility with the NDK.
   *stack_addr = (char*)attr->stack_base + attr->stack_size;
@@ -101,7 +101,7 @@
 }
 
 // Non-standard cruft that should only ever have been in system/core/toolbox.
-extern "C" char* strtotimeval(const char* str, struct timeval* ts) {
+char* strtotimeval(const char* str, struct timeval* ts) {
   char* s;
   ts->tv_sec = strtoumax(str, &s, 10);
 
@@ -143,7 +143,7 @@
 }
 
 // This non-standard function was in our <inttypes.h> for some reason.
-extern "C" uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) {
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) {
   const unsigned char*  p   = (const unsigned char *)nptr;
   const unsigned char*  end = p + n;
   int                   minus = 0;
@@ -191,12 +191,12 @@
 }
 
 // This non-standard function was in our <inttypes.h> for some reason.
-extern "C" intmax_t strntoimax(const char* nptr, char** endptr, int base, size_t n) {
+intmax_t strntoimax(const char* nptr, char** endptr, int base, size_t n) {
   return (intmax_t) strntoumax(nptr, endptr, base, n);
 }
 
 // POSIX calls this dprintf, but LP32 Android had fdprintf instead.
-extern "C" int fdprintf(int fd, const char* fmt, ...) {
+int fdprintf(int fd, const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   int rc = vdprintf(fd, fmt, ap);
@@ -205,7 +205,7 @@
 }
 
 // POSIX calls this vdprintf, but LP32 Android had fdprintf instead.
-extern "C" int vfdprintf(int fd, const char* fmt, va_list ap) {
+int vfdprintf(int fd, const char* fmt, va_list ap) {
   return vdprintf(fd, fmt, ap);
 }
 
@@ -216,64 +216,64 @@
 #undef __futex_wait
 
 // This used to be in <sys/atomics.h>.
-extern "C" int __futex_wake(volatile void* ftx, int count) {
+int __futex_wake(volatile void* ftx, int count) {
   return __real_futex_wake(ftx, count);
 }
 
 // This used to be in <sys/atomics.h>.
-extern "C" int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
+int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
   return __real_futex_wait(ftx, value, timeout);
 }
 
 // Unity's libmono uses this.
-extern "C" int tkill(pid_t tid, int sig) {
+int tkill(pid_t tid, int sig) {
   return syscall(__NR_tkill, tid, sig);
 }
 
 // This was removed from POSIX 2008.
-extern "C" wchar_t* wcswcs(wchar_t* haystack, wchar_t* needle) {
+wchar_t* wcswcs(wchar_t* haystack, wchar_t* needle) {
   return wcsstr(haystack, needle);
 }
 
 // This was removed from POSIX 2008.
-extern "C" sighandler_t bsd_signal(int signum, sighandler_t handler) {
+sighandler_t bsd_signal(int signum, sighandler_t handler) {
   return signal(signum, handler);
 }
 
 #if !defined(__i386__)
 // This was removed from POSIX 2008.
 #undef bcopy
-extern "C" void bcopy(const void* src, void* dst, size_t n) {
-  memcpy(dst, src, n);
+void bcopy(const void* src, void* dst, size_t n) {
+  memmove(dst, src, n);
 }
 #else
 // x86 has an assembler implementation.
 #endif
 
 // sysv_signal() was never in POSIX.
-extern sighandler_t _signal(int signum, sighandler_t handler, int flags);
-extern "C" sighandler_t sysv_signal(int signum, sighandler_t handler) {
+extern "C++" sighandler_t _signal(int signum, sighandler_t handler, int flags);
+sighandler_t sysv_signal(int signum, sighandler_t handler) {
   return _signal(signum, handler, SA_RESETHAND);
 }
 
 // This is a system call that was never in POSIX. Use readdir(3) instead.
-extern "C" int __getdents64(unsigned int, dirent*, unsigned int);
-extern "C" int getdents(unsigned int fd, dirent* dirp, unsigned int count) {
+int __getdents64(unsigned int, dirent*, unsigned int);
+int getdents(unsigned int fd, dirent* dirp, unsigned int count) {
   return __getdents64(fd, dirp, count);
 }
 
 // This is a BSDism that we never implemented correctly. Used by Firefox.
-extern "C" int issetugid() {
+int issetugid() {
   return 0;
 }
 
 // This was removed from POSIX 2004.
-extern "C" pid_t wait3(int* status, int options, struct rusage* rusage) {
+pid_t wait3(int* status, int options, struct rusage* rusage) {
   return wait4(-1, status, options, rusage);
 }
 
 // This was removed from POSIX 2004.
-extern "C" int getdtablesize() {
+int getdtablesize() {
   struct rlimit r;
 
   if (getrlimit(RLIMIT_NOFILE, &r) < 0) {
@@ -283,6 +283,10 @@
   return r.rlim_cur;
 }
 
+// A leaked BSD stdio implementation detail that's now a no-op.
+void __sinit() {}
+int __sdidinit = 1;
+
 // Only used by ftime, which was removed from POSIX 2008.
 struct timeb {
   time_t          time;
@@ -292,7 +296,7 @@
 };
 
 // This was removed from POSIX 2008.
-extern "C" int ftime(struct timeb* tb) {
+int ftime(struct timeb* tb) {
   struct timeval  tv;
   struct timezone tz;
 
@@ -314,35 +318,42 @@
 }
 
 // This was removed from POSIX 2008.
-extern "C" char* index(const char* str, int ch) {
+char* index(const char* str, int ch) {
   return strchr(str, ch);
 }
 
 // This was removed from BSD.
-extern "C" void arc4random_stir(void) {
+void arc4random_stir(void) {
   // The current implementation stirs itself as needed.
 }
 
 // This was removed from BSD.
-extern "C" void arc4random_addrandom(unsigned char*, int) {
+void arc4random_addrandom(unsigned char*, int) {
   // The current implementation adds randomness as needed.
 }
 
 // Old versions of the NDK did not export malloc_usable_size, but did
 // export dlmalloc_usable_size. We are moving away from dlmalloc in L
 // so make this call malloc_usable_size.
-extern "C" size_t dlmalloc_usable_size(void* ptr) {
+size_t dlmalloc_usable_size(void* ptr) {
   return malloc_usable_size(ptr);
 }
 
 // In L we added a public pthread_gettid_np, but some apps were using the private API.
-extern "C" pid_t __pthread_gettid(pthread_t t) {
+pid_t __pthread_gettid_libc(pthread_t t) {
   return pthread_gettid_np(t);
 }
 
+pid_t __pthread_gettid_libc_private(pthread_t t) {
+  return pthread_gettid_np(t);
+}
+
+__asm__(".symver __pthread_gettid_libc,__pthread_gettid@LIBC");
+__asm__(".symver __pthread_gettid_libc_private,__pthread_gettid@@LIBC_PRIVATE");
+
 // 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) {
+void* dlmalloc(size_t size) {
   return malloc(size);
 }
 
@@ -350,45 +361,39 @@
 #include "pthread_internal.h"
 #undef __get_thread
 // Various third-party apps contain a backport of our pthread_rwlock implementation that uses this.
-extern "C" pthread_internal_t* __get_thread() {
+pthread_internal_t* __get_thread() {
   return __real_get_thread();
 }
 
-#endif // !defined(__LP64__)
-
-// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
-extern "C" char* getusershell() {
-  return NULL;
+// This one exists only for the LP32 NDK and is not present anywhere else.
+extern long __set_errno_internal(int);
+long __set_errno(int n) {
+  return __set_errno_internal(n);
 }
 
-// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
-extern "C" void setusershell() { }
-
-// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
-extern "C" void endusershell() { }
-
-// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
-extern "C" void endpwent() { }
+// This was never implemented in bionic, only needed for ABI compatibility with the NDK.
+// In the M time frame, over 1000 apps have a reference to this!
+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*) {
+void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
+}
+int dlmalloc_trim(size_t) {
+    return 0;
 }
 #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) {
+void dlmalloc_inspect_all_real(void (*)(void*, void*, size_t, void*), void*);
+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) {
+int dlmalloc_trim_real(size_t);
+int dlmalloc_trim(size_t pad) {
   return dlmalloc_trim_real(pad);
 }
 #endif
+
+#endif // !defined(__BRILLO__) && !defined (__LP64__)
+
+} // extern "C"
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 093ffd2..2200a6c 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -45,7 +45,7 @@
 
 class atfork_list_t {
  public:
-  atfork_list_t() : first_(nullptr), last_(nullptr) {}
+  constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
 
   template<typename F>
   void walk_forward(F f) {
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index 7ad3431..cfa58fc 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -114,6 +114,36 @@
   return 0;
 }
 
+static uintptr_t __get_main_stack_startstack() {
+  FILE* fp = fopen("/proc/self/stat", "re");
+  if (fp == nullptr) {
+    __libc_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
+  }
+
+  char line[BUFSIZ];
+  if (fgets(line, sizeof(line), fp) == nullptr) {
+    __libc_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
+  }
+
+  fclose(fp);
+
+  // See man 5 proc. There's no reason comm can't contain ' ' or ')',
+  // so we search backwards for the end of it. We're looking for this field:
+  //
+  //  startstack %lu (28) The address of the start (i.e., bottom) of the stack.
+  uintptr_t startstack = 0;
+  const char* end_of_comm = strrchr(line, ')');
+  if (sscanf(end_of_comm + 1, " %*c "
+             "%*d %*d %*d %*d %*d "
+             "%*u %*u %*u %*u %*u %*u %*u "
+             "%*d %*d %*d %*d %*d %*d "
+             "%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) {
+    __libc_fatal("couldn't parse /proc/self/stat");
+  }
+
+  return startstack;
+}
+
 static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_size) {
   ErrnoRestorer errno_restorer;
 
@@ -127,20 +157,19 @@
     stack_limit.rlim_cur = 8 * 1024 * 1024;
   }
 
-  // It shouldn't matter which thread we are because we're just looking for "[stack]", but
-  // valgrind seems to mess with the stack enough that the kernel will report "[stack:pid]"
-  // instead if you look in /proc/self/maps, so we need to look in /proc/pid/task/pid/maps.
-  char path[64];
-  snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid());
-  FILE* fp = fopen(path, "re");
-  if (fp == NULL) {
-    return errno;
+  // Ask the kernel where our main thread's stack started.
+  uintptr_t startstack = __get_main_stack_startstack();
+
+  // Hunt for the region that contains that address.
+  FILE* fp = fopen("/proc/self/maps", "re");
+  if (fp == nullptr) {
+    __libc_fatal("couldn't open /proc/self/maps");
   }
   char line[BUFSIZ];
   while (fgets(line, sizeof(line), fp) != NULL) {
-    if (ends_with(line, " [stack]\n")) {
-      uintptr_t lo, hi;
-      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) {
+    uintptr_t lo, hi;
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) {
+      if (lo <= startstack && startstack <= hi) {
         *stack_size = stack_limit.rlim_cur;
         *stack_base = reinterpret_cast<void*>(hi - *stack_size);
         fclose(fp);
@@ -148,7 +177,7 @@
       }
     }
   }
-  __libc_fatal("No [stack] line found in \"%s\"!", path);
+  __libc_fatal("Stack not found in /proc/self/maps");
 }
 
 int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
diff --git a/libc/bionic/pthread_barrier.cpp b/libc/bionic/pthread_barrier.cpp
new file mode 100644
index 0000000..1bcd12a
--- /dev/null
+++ b/libc/bionic/pthread_barrier.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 <pthread.h>
+#include <stdatomic.h>
+#include <stdint.h>
+
+#include "private/bionic_futex.h"
+
+int pthread_barrierattr_init(pthread_barrierattr_t* attr) {
+  *attr = 0;
+  return 0;
+}
+
+int pthread_barrierattr_destroy(pthread_barrierattr_t* attr) {
+  *attr = 0;
+  return 0;
+}
+
+int pthread_barrierattr_getpshared(pthread_barrierattr_t* attr, int* pshared) {
+  *pshared = (*attr & 1) ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int pthread_barrierattr_setpshared(pthread_barrierattr_t* attr, int pshared) {
+  if (pshared == PTHREAD_PROCESS_SHARED) {
+    *attr |= 1;
+  } else {
+    *attr &= ~1;
+  }
+  return 0;
+}
+
+enum BarrierState {
+  WAIT,
+  RELEASE,
+};
+
+struct pthread_barrier_internal_t {
+  // One barrier can be used for unlimited number of cycles. In each cycle, [init_count]
+  // threads must call pthread_barrier_wait() before any of them successfully return from
+  // the call. It is undefined behavior if there are more than [init_count] threads call
+  // pthread_barrier_wait() in one cycle.
+  uint32_t init_count;
+  // Barrier state. It is WAIT if waiting for more threads to enter the barrier in this cycle,
+  // otherwise threads are leaving the barrier.
+  _Atomic(BarrierState) state;
+  // Number of threads having entered but not left the barrier in this cycle.
+  atomic_uint wait_count;
+  // Whether the barrier is shared across processes.
+  bool pshared;
+  uint32_t __reserved[4];
+};
+
+static_assert(sizeof(pthread_barrier_t) == sizeof(pthread_barrier_internal_t),
+              "pthread_barrier_t should actually be pthread_barrier_internal_t in implementation."
+              );
+
+static_assert(alignof(pthread_barrier_t) >= 4,
+              "pthread_barrier_t should fulfill the alignment of pthread_barrier_internal_t.");
+
+static inline pthread_barrier_internal_t* __get_internal_barrier(pthread_barrier_t* barrier) {
+  return reinterpret_cast<pthread_barrier_internal_t*>(barrier);
+}
+
+int pthread_barrier_init(pthread_barrier_t* barrier_interface, const pthread_barrierattr_t* attr,
+                         unsigned count) {
+  pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface);
+  if (count == 0) {
+    return EINVAL;
+  }
+  barrier->init_count = count;
+  atomic_init(&barrier->state, WAIT);
+  atomic_init(&barrier->wait_count, 0);
+  barrier->pshared = false;
+  if (attr != nullptr && (*attr & 1)) {
+    barrier->pshared = true;
+  }
+  return 0;
+}
+
+// According to POSIX standard, pthread_barrier_wait() synchronizes memory between participating
+// threads. It means all memory operations made by participating threads before calling
+// pthread_barrier_wait() can be seen by all participating threads after the function call.
+// We establish this by making a happens-before relation between all threads entering the barrier
+// with the last thread entering the barrier, and a happens-before relation between the last
+// thread entering the barrier with all threads leaving the barrier.
+int pthread_barrier_wait(pthread_barrier_t* barrier_interface) {
+  pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface);
+
+  // Wait until all threads for the previous cycle have left the barrier. This is needed
+  // as a participating thread can call pthread_barrier_wait() again before other
+  // threads have left the barrier. Use acquire operation here to synchronize with
+  // the last thread leaving the previous cycle, so we can read correct wait_count below.
+  while(atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
+  }
+
+  uint32_t prev_wait_count = atomic_load_explicit(&barrier->wait_count, memory_order_relaxed);
+  while (true) {
+    // It happens when there are more than [init_count] threads trying to enter the barrier
+    // at one cycle. We read the POSIX standard as disallowing this, since additional arriving
+    // threads are not synchronized with respect to the barrier reset. We also don't know of
+    // any reasonable cases in which this would be intentional.
+    if (prev_wait_count >= barrier->init_count) {
+      return EINVAL;
+    }
+    // Use memory_order_acq_rel operation here to synchronize between all threads entering
+    // the barrier with the last thread entering the barrier.
+    if (atomic_compare_exchange_weak_explicit(&barrier->wait_count, &prev_wait_count,
+                                              prev_wait_count + 1u, memory_order_acq_rel,
+                                              memory_order_relaxed)) {
+      break;
+    }
+  }
+
+  int result = 0;
+  if (prev_wait_count + 1 == barrier->init_count) {
+    result = PTHREAD_BARRIER_SERIAL_THREAD;
+    if (prev_wait_count != 0) {
+      // Use release operation here to synchronize between the last thread entering the
+      // barrier with all threads leaving the barrier.
+      atomic_store_explicit(&barrier->state, RELEASE, memory_order_release);
+      __futex_wake_ex(&barrier->state, barrier->pshared, prev_wait_count);
+    }
+  } else {
+    // Use acquire operation here to synchronize between the last thread entering the
+    // barrier with all threads leaving the barrier.
+    while (atomic_load_explicit(&barrier->state, memory_order_acquire) == WAIT) {
+      __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, false, nullptr);
+    }
+  }
+  // Use release operation here to make it not reordered with previous operations.
+  if (atomic_fetch_sub_explicit(&barrier->wait_count, 1, memory_order_release) == 1) {
+    // Use release operation here to synchronize with threads entering the barrier for
+    // the next cycle, or the thread calling pthread_barrier_destroy().
+    atomic_store_explicit(&barrier->state, WAIT, memory_order_release);
+    __futex_wake_ex(&barrier->state, barrier->pshared, barrier->init_count);
+  }
+  return result;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier_interface) {
+  pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface);
+  if (barrier->init_count == 0) {
+    return EINVAL;
+  }
+  // Use acquire operation here to synchronize with the last thread leaving the barrier.
+  // So we can read correct wait_count below.
+  while (atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
+  }
+  if (atomic_load_explicit(&barrier->wait_count, memory_order_relaxed) != 0) {
+    return EBUSY;
+  }
+  barrier->init_count = 0;
+  return 0;
+}
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index 4a69da5..d36426c 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -111,8 +111,8 @@
     return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed));
   }
 
-  int get_clock() {
-    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed));
+  bool use_realtime_clock() {
+    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed)) == CLOCK_REALTIME;
   }
 
 #if defined(__LP64__)
@@ -170,12 +170,17 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                             const timespec* rel_timeout_or_null) {
-  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
+                                    bool use_realtime_clock, const timespec* abs_timeout_or_null) {
+  int result = check_timespec(abs_timeout_or_null, true);
+  if (result != 0) {
+    return result;
+  }
 
+  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
   pthread_mutex_unlock(mutex);
-  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, rel_timeout_or_null);
+  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
+                               use_realtime_clock, abs_timeout_or_null);
   pthread_mutex_lock(mutex);
 
   if (status == -ETIMEDOUT) {
@@ -184,21 +189,6 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                    const timespec* abs_timeout_or_null, clockid_t clock) {
-  timespec ts;
-  timespec* rel_timeout = NULL;
-
-  if (abs_timeout_or_null != NULL) {
-    rel_timeout = &ts;
-    if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-      return ETIMEDOUT;
-    }
-  }
-
-  return __pthread_cond_timedwait_relative(cond, mutex, rel_timeout);
-}
-
 int pthread_cond_broadcast(pthread_cond_t* cond_interface) {
   return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX);
 }
@@ -209,14 +199,14 @@
 
 int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) {
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, NULL, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, false, nullptr);
 }
 
 int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex,
                            const timespec *abstime) {
 
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, abstime, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
 }
 
 #if !defined(__LP64__)
@@ -225,8 +215,7 @@
                                                 pthread_mutex_t* mutex,
                                                 const timespec* abs_timeout) {
 
-  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, abs_timeout,
-                                  CLOCK_MONOTONIC);
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
 }
 
 extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
@@ -238,8 +227,13 @@
 extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
                                                   pthread_mutex_t* mutex,
                                                   const timespec* rel_timeout) {
-
-  return __pthread_cond_timedwait_relative(__get_internal_cond(cond_interface), mutex, rel_timeout);
+  timespec ts;
+  timespec* abs_timeout = nullptr;
+  if (rel_timeout != nullptr) {
+    absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_REALTIME);
+    abs_timeout = &ts;
+  }
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout);
 }
 
 extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index dbdb180..34826db 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -53,13 +53,6 @@
 
 // This code is used both by each new pthread and the code that initializes the main thread.
 void __init_tls(pthread_internal_t* thread) {
-  if (thread->mmap_size == 0) {
-    // If the TLS area was not allocated by mmap(), it may not have been cleared to zero.
-    // So assume the worst and zero the TLS area.
-    memset(thread->tls, 0, sizeof(thread->tls));
-    memset(thread->key_data, 0, sizeof(thread->key_data));
-  }
-
   // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
   thread->tls[TLS_SLOT_SELF] = thread->tls;
   thread->tls[TLS_SLOT_THREAD_ID] = thread;
@@ -87,6 +80,7 @@
     // We can only use const static allocated string for mapped region name, as Android kernel
     // uses the string pointer directly when dumping /proc/pid/maps.
     prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
+    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, stack_base, PAGE_SIZE, "thread signal stack guard page");
   }
 }
 
@@ -140,6 +134,7 @@
     munmap(space, mmap_size);
     return NULL;
   }
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, space, stack_guard_size, "thread stack guard page");
 
   return space;
 }
@@ -173,6 +168,11 @@
                 (reinterpret_cast<uintptr_t>(stack_top) - sizeof(pthread_internal_t)) & ~0xf);
 
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
+  if (mmap_size == 0) {
+    // If thread was not allocated by mmap(), it may not have been cleared to zero.
+    // So assume the worst and zero it.
+    memset(thread, 0, sizeof(pthread_internal_t));
+  }
   attr->stack_size = stack_top - reinterpret_cast<uint8_t*>(attr->stack_base);
 
   thread->mmap_size = mmap_size;
@@ -191,8 +191,7 @@
   // notify gdb about this thread before we start doing anything.
   // This also provides the memory barrier needed to ensure that all memory
   // accesses previously made by the creating thread are visible to us.
-  pthread_mutex_lock(&thread->startup_handshake_mutex);
-  pthread_mutex_destroy(&thread->startup_handshake_mutex);
+  thread->startup_handshake_lock.lock();
 
   __init_alternate_signal_stack(thread);
 
@@ -231,14 +230,14 @@
     return result;
   }
 
-  // Create a mutex for the thread in TLS to wait on once it starts so we can keep
+  // Create a lock for the thread to wait on once it starts so we can keep
   // it from doing anything until after we notify the debugger about it
   //
   // This also provides the memory barrier we need to ensure that all
   // memory accesses previously performed by this thread are visible to
   // the new thread.
-  pthread_mutex_init(&thread->startup_handshake_mutex, NULL);
-  pthread_mutex_lock(&thread->startup_handshake_mutex);
+  thread->startup_handshake_lock.init(false);
+  thread->startup_handshake_lock.lock();
 
   thread->start_routine = start_routine;
   thread->start_routine_arg = arg;
@@ -261,7 +260,7 @@
     // We don't have to unlock the mutex at all because clone(2) failed so there's no child waiting to
     // be unblocked, but we're about to unmap the memory the mutex is stored in, so this serves as a
     // reminder that you can't rewrite this function to use a ScopedPthreadMutexLocker.
-    pthread_mutex_unlock(&thread->startup_handshake_mutex);
+    thread->startup_handshake_lock.unlock();
     if (thread->mmap_size != 0) {
       munmap(thread->attr.stack_base, thread->mmap_size);
     }
@@ -276,13 +275,13 @@
     atomic_store(&thread->join_state, THREAD_DETACHED);
     __pthread_internal_add(thread);
     thread->start_routine = __do_nothing;
-    pthread_mutex_unlock(&thread->startup_handshake_mutex);
+    thread->startup_handshake_lock.unlock();
     return init_errno;
   }
 
   // Publish the pthread_t and unlock the mutex to let the new thread start running.
   *thread_out = __pthread_internal_add(thread);
-  pthread_mutex_unlock(&thread->startup_handshake_mutex);
+  thread->startup_handshake_lock.unlock();
 
   return 0;
 }
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 6a39a21..e8be4ae 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -31,6 +31,7 @@
 #include <pthread.h>
 #include <stdatomic.h>
 
+#include "private/bionic_lock.h"
 #include "private/bionic_tls.h"
 
 /* Has the thread been detached by a pthread_join or pthread_detach call? */
@@ -39,7 +40,8 @@
 /* Has the thread been joined by another thread? */
 #define PTHREAD_ATTR_FLAG_JOINED 0x00000002
 
-struct pthread_key_data_t {
+class pthread_key_data_t {
+ public:
   uintptr_t seq; // Use uintptr_t just for alignment, as we use pointer below.
   void* data;
 };
@@ -51,9 +53,12 @@
   THREAD_DETACHED
 };
 
-struct pthread_internal_t {
-  struct pthread_internal_t* next;
-  struct pthread_internal_t* prev;
+class thread_local_dtor;
+
+class pthread_internal_t {
+ public:
+  class pthread_internal_t* next;
+  class pthread_internal_t* prev;
 
   pid_t tid;
 
@@ -89,10 +94,12 @@
 
   void* alternate_signal_stack;
 
-  pthread_mutex_t startup_handshake_mutex;
+  Lock startup_handshake_lock;
 
   size_t mmap_size;
 
+  thread_local_dtor* thread_local_dtors;
+
   void* tls[BIONIC_TLS_SLOTS];
 
   pthread_key_data_t key_data[BIONIC_PTHREAD_KEY_COUNT];
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 851fc3d..7d8e8a8 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -166,11 +166,14 @@
 #define  MUTEX_STATE_BITS_LOCKED_UNCONTENDED  MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_UNCONTENDED)
 #define  MUTEX_STATE_BITS_LOCKED_CONTENDED    MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_CONTENDED)
 
-/* return true iff the mutex if locked with no waiters */
-#define  MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v)  (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED)
+// Return true iff the mutex is unlocked.
+#define MUTEX_STATE_BITS_IS_UNLOCKED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_UNLOCKED)
 
-/* return true iff the mutex if locked with maybe waiters */
-#define  MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v)   (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED)
+// Return true iff the mutex is locked with no waiters.
+#define MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v)  (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED)
+
+// return true iff the mutex is locked with maybe waiters.
+#define MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v)   (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED)
 
 /* used to flip from LOCKED_UNCONTENDED to LOCKED_CONTENDED */
 #define  MUTEX_STATE_BITS_FLIP_CONTENTION(v)      ((v) ^ (MUTEX_STATE_BITS_LOCKED_CONTENDED ^ MUTEX_STATE_BITS_LOCKED_UNCONTENDED))
@@ -296,11 +299,15 @@
  */
 static inline __always_inline int __pthread_normal_mutex_lock(pthread_mutex_internal_t* mutex,
                                                               uint16_t shared,
-                                                              const timespec* abs_timeout_or_null,
-                                                              clockid_t clock) {
+                                                              bool use_realtime_clock,
+                                                              const timespec* abs_timeout_or_null) {
     if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) {
         return 0;
     }
+    int result = check_timespec(abs_timeout_or_null, true);
+    if (result != 0) {
+        return result;
+    }
 
     ScopedTrace trace("Contending for pthread mutex");
 
@@ -317,15 +324,8 @@
     // made by other threads visible to the current CPU.
     while (atomic_exchange_explicit(&mutex->state, locked_contended,
                                     memory_order_acquire) != unlocked) {
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
-        }
-        if (__futex_wait_ex(&mutex->state, shared, locked_contended, rel_timeout) == -ETIMEDOUT) {
+        if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,
+                            abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
     }
@@ -396,14 +396,15 @@
                                                       pthread_mutex_internal_t* mutex,
                                                       uint16_t shared,
                                                       uint16_t old_state,
-                                                      const timespec* rel_timeout) {
+                                                      bool use_realtime_clock,
+                                                      const timespec* abs_timeout) {
 // __futex_wait always waits on a 32-bit value. But state is 16-bit. For a normal mutex, the owner_tid
 // field in mutex is not used. On 64-bit devices, the __pad field in mutex is not used.
 // But when a recursive or errorcheck mutex is used on 32-bit devices, we need to add the
 // owner_tid value in the value argument for __futex_wait, otherwise we may always get EAGAIN error.
 
 #if defined(__LP64__)
-  return __futex_wait_ex(&mutex->state, shared, old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, old_state, use_realtime_clock, abs_timeout);
 
 #else
   // This implementation works only when the layout of pthread_mutex_internal_t matches below expectation.
@@ -412,19 +413,21 @@
   static_assert(offsetof(pthread_mutex_internal_t, owner_tid) == 2, "");
 
   uint32_t owner_tid = atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed);
-  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state,
+                         use_realtime_clock, abs_timeout);
 #endif
 }
 
 static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,
-                                           const timespec* abs_timeout_or_null, clockid_t clock) {
+                                             bool use_realtime_clock,
+                                             const timespec* abs_timeout_or_null) {
     uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
     uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
     uint16_t shared = (old_state & MUTEX_SHARED_MASK);
 
     // Handle common case first.
     if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) {
-        return __pthread_normal_mutex_lock(mutex, shared, abs_timeout_or_null, clock);
+        return __pthread_normal_mutex_lock(mutex, shared, use_realtime_clock, abs_timeout_or_null);
     }
 
     // Do we already own this recursive or error-check mutex?
@@ -484,16 +487,13 @@
             old_state = new_state;
         }
 
-        // We are in locked_contended state, sleep until someone wakes us up.
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
+        int result = check_timespec(abs_timeout_or_null, true);
+        if (result != 0) {
+            return result;
         }
-        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, rel_timeout) == -ETIMEDOUT) {
+        // We are in locked_contended state, sleep until someone wakes us up.
+        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, use_realtime_clock,
+                                                 abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
         old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
@@ -518,7 +518,7 @@
         return 0;
       }
     }
-    return __pthread_mutex_lock_with_timeout(mutex, NULL, 0);
+    return __pthread_mutex_lock_with_timeout(mutex, false, nullptr);
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
@@ -613,17 +613,12 @@
 
 #if !defined(__LP64__)
 extern "C" int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex_interface, unsigned ms) {
+    timespec ts;
+    timespec_from_ms(ts, ms);
     timespec abs_timeout;
-    clock_gettime(CLOCK_MONOTONIC, &abs_timeout);
-    abs_timeout.tv_sec  += ms / 1000;
-    abs_timeout.tv_nsec += (ms % 1000) * 1000000;
-    if (abs_timeout.tv_nsec >= NS_PER_S) {
-        abs_timeout.tv_sec++;
-        abs_timeout.tv_nsec -= NS_PER_S;
-    }
-
+    absolute_timespec_from_timespec(abs_timeout, ts, CLOCK_MONOTONIC);
     int error = __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                                  &abs_timeout, CLOCK_MONOTONIC);
+                                                  false, &abs_timeout);
     if (error == ETIMEDOUT) {
         error = EBUSY;
     }
@@ -633,14 +628,18 @@
 
 int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const timespec* abs_timeout) {
     return __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                             abs_timeout, CLOCK_REALTIME);
+                                             true, abs_timeout);
 }
 
 int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
-    // Use trylock to ensure that the mutex is valid and not already locked.
-    int error = pthread_mutex_trylock(mutex_interface);
-    if (error != 0) {
-        return error;
+    pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
+    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
+    // Store 0xffff to make the mutex unusable. Although POSIX standard says it is undefined
+    // behavior to destroy a locked mutex, we prefer not to change mutex->state in that situation.
+    if (MUTEX_STATE_BITS_IS_UNLOCKED(old_state) &&
+        atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, 0xffff,
+                                                memory_order_relaxed, memory_order_relaxed)) {
+      return 0;
     }
-    return 0;
+    return EBUSY;
 }
diff --git a/libc/bionic/pthread_once.cpp b/libc/bionic/pthread_once.cpp
index 7688a23..f48eadc 100644
--- a/libc/bionic/pthread_once.cpp
+++ b/libc/bionic/pthread_once.cpp
@@ -79,7 +79,7 @@
     }
 
     // The initialization is underway, wait for its finish.
-    __futex_wait_ex(once_control_ptr, 0, old_value, NULL);
+    __futex_wait_ex(once_control_ptr, 0, old_value, false, nullptr);
     old_value = atomic_load_explicit(once_control_ptr, memory_order_acquire);
   }
 }
diff --git a/libc/bionic/pthread_rwlock.cpp b/libc/bionic/pthread_rwlock.cpp
index 934210e..a065295 100644
--- a/libc/bionic/pthread_rwlock.cpp
+++ b/libc/bionic/pthread_rwlock.cpp
@@ -294,9 +294,13 @@
   }
 
   while (true) {
-    int ret = __pthread_rwlock_tryrdlock(rwlock);
-    if (ret == 0 || ret == EAGAIN) {
-      return ret;
+    int result = __pthread_rwlock_tryrdlock(rwlock);
+    if (result == 0 || result == EAGAIN) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null, true);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -304,16 +308,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_reader_count++;
 
@@ -327,10 +321,10 @@
     int old_serial = rwlock->pending_reader_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -341,7 +335,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -372,9 +366,13 @@
     return EDEADLK;
   }
   while (true) {
-    int ret = __pthread_rwlock_trywrlock(rwlock);
-    if (ret == 0) {
-      return ret;
+    int result = __pthread_rwlock_trywrlock(rwlock);
+    if (result == 0) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null, true);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -382,16 +380,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_writer_count++;
 
@@ -401,10 +389,10 @@
     int old_serial = rwlock->pending_writer_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_write_lock(old_state)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -415,7 +403,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -427,7 +415,7 @@
   if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedrdlock(rwlock, NULL);
+  return __pthread_rwlock_timedrdlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
@@ -446,7 +434,7 @@
   if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedwrlock(rwlock, NULL);
+  return __pthread_rwlock_timedwrlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
diff --git a/libc/bionic/pthread_spinlock.cpp b/libc/bionic/pthread_spinlock.cpp
new file mode 100644
index 0000000..f26f283
--- /dev/null
+++ b/libc/bionic/pthread_spinlock.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 <pthread.h>
+
+#include "private/bionic_lock.h"
+
+// User-level spinlocks can be hazardous to battery life on Android.
+// We implement a simple compromise that behaves mostly like a spinlock,
+// but prevents excessively long spinning.
+
+struct pthread_spinlock_internal_t {
+  Lock lock;
+};
+
+static_assert(sizeof(pthread_spinlock_t) == sizeof(pthread_spinlock_internal_t),
+              "pthread_spinlock_t should actually be pthread_spinlock_internal_t.");
+
+static_assert(alignof(pthread_spinlock_t) >= 4,
+              "pthread_spinlock_t should fulfill the alignment of pthread_spinlock_internal_t.");
+
+static inline pthread_spinlock_internal_t* __get_internal_spinlock(pthread_spinlock_t* lock) {
+  return reinterpret_cast<pthread_spinlock_internal_t*>(lock);
+}
+
+int pthread_spin_init(pthread_spinlock_t* lock_interface, int pshared) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  lock->lock.init(pshared);
+  return 0;
+}
+
+int pthread_spin_destroy(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  return lock->lock.trylock() ? 0 : EBUSY;
+}
+
+int pthread_spin_trylock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  return lock->lock.trylock() ? 0 : EBUSY;
+}
+
+int pthread_spin_lock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  for (int i = 0; i < 10000; ++i) {
+    if (lock->lock.trylock()) {
+      return 0;
+    }
+  }
+  lock->lock.lock();
+  return 0;
+}
+
+int pthread_spin_unlock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  lock->lock.unlock();
+  return 0;
+}
diff --git a/libc/bionic/scandir.cpp b/libc/bionic/scandir.cpp
index ee62fee..e55be42 100644
--- a/libc/bionic/scandir.cpp
+++ b/libc/bionic/scandir.cpp
@@ -16,9 +16,11 @@
 
 #include <dirent.h>
 
+#include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "private/bionic_macros.h"
 #include "private/ScopedReaddir.h"
@@ -26,7 +28,7 @@
 // A smart pointer to the scandir dirent**.
 class ScandirResult {
  public:
-  ScandirResult() : names_(NULL), size_(0), capacity_(0) {
+  ScandirResult() : names_(nullptr), size_(0), capacity_(0) {
   }
 
   ~ScandirResult() {
@@ -42,7 +44,7 @@
 
   dirent** release() {
     dirent** result = names_;
-    names_ = NULL;
+    names_ = nullptr;
     size_ = capacity_ = 0;
     return result;
   }
@@ -52,7 +54,7 @@
       size_t new_capacity = capacity_ + 32;
       dirent** new_names =
           reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*)));
-      if (new_names == NULL) {
+      if (new_names == nullptr) {
         return false;
       }
       names_ = new_names;
@@ -60,7 +62,7 @@
     }
 
     dirent* copy = CopyDirent(entry);
-    if (copy == NULL) {
+    if (copy == nullptr) {
       return false;
     }
     names_[size_++] = copy;
@@ -69,7 +71,7 @@
 
   void Sort(int (*comparator)(const dirent**, const dirent**)) {
     // If we have entries and a comparator, sort them.
-    if (size_ > 0 && comparator != NULL) {
+    if (size_ > 0 && comparator != nullptr) {
       qsort(names_, size_, sizeof(dirent*),
             reinterpret_cast<int (*)(const void*, const void*)>(comparator));
     }
@@ -91,19 +93,29 @@
   DISALLOW_COPY_AND_ASSIGN(ScandirResult);
 };
 
-int scandir(const char* dirname, dirent*** name_list,
-            int (*filter)(const dirent*),
-            int (*comparator)(const dirent**, const dirent**)) {
-  ScopedReaddir reader(dirname);
+int scandirat(int parent_fd, const char* dir_name, dirent*** name_list,
+              int (*filter)(const dirent*),
+              int (*comparator)(const dirent**, const dirent**)) {
+  DIR* dir = nullptr;
+  if (parent_fd == AT_FDCWD) {
+    dir = opendir(dir_name);
+  } else {
+    int dir_fd = openat(parent_fd, dir_name, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
+    if (dir_fd != -1) {
+      dir = fdopendir(dir_fd);
+    }
+  }
+
+  ScopedReaddir reader(dir);
   if (reader.IsBad()) {
     return -1;
   }
 
   ScandirResult names;
   dirent* entry;
-  while ((entry = reader.ReadEntry()) != NULL) {
+  while ((entry = reader.ReadEntry()) != nullptr) {
     // If we have a filter, skip names that don't match.
-    if (filter != NULL && !(*filter)(entry)) {
+    if (filter != nullptr && !(*filter)(entry)) {
       continue;
     }
     names.Add(entry);
@@ -115,4 +127,11 @@
   *name_list = names.release();
   return size;
 }
+__strong_alias(scandirat64, scandirat);
+
+int scandir(const char* dir_path, dirent*** name_list,
+            int (*filter)(const dirent*),
+            int (*comparator)(const dirent**, const dirent**)) {
+  return scandirat(AT_FDCWD, dir_path, name_list, filter, comparator);
+}
 __strong_alias(scandir64, scandir);
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index 0b04650..b30c0b0 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -80,7 +80,7 @@
 #define SEMCOUNT_ONE              SEMCOUNT_FROM_VALUE(1)
 
 // The value -1 as a sem->count bit-pattern.
-#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(-1)
+#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(~0U)
 
 #define SEMCOUNT_DECREMENT(sval)    (((sval) - (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 #define SEMCOUNT_INCREMENT(sval)    (((sval) + (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
@@ -220,7 +220,7 @@
       return 0;
     }
 
-    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, NULL);
+    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
   }
 }
 
@@ -235,36 +235,29 @@
   }
 
   // Check it as per POSIX.
-  if (abs_timeout == NULL || abs_timeout->tv_sec < 0 || abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= NS_PER_S) {
-    errno = EINVAL;
+  int result = check_timespec(abs_timeout, false);
+  if (result != 0) {
+    errno = result;
     return -1;
   }
 
   unsigned int shared = SEM_GET_SHARED(sem_count_ptr);
 
   while (true) {
-    // POSIX mandates CLOCK_REALTIME here.
-    timespec ts;
-    if (!timespec_from_absolute_timespec(ts, *abs_timeout, CLOCK_REALTIME)) {
-      errno = ETIMEDOUT;
-      return -1;
-    }
-
     // Try to grab the semaphore. If the value was 0, this will also change it to -1.
     if (__sem_dec(sem_count_ptr) > 0) {
-      break;
+      return 0;
     }
 
     // Contention detected. Wait for a wakeup event.
-    int ret = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, &ts);
+    int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, true, abs_timeout);
 
     // Return in case of timeout or interrupt.
-    if (ret == -ETIMEDOUT || ret == -EINTR) {
-      errno = -ret;
+    if (result == -ETIMEDOUT || result == -EINTR) {
+      errno = -result;
       return -1;
     }
   }
-  return 0;
 }
 
 int sem_post(sem_t* sem) {
diff --git a/libc/bionic/setjmp_cookie.cpp b/libc/bionic/setjmp_cookie.cpp
new file mode 100644
index 0000000..ce57fd1
--- /dev/null
+++ b/libc/bionic/setjmp_cookie.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <sys/cdefs.h>
+
+#include "private/bionic_globals.h"
+#include "private/libc_logging.h"
+#include "private/KernelArgumentBlock.h"
+
+void __libc_init_setjmp_cookie(libc_globals* globals,
+                               KernelArgumentBlock& args) {
+  char* random_data = reinterpret_cast<char*>(args.getauxval(AT_RANDOM));
+  long value = *reinterpret_cast<long*>(random_data + 8);
+
+  // Mask off the last bit to store the signal flag.
+  globals->setjmp_cookie = value & ~1;
+}
+
+extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) {
+  if (sigflag & ~1) {
+    __libc_fatal("unexpected sigflag value: %ld", sigflag);
+  }
+
+  return __libc_globals->setjmp_cookie | sigflag;
+}
+
+// Aborts if cookie doesn't match, returns the signal flag otherwise.
+extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) {
+  if (__libc_globals->setjmp_cookie != (cookie & ~1)) {
+    __libc_fatal("setjmp cookie mismatch");
+  }
+
+  return cookie & 1;
+}
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index 74a2f65..13d1882 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -28,12 +28,7 @@
 
 #include <signal.h>
 
-#ifdef __LP64__
-static
-#else
-__LIBC_HIDDEN__
-#endif
-sighandler_t _signal(int signum, sighandler_t handler, int flags) {
+__LIBC_HIDDEN__ sighandler_t _signal(int signum, sighandler_t handler, int flags) {
   struct sigaction sa;
   sigemptyset(&sa.sa_mask);
   sa.sa_handler = handler;
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/libc/bionic/strchrnul.cpp
similarity index 71%
copy from libc/upstream-freebsd/android/include/spinlock.h
copy to libc/bionic/strchrnul.cpp
index f5c3785..55422e0 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/libc/bionic/strchrnul.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 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.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
-
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
+extern "C" const char* strchrnul(const char* s, int ch) {
+  while (*s && *s != ch) {
+    ++s;
+  }
+  return s;
+}
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 41c78bc..0340f0e 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -206,7 +206,7 @@
 // u0_a1234 -> 0 * AID_USER + AID_APP + 1234
 // u2_i1000 -> 2 * AID_USER + AID_ISOLATED_START + 1000
 // u1_system -> 1 * AID_USER + android_ids['system']
-// returns 0 and sets errno to ENOENT in case of error
+// returns 0 and sets errno to ENOENT in case of error.
 static id_t app_id_from_name(const char* name, bool is_group) {
   char* end;
   unsigned long userid;
@@ -312,6 +312,54 @@
   }
 }
 
+// Translate an OEM name to the corresponding user/group id.
+// oem_XXX -> AID_OEM_RESERVED_2_START + XXX, iff XXX is within range.
+static id_t oem_id_from_name(const char* name) {
+  unsigned int id;
+  if (sscanf(name, "oem_%u", &id) != 1) {
+    return 0;
+  }
+  // Check OEM id is within range.
+  if (id > (AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START)) {
+    return 0;
+  }
+  return AID_OEM_RESERVED_2_START + static_cast<id_t>(id);
+}
+
+static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
+  if (uid < AID_OEM_RESERVED_2_START || uid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u",
+           uid - AID_OEM_RESERVED_2_START);
+  snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
+  snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+
+  passwd* pw = &state->passwd_;
+  pw->pw_name  = state->name_buffer_;
+  pw->pw_dir   = state->dir_buffer_;
+  pw->pw_shell = state->sh_buffer_;
+  pw->pw_uid   = uid;
+  pw->pw_gid   = uid;
+  return pw;
+}
+
+static group* oem_id_to_group(gid_t gid, group_state_t* state) {
+  if (gid < AID_OEM_RESERVED_2_START || gid > AID_OEM_RESERVED_2_END) {
+    return NULL;
+  }
+
+  snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
+           "oem_%u", gid - AID_OEM_RESERVED_2_START);
+
+  group* gr = &state->group_;
+  gr->gr_name   = state->group_name_buffer_;
+  gr->gr_gid    = gid;
+  gr->gr_mem[0] = gr->gr_name;
+  return gr;
+}
+
 // Translate a uid into the corresponding name.
 // 0 to AID_APP-1                   -> "system", "radio", etc.
 // AID_APP to AID_ISOLATED_START-1  -> u0_a1234
@@ -371,6 +419,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(uid, state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(uid, state);
 }
 
@@ -384,6 +437,11 @@
   if (pw != NULL) {
     return pw;
   }
+  // Handle OEM range.
+  pw = oem_id_to_passwd(oem_id_from_name(login), state);
+  if (pw != NULL) {
+    return pw;
+  }
   return app_id_to_passwd(app_id_from_name(login, false), state);
 }
 
@@ -407,6 +465,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(gid, state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(gid, state);
 }
 
@@ -423,6 +486,11 @@
   if (grp != NULL) {
     return grp;
   }
+  // Handle OEM range.
+  grp = oem_id_to_group(oem_id_from_name(name), state);
+  if (grp != NULL) {
+    return grp;
+  }
   return app_id_to_group(app_id_from_name(name, true), state);
 }
 
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index c301b27..8a55f7e 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -97,8 +97,11 @@
     case _SC_ATEXIT_MAX:        return LONG_MAX;    // Unlimited.
     case _SC_IOV_MAX:           return UIO_MAXIOV;
 
-    case _SC_PAGESIZE:          // Fall through, PAGESIZE and PAGE_SIZE always hold the same value.
-    case _SC_PAGE_SIZE:         return PAGE_SIZE;
+    // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
+    case _SC_PAGESIZE:
+    case _SC_PAGE_SIZE:
+      return static_cast<long>(getauxval(AT_PAGESZ));
+
     case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
     case _SC_AIO_LISTIO_MAX:    return _POSIX_AIO_LISTIO_MAX;     // Minimum requirement.
     case _SC_AIO_MAX:           return _POSIX_AIO_MAX;            // Minimum requirement.
diff --git a/libc/bionic/sysinfo.cpp b/libc/bionic/sysinfo.cpp
index 82cb76a..1cb5c79 100644
--- a/libc/bionic/sysinfo.cpp
+++ b/libc/bionic/sysinfo.cpp
@@ -29,10 +29,11 @@
 #include <sys/sysinfo.h>
 
 #include <dirent.h>
-#include <limits.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
+#include "private/get_cpu_count_from_string.h"
 #include "private/ScopedReaddir.h"
 
 static bool __matches_cpuN(const char* s) {
@@ -61,26 +62,18 @@
 }
 
 int get_nprocs() {
-  FILE* fp = fopen("/proc/stat", "re");
-  if (fp == NULL) {
-    return 1;
-  }
-
-  int result = 0;
-  char buf[256];
-  while (fgets(buf, sizeof(buf), fp) != NULL) {
-    // Extract just the first word from the line.
-    // 'cpu0 7976751 1364388 3116842 469770388 8629405 0 49047 0 0 0'
-    char* p = strchr(buf, ' ');
-    if (p != NULL) {
-      *p = 0;
+  int cpu_count = 1;
+  FILE* fp = fopen("/sys/devices/system/cpu/online", "re");
+  if (fp != nullptr) {
+    char* line = nullptr;
+    size_t len = 0;
+    if (getline(&line, &len, fp) != -1) {
+      cpu_count = GetCpuCountFromString(line);
+      free(line);
     }
-    if (__matches_cpuN(buf)) {
-      ++result;
-    }
+    fclose(fp);
   }
-  fclose(fp);
-  return result;
+  return cpu_count;
 }
 
 static int __get_meminfo_page_count(const char* pattern) {
@@ -94,7 +87,7 @@
   while (fgets(buf, sizeof(buf), fp) != NULL) {
     long total;
     if (sscanf(buf, pattern, &total) == 1) {
-      page_count = static_cast<int>(total / (PAGE_SIZE / 1024));
+      page_count = static_cast<int>(total / (sysconf(_SC_PAGE_SIZE) / 1024));
       break;
     }
   }
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index c436a16..2720455 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -25,34 +25,38 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <new>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
+#include <ctype.h>
 #include <errno.h>
-#include <poll.h>
 #include <fcntl.h>
+#include <poll.h>
+#include <stdatomic.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <new>
 
+#include <linux/xattr.h>
+#include <netinet/in.h>
 #include <sys/mman.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <sys/select.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/xattr.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 #include <sys/system_properties.h>
 
 #include "private/bionic_futex.h"
+#include "private/bionic_lock.h"
 #include "private/bionic_macros.h"
+#include "private/libc_logging.h"
 
 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
 
@@ -112,23 +116,57 @@
     DISALLOW_COPY_AND_ASSIGN(prop_bt);
 };
 
-struct prop_area {
-    uint32_t bytes_used;
-    atomic_uint_least32_t serial;
-    uint32_t magic;
-    uint32_t version;
-    uint32_t reserved[28];
-    char data[0];
+class prop_area {
+public:
 
     prop_area(const uint32_t magic, const uint32_t version) :
-        magic(magic), version(version) {
-        atomic_init(&serial, 0);
-        memset(reserved, 0, sizeof(reserved));
+        magic_(magic), version_(version) {
+        atomic_init(&serial_, 0);
+        memset(reserved_, 0, sizeof(reserved_));
         // Allocate enough space for the root node.
-        bytes_used = sizeof(prop_bt);
+        bytes_used_ = sizeof(prop_bt);
     }
 
+    const prop_info *find(const char *name);
+    bool add(const char *name, unsigned int namelen,
+             const char *value, unsigned int valuelen);
+
+    bool foreach(void (*propfn)(const prop_info *pi, void *cookie), void *cookie);
+
+    atomic_uint_least32_t *serial() { return &serial_; }
+    uint32_t magic() const { return magic_; }
+    uint32_t version() const { return version_; }
+
 private:
+    void *allocate_obj(const size_t size, uint_least32_t *const off);
+    prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off);
+    prop_info *new_prop_info(const char *name, uint8_t namelen,
+                             const char *value, uint8_t valuelen,
+                             uint_least32_t *const off);
+    void *to_prop_obj(uint_least32_t off);
+    prop_bt *to_prop_bt(atomic_uint_least32_t *off_p);
+    prop_info *to_prop_info(atomic_uint_least32_t *off_p);
+
+    prop_bt *root_node();
+
+    prop_bt *find_prop_bt(prop_bt *const bt, const char *name,
+                          uint8_t namelen, bool alloc_if_needed);
+
+    const prop_info *find_property(prop_bt *const trie, const char *name,
+                                   uint8_t namelen, const char *value,
+                                   uint8_t valuelen, bool alloc_if_needed);
+
+    bool foreach_property(prop_bt *const trie,
+                          void (*propfn)(const prop_info *pi, void *cookie),
+                          void *cookie);
+
+    uint32_t bytes_used_;
+    atomic_uint_least32_t serial_;
+    uint32_t magic_;
+    uint32_t version_;
+    uint32_t reserved_[28];
+    char data_[0];
+
     DISALLOW_COPY_AND_ASSIGN(prop_area);
 };
 
@@ -158,10 +196,11 @@
     }
 };
 
-static char property_filename[PATH_MAX] = PROP_FILENAME;
+static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
 static bool compat_mode = false;
 static size_t pa_data_size;
 static size_t pa_size;
+static bool initialized = false;
 
 // NOTE: This isn't static because system_properties_compat.c
 // requires it.
@@ -182,13 +221,12 @@
     return atoi(env);
 }
 
-static int map_prop_area_rw()
-{
+static prop_area* map_prop_area_rw(const char* filename, const char* context,
+                                   bool* fsetxattr_failed) {
     /* dev is a tmpfs that we can use to carve a shared workspace
      * out of, so let's do that...
      */
-    const int fd = open(property_filename,
-                        O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
+    const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
 
     if (fd < 0) {
         if (errno == EACCES) {
@@ -197,12 +235,31 @@
              */
             abort();
         }
-        return -1;
+        return nullptr;
+    }
+
+    if (context) {
+        if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
+            __libc_format_log(ANDROID_LOG_ERROR, "libc",
+                              "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
+            /*
+             * fsetxattr() will fail during system properties tests due to selinux policy.
+             * We do not want to create a custom policy for the tester, so we will continue in
+             * this function but set a flag that an error has occurred.
+             * Init, which is the only daemon that should ever call this function will abort
+             * when this error occurs.
+             * Otherwise, the tester will ignore it and continue, albeit without any selinux
+             * property separation.
+             */
+            if (fsetxattr_failed) {
+                *fsetxattr_failed = true;
+            }
+        }
     }
 
     if (ftruncate(fd, PA_SIZE) < 0) {
         close(fd);
-        return -1;
+        return nullptr;
     }
 
     pa_size = PA_SIZE;
@@ -212,29 +269,26 @@
     void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     if (memory_area == MAP_FAILED) {
         close(fd);
-        return -1;
+        return nullptr;
     }
 
     prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
 
-    /* plug into the lib property services */
-    __system_property_area__ = pa;
-
     close(fd);
-    return 0;
+    return pa;
 }
 
-static int map_fd_ro(const int fd) {
+static prop_area* map_fd_ro(const int fd) {
     struct stat fd_stat;
     if (fstat(fd, &fd_stat) < 0) {
-        return -1;
+        return nullptr;
     }
 
     if ((fd_stat.st_uid != 0)
             || (fd_stat.st_gid != 0)
             || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
             || (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area))) ) {
-        return -1;
+        return nullptr;
     }
 
     pa_size = fd_stat.st_size;
@@ -242,29 +296,28 @@
 
     void* const map_result = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);
     if (map_result == MAP_FAILED) {
-        return -1;
+        return nullptr;
     }
 
     prop_area* pa = reinterpret_cast<prop_area*>(map_result);
-    if ((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION &&
-                pa->version != PROP_AREA_VERSION_COMPAT)) {
+    if ((pa->magic() != PROP_AREA_MAGIC) ||
+        (pa->version() != PROP_AREA_VERSION &&
+         pa->version() != PROP_AREA_VERSION_COMPAT)) {
         munmap(pa, pa_size);
-        return -1;
+        return nullptr;
     }
 
-    if (pa->version == PROP_AREA_VERSION_COMPAT) {
+    if (pa->version() == PROP_AREA_VERSION_COMPAT) {
         compat_mode = true;
     }
 
-    __system_property_area__ = pa;
-    return 0;
+    return pa;
 }
 
-static int map_prop_area()
-{
-    int fd = open(property_filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
+static prop_area* map_prop_area(const char* filename, bool is_legacy) {
+    int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
     bool close_fd = true;
-    if (fd == -1 && errno == ENOENT) {
+    if (fd == -1 && errno == ENOENT && is_legacy) {
         /*
          * For backwards compatibility, if the file doesn't
          * exist, we use the environment to get the file descriptor.
@@ -273,16 +326,18 @@
          * returns other errors such as ENOMEM or ENFILE, since it
          * might be possible for an external program to trigger this
          * condition.
+         * Only do this for the legacy prop file, secured prop files
+         * do not have a backup
          */
         fd = get_fd_from_env();
         close_fd = false;
     }
 
     if (fd < 0) {
-        return -1;
+        return nullptr;
     }
 
-    const int map_result = map_fd_ro(fd);
+    prop_area* map_result = map_fd_ro(fd);
     if (close_fd) {
         close(fd);
     }
@@ -290,20 +345,19 @@
     return map_result;
 }
 
-static void *allocate_obj(const size_t size, uint_least32_t *const off)
+void *prop_area::allocate_obj(const size_t size, uint_least32_t *const off)
 {
-    prop_area *pa = __system_property_area__;
     const size_t aligned = BIONIC_ALIGN(size, sizeof(uint_least32_t));
-    if (pa->bytes_used + aligned > pa_data_size) {
+    if (bytes_used_ + aligned > pa_data_size) {
         return NULL;
     }
 
-    *off = pa->bytes_used;
-    pa->bytes_used += aligned;
-    return pa->data + *off;
+    *off = bytes_used_;
+    bytes_used_ += aligned;
+    return data_ + *off;
 }
 
-static prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off)
+prop_bt *prop_area::new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off)
 {
     uint_least32_t new_offset;
     void *const p = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
@@ -316,7 +370,7 @@
     return NULL;
 }
 
-static prop_info *new_prop_info(const char *name, uint8_t namelen,
+prop_info *prop_area::new_prop_info(const char *name, uint8_t namelen,
         const char *value, uint8_t valuelen, uint_least32_t *const off)
 {
     uint_least32_t new_offset;
@@ -330,27 +384,25 @@
     return NULL;
 }
 
-static void *to_prop_obj(uint_least32_t off)
+void *prop_area::to_prop_obj(uint_least32_t off)
 {
     if (off > pa_data_size)
         return NULL;
-    if (!__system_property_area__)
-        return NULL;
 
-    return (__system_property_area__->data + off);
+    return (data_ + off);
 }
 
-static inline prop_bt *to_prop_bt(atomic_uint_least32_t* off_p) {
+inline prop_bt *prop_area::to_prop_bt(atomic_uint_least32_t* off_p) {
   uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
   return reinterpret_cast<prop_bt*>(to_prop_obj(off));
 }
 
-static inline prop_info *to_prop_info(atomic_uint_least32_t* off_p) {
+inline prop_info *prop_area::to_prop_info(atomic_uint_least32_t* off_p) {
   uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
   return reinterpret_cast<prop_info*>(to_prop_obj(off));
 }
 
-static inline prop_bt *root_node()
+inline prop_bt *prop_area::root_node()
 {
     return reinterpret_cast<prop_bt*>(to_prop_obj(0));
 }
@@ -366,8 +418,8 @@
         return strncmp(one, two, one_len);
 }
 
-static prop_bt *find_prop_bt(prop_bt *const bt, const char *name,
-                             uint8_t namelen, bool alloc_if_needed)
+prop_bt *prop_area::find_prop_bt(prop_bt *const bt, const char *name,
+                                 uint8_t namelen, bool alloc_if_needed)
 {
 
     prop_bt* current = bt;
@@ -417,7 +469,7 @@
     }
 }
 
-static const prop_info *find_property(prop_bt *const trie, const char *name,
+const prop_info *prop_area::find_property(prop_bt *const trie, const char *name,
         uint8_t namelen, const char *value, uint8_t valuelen,
         bool alloc_if_needed)
 {
@@ -543,44 +595,439 @@
     cookie->count++;
 }
 
-static int foreach_property(prop_bt *const trie,
+bool prop_area::foreach_property(prop_bt *const trie,
         void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
 {
     if (!trie)
-        return -1;
+        return false;
 
     uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
     if (left_offset != 0) {
         const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
         if (err < 0)
-            return -1;
+            return false;
     }
     uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
     if (prop_offset != 0) {
         prop_info *info = to_prop_info(&trie->prop);
         if (!info)
-            return -1;
+            return false;
         propfn(info, cookie);
     }
     uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
     if (children_offset != 0) {
         const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
         if (err < 0)
-            return -1;
+            return false;
     }
     uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
     if (right_offset != 0) {
         const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
         if (err < 0)
+            return false;
+    }
+
+    return true;
+}
+
+const prop_info *prop_area::find(const char *name) {
+    return find_property(root_node(), name, strlen(name), nullptr, 0, false);
+}
+
+bool prop_area::add(const char *name, unsigned int namelen,
+                    const char *value, unsigned int valuelen) {
+    return find_property(root_node(), name, namelen, value, valuelen, true);
+}
+
+bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
+    return foreach_property(root_node(), propfn, cookie);
+}
+
+class context_node {
+public:
+    context_node(context_node* next, const char* context, prop_area* pa)
+        : next(next), context_(strdup(context)), pa_(pa), no_access_(false) {
+        lock_.init(false);
+    }
+    ~context_node() {
+        unmap();
+        free(context_);
+    }
+    bool open(bool access_rw, bool* fsetxattr_failed);
+    bool check_access_and_open();
+    void reset_access();
+
+    const char* context() const { return context_; }
+    prop_area* pa() { return pa_; }
+
+    context_node* next;
+
+private:
+    bool check_access();
+    void unmap();
+
+    Lock lock_;
+    char* context_;
+    prop_area* pa_;
+    bool no_access_;
+};
+
+struct prefix_node {
+    prefix_node(struct prefix_node* next, const char* prefix, context_node* context)
+        : prefix(strdup(prefix)), prefix_len(strlen(prefix)), context(context), next(next) {
+    }
+    ~prefix_node() {
+        free(prefix);
+    }
+    char* prefix;
+    const size_t prefix_len;
+    context_node* context;
+    struct prefix_node* next;
+};
+
+template <typename List, typename... Args>
+static inline void list_add(List** list, Args... args) {
+    *list = new List(*list, args...);
+}
+
+static void list_add_after_len(prefix_node** list, const char* prefix, context_node* context) {
+    size_t prefix_len = strlen(prefix);
+
+    auto next_list = list;
+
+    while (*next_list) {
+        if ((*next_list)->prefix_len < prefix_len || (*next_list)->prefix[0] == '*') {
+            list_add(next_list, prefix, context);
+            return;
+        }
+        next_list = &(*next_list)->next;
+    }
+    list_add(next_list, prefix, context);
+}
+
+template <typename List, typename Func>
+static void list_foreach(List* list, Func func) {
+    while (list) {
+        func(list);
+        list = list->next;
+    }
+}
+
+template <typename List, typename Func>
+static List* list_find(List* list, Func func) {
+    while (list) {
+        if (func(list)) {
+            return list;
+        }
+        list = list->next;
+    }
+    return nullptr;
+}
+
+template <typename List>
+static void list_free(List** list) {
+    while (*list) {
+        auto old_list = *list;
+        *list = old_list->next;
+        delete old_list;
+    }
+}
+
+static prefix_node* prefixes = nullptr;
+static context_node* contexts = nullptr;
+
+/*
+ * pthread_mutex_lock() calls into system_properties in the case of contention.
+ * This creates a risk of dead lock if any system_properties functions
+ * use pthread locks after system_property initialization.
+ *
+ * For this reason, the below three functions use a bionic Lock and static
+ * allocation of memory for each filename.
+ */
+
+bool context_node::open(bool access_rw, bool* fsetxattr_failed) {
+    lock_.lock();
+    if (pa_) {
+        lock_.unlock();
+        return true;
+    }
+
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        lock_.unlock();
+        return false;
+    }
+
+    if (access_rw) {
+        pa_ = map_prop_area_rw(filename, context_, fsetxattr_failed);
+    } else {
+        pa_ = map_prop_area(filename, false);
+    }
+    lock_.unlock();
+    return pa_;
+}
+
+bool context_node::check_access_and_open() {
+    if (!pa_ && !no_access_) {
+        if (!check_access() || !open(false, nullptr)) {
+            no_access_ = true;
+        }
+    }
+    return pa_;
+}
+
+void context_node::reset_access() {
+    if (!check_access()) {
+        unmap();
+        no_access_ = true;
+    } else {
+        no_access_ = false;
+    }
+}
+
+bool context_node::check_access() {
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        return false;
+    }
+
+    return access(filename, R_OK) == 0;
+}
+
+void context_node::unmap() {
+    if (!pa_) {
+        return;
+    }
+
+    munmap(pa_, pa_size);
+    if (pa_ == __system_property_area__) {
+        __system_property_area__ = nullptr;
+    }
+    pa_ = nullptr;
+}
+
+static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        __system_property_area__ = nullptr;
+        return false;
+    }
+
+    if (access_rw) {
+        __system_property_area__ =
+            map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
+    } else {
+        __system_property_area__ = map_prop_area(filename, false);
+    }
+    return __system_property_area__;
+}
+
+static prop_area* get_prop_area_for_name(const char* name) {
+    auto entry = list_find(prefixes, [name](prefix_node* l) {
+        return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
+    });
+    if (!entry) {
+        return nullptr;
+    }
+
+    auto cnode = entry->context;
+    if (!cnode->pa()) {
+        /*
+         * We explicitly do not check no_access_ in this case because unlike the
+         * case of foreach(), we want to generate an selinux audit for each
+         * non-permitted property access in this function.
+         */
+        cnode->open(false, nullptr);
+    }
+    return cnode->pa();
+}
+
+/*
+ * The below two functions are duplicated from label_support.c in libselinux.
+ * TODO: Find a location suitable for these functions such that both libc and
+ * libselinux can share a common source file.
+ */
+
+/*
+ * The read_spec_entries and read_spec_entry functions may be used to
+ * replace sscanf to read entries from spec files. The file and
+ * property services now use these.
+ */
+
+/* Read an entry from a spec file (e.g. file_contexts) */
+static inline int read_spec_entry(char **entry, char **ptr, int *len)
+{
+    *entry = NULL;
+    char *tmp_buf = NULL;
+
+    while (isspace(**ptr) && **ptr != '\0')
+        (*ptr)++;
+
+    tmp_buf = *ptr;
+    *len = 0;
+
+    while (!isspace(**ptr) && **ptr != '\0') {
+        (*ptr)++;
+        (*len)++;
+    }
+
+    if (*len) {
+        *entry = strndup(tmp_buf, *len);
+        if (!*entry)
             return -1;
     }
 
     return 0;
 }
 
+/*
+ * line_buf - Buffer containing the spec entries .
+ * num_args - The number of spec parameter entries to process.
+ * ...      - A 'char **spec_entry' for each parameter.
+ * returns  - The number of items processed.
+ *
+ * This function calls read_spec_entry() to do the actual string processing.
+ */
+static int read_spec_entries(char *line_buf, int num_args, ...)
+{
+    char **spec_entry, *buf_p;
+    int len, rc, items, entry_len = 0;
+    va_list ap;
+
+    len = strlen(line_buf);
+    if (line_buf[len - 1] == '\n')
+        line_buf[len - 1] = '\0';
+    else
+        /* Handle case if line not \n terminated by bumping
+         * the len for the check below (as the line is NUL
+         * terminated by getline(3)) */
+        len++;
+
+    buf_p = line_buf;
+    while (isspace(*buf_p))
+        buf_p++;
+
+    /* Skip comment lines and empty lines. */
+    if (*buf_p == '#' || *buf_p == '\0')
+        return 0;
+
+    /* Process the spec file entries */
+    va_start(ap, num_args);
+
+    items = 0;
+    while (items < num_args) {
+        spec_entry = va_arg(ap, char **);
+
+        if (len - 1 == buf_p - line_buf) {
+            va_end(ap);
+            return items;
+        }
+
+        rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
+        if (rc < 0) {
+            va_end(ap);
+            return rc;
+        }
+        if (entry_len)
+            items++;
+    }
+    va_end(ap);
+    return items;
+}
+
+static bool initialize_properties() {
+    FILE* file = fopen("/property_contexts", "re");
+
+    if (!file) {
+        return false;
+    }
+
+    char* buffer = nullptr;
+    size_t line_len;
+    char* prop_prefix = nullptr;
+    char* context = nullptr;
+
+    while (getline(&buffer, &line_len, file) > 0) {
+        int items = read_spec_entries(buffer, 2, &prop_prefix, &context);
+        if (items <= 0) {
+            continue;
+        }
+        if (items == 1) {
+            free(prop_prefix);
+            continue;
+        }
+        /*
+         * init uses ctl.* properties as an IPC mechanism and does not write them
+         * to a property file, therefore we do not need to create property files
+         * to store them.
+         */
+        if (!strncmp(prop_prefix, "ctl.", 4)) {
+            free(prop_prefix);
+            free(context);
+            continue;
+        }
+
+        auto old_context = list_find(
+            contexts, [context](context_node* l) { return !strcmp(l->context(), context); });
+        if (old_context) {
+            list_add_after_len(&prefixes, prop_prefix, old_context);
+        } else {
+            list_add(&contexts, context, nullptr);
+            list_add_after_len(&prefixes, prop_prefix, contexts);
+        }
+        free(prop_prefix);
+        free(context);
+    }
+
+    free(buffer);
+    fclose(file);
+    return true;
+}
+
+static bool is_dir(const char* pathname) {
+    struct stat info;
+    if (stat(pathname, &info) == -1) {
+        return false;
+    }
+    return S_ISDIR(info.st_mode);
+}
+
+static void free_and_unmap_contexts() {
+    list_free(&prefixes);
+    list_free(&contexts);
+    if (__system_property_area__) {
+        munmap(__system_property_area__, pa_size);
+        __system_property_area__ = nullptr;
+    }
+}
+
 int __system_properties_init()
 {
-    return map_prop_area();
+    if (initialized) {
+        list_foreach(contexts, [](context_node* l) { l->reset_access(); });
+        return 0;
+    }
+    if (is_dir(property_filename)) {
+        if (!initialize_properties()) {
+            return -1;
+        }
+        if (!map_system_property_area(false, nullptr)) {
+            free_and_unmap_contexts();
+            return -1;
+        }
+    } else {
+        __system_property_area__ = map_prop_area(property_filename, true);
+        if (!__system_property_area__) {
+            return -1;
+        }
+        list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
+        list_add_after_len(&prefixes, "*", contexts);
+    }
+    initialized = true;
+    return 0;
 }
 
 int __system_property_set_filename(const char *filename)
@@ -595,7 +1042,24 @@
 
 int __system_property_area_init()
 {
-    return map_prop_area_rw();
+    free_and_unmap_contexts();
+    mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+    if (!initialize_properties()) {
+        return -1;
+    }
+    bool open_failed = false;
+    bool fsetxattr_failed = false;
+    list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
+        if (!l->open(true, &fsetxattr_failed)) {
+            open_failed = true;
+        }
+    });
+    if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
+        free_and_unmap_contexts();
+        return -1;
+    }
+    initialized = true;
+    return fsetxattr_failed ? -2 : 0;
 }
 
 unsigned int __system_property_area_serial()
@@ -605,15 +1069,26 @@
         return -1;
     }
     // Make sure this read fulfilled before __system_property_serial
-    return atomic_load_explicit(&(pa->serial), memory_order_acquire);
+    return atomic_load_explicit(pa->serial(), memory_order_acquire);
 }
 
 const prop_info *__system_property_find(const char *name)
 {
+    if (!__system_property_area__) {
+        return nullptr;
+    }
+
     if (__predict_false(compat_mode)) {
         return __system_property_find_compat(name);
     }
-    return find_property(root_node(), name, strlen(name), NULL, 0, false);
+
+    prop_area* pa = get_prop_area_for_name(name);
+    if (!pa) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
+        return nullptr;
+    }
+
+    return pa->find(name);
 }
 
 // The C11 standard doesn't allow atomic loads from const fields,
@@ -688,11 +1163,15 @@
 
 int __system_property_update(prop_info *pi, const char *value, unsigned int len)
 {
-    prop_area *pa = __system_property_area__;
-
     if (len >= PROP_VALUE_MAX)
         return -1;
 
+    prop_area* pa = __system_property_area__;
+
+    if (!pa) {
+        return -1;
+    }
+
     uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
     serial |= 1;
     atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
@@ -708,10 +1187,10 @@
     __futex_wake(&pi->serial, INT32_MAX);
 
     atomic_store_explicit(
-        &pa->serial,
-        atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+        pa->serial(),
+        atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
         memory_order_release);
-    __futex_wake(&pa->serial, INT32_MAX);
+    __futex_wake(pa->serial(), INT32_MAX);
 
     return 0;
 }
@@ -719,9 +1198,6 @@
 int __system_property_add(const char *name, unsigned int namelen,
             const char *value, unsigned int valuelen)
 {
-    prop_area *pa = __system_property_area__;
-    const prop_info *pi;
-
     if (namelen >= PROP_NAME_MAX)
         return -1;
     if (valuelen >= PROP_VALUE_MAX)
@@ -729,17 +1205,28 @@
     if (namelen < 1)
         return -1;
 
-    pi = find_property(root_node(), name, namelen, value, valuelen, true);
-    if (!pi)
+    if (!__system_property_area__) {
+        return -1;
+    }
+
+    prop_area* pa = get_prop_area_for_name(name);
+
+    if (!pa) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
+        return -1;
+    }
+
+    bool ret = pa->add(name, namelen, value, valuelen);
+    if (!ret)
         return -1;
 
     // There is only a single mutator, but we want to make sure that
     // updates are visible to a reader waiting for the update.
     atomic_store_explicit(
-        &pa->serial,
-        atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+        __system_property_area__->serial(),
+        atomic_load_explicit(__system_property_area__->serial(), memory_order_relaxed) + 1,
         memory_order_release);
-    __futex_wake(&pa->serial, INT32_MAX);
+    __futex_wake(__system_property_area__->serial(), INT32_MAX);
     return 0;
 }
 
@@ -761,9 +1248,13 @@
     prop_area *pa = __system_property_area__;
     uint32_t my_serial;
 
+    if (!pa) {
+        return 0;
+    }
+
     do {
-        __futex_wait(&pa->serial, serial, NULL);
-        my_serial = atomic_load_explicit(&pa->serial, memory_order_acquire);
+        __futex_wait(pa->serial(), serial, NULL);
+        my_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
     } while (my_serial == serial);
 
     return my_serial;
@@ -784,9 +1275,18 @@
 int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
         void *cookie)
 {
+    if (!__system_property_area__) {
+        return -1;
+    }
+
     if (__predict_false(compat_mode)) {
         return __system_property_foreach_compat(propfn, cookie);
     }
 
-    return foreach_property(root_node(), propfn, cookie);
+    list_foreach(contexts, [propfn, cookie](context_node* l) {
+        if (l->check_access_and_open()) {
+            l->pa()->foreach(propfn, cookie);
+        }
+    });
+    return 0;
 }
diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp
index a240663..029c148 100644
--- a/libc/bionic/vdso.cpp
+++ b/libc/bionic/vdso.cpp
@@ -14,60 +14,49 @@
  * limitations under the License.
  */
 
+#include "private/bionic_globals.h"
+#include "private/bionic_vdso.h"
+
+#if defined(__aarch64__) || defined(__x86_64__) || defined (__i386__)
+
+#include <limits.h>
 #include <link.h>
 #include <string.h>
-#include <sys/auxv.h>
-#include <unistd.h>
-
-// x86 has a vdso, but there's nothing useful to us in it.
-#if defined(__aarch64__) || defined(__x86_64__)
-
-#if defined(__aarch64__)
-#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
-#elif defined(__x86_64__)
-#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
-#endif
-
+#include <sys/cdefs.h>
+#include <sys/time.h>
 #include <time.h>
-
-extern "C" int __clock_gettime(int, timespec*);
-extern "C" int __gettimeofday(timeval*, struct timezone*);
-
-struct vdso_entry {
-  const char* name;
-  void* fn;
-};
-
-enum {
-  VDSO_CLOCK_GETTIME = 0,
-  VDSO_GETTIMEOFDAY,
-  VDSO_END
-};
-
-static vdso_entry vdso_entries[] = {
-  [VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) },
-  [VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
-};
+#include <unistd.h>
+#include "private/KernelArgumentBlock.h"
 
 int clock_gettime(int clock_id, timespec* tp) {
-  static int (*vdso_clock_gettime)(int, timespec*) =
-      reinterpret_cast<int (*)(int, timespec*)>(vdso_entries[VDSO_CLOCK_GETTIME].fn);
-  return vdso_clock_gettime(clock_id, tp);
+  auto vdso_clock_gettime = reinterpret_cast<decltype(&clock_gettime)>(
+    __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn);
+  if (__predict_true(vdso_clock_gettime)) {
+    return vdso_clock_gettime(clock_id, tp);
+  }
+  return __clock_gettime(clock_id, tp);
 }
 
 int gettimeofday(timeval* tv, struct timezone* tz) {
-  static int (*vdso_gettimeofday)(timeval*, struct timezone*) =
-      reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso_entries[VDSO_GETTIMEOFDAY].fn);
-  return vdso_gettimeofday(tv, tz);
+  auto vdso_gettimeofday = reinterpret_cast<decltype(&gettimeofday)>(
+    __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn);
+  if (__predict_true(vdso_gettimeofday)) {
+    return vdso_gettimeofday(tv, tz);
+  }
+  return __gettimeofday(tv, tz);
 }
 
-void __libc_init_vdso() {
+void __libc_init_vdso(libc_globals* globals, KernelArgumentBlock& args) {
+  auto&& vdso = globals->vdso;
+  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL,
+                               reinterpret_cast<void*>(__clock_gettime) };
+  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL,
+                              reinterpret_cast<void*>(__gettimeofday) };
+
   // Do we have a vdso?
-  uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
+  uintptr_t vdso_ehdr_addr = args.getauxval(AT_SYSINFO_EHDR);
   ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
-  if (vdso_ehdr == NULL) {
+  if (vdso_ehdr == nullptr) {
     return;
   }
 
@@ -85,7 +74,7 @@
 
   // Where's the dynamic table?
   ElfW(Addr) vdso_addr = 0;
-  ElfW(Dyn)* vdso_dyn = NULL;
+  ElfW(Dyn)* vdso_dyn = nullptr;
   ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
   for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
     if (vdso_phdr[i].p_type == PT_DYNAMIC) {
@@ -94,13 +83,13 @@
       vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
     }
   }
-  if (vdso_addr == 0 || vdso_dyn == NULL) {
+  if (vdso_addr == 0 || vdso_dyn == nullptr) {
     return;
   }
 
   // Where are the string and symbol tables?
-  const char* strtab = NULL;
-  ElfW(Sym)* symtab = NULL;
+  const char* strtab = nullptr;
+  ElfW(Sym)* symtab = nullptr;
   for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
     if (d->d_tag == DT_STRTAB) {
       strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr);
@@ -108,15 +97,15 @@
       symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr);
     }
   }
-  if (strtab == NULL || symtab == NULL) {
+  if (strtab == nullptr || symtab == nullptr) {
     return;
   }
 
   // Are there any symbols we want?
   for (size_t i = 0; i < symbol_count; ++i) {
     for (size_t j = 0; j < VDSO_END; ++j) {
-      if (strcmp(vdso_entries[j].name, strtab + symtab[i].st_name) == 0) {
-        vdso_entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
+      if (strcmp(vdso[j].name, strtab + symtab[i].st_name) == 0) {
+        vdso[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
       }
     }
   }
@@ -124,7 +113,7 @@
 
 #else
 
-void __libc_init_vdso() {
+void __libc_init_vdso(libc_globals*, KernelArgumentBlock&) {
 }
 
 #endif
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index 40f610f..d5ec386 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -80,6 +80,29 @@
    */
   ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
 
+  /* Instructs dlopen to load the library at the address specified by reserved_addr.
+   *
+   * The difference between ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS and ANDROID_DLEXT_RESERVED_ADDRESS
+   * is that for ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS the linker reserves memory at reserved_addr
+   * whereas for ANDROID_DLEXT_RESERVED_ADDRESS the linker relies on the caller to reserve the memory.
+   *
+   * This flag can be used with ANDROID_DLEXT_FORCE_FIXED_VADDR; when ANDROID_DLEXT_FORCE_FIXED_VADDR
+   * is set and load_bias is not 0 (load_bias is min(p_vaddr) of PT_LOAD segments) this flag is ignored.
+   * This is implemented this way because the linker has to pick one address over the other and this
+   * way is more convenient for art. Note that ANDROID_DLEXT_FORCE_FIXED_VADDR does not generate
+   * an error when min(p_vaddr) is 0.
+   *
+   * Cannot be used with ANDROID_DLEXT_RESERVED_ADDRESS or ANDROID_DLEXT_RESERVED_ADDRESS_HINT.
+   *
+   * This flag is for ART internal use only.
+   */
+  ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100,
+
+  /* This flag used to load library in a different namespace. The namespace is
+   * specified in library_namespace.
+   */
+  ANDROID_DLEXT_USE_NAMESPACE = 0x200,
+
   /* Mask of valid bits */
   ANDROID_DLEXT_VALID_FLAG_BITS       = ANDROID_DLEXT_RESERVED_ADDRESS |
                                         ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
@@ -88,9 +111,13 @@
                                         ANDROID_DLEXT_USE_LIBRARY_FD |
                                         ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
                                         ANDROID_DLEXT_FORCE_LOAD |
-                                        ANDROID_DLEXT_FORCE_FIXED_VADDR,
+                                        ANDROID_DLEXT_FORCE_FIXED_VADDR |
+                                        ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS |
+                                        ANDROID_DLEXT_USE_NAMESPACE,
 };
 
+struct android_namespace_t;
+
 typedef struct {
   uint64_t flags;
   void*   reserved_addr;
@@ -98,10 +125,75 @@
   int     relro_fd;
   int     library_fd;
   off64_t library_fd_offset;
+  struct android_namespace_t* library_namespace;
 } android_dlextinfo;
 
 extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
 
+/*
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
+ * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
+ */
+extern bool android_init_namespaces(const char* public_ns_sonames,
+                                    const char* anon_ns_library_path);
+
+
+enum {
+  /* A regular namespace is the namespace with a custom search path that does
+   * not impose any restrictions on the location of native libraries.
+   */
+  ANDROID_NAMESPACE_TYPE_REGULAR = 0,
+
+  /* An isolated namespace requires all the libraries to be on the search path
+   * or under permitted_when_isolated_path. The search path is the union of
+   * ld_library_path and default_library_path.
+   */
+  ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+
+  /* The shared namespace clones the list of libraries of the caller namespace upon creation
+   * which means that they are shared between namespaces - the caller namespace and the new one
+   * will use the same copy of a library if it was loaded prior to android_create_namespace call.
+   *
+   * Note that libraries loaded after the namespace is created will not be shared.
+   *
+   * Shared namespaces can be isolated or regular. Note that they do not inherit the search path nor
+   * permitted_path from the caller's namespace.
+   */
+  ANDROID_NAMESPACE_TYPE_SHARED = 2,
+  ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
+                                           ANDROID_NAMESPACE_TYPE_ISOLATED,
+};
+
+/*
+ * Creates new linker namespace.
+ * ld_library_path and default_library_path represent the search path
+ * for the libraries in the namespace.
+ *
+ * The libraries in the namespace are searched by folowing order:
+ * 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+ * 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+ * 3. deault_library_path (This of this as namespace-local default library path)
+ *
+ * When type is ANDROID_NAMESPACE_TYPE_ISOLATED the resulting namespace requires all of
+ * the libraries to be on the search path or under the permitted_when_isolated_path;
+ * the search_path is ld_library_path:default_library_path. Note that the
+ * permitted_when_isolated_path path is not part of the search_path and
+ * does not affect the search order. It is a way to allow loading libraries from specific
+ * locations when using absolute path.
+ * If a library or any of its dependencies are outside of the permitted_when_isolated_path
+ * and search_path, and it is not part of the public namespace dlopen will fail.
+ */
+extern struct android_namespace_t* android_create_namespace(const char* name,
+                                                            const char* ld_library_path,
+                                                            const char* default_library_path,
+                                                            uint64_t type,
+                                                            const char* permitted_when_isolated_path);
+
 __END_DECLS
 
 #endif /* __ANDROID_DLEXT_H__ */
diff --git a/libc/include/byteswap.h b/libc/include/byteswap.h
index 74b0e91..628fb7f 100644
--- a/libc/include/byteswap.h
+++ b/libc/include/byteswap.h
@@ -28,11 +28,10 @@
 #ifndef _BYTESWAP_H_
 #define _BYTESWAP_H_
 
-/* endian.h rather than sys/endian.h so we get the machine-specific file. */
-#include <endian.h>
+#include <sys/endian.h>
 
-#define  bswap_16(x)   swap16(x)
-#define  bswap_32(x)   swap32(x)
-#define  bswap_64(x)   swap64(x)
+#define bswap_16(x) __swap16(x)
+#define bswap_32(x) __swap32(x)
+#define bswap_64(x) __swap64(x)
 
 #endif /* _BYTESWAP_H_ */
diff --git a/libc/include/dirent.h b/libc/include/dirent.h
index 63716a4..3cdfa68 100644
--- a/libc/include/dirent.h
+++ b/libc/include/dirent.h
@@ -81,8 +81,13 @@
 extern int dirfd(DIR*);
 extern int alphasort(const struct dirent**, const struct dirent**);
 extern int alphasort64(const struct dirent64**, const struct dirent64**);
-extern int scandir(const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
 extern int scandir64(const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));
+extern int scandir(const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
+
+#if defined(__USE_GNU)
+int scandirat64(int, const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));
+int scandirat(int, const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
+#endif
 
 __END_DECLS
 
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index afa7687..c2e8980 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -43,11 +43,12 @@
                                in dli_sname */
 } Dl_info;
 
-extern void*        dlopen(const char*  filename, int flag);
-extern int          dlclose(void*  handle);
-extern const char*  dlerror(void);
-extern void*        dlsym(void*  handle, const char*  symbol);
-extern int          dladdr(const void* addr, Dl_info *info);
+extern void* dlopen(const char*  filename, int flag);
+extern int dlclose(void*  handle);
+extern const char* dlerror(void);
+extern void* dlsym(void* handle, const char* symbol) __nonnull((2));
+extern void* dlvsym(void* handle, const char* symbol, const char* version) __nonnull((2, 3));
+extern int dladdr(const void* addr, Dl_info *info);
 
 enum {
 #if defined(__LP64__)
diff --git a/libc/private/bionic_time.h b/libc/include/ifaddrs.h
similarity index 70%
rename from libc/private/bionic_time.h
rename to libc/include/ifaddrs.h
index 030dcfd..54a5a2c 100644
--- a/libc/private/bionic_time.h
+++ b/libc/include/ifaddrs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,35 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _BIONIC_TIME_H
-#define _BIONIC_TIME_H
 
-#include <time.h>
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
 #include <sys/cdefs.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 
 __BEGIN_DECLS
 
-// We can't remove this (and this file) until we fix MtpUtils.cpp.
-time_t mktime_tz(struct tm* const, char const*);
+struct ifaddrs {
+  struct ifaddrs* ifa_next;
+  char* ifa_name;
+  unsigned int ifa_flags;
+  struct sockaddr* ifa_addr;
+  struct sockaddr* ifa_netmask;
+  union {
+    struct sockaddr* ifu_broadaddr;
+    struct sockaddr* ifu_dstaddr;
+  } ifa_ifu;
+  void* ifa_data;
+};
+
+#define ifa_broadaddr ifa_ifu.ifu_broadaddr
+#define ifa_dstaddr ifa_ifu.ifu_dstaddr
+
+void freeifaddrs(struct ifaddrs*);
+int getifaddrs(struct ifaddrs**);
 
 __END_DECLS
 
-#endif /* _BIONIC_TIME_H */
+#endif
diff --git a/libc/include/libgen.h b/libc/include/libgen.h
index e89328e..4d22d15 100644
--- a/libc/include/libgen.h
+++ b/libc/include/libgen.h
@@ -32,18 +32,19 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+
 __BEGIN_DECLS
 
-#if !defined(__bionic_using_gnu_basename)
 /*
- * <string.h> gets you the GNU basename.
- * <libgen.h> the POSIX one.
- * Note that our "POSIX" one has the wrong argument cv-qualifiers, but doesn't
- * modify its input and uses thread-local storage for the result if necessary.
+ * Including <string.h> will get you the GNU basename, unless <libgen.h> is
+ * included, either before or after including <string.h>.
+ *
+ * Note that this has the wrong argument cv-qualifiers, but doesn't modify its
+ * input and uses thread-local storage for the result if necessary.
  */
-extern char* basename(const char*);
-#define __bionic_using_posix_basename
-#endif
+extern char* __posix_basename(const char*) __RENAME(basename);
+
+#define basename __posix_basename
 
 /* This has the wrong argument cv-qualifiers, but doesn't modify its input and uses thread-local storage for the result if necessary. */
 extern char* dirname(const char*);
diff --git a/libc/include/limits.h b/libc/include/limits.h
index 6ae629b..67c7719 100644
--- a/libc/include/limits.h
+++ b/libc/include/limits.h
@@ -81,17 +81,6 @@
 
 #define MB_LEN_MAX 4
 
-/* New code should use sysconf(_SC_PAGE_SIZE) instead. */
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-#ifndef PAGESIZE
-#define  PAGESIZE  PAGE_SIZE
-#endif
-
-/* glibc's PAGE_MASK is the bitwise negation of BSD's! TODO: remove? */
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-
 #define SEM_VALUE_MAX 0x3fffffff
 
 /* POSIX says these belong in <unistd.h> but BSD has some in <limits.h>. */
diff --git a/libc/include/netinet/udp.h b/libc/include/netinet/udp.h
index 25e0dfc..d4eb368 100644
--- a/libc/include/netinet/udp.h
+++ b/libc/include/netinet/udp.h
@@ -25,31 +25,29 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _NETINET_UDP_H
 #define _NETINET_UDP_H
 
-/*
- * We would include linux/udp.h, but it brings in too much other stuff
- */
+#include <sys/types.h>
 
-#ifdef __FAVOR_BSD
+#include <linux/udp.h>
 
 struct udphdr {
-    u_int16_t uh_sport;	/* source port */
-    u_int16_t uh_dport;	/* destination port */
-    u_int16_t uh_ulen;	/* udp length */
-    u_int16_t uh_sum;	/* udp checksum */
+    __extension__ union {
+        struct /* BSD names */ {
+            u_int16_t uh_sport;
+            u_int16_t uh_dport;
+            u_int16_t uh_ulen;
+            u_int16_t uh_sum;
+        };
+        struct /* Linux names */ {
+            u_int16_t source;
+            u_int16_t dest;
+            u_int16_t len;
+            u_int16_t check;
+        };
+    };
 };
 
-#else
-
-struct udphdr {
-    __u16  source;
-    __u16  dest;
-    __u16  len;
-    __u16  check;
-};
-
-#endif /* __FAVOR_BSD */
-
 #endif /* _NETINET_UDP_H */
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 260ae5b..21d34fb 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -96,6 +96,26 @@
 
 #define PTHREAD_ONCE_INIT 0
 
+typedef struct {
+#if defined(__LP64__)
+  int64_t __private[4];
+#else
+  int32_t __private[8];
+#endif
+} pthread_barrier_t;
+
+typedef int pthread_barrierattr_t;
+
+#define PTHREAD_BARRIER_SERIAL_THREAD -1
+
+typedef struct {
+#if defined(__LP64__)
+  int64_t __private;
+#else
+  int32_t __private[2];
+#endif
+} pthread_spinlock_t;
+
 #if defined(__LP64__)
 #define PTHREAD_STACK_MIN (4 * PAGE_SIZE)
 #else
@@ -130,7 +150,7 @@
 int pthread_attr_setschedpolicy(pthread_attr_t*, int) __nonnull((1));
 int pthread_attr_setscope(pthread_attr_t*, int) __nonnull((1));
 int pthread_attr_setstack(pthread_attr_t*, void*, size_t) __nonnull((1));
-int pthread_attr_setstacksize(pthread_attr_t*, size_t stack_size) __nonnull((1));
+int pthread_attr_setstacksize(pthread_attr_t*, size_t) __nonnull((1));
 
 int pthread_condattr_destroy(pthread_condattr_t*) __nonnull((1));
 int pthread_condattr_getclock(const pthread_condattr_t*, clockid_t*) __nonnull((1, 2));
@@ -205,9 +225,24 @@
 int pthread_rwlock_timedwrlock(pthread_rwlock_t*, const struct timespec*) __nonnull((1, 2));
 int pthread_rwlock_tryrdlock(pthread_rwlock_t*) __nonnull((1));
 int pthread_rwlock_trywrlock(pthread_rwlock_t*) __nonnull((1));
-int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) __nonnull((1));
+int pthread_rwlock_unlock(pthread_rwlock_t *) __nonnull((1));
 int pthread_rwlock_wrlock(pthread_rwlock_t*) __nonnull((1));
 
+int pthread_barrierattr_init(pthread_barrierattr_t* attr) __nonnull((1));
+int pthread_barrierattr_destroy(pthread_barrierattr_t* attr) __nonnull((1));
+int pthread_barrierattr_getpshared(pthread_barrierattr_t* attr, int* pshared) __nonnull((1, 2));
+int pthread_barrierattr_setpshared(pthread_barrierattr_t* attr, int pshared) __nonnull((1));
+
+int pthread_barrier_init(pthread_barrier_t*, const pthread_barrierattr_t*, unsigned) __nonnull((1));
+int pthread_barrier_destroy(pthread_barrier_t*) __nonnull((1));
+int pthread_barrier_wait(pthread_barrier_t*) __nonnull((1));
+
+int pthread_spin_destroy(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_init(pthread_spinlock_t*, int) __nonnull((1));
+int pthread_spin_lock(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_trylock(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_unlock(pthread_spinlock_t*) __nonnull((1));
+
 pthread_t pthread_self(void) __pure2;
 
 int pthread_setname_np(pthread_t, const char*) __nonnull((2));
diff --git a/libc/include/regex.h b/libc/include/regex.h
index aec38e3..b06a515 100644
--- a/libc/include/regex.h
+++ b/libc/include/regex.h
@@ -42,8 +42,9 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
-/* types */
-typedef off_t regoff_t;
+/* POSIX says regoff_t is at least as large as the larger of ptrdiff_t and
+ * ssize_t. BSD uses off_t, but that interacts badly with _FILE_OFFSET_BITS. */
+typedef ssize_t regoff_t;
 
 typedef struct {
 	int re_magic;
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 554e0ac..7a171b4 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -105,15 +105,15 @@
 
 extern int sigaction(int, const struct sigaction*, struct sigaction*);
 
-_BIONIC_NOT_BEFORE_21(extern sighandler_t signal(int, sighandler_t);)
+extern sighandler_t signal(int, sighandler_t) __INTRODUCED_IN(21);
 
 extern int siginterrupt(int, int);
 
-_BIONIC_NOT_BEFORE_21(extern int sigaddset(sigset_t*, int);)
-_BIONIC_NOT_BEFORE_21(extern int sigdelset(sigset_t*, int);)
-_BIONIC_NOT_BEFORE_21(extern int sigemptyset(sigset_t*);)
-_BIONIC_NOT_BEFORE_21(extern int sigfillset(sigset_t*);)
-_BIONIC_NOT_BEFORE_21(extern int sigismember(const sigset_t*, int);)
+extern int sigaddset(sigset_t*, int) __INTRODUCED_IN(21);
+extern int sigdelset(sigset_t*, int) __INTRODUCED_IN(21);
+extern int sigemptyset(sigset_t*) __INTRODUCED_IN(21);
+extern int sigfillset(sigset_t*) __INTRODUCED_IN(21);
+extern int sigismember(const sigset_t*, int) __INTRODUCED_IN(21);
 
 extern int sigpending(sigset_t*) __nonnull((1));
 extern int sigprocmask(int, const sigset_t*, sigset_t*);
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index f5ed652..fd653d9 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -38,14 +38,6 @@
 #ifndef	_STDIO_H_
 #define	_STDIO_H_
 
-/*
- * This file must contain a reference to __gnuc_va_list so that GCC's
- * fixincludes knows that that's what's being used for va_list, and so
- * to leave our <stdio.h> alone. (fixincludes gets in the way of pointing
- * one toolchain at various different sets of platform headers.)
- * If you alter this comment, be sure to keep "__gnuc_va_list" in it!
- */
-
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
@@ -59,94 +51,9 @@
 
 typedef off_t fpos_t;		/* stdio file position type */
 
-/*
- * NB: to fit things in six character monocase externals, the stdio
- * code uses the prefix `__s' for stdio objects, typically followed
- * by a three-character attempt at a mnemonic.
- */
+struct __sFILE;
+typedef struct __sFILE FILE;
 
-/* stdio buffers */
-#if defined(__LP64__)
-struct __sbuf {
-  unsigned char* _base;
-  size_t _size;
-};
-#else
-struct __sbuf {
-	unsigned char *_base;
-	int	_size;
-};
-#endif
-
-/*
- * stdio state variables.
- *
- * The following always hold:
- *
- *	if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
- *		_lbfsize is -_bf._size, else _lbfsize is 0
- *	if _flags&__SRD, _w is 0
- *	if _flags&__SWR, _r is 0
- *
- * This ensures that the getc and putc macros (or inline functions) never
- * try to write or read from a file that is in `read' or `write' mode.
- * (Moreover, they can, and do, automatically switch from read mode to
- * write mode, and back, on "r+" and "w+" files.)
- *
- * _lbfsize is used only to make the inline line-buffered output stream
- * code as compact as possible.
- *
- * _ub, _up, and _ur are used when ungetc() pushes back more characters
- * than fit in the current _bf, or when ungetc() pushes back a character
- * that does not match the previous one in _bf.  When this happens,
- * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
- * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
- *
- * NOTE: if you change this structure, you also need to update the
- * std() initializer in findfp.c.
- */
-typedef	struct __sFILE {
-	unsigned char *_p;	/* current position in (some) buffer */
-	int	_r;		/* read space left for getc() */
-	int	_w;		/* write space left for putc() */
-#if defined(__LP64__)
-	int	_flags;		/* flags, below; this FILE is free if 0 */
-	int	_file;		/* fileno, if Unix descriptor, else -1 */
-#else
-	short	_flags;		/* flags, below; this FILE is free if 0 */
-	short	_file;		/* fileno, if Unix descriptor, else -1 */
-#endif
-	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
-	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
-
-	/* operations */
-	void	*_cookie;	/* cookie passed to io functions */
-	int	(*_close)(void *);
-	int	(*_read)(void *, char *, int);
-	fpos_t	(*_seek)(void *, fpos_t, int);
-	int	(*_write)(void *, const char *, int);
-
-	/* extension data, to avoid further ABI breakage */
-	struct	__sbuf _ext;
-	/* data for long sequences of ungetc() */
-	unsigned char *_up;	/* saved _p when _p is doing ungetc data */
-	int	_ur;		/* saved _r when _r is counting ungetc data */
-
-	/* tricks to meet minimum requirements even when malloc() fails */
-	unsigned char _ubuf[3];	/* guarantee an ungetc() buffer */
-	unsigned char _nbuf[1];	/* guarantee a getc() buffer */
-
-	/* separate buffer for fgetln() when line crosses buffer boundary */
-	struct	__sbuf _lb;	/* buffer for fgetln() */
-
-	/* Unix stdio files get aligned to block boundaries on fseek() */
-	int	_blksize;	/* stat.st_blksize (may be != _bf._size) */
-	fpos_t	_offset;	/* current lseek offset */
-} FILE;
-
-/* Legacy BSD implementation of stdin/stdout/stderr. */
-extern FILE __sF[];
-/* More obvious implementation. */
 extern FILE* stdin;
 extern FILE* stdout;
 extern FILE* stderr;
@@ -363,6 +270,7 @@
 void clearerr_unlocked(FILE*);
 int feof_unlocked(FILE*);
 int ferror_unlocked(FILE*);
+int fileno_unlocked(FILE*);
 
 /*
  * Stdio function-access interface.
@@ -382,6 +290,16 @@
 __errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
 __errordecl(__fgets_too_small_error, "fgets called with size less than zero");
 
+extern size_t __fread_chk(void * __restrict, size_t, size_t, FILE * __restrict, size_t);
+extern size_t __fread_real(void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fread);
+__errordecl(__fread_too_big_error, "fread called with size * count bigger than buffer");
+__errordecl(__fread_overflow, "fread called with overflowing size * count");
+
+extern size_t __fwrite_chk(const void * __restrict, size_t, size_t, FILE * __restrict, size_t);
+extern size_t __fwrite_real(const void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fwrite);
+__errordecl(__fwrite_too_big_error, "fwrite called with size * count bigger than buffer");
+__errordecl(__fwrite_overflow, "fwrite called with overflowing size * count");
+
 #if defined(__BIONIC_FORTIFY)
 
 __BIONIC_FORTIFY_INLINE
@@ -428,6 +346,58 @@
 }
 #endif
 
+__BIONIC_FORTIFY_INLINE
+size_t fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+    size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __fread_real(buf, size, count, stream);
+    }
+
+    if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+        size_t total;
+        if (__size_mul_overflow(size, count, &total)) {
+            __fread_overflow();
+        }
+
+        if (total > bos) {
+            __fread_too_big_error();
+        }
+
+        return __fread_real(buf, size, count, stream);
+    }
+#endif
+
+    return __fread_chk(buf, size, count, stream, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+    size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __fwrite_real(buf, size, count, stream);
+    }
+
+    if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+        size_t total;
+        if (__size_mul_overflow(size, count, &total)) {
+            __fwrite_overflow();
+        }
+
+        if (total > bos) {
+            __fwrite_too_big_error();
+        }
+
+        return __fwrite_real(buf, size, count, stream);
+    }
+#endif
+
+    return __fwrite_chk(buf, size, count, stream, bos);
+}
+
 #if !defined(__clang__)
 
 __BIONIC_FORTIFY_INLINE
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index efca577..d9d277a 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -76,10 +76,10 @@
 
 extern int posix_memalign(void **memptr, size_t alignment, size_t size);
 
-_BIONIC_NOT_BEFORE_21(extern double atof(const char*);)
+extern double atof(const char*) __INTRODUCED_IN(21);
 
 extern double strtod(const char*, char**) __LIBC_ABI_PUBLIC__;
-_BIONIC_NOT_BEFORE_21(extern float strtof(const char*, char**) __LIBC_ABI_PUBLIC__;)
+extern float strtof(const char*, char**) __LIBC_ABI_PUBLIC__ __INTRODUCED_IN(21);
 extern long double strtold(const char*, char**) __LIBC_ABI_PUBLIC__;
 
 extern long double strtold_l(const char *, char **, locale_t) __LIBC_ABI_PUBLIC__;
@@ -90,9 +90,9 @@
 extern long atol(const char*) __purefunc;
 extern long long atoll(const char*) __purefunc;
 
-_BIONIC_NOT_BEFORE_21(extern int abs(int) __pure2;)
-_BIONIC_NOT_BEFORE_21(extern long labs(long) __pure2;)
-_BIONIC_NOT_BEFORE_21(extern long long llabs(long long) __pure2;)
+extern int abs(int) __pure2 __INTRODUCED_IN(21);
+extern long labs(long) __pure2 __INTRODUCED_IN(21);
+extern long long llabs(long long) __pure2 __INTRODUCED_IN(21);
 
 extern char * realpath(const char *path, char *resolved);
 extern int system(const char *string);
@@ -109,9 +109,9 @@
 
 #define RAND_MAX 0x7fffffff
 
-_BIONIC_NOT_BEFORE_21(int rand(void);)
+int rand(void) __INTRODUCED_IN(21);
 int rand_r(unsigned int*);
-_BIONIC_NOT_BEFORE_21(void srand(unsigned int);)
+void srand(unsigned int) __INTRODUCED_IN(21);
 
 double drand48(void);
 double erand48(unsigned short[3]);
@@ -124,12 +124,12 @@
 void srand48(long);
 
 char* initstate(unsigned int, char*, size_t);
-_BIONIC_NOT_BEFORE_21(long random(void);)
+long random(void) __INTRODUCED_IN(21);
 char* setstate(char*);
-_BIONIC_NOT_BEFORE_21(void srandom(unsigned int);)
+void srandom(unsigned int) __INTRODUCED_IN(21);
 
 int getpt(void);
-_BIONIC_NOT_BEFORE_21(int grantpt(int);)
+int grantpt(int) __INTRODUCED_IN(21);
 int posix_openpt(int);
 char* ptsname(int);
 int ptsname_r(int, char*, size_t);
diff --git a/libc/include/string.h b/libc/include/string.h
index d32c164..32d4a18 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -53,6 +53,14 @@
 
 extern char*  strchr(const char *, int) __purefunc;
 extern char* __strchr_chk(const char *, int, size_t);
+#if defined(__USE_GNU)
+#if defined(__cplusplus)
+extern "C++" char* strchrnul(char*, int) __RENAME(strchrnul) __purefunc;
+extern "C++" const char* strchrnul(const char*, int) __RENAME(strchrnul) __purefunc;
+#else
+char* strchrnul(const char*, int) __purefunc;
+#endif
+#endif
 
 extern char*  strrchr(const char *, int) __purefunc;
 extern char* __strrchr_chk(const char *, int, size_t);
@@ -107,18 +115,18 @@
 extern int    strcoll_l(const char *, const char *, locale_t) __purefunc;
 extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t);
 
-#if defined(__USE_GNU) && !defined(__bionic_using_posix_basename)
+#if defined(__USE_GNU) && !defined(basename)
 /*
  * glibc has a basename in <string.h> that's different to the POSIX one in <libgen.h>.
  * It doesn't modify its argument, and in C++ it's const-correct.
  */
+
 #if defined(__cplusplus)
 extern "C++" char* basename(char*) __RENAME(__gnu_basename) __nonnull((1));
 extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
 #else
 extern char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
 #endif
-#define __bionic_using_gnu_basename
 #endif
 
 extern void* __memchr_chk(const void*, int, size_t, size_t);
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index a0315b5..3b1f7d0 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -41,6 +41,7 @@
 #define PROP_AREA_VERSION_COMPAT 0x45434f76
 
 #define PROP_SERVICE_NAME "property_service"
+#define PROP_FILENAME_MAX 1024
 #define PROP_FILENAME "/dev/__properties__"
 
 #define PA_SIZE         (128 * 1024)
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 7df8b60..342cfad 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -130,30 +130,9 @@
 #define	__volatile
 #endif	/* !__GNUC__ */
 
-/*
- * In non-ANSI C environments, new programs will want ANSI-only C keywords
- * deleted from the program and old programs will want them left alone.
- * Programs using the ANSI C keywords const, inline etc. as normal
- * identifiers should define -DNO_ANSI_KEYWORDS.
- */
-#ifndef	NO_ANSI_KEYWORDS
-#define	const		__const		/* convert ANSI C keywords */
-#define	inline		__inline
-#define	signed		__signed
-#define	volatile	__volatile
-#endif /* !NO_ANSI_KEYWORDS */
 #endif	/* !(__STDC__ || __cplusplus) */
 
 /*
- * Used for internal auditing of the NetBSD source tree.
- */
-#ifdef __AUDIT__
-#define	__aconst	__const
-#else
-#define	__aconst
-#endif
-
-/*
  * The following macro is used to remove const cast-away warnings
  * from gcc -Wcast-qual; it should be used with caution because it
  * can hide valid errors; in particular most valid uses are in
@@ -164,75 +143,19 @@
  */
 #define __UNCONST(a)	((void *)(unsigned long)(const void *)(a))
 
-/*
- * GCC2 provides __extension__ to suppress warnings for various GNU C
- * language extensions under "-ansi -pedantic".
- */
-#if !__GNUC_PREREQ(2, 0)
-#define	__extension__		/* delete __extension__ if non-gcc or gcc1 */
-#endif
-
-/*
- * GCC1 and some versions of GCC2 declare dead (non-returning) and
- * pure (no side effects) functions using "volatile" and "const";
- * unfortunately, these then cause warnings under "-ansi -pedantic".
- * GCC2 uses a new, peculiar __attribute__((attrs)) style.  All of
- * these work for GNU C++ (modulo a slight glitch in the C++ grammar
- * in the distribution version of 2.5.5).
- */
-#if !__GNUC_PREREQ(2, 5)
-#define	__attribute__(x)	/* delete __attribute__ if non-gcc or gcc1 */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define	__dead		__volatile
-#define	__pure		__const
-#endif
-#endif
-
-/* Delete pseudo-keywords wherever they are not available or needed. */
-#ifndef __dead
-#define	__dead
-#define	__pure
-#endif
-
-#if __GNUC_PREREQ(2, 7)
-#define	__unused	__attribute__((__unused__))
-#else
-#define	__unused	/* delete */
-#endif
-
+#define __dead __attribute__((__noreturn__))
+#define __pure __attribute__((__const__))
 #define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */
 
-#if __GNUC_PREREQ(3, 1)
-#define	__used		__attribute__((__used__))
-#else
-#define	__used		/* delete */
-#endif
+#define	__unused	__attribute__((__unused__))
 
-#if __GNUC_PREREQ(2, 7)
+#define	__used		__attribute__((__used__))
+
 #define	__packed	__attribute__((__packed__))
 #define	__aligned(x)	__attribute__((__aligned__(x)))
 #define	__section(x)	__attribute__((__section__(x)))
-#elif defined(__lint__)
-#define	__packed	/* delete */
-#define	__aligned(x)	/* delete */
-#define	__section(x)	/* delete */
-#else
-#define	__packed	error: no __packed for this compiler
-#define	__aligned(x)	error: no __aligned for this compiler
-#define	__section(x)	error: no __section for this compiler
-#endif
 
-#if !__GNUC_PREREQ(2, 8)
-#define	__extension__
-#endif
-
-#if __GNUC_PREREQ(2, 8)
 #define __statement(x)	__extension__(x)
-#elif defined(lint)
-#define __statement(x)	(0)
-#else
-#define __statement(x)	(x)
-#endif
 
 #define __nonnull(args) __attribute__((__nonnull__ args))
 
@@ -240,43 +163,20 @@
 #define __scanflike(x, y) __attribute__((__format__(scanf, x, y))) __nonnull((x))
 
 /*
- * C99 defines the restrict type qualifier keyword, which was made available
- * in GCC 2.92.
+ * C99 defines the restrict type qualifier keyword.
  */
 #if defined(__STDC__VERSION__) && __STDC_VERSION__ >= 199901L
 #define	__restrict	restrict
-#else
-#if !__GNUC_PREREQ(2, 92)
-#define	__restrict	/* delete __restrict when not supported */
-#endif
 #endif
 
 /*
- * C99 defines __func__ predefined identifier, which was made available
- * in GCC 2.95.
+ * C99 defines __func__ predefined identifier.
  */
 #if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L)
-#if __GNUC_PREREQ(2, 6)
 #define	__func__	__PRETTY_FUNCTION__
-#elif __GNUC_PREREQ(2, 4)
-#define	__func__	__FUNCTION__
-#else
-#define	__func__	""
-#endif
 #endif /* !(__STDC_VERSION__ >= 199901L) */
 
 /*
- * A barrier to stop the optimizer from moving code or assume live
- * register values. This is gcc specific, the version is more or less
- * arbitrary, might work with older compilers.
- */
-#if __GNUC_PREREQ(2, 95)
-#define	__insn_barrier()	__asm __volatile("":::"memory")
-#else
-#define	__insn_barrier()	/* */
-#endif
-
-/*
  * GNU C version 2.96 adds explicit branch prediction so that
  * the CPU back-end can hint the processor and also so that
  * code blocks can be reordered such that the predicted path
@@ -304,43 +204,19 @@
  *	  basic block reordering that this affects can often generate
  *	  larger code.
  */
-#if __GNUC_PREREQ(2, 96)
 #define	__predict_true(exp)	__builtin_expect((exp) != 0, 1)
 #define	__predict_false(exp)	__builtin_expect((exp) != 0, 0)
-#else
-#define	__predict_true(exp)	(exp)
-#define	__predict_false(exp)	(exp)
-#endif
 
-#if __GNUC_PREREQ(2, 96)
 #define __noreturn    __attribute__((__noreturn__))
 #define __mallocfunc  __attribute__((malloc))
 #define __purefunc    __attribute__((pure))
-#else
-#define __noreturn
-#define __mallocfunc
-#define __purefunc
-#endif
 
-#if __GNUC_PREREQ(3, 1)
 #define __always_inline __attribute__((__always_inline__))
-#else
-#define __always_inline
-#endif
 
-#if __GNUC_PREREQ(3, 4)
 #define __wur __attribute__((__warn_unused_result__))
-#else
-#define __wur
-#endif
 
-#if __GNUC_PREREQ(4, 3)
 #define __errorattr(msg) __attribute__((__error__(msg)))
 #define __warnattr(msg) __attribute__((__warning__(msg)))
-#else
-#define __errorattr(msg)
-#define __warnattr(msg)
-#endif
 
 #define __errordecl(name, msg) extern void name(void) __errorattr(msg)
 
@@ -540,19 +416,14 @@
  * http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html for details.
  */
 #if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
-#define __BIONIC_FORTIFY 1
-#if _FORTIFY_SOURCE == 2
-#define __bos(s) __builtin_object_size((s), 1)
-#else
-#define __bos(s) __builtin_object_size((s), 0)
-#endif
-#define __bos0(s) __builtin_object_size((s), 0)
-
-#if __GNUC_PREREQ(4,3) || __has_attribute(__artificial__)
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
-#else
-#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
-#endif
+#  define __BIONIC_FORTIFY 1
+#  if _FORTIFY_SOURCE == 2
+#    define __bos(s) __builtin_object_size((s), 1)
+#  else
+#    define __bos(s) __builtin_object_size((s), 0)
+#  endif
+#  define __bos0(s) __builtin_object_size((s), 0)
+#  define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__))
 #endif
 #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
 
@@ -561,9 +432,9 @@
 
 /* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */
 #ifdef __LP64__
-#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__
+#define __LIBC32_LEGACY_PUBLIC__ __LIBC_HIDDEN__
 #else
-#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__
+#define __LIBC32_LEGACY_PUBLIC__ __LIBC_ABI_PUBLIC__
 #endif
 
 /* Used to tag non-static symbols that are public and exposed by the shared library. */
@@ -572,10 +443,31 @@
 /* Used to rename functions so that the compiler emits a call to 'x' rather than the function this was applied to. */
 #define __RENAME(x) __asm__(#x)
 
-#if __ANDROID_API__ >= 21
-#define _BIONIC_NOT_BEFORE_21(x) x
+#ifdef __clang__
+#define __AVAILABILITY(...) __attribute__((availability(android,__VA_ARGS__)))
+#define __INTRODUCED_IN(api_level) __AVAILABILITY(introduced=api_level)
+#define __DEPRECATED_IN(api_level) __AVAILABILITY(deprecated=api_level)
+#define __REMOVED_IN(api_level) __AVAILABILITY(obsoleted=api_level)
 #else
-#define _BIONIC_NOT_BEFORE_21(x)
-#endif /* __ANDROID_API__ >= 21 */
+#define __AVAILABILITY(...)
+#define __INTRODUCED_IN(api_level)
+#define __DEPRECATED_IN(api_level)
+#define __REMOVED_IN(api_level)
+#endif // __clang__
+
+#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
+#if __LP64__
+#define __size_mul_overflow(a, b, result) __builtin_umull_overflow(a, b, result)
+#else
+#define __size_mul_overflow(a, b, result) __builtin_umul_overflow(a, b, result)
+#endif
+#else
+static __inline__ __always_inline int __size_mul_overflow(__SIZE_TYPE__ a, __SIZE_TYPE__ b,
+                                                          __SIZE_TYPE__ *result) {
+    *result = a * b;
+    static const __SIZE_TYPE__ mul_no_overflow = 1UL << (sizeof(__SIZE_TYPE__) * 4);
+    return (a >= mul_no_overflow || b >= mul_no_overflow) && a > 0 && (__SIZE_TYPE__)-1 / a < b;
+}
+#endif
 
 #endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/include/sys/endian.h b/libc/include/sys/endian.h
index 2fd480d..60cc030 100644
--- a/libc/include/sys/endian.h
+++ b/libc/include/sys/endian.h
@@ -75,10 +75,6 @@
 #define	HTONL(x) (x) = htonl((u_int32_t)(x))
 #define	HTONS(x) (x) = htons((u_int16_t)(x))
 
-#define swap16 __swap16
-#define swap32 __swap32
-#define swap64 __swap64
-
 #define htobe16 __swap16
 #define htobe32 __swap32
 #define htobe64 __swap64
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index 6857f60..a19ceb5 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -59,7 +59,7 @@
 extern int munmap(void*, size_t);
 extern int msync(const void*, size_t, int);
 extern int mprotect(const void*, size_t, int);
-extern void* mremap(void*, size_t, size_t, unsigned long);
+extern void* mremap(void*, size_t, size_t, int, ...);
 
 extern int mlockall(int);
 extern int munlockall(void);
diff --git a/libc/include/sys/procfs.h b/libc/include/sys/procfs.h
index b5b1a46..7ef5023 100644
--- a/libc/include/sys/procfs.h
+++ b/libc/include/sys/procfs.h
@@ -39,6 +39,10 @@
 
 typedef fpregset_t elf_fpregset_t;
 
+#if defined(__i386__)
+typedef struct user_fpxregs_struct elf_fpxregset_t;
+#endif
+
 typedef elf_gregset_t prgregset_t;
 typedef elf_fpregset_t prfpregset_t;
 
diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h
index 3f8dd45..8209dfb 100644
--- a/libc/include/sys/resource.h
+++ b/libc/include/sys/resource.h
@@ -53,10 +53,7 @@
 
 extern int getrusage(int, struct rusage*);
 
-#if __LP64__
-/* Implementing prlimit for 32-bit isn't worth the effort. */
 extern int prlimit(pid_t, int, const struct rlimit*, struct rlimit*);
-#endif
 extern int prlimit64(pid_t, int, const struct rlimit64*, struct rlimit64*);
 
 __END_DECLS
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 43d1586..c0720b8 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -50,19 +50,15 @@
 #ifdef __mips__
 #define SOCK_DGRAM      1
 #define SOCK_STREAM     2
+#else
+#define SOCK_STREAM     1
+#define SOCK_DGRAM      2
+#endif
 #define SOCK_RAW        3
 #define SOCK_RDM        4
 #define SOCK_SEQPACKET  5
 #define SOCK_DCCP       6
 #define SOCK_PACKET     10
-#else
-#define SOCK_STREAM      1
-#define SOCK_DGRAM       2
-#define SOCK_RAW         3
-#define SOCK_RDM         4
-#define SOCK_SEQPACKET   5
-#define SOCK_PACKET      10
-#endif
 
 #define SOCK_CLOEXEC O_CLOEXEC
 #define SOCK_NONBLOCK O_NONBLOCK
@@ -109,7 +105,7 @@
 
 #define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr((mhdr), (cmsg))
 #define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
-#define CMSG_DATA(cmsg) ((void*)((char*)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_DATA(cmsg) (((unsigned char*)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
 #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
 #define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
 #define CMSG_FIRSTHDR(msg) \
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index c22516f..65aa190 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -171,7 +171,7 @@
 }
 #endif /* defined(__BIONIC_FORTIFY) */
 
-_BIONIC_NOT_BEFORE_21(extern int mkfifo(const char*, mode_t);)
+extern int mkfifo(const char*, mode_t) __INTRODUCED_IN(21);
 extern int mkfifoat(int, const char*, mode_t);
 
 extern int fchmodat(int, const char*, mode_t, int);
diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h
index 67107c6..f60c905 100644
--- a/libc/include/sys/time.h
+++ b/libc/include/sys/time.h
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SYS_TIME_H_
 #define _SYS_TIME_H_
 
@@ -32,6 +33,9 @@
 #include <sys/types.h>
 #include <linux/time.h>
 
+/* POSIX says <sys/time.h> gets you most of <sys/select.h> and may get you all of it. */
+#include <sys/select.h>
+
 __BEGIN_DECLS
 
 extern int gettimeofday(struct timeval *, struct timezone *);
diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h
index 399458e..9e3c653 100644
--- a/libc/include/sys/ucontext.h
+++ b/libc/include/sys/ucontext.h
@@ -82,12 +82,6 @@
 #define NGREG 34 /* x0..x30 + sp + pc + pstate */
 typedef unsigned long greg_t;
 typedef greg_t gregset_t[NGREG];
-
-struct user_fpsimd_struct {
-  long double vregs[32];
-  uint32_t fpsr;
-  uint32_t fpcr;
-};
 typedef struct user_fpsimd_struct fpregset_t;
 
 #include <asm/sigcontext.h>
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
index 187ec22..72675d1 100644
--- a/libc/include/sys/uio.h
+++ b/libc/include/sys/uio.h
@@ -38,6 +38,18 @@
 int writev(int, const struct iovec*, int);
 
 #if defined(__USE_GNU)
+#if defined(__USE_FILE_OFFSET64)
+ssize_t preadv(int, const struct iovec*, int, off_t) __RENAME(preadv64);
+ssize_t pwritev(int, const struct iovec*, int, off_t) __RENAME(pwritev64);
+#else
+ssize_t preadv(int, const struct iovec*, int, off_t);
+ssize_t pwritev(int, const struct iovec*, int, off_t);
+#endif
+ssize_t preadv64(int, const struct iovec*, int, off64_t);
+ssize_t pwritev64(int, const struct iovec*, int, off64_t);
+#endif
+
+#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
diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h
index b370add..3312981 100644
--- a/libc/include/sys/user.h
+++ b/libc/include/sys/user.h
@@ -30,11 +30,13 @@
 #define _SYS_USER_H_
 
 #include <sys/cdefs.h>
-#include <limits.h> /* For PAGE_SIZE. */
 #include <stddef.h> /* For size_t. */
 
 __BEGIN_DECLS
 
+#define PAGE_SIZE 4096
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
 #if __i386__
 
 struct user_fpregs_struct {
@@ -47,7 +49,7 @@
   long fos;
   long st_space[20];
 };
-struct user_fxsr_struct {
+struct user_fpxregs_struct {
   unsigned short cwd;
   unsigned short swd;
   unsigned short twd;
@@ -230,7 +232,17 @@
 
 #elif defined(__aarch64__)
 
-// There are no user structures for 64 bit arm.
+struct user_regs_struct {
+  uint64_t regs[31];
+  uint64_t sp;
+  uint64_t pc;
+  uint64_t pstate;
+};
+struct user_fpsimd_struct {
+  __uint128_t vregs[32];
+  uint32_t fpsr;
+  uint32_t fpcr;
+};
 
 #else
 
diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h
index 12b7308..2317b02 100644
--- a/libc/include/sys/wait.h
+++ b/libc/include/sys/wait.h
@@ -44,6 +44,7 @@
 #define WIFEXITED(s)    (WTERMSIG(s) == 0)
 #define WIFSTOPPED(s)   (WTERMSIG(s) == 0x7f)
 #define WIFSIGNALED(s)  (WTERMSIG((s)+1) >= 2)
+#define WIFCONTINUED(s) ((s) == 0xffff)
 
 #define W_EXITCODE(ret, sig)    ((ret) << 8 | (sig))
 #define W_STOPCODE(sig)         ((sig) << 8 | 0x7f)
diff --git a/libc/include/uchar.h b/libc/include/uchar.h
index e1fcb5c..a5e72ea 100644
--- a/libc/include/uchar.h
+++ b/libc/include/uchar.h
@@ -34,6 +34,11 @@
 
 __BEGIN_DECLS
 
+#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
+
 #define __STD_UTF_16__ 1
 #define __STD_UTF_32__ 1
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index f0de29e..23b47a3 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -75,146 +75,168 @@
 
 extern char** environ;
 
-extern __noreturn void _exit(int);
+extern __noreturn void _exit(int __status);
 
 extern pid_t  fork(void);
 extern pid_t  vfork(void);
 extern pid_t  getpid(void);
 extern pid_t  gettid(void) __pure2;
-extern pid_t  getpgid(pid_t);
-extern int    setpgid(pid_t, pid_t);
+extern pid_t  getpgid(pid_t __pid);
+extern int    setpgid(pid_t __pid, pid_t __pgid);
 extern pid_t  getppid(void);
 extern pid_t  getpgrp(void);
 extern int    setpgrp(void);
-extern pid_t  getsid(pid_t);
+extern pid_t  getsid(pid_t __pid) __INTRODUCED_IN(21);
 extern pid_t  setsid(void);
 
-extern int execv(const char *, char * const *);
-extern int execvp(const char *, char * const *);
-extern int execvpe(const char *, char * const *, char * const *);
-extern int execve(const char *, char * const *, char * const *);
-extern int execl(const char *, const char *, ...);
-extern int execlp(const char *, const char *, ...);
-extern int execle(const char *, const char *, ...);
+extern int execv(const char* __path, char* const* __argv);
+extern int execvp(const char* __file, char* const* __argv);
+extern int execvpe(const char* __file, char* const* __argv, char* const* __envp)
+  __INTRODUCED_IN(21);
+extern int execve(const char* __file, char* const* __argv, char* const* __envp);
+extern int execl(const char* __path, const char* __arg0, ...);
+extern int execlp(const char* __file, const char* __arg0, ...);
+extern int execle(const char* __path, const char* __arg0, ...);
 
-extern int nice(int);
+extern int nice(int __incr);
 
-extern int setuid(uid_t);
+extern int setuid(uid_t __uid);
 extern uid_t getuid(void);
-extern int seteuid(uid_t);
+extern int seteuid(uid_t __uid);
 extern uid_t geteuid(void);
-extern int setgid(gid_t);
+extern int setgid(gid_t __gid);
 extern gid_t getgid(void);
-extern int setegid(gid_t);
+extern int setegid(gid_t __gid);
 extern gid_t getegid(void);
-extern int getgroups(int, gid_t *);
-extern int setgroups(size_t, const gid_t *);
-extern int setreuid(uid_t, uid_t);
-extern int setregid(gid_t, gid_t);
-extern int setresuid(uid_t, uid_t, uid_t);
-extern int setresgid(gid_t, gid_t, gid_t);
-extern int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-extern int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
+extern int getgroups(int __size, gid_t* __list);
+extern int setgroups(size_t __size, const gid_t* __list);
+extern int setreuid(uid_t __ruid, uid_t __euid);
+extern int setregid(gid_t __rgid, gid_t __egid);
+extern int setresuid(uid_t __ruid, uid_t __euid, uid_t __suid);
+extern int setresgid(gid_t __rgid, gid_t __egid, gid_t __sgid);
+extern int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
+extern int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
 extern char* getlogin(void);
 
-extern long fpathconf(int, int);
-extern long pathconf(const char*, int);
+extern long fpathconf(int __fd, int __name);
+extern long pathconf(const char* __path, int __name);
 
-extern int access(const char*, int);
-extern int faccessat(int, const char*, int, int);
-extern int link(const char*, const char*);
-extern int linkat(int, const char*, int, const char*, int);
-extern int unlink(const char*);
-extern int unlinkat(int, const char*, int);
-extern int chdir(const char *);
-extern int fchdir(int);
-extern int rmdir(const char *);
-extern int pipe(int *);
+extern int access(const char* __path, int __mode);
+extern int faccessat(int __dirfd, const char* __path, int __mode, int __flags)
+  __INTRODUCED_IN(21);
+extern int link(const char* __oldpath, const char* __newpath);
+extern int linkat(int __olddirfd, const char* __oldpath, int __newdirfd,
+                  const char* __newpath, int __flags) __INTRODUCED_IN(21);
+extern int unlink(const char* __path);
+extern int unlinkat(int __dirfd, const char* __path, int __flags);
+extern int chdir(const char* __path);
+extern int fchdir(int __fd);
+extern int rmdir(const char* __path);
+extern int pipe(int* __pipefd);
 #if defined(__USE_GNU)
-extern int pipe2(int *, int);
+extern int pipe2(int* __pipefd, int __flags) __INTRODUCED_IN(9);
 #endif
-extern int chroot(const char *);
-extern int symlink(const char*, const char*);
-extern int symlinkat(const char*, int, const char*);
-extern ssize_t readlink(const char*, char*, size_t);
-extern ssize_t readlinkat(int, const char*, char*, size_t);
-extern int chown(const char *, uid_t, gid_t);
-extern int fchown(int, uid_t, gid_t);
-extern int fchownat(int, const char*, uid_t, gid_t, int);
-extern int lchown(const char *, uid_t, gid_t);
-extern char *getcwd(char *, size_t);
+extern int chroot(const char* __path);
+extern int symlink(const char* __oldpath, const char* __newpath);
+extern int symlinkat(const char* __oldpath, int __newdirfd,
+                     const char* __newpath) __INTRODUCED_IN(21);
+extern ssize_t readlink(const char* __path, char* __buf, size_t __bufsiz);
+extern ssize_t readlinkat(int __dirfd, const char* __path, char* __buf,
+                          size_t __bufsiz) __INTRODUCED_IN(21);
+extern int chown(const char* __path, uid_t __owner, gid_t __group);
+extern int fchown(int __fd, uid_t __owner, gid_t __group);
+extern int fchownat(int __dirfd, const char* __path, uid_t __owner,
+                    gid_t __group, int __flags);
+extern int lchown(const char* __path, uid_t __owner, gid_t __group);
+extern char* getcwd(char* __buf, size_t __size);
 
 extern int sync(void);
 
-extern int close(int);
+extern int close(int __fd);
 
-extern ssize_t read(int, void *, size_t);
-extern ssize_t write(int, const void *, size_t);
+extern ssize_t read(int __fd, void* __buf, size_t __count);
+extern ssize_t write(int __fd, const void* __buf, size_t __count);
 
-extern int dup(int);
-extern int dup2(int, int);
-extern int dup3(int, int, int);
-extern int fcntl(int, int, ...);
-extern int ioctl(int, int, ...);
-extern int fsync(int);
-extern int fdatasync(int);
+extern int dup(int __oldfd);
+extern int dup2(int __oldfd, int __newfd);
+extern int dup3(int __oldfd, int __newfd, int __flags) __INTRODUCED_IN(21);
+extern int fcntl(int __fd, int __cmd, ...);
+extern int ioctl(int __fd, int __request, ...);
+extern int fsync(int __fd);
+extern int fdatasync(int __fd) __INTRODUCED_IN(9);
 
 #if defined(__USE_FILE_OFFSET64)
-extern int truncate(const char *, off_t) __RENAME(truncate64);
-extern off_t lseek(int, off_t, int) __RENAME(lseek64);
-extern ssize_t pread(int, void *, size_t, off_t) __RENAME(pread64);
-extern ssize_t pwrite(int, const void *, size_t, off_t) __RENAME(pwrite64);
-extern int ftruncate(int, off_t) __RENAME(ftruncate64);
+extern off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
 #else
-extern int truncate(const char *, off_t);
-extern off_t lseek(int, off_t, int);
-extern ssize_t pread(int, void *, size_t, off_t);
-extern ssize_t pwrite(int, const void *, size_t, off_t);
-extern int ftruncate(int, off_t);
+extern off_t lseek(int __fd, off_t __offset, int __whence);
 #endif
-extern int truncate64(const char *, off64_t);
-extern off64_t lseek64(int, off64_t, int);
-extern ssize_t pread64(int, void *, size_t, off64_t);
-extern ssize_t pwrite64(int, const void *, size_t, off64_t);
-extern int ftruncate64(int, off64_t);
+
+extern off64_t lseek64(int __fd, off64_t __offset, int __whence);
+
+#if defined(__USE_FILE_OFFSET64) && __ANDROID_API__ >= 21
+extern int truncate(const char* __path, off_t __length) __RENAME(truncate64);
+extern ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset)
+  __RENAME(pread64);
+extern ssize_t pwrite(int __fd, const void* __buf, size_t __count,
+                      off_t __offset) __RENAME(pwrite64);
+extern int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64);
+#else
+extern int truncate(const char* __path, off_t __length);
+extern ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset);
+extern ssize_t pwrite(int __fd, const void* __buf, size_t __count,
+                      off_t __offset);
+extern int ftruncate(int __fd, off_t __length);
+#endif
+
+extern int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);
+extern ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset) __INTRODUCED_IN(21);
+extern ssize_t pwrite64(int __fd, const void* __buf, size_t __count,
+                        off64_t __offset) __INTRODUCED_IN(21);
+extern int ftruncate64(int __fd, off64_t __length) __INTRODUCED_IN(21);
 
 extern int pause(void);
-extern unsigned int alarm(unsigned int);
-extern unsigned int sleep(unsigned int);
-extern int usleep(useconds_t);
+extern unsigned int alarm(unsigned int __seconds);
+extern unsigned int sleep(unsigned int __seconds);
+extern int usleep(useconds_t __usec);
 
-int gethostname(char*, size_t);
-int sethostname(const char*, size_t);
+int gethostname(char* __name, size_t __len);
+int sethostname(const char* __name, size_t __len);
 
-extern void *__brk(void *);
-extern int brk(void *);
-extern void *sbrk(ptrdiff_t);
+extern void* __brk(void* __addr);
+extern int brk(void* __addr);
+extern void* sbrk(ptrdiff_t __increment);
 
-extern int getopt(int, char * const *, const char *);
-extern char *optarg;
+extern int getopt(int __argc, char* const* __argv, const char* __argstring);
+extern char* optarg;
 extern int optind, opterr, optopt;
 
-extern int isatty(int);
-extern char* ttyname(int);
-extern int ttyname_r(int, char*, size_t);
+extern int isatty(int __fd);
+extern char* ttyname(int __fd);
+extern int ttyname_r(int __fd, char* __buf, size_t __buflen) __INTRODUCED_IN(8);
 
-extern int  acct(const char*  filepath);
+extern int acct(const char* __filepath);
 
+long sysconf(int __name);
+
+#if __ANDROID_API__ >= 21
 int getpagesize(void);
+#else
+__inline__ int getpagesize(void) {
+  return sysconf(_SC_PAGESIZE);
+}
+#endif
 
-long sysconf(int);
+long syscall(long __number, ...);
 
-long syscall(long number, ...);
-
-extern int daemon(int, int);
+extern int daemon(int __nochdir, int __noclose);
 
 #if defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
-extern int cacheflush(long, long, long);
+extern int cacheflush(long __addr, long __nbytes, long __cache);
     /* __attribute__((deprecated("use __builtin___clear_cache instead"))); */
 #endif
 
-extern pid_t tcgetpgrp(int fd);
-extern int   tcsetpgrp(int fd, pid_t _pid);
+extern pid_t tcgetpgrp(int __fd);
+extern int tcsetpgrp(int __fd, pid_t __pid);
 
 /* Used to retry syscalls that can return EINTR. */
 #define TEMP_FAILURE_RETRY(exp) ({         \
@@ -224,6 +246,11 @@
     } while (_rc == -1 && errno == EINTR); \
     _rc; })
 
+/* TODO(unified-headers): Factor out all the FORTIFY features. */
+extern char* __getcwd_chk(char*, size_t, size_t);
+__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
+extern char* __getcwd_real(char*, size_t) __RENAME(getcwd);
+
 extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
 __errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
 __errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
@@ -234,11 +261,26 @@
 __errordecl(__pread64_count_toobig_error, "pread64 called with count > SSIZE_MAX");
 extern ssize_t __pread64_real(int, void*, size_t, off64_t) __RENAME(pread64);
 
+extern ssize_t __pwrite_chk(int, const void*, size_t, off_t, size_t);
+__errordecl(__pwrite_dest_size_error, "pwrite called with size bigger than destination");
+__errordecl(__pwrite_count_toobig_error, "pwrite called with count > SSIZE_MAX");
+extern ssize_t __pwrite_real(int, const void*, size_t, off_t) __RENAME(pwrite);
+
+extern ssize_t __pwrite64_chk(int, const void*, size_t, off64_t, size_t);
+__errordecl(__pwrite64_dest_size_error, "pwrite64 called with size bigger than destination");
+__errordecl(__pwrite64_count_toobig_error, "pwrite64 called with count > SSIZE_MAX");
+extern ssize_t __pwrite64_real(int, const void*, size_t, off64_t) __RENAME(pwrite64);
+
 extern ssize_t __read_chk(int, void*, size_t, size_t);
 __errordecl(__read_dest_size_error, "read called with size bigger than destination");
 __errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
 extern ssize_t __read_real(int, void*, size_t) __RENAME(read);
 
+extern ssize_t __write_chk(int, const void*, size_t, size_t);
+__errordecl(__write_dest_size_error, "write called with size bigger than destination");
+__errordecl(__write_count_toobig_error, "write called with count > SSIZE_MAX");
+extern ssize_t __write_real(int, const void*, size_t) __RENAME(write);
+
 extern ssize_t __readlink_chk(const char*, char*, size_t, size_t);
 __errordecl(__readlink_dest_size_error, "readlink called with size bigger than destination");
 __errordecl(__readlink_size_toobig_error, "readlink called with size > SSIZE_MAX");
@@ -251,6 +293,37 @@
 
 #if defined(__BIONIC_FORTIFY)
 
+__BIONIC_FORTIFY_INLINE
+char* getcwd(char* buf, size_t size) {
+    size_t bos = __bos(buf);
+
+#if defined(__clang__)
+    /*
+     * Work around LLVM's incorrect __builtin_object_size implementation here
+     * to avoid needing the workaround in the __getcwd_chk ABI forever.
+     *
+     * https://llvm.org/bugs/show_bug.cgi?id=23277
+     */
+    if (buf == NULL) {
+        bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
+    }
+#else
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __getcwd_real(buf, size);
+    }
+
+    if (__builtin_constant_p(size) && (size > bos)) {
+        __getcwd_dest_size_error();
+    }
+
+    if (__builtin_constant_p(size) && (size <= bos)) {
+        return __getcwd_real(buf, size);
+    }
+#endif
+
+    return __getcwd_chk(buf, size, bos);
+}
+
 #if defined(__USE_FILE_OFFSET64)
 #define __PREAD_PREFIX(x) __pread64_ ## x
 #else
@@ -307,6 +380,62 @@
     return __pread64_chk(fd, buf, count, offset, bos);
 }
 
+#if defined(__USE_FILE_OFFSET64)
+#define __PWRITE_PREFIX(x) __pwrite64_ ## x
+#else
+#define __PWRITE_PREFIX(x) __pwrite_ ## x
+#endif
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
+    size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __PWRITE_PREFIX(count_toobig_error)();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __PWRITE_PREFIX(dest_size_error)();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __PWRITE_PREFIX(real)(fd, buf, count, offset);
+    }
+#endif
+
+    return __PWRITE_PREFIX(chk)(fd, buf, count, offset, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t pwrite64(int fd, const void* buf, size_t count, off64_t offset) {
+    size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __pwrite64_count_toobig_error();
+    }
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __pwrite64_real(fd, buf, count, offset);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __pwrite64_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __pwrite64_real(fd, buf, count, offset);
+    }
+#endif
+
+    return __pwrite64_chk(fd, buf, count, offset, bos);
+}
+
 __BIONIC_FORTIFY_INLINE
 ssize_t read(int fd, void* buf, size_t count) {
     size_t bos = __bos0(buf);
@@ -333,6 +462,33 @@
 }
 
 __BIONIC_FORTIFY_INLINE
+ssize_t write(int fd, const void* buf, size_t count) {
+    size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+#if 0 /* work around a false positive due to a missed optimization */
+    if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
+        __write_count_toobig_error();
+    }
+#endif
+
+    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+        return __write_real(fd, buf, count);
+    }
+
+    if (__builtin_constant_p(count) && (count > bos)) {
+        __write_dest_size_error();
+    }
+
+    if (__builtin_constant_p(count) && (count <= bos)) {
+        return __write_real(fd, buf, count);
+    }
+#endif
+
+    return __write_chk(fd, buf, count, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
 ssize_t readlink(const char* path, char* buf, size_t size) {
     size_t bos = __bos(buf);
 
diff --git a/libc/include/utmp.h b/libc/include/utmp.h
index ebf2372..c6f22a5 100644
--- a/libc/include/utmp.h
+++ b/libc/include/utmp.h
@@ -46,7 +46,16 @@
 #define UT_HOSTSIZE 16
 #endif
 
-#define USER_PROCESS 7
+#define EMPTY         0
+#define RUN_LVL       1
+#define BOOT_TIME     2
+#define NEW_TIME      3
+#define OLD_TIME      4
+#define INIT_PROCESS  5
+#define LOGIN_PROCESS 6
+#define USER_PROCESS  7
+#define DEAD_PROCESS  8
+#define ACCOUNTING    9
 
 struct lastlog
 {
@@ -88,8 +97,9 @@
 __BEGIN_DECLS
 
 int utmpname(const char*);
-void setutent();
-struct utmp* getutent();
+void setutent(void);
+struct utmp* getutent(void);
+void endutent(void);
 
 int login_tty(int);
 
diff --git a/libc/kernel/common/scsi/scsi.h b/libc/kernel/common/scsi/scsi.h
new file mode 100644
index 0000000..9e5edd7
--- /dev/null
+++ b/libc/kernel/common/scsi/scsi.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_SCSI_H
+#define _SCSI_SCSI_H
+#include <linux/types.h>
+#define TEST_UNIT_READY 0x00
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define REZERO_UNIT 0x01
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define READ_BLOCK_LIMITS 0x05
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define REASSIGN_BLOCKS 0x07
+#define INITIALIZE_ELEMENT_STATUS 0x07
+#define READ_6 0x08
+#define WRITE_6 0x0a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SEEK_6 0x0b
+#define READ_REVERSE 0x0f
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define INQUIRY 0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT 0x15
+#define RESERVE 0x16
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RELEASE 0x17
+#define COPY 0x18
+#define ERASE 0x19
+#define MODE_SENSE 0x1a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define START_STOP 0x1b
+#define RECEIVE_DIAGNOSTIC 0x1c
+#define SEND_DIAGNOSTIC 0x1d
+#define ALLOW_MEDIUM_REMOVAL 0x1e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_FORMAT_CAPACITIES 0x23
+#define SET_WINDOW 0x24
+#define READ_CAPACITY 0x25
+#define READ_10 0x28
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define WRITE_10 0x2a
+#define SEEK_10 0x2b
+#define POSITION_TO_ELEMENT 0x2b
+#define WRITE_VERIFY 0x2e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VERIFY 0x2f
+#define SEARCH_HIGH 0x30
+#define SEARCH_EQUAL 0x31
+#define SEARCH_LOW 0x32
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SET_LIMITS 0x33
+#define PRE_FETCH 0x34
+#define READ_POSITION 0x34
+#define SYNCHRONIZE_CACHE 0x35
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define LOCK_UNLOCK_CACHE 0x36
+#define READ_DEFECT_DATA 0x37
+#define MEDIUM_SCAN 0x38
+#define COMPARE 0x39
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define COPY_VERIFY 0x3a
+#define WRITE_BUFFER 0x3b
+#define READ_BUFFER 0x3c
+#define UPDATE_BLOCK 0x3d
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_LONG 0x3e
+#define WRITE_LONG 0x3f
+#define CHANGE_DEFINITION 0x40
+#define WRITE_SAME 0x41
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define UNMAP 0x42
+#define READ_TOC 0x43
+#define READ_HEADER 0x44
+#define GET_EVENT_STATUS_NOTIFICATION 0x4a
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define LOG_SELECT 0x4c
+#define LOG_SENSE 0x4d
+#define XDWRITEREAD_10 0x53
+#define MODE_SELECT_10 0x55
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RESERVE_10 0x56
+#define RELEASE_10 0x57
+#define MODE_SENSE_10 0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD 0x7f
+#define REPORT_LUNS 0xa0
+#define SECURITY_PROTOCOL_IN 0xa2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MAINTENANCE_IN 0xa3
+#define MAINTENANCE_OUT 0xa4
+#define MOVE_MEDIUM 0xa5
+#define EXCHANGE_MEDIUM 0xa6
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_12 0xa8
+#define WRITE_12 0xaa
+#define READ_MEDIA_SERIAL_NUMBER 0xab
+#define WRITE_VERIFY_12 0xae
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VERIFY_12 0xaf
+#define SEARCH_HIGH_12 0xb0
+#define SEARCH_EQUAL_12 0xb1
+#define SEARCH_LOW_12 0xb2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SECURITY_PROTOCOL_OUT 0xb5
+#define READ_ELEMENT_STATUS 0xb8
+#define SEND_VOLUME_TAG 0xb6
+#define WRITE_LONG_2 0xea
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_COPY 0x83
+#define RECEIVE_COPY_RESULTS 0x84
+#define ACCESS_CONTROL_IN 0x86
+#define ACCESS_CONTROL_OUT 0x87
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define READ_16 0x88
+#define COMPARE_AND_WRITE 0x89
+#define WRITE_16 0x8a
+#define READ_ATTRIBUTE 0x8c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define WRITE_ATTRIBUTE 0x8d
+#define VERIFY_16 0x8f
+#define SYNCHRONIZE_CACHE_16 0x91
+#define WRITE_SAME_16 0x93
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SERVICE_ACTION_IN 0x9e
+#define GOOD 0x00
+#define CHECK_CONDITION 0x01
+#define CONDITION_GOOD 0x02
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define BUSY 0x04
+#define INTERMEDIATE_GOOD 0x08
+#define INTERMEDIATE_C_GOOD 0x0a
+#define RESERVATION_CONFLICT 0x0c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define COMMAND_TERMINATED 0x11
+#define QUEUE_FULL 0x14
+#define ACA_ACTIVE 0x18
+#define TASK_ABORTED 0x20
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define STATUS_MASK 0xfe
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define COPY_ABORTED 0x0a
+#define ABORTED_COMMAND 0x0b
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define VOLUME_OVERFLOW 0x0d
+#define MISCOMPARE 0x0e
+#define TYPE_DISK 0x00
+#define TYPE_TAPE 0x01
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_PRINTER 0x02
+#define TYPE_PROCESSOR 0x03
+#define TYPE_WORM 0x04
+#define TYPE_ROM 0x05
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_SCANNER 0x06
+#define TYPE_MOD 0x07
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_COMM 0x09
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_RAID 0x0c
+#define TYPE_ENCLOSURE 0x0d
+#define TYPE_RBC 0x0e
+#define TYPE_OSD 0x11
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TYPE_ZBC 0x14
+#define TYPE_WLUN 0x1e
+#define TYPE_NO_LUN 0x7f
+struct ccs_modesel_head {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 _r1;
+  __u8 medium;
+  __u8 _r2;
+  __u8 block_desc_length;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 density;
+  __u8 number_blocks_hi;
+  __u8 number_blocks_med;
+  __u8 number_blocks_lo;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  __u8 _r3;
+  __u8 block_length_hi;
+  __u8 block_length_med;
+  __u8 block_length_lo;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+#define COMMAND_COMPLETE 0x00
+#define EXTENDED_MESSAGE 0x01
+#define EXTENDED_MODIFY_DATA_POINTER 0x00
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_SDTR 0x01
+#define EXTENDED_EXTENDED_IDENTIFY 0x02
+#define EXTENDED_WDTR 0x03
+#define EXTENDED_PPR 0x04
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05
+#define SAVE_POINTERS 0x02
+#define RESTORE_POINTERS 0x03
+#define DISCONNECT 0x04
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define INITIATOR_ERROR 0x05
+#define ABORT_TASK_SET 0x06
+#define MESSAGE_REJECT 0x07
+#define NOP 0x08
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MSG_PARITY_ERROR 0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define TARGET_RESET 0x0c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ABORT_TASK 0x0d
+#define CLEAR_TASK_SET 0x0e
+#define INITIATE_RECOVERY 0x0f
+#define RELEASE_RECOVERY 0x10
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define CLEAR_ACA 0x16
+#define LOGICAL_UNIT_RESET 0x17
+#define SIMPLE_QUEUE_TAG 0x20
+#define HEAD_OF_QUEUE_TAG 0x21
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ORDERED_QUEUE_TAG 0x22
+#define IGNORE_WIDE_RESIDUE 0x23
+#define ACA 0x24
+#define QAS_REQUEST 0x55
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define BUS_DEVICE_RESET TARGET_RESET
+#define ABORT ABORT_TASK_SET
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
+#define SCSI_IOCTL_GET_PCI 0x5387
+#endif
diff --git a/libc/kernel/common/scsi/scsi_ioctl.h b/libc/kernel/common/scsi/scsi_ioctl.h
new file mode 100644
index 0000000..c2f64a7
--- /dev/null
+++ b/libc/kernel/common/scsi/scsi_ioctl.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_IOCTL_H
+#define _SCSI_IOCTL_H
+#define SCSI_IOCTL_SEND_COMMAND 1
+#define SCSI_IOCTL_TEST_UNIT_READY 2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_BENCHMARK_COMMAND 3
+#define SCSI_IOCTL_SYNC 4
+#define SCSI_IOCTL_START_UNIT 5
+#define SCSI_IOCTL_STOP_UNIT 6
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SCSI_IOCTL_DOORLOCK 0x5380
+#define SCSI_IOCTL_DOORUNLOCK 0x5381
+#define SCSI_REMOVAL_PREVENT 1
+#define SCSI_REMOVAL_ALLOW 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/kernel/common/scsi/sg.h b/libc/kernel/common/scsi/sg.h
new file mode 100644
index 0000000..a38eccb
--- /dev/null
+++ b/libc/kernel/common/scsi/sg.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _SCSI_GENERIC_H
+#define _SCSI_GENERIC_H
+#include <linux/compiler.h>
+typedef struct sg_iovec {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * iov_base;
+  size_t iov_len;
+} sg_iovec_t;
+typedef struct sg_io_hdr {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int interface_id;
+  int dxfer_direction;
+  unsigned char cmd_len;
+  unsigned char mx_sb_len;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned short iovec_count;
+  unsigned int dxfer_len;
+  void __user * dxferp;
+  unsigned char __user * cmdp;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * sbp;
+  unsigned int timeout;
+  unsigned int flags;
+  int pack_id;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  void __user * usr_ptr;
+  unsigned char status;
+  unsigned char masked_status;
+  unsigned char msg_status;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned char sb_len_wr;
+  unsigned short host_status;
+  unsigned short driver_status;
+  int resid;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int duration;
+  unsigned int info;
+} sg_io_hdr_t;
+#define SG_INTERFACE_ID_ORIG 'S'
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DXFER_NONE (- 1)
+#define SG_DXFER_TO_DEV (- 2)
+#define SG_DXFER_FROM_DEV (- 3)
+#define SG_DXFER_TO_FROM_DEV (- 4)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DXFER_UNKNOWN (- 5)
+#define SG_FLAG_DIRECT_IO 1
+#define SG_FLAG_UNUSED_LUN_INHIBIT 2
+#define SG_FLAG_MMAP_IO 4
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_FLAG_NO_DXFER 0x10000
+#define SG_FLAG_Q_AT_TAIL 0x10
+#define SG_FLAG_Q_AT_HEAD 0x20
+#define SG_INFO_OK_MASK 0x1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_INFO_OK 0x0
+#define SG_INFO_CHECK 0x1
+#define SG_INFO_DIRECT_IO_MASK 0x6
+#define SG_INFO_INDIRECT_IO 0x0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_INFO_DIRECT_IO 0x2
+#define SG_INFO_MIXED_IO 0x4
+typedef struct sg_scsi_id {
+  int host_no;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int channel;
+  int scsi_id;
+  int lun;
+  int scsi_type;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  short h_cmd_per_lun;
+  short d_queue_depth;
+  int unused[2];
+} sg_scsi_id_t;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+typedef struct sg_req_info {
+  char req_state;
+  char orphan;
+  char sg_io_owned;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  char problem;
+  int pack_id;
+  void __user * usr_ptr;
+  unsigned int duration;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int unused;
+} sg_req_info_t;
+#define SG_EMULATED_HOST 0x2203
+#define SG_SET_TRANSFORM 0x2204
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_TRANSFORM 0x2205
+#define SG_SET_RESERVED_SIZE 0x2275
+#define SG_GET_RESERVED_SIZE 0x2272
+#define SG_GET_SCSI_ID 0x2276
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SET_FORCE_LOW_DMA 0x2279
+#define SG_GET_LOW_DMA 0x227a
+#define SG_SET_FORCE_PACK_ID 0x227b
+#define SG_GET_PACK_ID 0x227c
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_NUM_WAITING 0x227d
+#define SG_GET_SG_TABLESIZE 0x227F
+#define SG_GET_VERSION_NUM 0x2282
+#define SG_SCSI_RESET 0x2284
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SCSI_RESET_NOTHING 0
+#define SG_SCSI_RESET_DEVICE 1
+#define SG_SCSI_RESET_BUS 2
+#define SG_SCSI_RESET_HOST 3
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_SCSI_RESET_TARGET 4
+#define SG_IO 0x2285
+#define SG_GET_REQUEST_TABLE 0x2286
+#define SG_SET_KEEP_ORPHAN 0x2287
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_KEEP_ORPHAN 0x2288
+#define SG_GET_ACCESS_COUNT 0x2289
+#define SG_SCATTER_SZ (8 * 4096)
+#define SG_DEFAULT_RETRIES 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_DEF_FORCE_LOW_DMA 0
+#define SG_DEF_FORCE_PACK_ID 0
+#define SG_DEF_KEEP_ORPHAN 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_MAX_QUEUE 16
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE
+typedef struct sg_io_hdr Sg_io_hdr;
+typedef struct sg_io_vec Sg_io_vec;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+typedef struct sg_scsi_id Sg_scsi_id;
+typedef struct sg_req_info Sg_req_info;
+#define SG_MAX_SENSE 16
+struct sg_header {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  int pack_len;
+  int reply_len;
+  int pack_id;
+  int result;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int twelve_byte : 1;
+  unsigned int target_status : 5;
+  unsigned int host_status : 8;
+  unsigned int driver_status : 8;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int other_flags : 10;
+  unsigned char sense_buffer[SG_MAX_SENSE];
+};
+#define SG_SET_TIMEOUT 0x2201
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_GET_TIMEOUT 0x2202
+#define SG_GET_COMMAND_Q 0x2270
+#define SG_SET_COMMAND_Q 0x2271
+#define SG_SET_DEBUG 0x227e
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SG_NEXT_CMD_LEN 0x2283
+#define SG_DEFAULT_TIMEOUT (60 * HZ)
+#define SG_DEF_COMMAND_Q 0
+#define SG_DEF_UNDERRUN_FLAG 0
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 0e0ed76..e84bcf9 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -73,90 +73,77 @@
 from defaults import *
 from utils import *
 
-noUpdate = 1
+def print_error(no_update, msg):
+    if no_update:
+        panic(msg)
+    sys.stderr.write("warning: " + msg)
 
-def cleanupFile(path, original_path):
+
+def cleanupFile(dst_dir, src_dir, rel_path, no_update = True):
     """reads an original header and perform the cleanup operation on it
        this functions returns the destination path and the clean header
        as a single string"""
     # check the header path
-    src_path = path
+    full_path = os.path.join(src_dir, rel_path)
 
-    if not os.path.exists(src_path):
-        if noUpdate:
-            panic( "file does not exist: '%s'\n" % path )
-        sys.stderr.write( "warning: file does not exit: %s\n" % path )
+    if not os.path.exists(full_path):
+        print_error(no_update, "file does not exist: '%s'\n" % full_path)
         return None, None
 
-    if not os.path.isfile(src_path):
-        if noUpdate:
-            panic( "path is not a file: '%s'\n" % path )
-        sys.stderr.write( "warning: not a file: %s\n" % path )
+    if not os.path.isfile(full_path):
+        print_error(no_update, "path is not a file: '%s'\n" % full_path)
         return None, None
 
-    if os.path.commonprefix( [ src_path, original_path ] ) != original_path:
-        if noUpdate:
-            panic( "file is not in 'original' directory: %s\n" % path );
-        sys.stderr.write( "warning: file not in 'original' ignored: %s\n" % path )
-        return None, None
-
-    src_path = src_path[len(original_path):]
-    if len(src_path) > 0 and src_path[0] == '/':
-        src_path = src_path[1:]
-
-    if len(src_path) == 0:
-        panic( "oops, internal error, can't extract correct relative path\n" )
-
     # convert into destination path, extracting architecture if needed
     # and the corresponding list of known static functions
     #
     arch = None
     statics = kernel_known_generic_statics
-    m = re.match(r"asm-([\w\d_\+\.\-]+)(/.*)", src_path)
+    m = re.match(r"asm-([\w\d_\+\.\-]+)(/.*)", rel_path)
     if m and m.group(1) != 'generic':
         dst_path = "arch-%s/asm/%s" % m.groups()
-        arch     = m.group(1)
-        statics  = statics.union( kernel_known_statics.get( arch, set() ) )
+        arch = m.group(1)
+        statics  = statics.union(kernel_known_statics.get(arch, set()))
     else:
         # process headers under the uapi directory
         # note the "asm" level has been explicitly added in the original
         # kernel header tree for architectural-dependent uapi headers
-        m_uapi = re.match(r"(uapi)/([\w\d_\+\.\-]+)(/.*)", src_path)
+        m_uapi = re.match(r"(uapi)/([\w\d_\+\.\-]+)(/.*)", rel_path)
         if m_uapi:
-            dst_path = src_path
+            dst_path = rel_path
             m_uapi_arch = re.match(r"asm-([\w\d_\+\.\-]+)", m_uapi.group(2))
             if m_uapi_arch and m_uapi_arch.group(1) != 'generic':
-                arch     = m_uapi_arch.group(1)
-                statics  = statics.union( kernel_known_statics.get( arch, set() ) )
+                arch = m_uapi_arch.group(1)
+                statics = statics.union(kernel_known_statics.get(arch, set()))
         # common headers (ie non-asm and non-uapi)
         else:
-            dst_path = "common/" + src_path
+            dst_path = os.path.join("common", rel_path)
 
-    dst_path = os.path.normpath( kernel_cleaned_path + "/" + dst_path )
+    dst_path = os.path.join(dst_dir, dst_path)
 
     # now, let's parse the file
     #
     parser = cpp.BlockParser()
-    blocks = parser.parseFile(path)
+    blocks = parser.parseFile(full_path)
     if not parser.parsed:
-        sys.stderr.write( "error: can't parse '%s'" % path )
-        sys.exit(1)
+        print_error(no_update, "can't parse '%s'%" % full_path)
+        return None, None
 
     macros = kernel_known_macros.copy()
     if arch and arch in kernel_default_arch_macros:
         macros.update(kernel_default_arch_macros[arch])
 
     if arch and arch in kernel_arch_token_replacements:
-        blocks.replaceTokens( kernel_arch_token_replacements[arch] )
+        blocks.replaceTokens(kernel_arch_token_replacements[arch])
 
-    blocks.optimizeMacros( macros )
+    blocks.optimizeMacros(macros)
     blocks.optimizeIf01()
-    blocks.removeVarsAndFuncs( statics )
-    blocks.replaceTokens( kernel_token_replacements )
-    blocks.removeMacroDefines( kernel_ignored_macros )
+    blocks.removeVarsAndFuncs(statics)
+    blocks.replaceTokens(kernel_token_replacements)
+    blocks.removeMacroDefines(kernel_ignored_macros)
 
     out = StringOutput()
-    out.write( kernel_disclaimer )
+    out.write(kernel_disclaimer)
     blocks.writeWithWarning(out, kernel_warning, 4)
     return dst_path, out.get()
 
@@ -183,28 +170,31 @@
         sys.exit(1)
 
     try:
-        optlist, args = getopt.getopt( sys.argv[1:], 'uvk:d:' )
+        optlist, args = getopt.getopt(sys.argv[1:], 'uvk:d:')
     except:
         # unrecognized option
-        sys.stderr.write( "error: unrecognized option\n" )
+        sys.stderr.write("error: unrecognized option\n")
         usage()
 
+    no_update = True
+    dst_dir = get_kernel_dir()
+    src_dir = get_kernel_headers_original_dir()
     for opt, arg in optlist:
         if opt == '-u':
-            noUpdate = 0
+            no_update = False
         elif opt == '-v':
             logging.basicConfig(level=logging.DEBUG)
         elif opt == '-k':
-            kernel_original_path = arg
+            src_dir = arg
         elif opt == '-d':
-            kernel_cleaned_path = arg
+            dst_dir = arg
 
     if len(args) == 0:
         usage()
 
-    if noUpdate:
+    if no_update:
         for path in args:
-            dst_path, newdata = cleanupFile(path,kernel_original_path)
+            dst_path, newdata = cleanupFile(dst_dir, src_dir, path)
             print newdata
 
         sys.exit(0)
@@ -214,12 +204,12 @@
     b = BatchFileUpdater()
 
     for path in args:
-        dst_path, newdata = cleanupFile(path,kernel_original_path)
+        dst_path, newdata = cleanupFile(dst_dir, src_dir, path, no_update)
         if not dst_path:
             continue
 
-        b.readFile( dst_path )
-        r = b.editFile( dst_path, newdata )
+        b.readFile(dst_path)
+        r = b.editFile(dst_path, newdata)
         if r == 0:
             r = "unchanged"
         elif r == 1:
@@ -227,7 +217,7 @@
         else:
             r = "added"
 
-        print "cleaning: %-*s -> %-*s (%s)" % ( 35, path, 35, dst_path, r )
+        print "cleaning: %-*s -> %-*s (%s)" % (35, path, 35, dst_path, r)
 
 
     b.updateGitFiles()
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 8aba998..773d22f 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -12,12 +12,6 @@
 # tree. used when looking for sources...
 kernel_dirs = [ "linux", "asm", "asm-generic", "mtd" ]
 
-# path to the directory containing the original kernel headers
-kernel_original_path = os.path.normpath( find_program_dir() + '/../../../../external/kernel-headers/original' )
-
-# path to the default location of the cleaned-up headers
-kernel_cleaned_path = os.path.normpath( find_program_dir() + '/..' )
-
 # a special value that is used to indicate that a given macro is known to be
 # undefined during optimization
 kCppUndefinedMacro = "<<<undefined>>>"
@@ -70,6 +64,8 @@
     # The kernel's SIGRTMIN/SIGRTMAX are absolute limits; userspace steals a few.
     "SIGRTMIN": "__SIGRTMIN",
     "SIGRTMAX": "__SIGRTMAX",
+    # We want to support both BSD and Linux member names in struct udphdr.
+    "udphdr": "__kernel_udphdr",
     }
 
 # this is the set of known static inline functions that we want to keep
diff --git a/libc/kernel/tools/generate_uapi_headers.sh b/libc/kernel/tools/generate_uapi_headers.sh
index 90ba0ed..3c80d9f 100755
--- a/libc/kernel/tools/generate_uapi_headers.sh
+++ b/libc/kernel/tools/generate_uapi_headers.sh
@@ -99,6 +99,35 @@
   done
 }
 
+function check_hdrs () {
+  local src_dir=$1
+  local tgt_dir=$2
+  local kernel_dir=$3
+
+  local search_dirs=()
+
+  # This only works if none of the filenames have spaces.
+  for file in $(ls -d ${src_dir}/* 2> /dev/null); do
+    if [[ -d "${file}" ]]; then
+      search_dirs+=("${file}")
+    elif [[ -f  "${file}" ]] && [[ "${file}" =~ .h$ ]]; then
+      tgt_file=${tgt_dir}/$(basename ${file})
+      if [[ -e ${tgt_file} ]] && ! diff "${file}" "${tgt_file}" > /dev/null; then
+        if [[ ${file} =~ ${kernel_dir}/*(.+) ]]; then
+          echo "New version of ${BASH_REMATCH[1]} found in kernel headers."
+        else
+          echo "New version of ${file} found in kernel headers."
+        fi
+        echo "This file needs to be updated manually."
+      fi
+    fi
+  done
+
+  for dir in "${search_dirs[@]}"; do
+    check_hdrs "${dir}" ${tgt_dir}/$(basename ${dir}) "${kernel_dir}"
+  done
+}
+
 trap cleanup EXIT
 # This automatically triggers a call to cleanup.
 trap "exit 1" HUP INT TERM TSTP
@@ -207,3 +236,8 @@
                  "${KERNEL_DIR}/${src_dir}/arch/${arch}/include/generated/asm" \
                  "${ANDROID_KERNEL_DIR}/uapi/asm-${arch}/asm"
 done
+
+# Verify if modified headers have changed.
+check_hdrs "${KERNEL_DIR}/${src_dir}/include/scsi" \
+           "${ANDROID_KERNEL_DIR}/scsi" \
+           "${KERNEL_DIR}/${src_dir}"
diff --git a/libc/kernel/tools/update_all.py b/libc/kernel/tools/update_all.py
index f45d4e0..7f3657c 100755
--- a/libc/kernel/tools/update_all.py
+++ b/libc/kernel/tools/update_all.py
@@ -6,72 +6,93 @@
 
 def usage():
     print """\
-  usage: %(progname)s [kernel-original-path]
+  usage: %(progname)s [kernel-original-path] [kernel-modified-path]
 
     this program is used to update all the auto-generated clean headers
     used by the Bionic C library. it assumes the following:
 
-      - a set of source kernel headers is located in '../original',
-        relative to the program's directory
+      - a set of source kernel headers is located in
+        'external/kernel-headers/original', relative to the current
+        android tree
 
-      - the clean headers will be placed in '../arch-<arch>/asm',
-        '../common/linux', '../common/asm-generic', etc..
+      - a set of manually modified kernel header files located in
+        'external/kernel-headers/modified', relative to the current
+        android tree
+
+      - the clean headers will be placed in 'bionic/libc/kernel/arch-<arch>/asm',
+        'bionic/libc/kernel/common', etc..
 """ % { "progname" : os.path.basename(sys.argv[0]) }
     sys.exit(0)
 
 try:
-    optlist, args = getopt.getopt( sys.argv[1:], '' )
+    optlist, args = getopt.getopt(sys.argv[1:], '')
 except:
     # unrecognized option
-    sys.stderr.write( "error: unrecognized option\n" )
+    sys.stderr.write("error: unrecognized option\n")
     usage()
 
-if len(optlist) > 0 or len(args) > 1:
+if len(optlist) > 0 or len(args) > 2:
     usage()
 
-progdir = find_program_dir()
-
-if len(args) == 1:
+modified_dir = get_kernel_headers_modified_dir()
+if len(args) == 1 or len(args) == 2:
     original_dir = args[0]
     if not os.path.isdir(original_dir):
-        panic( "Not a directory: %s\n" % original_dir )
+        panic("Not a directory: %s\n" % original_dir)
+
+    if len(args) == 2:
+        modified_dir = args[1]
+        if not os.path.isdir(modified_dir):
+            panic("Not a directory: %s\n" % modified_dir)
 else:
-    original_dir = kernel_original_path
+    original_dir = get_kernel_headers_original_dir()
     if not os.path.isdir(original_dir):
-        panic( "Missing directory, please specify one through command-line: %s\n" % original_dir )
+        panic("Missing directory, please specify one through command-line: %s\n" % original_dir)
 
-skip_ion = False
+if not os.path.isdir(modified_dir):
+    modified_dir = None
 
-# find all source files in 'original'
-#
-sources = []
-warning_ion = []
-for root, dirs, files in os.walk( original_dir ):
+# Find all source files in 'original'.
+sources = dict()
+original_dir = os.path.normpath(original_dir)
+original_dir_len = len(original_dir) + 1
+for root, _, files in os.walk(original_dir):
     for file in files:
-        if skip_ion and (file == "ion.h" or file == "ion_test.h"):
-            warning_ion.append("  Skipped file %s/%s" % (root, file))
-            continue
-        base, ext = os.path.splitext(file)
+        _, ext = os.path.splitext(file)
         if ext == ".h":
-            sources.append( "%s/%s" % (root,file) )
+            rel_path = os.path.normpath(os.path.join(root, file))
+            rel_path = rel_path[original_dir_len:]
+            # Check to see if there is a modified header to use instead.
+            if modified_dir and os.path.exists(os.path.join(modified_dir, rel_path)):
+                sources[rel_path] = False
+            else:
+                sources[rel_path] = True
+
 
 b = BatchFileUpdater()
 
+kernel_dir = get_kernel_dir()
 for arch in kernel_archs:
-    b.readDir( os.path.normpath( progdir + "/../arch-%s" % arch ) )
+    b.readDir(os.path.join(kernel_dir, "arch-%s" % arch))
 
-b.readDir( os.path.normpath( progdir + "/../common" ) )
-
-#print "OLD " + repr(b.old_files)
+b.readDir(os.path.join(kernel_dir, "common"))
 
 oldlen = 120
-for path in sources:
-    dst_path, newdata = clean_header.cleanupFile(path, original_dir)
+android_root_len = len(get_android_root()) + 1
+for rel_path in sorted(sources):
+    if sources[rel_path]:
+        src_dir = original_dir
+        src_str = "<original>/"
+    else:
+        src_dir = modified_dir
+        src_str = "<modified>/"
+    dst_path, newdata = clean_header.cleanupFile(kernel_dir, src_dir, rel_path)
     if not dst_path:
         continue
 
-    b.readFile( dst_path )
-    r = b.editFile( dst_path, newdata )
+    dst_path = os.path.join(kernel_dir, dst_path)
+    b.readFile(dst_path)
+    r = b.editFile(dst_path, newdata)
     if r == 0:
         state = "unchanged"
     elif r == 1:
@@ -79,9 +100,11 @@
     else:
         state = "added"
 
-    str = "cleaning: %-*s -> %-*s (%s)" % ( 35, "<original>" + path[len(original_dir):], 35, dst_path, state )
+    # dst_path is guaranteed to include android root.
+    rel_dst_path = dst_path[android_root_len:]
+    str = "cleaning: %-*s -> %-*s (%s)" % (35, src_str + rel_path, 35, rel_dst_path, state)
     if sys.stdout.isatty():
-        print "%-*s" % (oldlen,str),
+        print "%-*s" % (oldlen, str),
         if (r == 0):
             print "\r",
         else:
@@ -92,11 +115,8 @@
 
     oldlen = len(str)
 
-print "%-*s" % (oldlen,"Done!")
+print "%-*s" % (oldlen, "Done!")
 
 b.updateGitFiles()
 
-if warning_ion:
-    print "NOTE: Due to import into aosp, some files were not processed."
-    print "\n".join(warning_ion)
 sys.exit(0)
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
index e5a310e..e2cc9ce 100644
--- a/libc/kernel/tools/utils.py
+++ b/libc/kernel/tools/utils.py
@@ -13,8 +13,26 @@
     sys.exit(1)
 
 
-def find_program_dir():
-    return os.path.dirname(sys.argv[0])
+def get_kernel_headers_dir():
+    return os.path.join(get_android_root(), "external/kernel-headers")
+
+
+def get_kernel_headers_original_dir():
+    return os.path.join(get_kernel_headers_dir(), "original")
+
+
+def get_kernel_headers_modified_dir():
+    return os.path.join(get_kernel_headers_dir(), "modified")
+
+
+def get_kernel_dir():
+    return os.path.join(get_android_root(), "bionic/libc/kernel")
+
+
+def get_android_root():
+    if "ANDROID_BUILD_TOP" in os.environ:
+        return os.environ["ANDROID_BUILD_TOP"]
+    panic("Unable to find root of tree, did you forget to lunch a target?")
 
 
 class StringOutput:
diff --git a/libc/kernel/uapi/drm/radeon_drm.h b/libc/kernel/uapi/drm/radeon_drm.h
index 6fb86f1..abe3c4f 100644
--- a/libc/kernel/uapi/drm/radeon_drm.h
+++ b/libc/kernel/uapi/drm/radeon_drm.h
@@ -961,29 +961,30 @@
 #define RADEON_INFO_GTT_USAGE 0x1f
 #define RADEON_INFO_ACTIVE_CU_COUNT 0x20
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define RADEON_INFO_VA_UNMAP_WORKING 0x25
 struct drm_radeon_info {
   uint32_t request;
   uint32_t pad;
-  uint64_t value;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  uint64_t value;
 };
 #define SI_TILE_MODE_COLOR_LINEAR_ALIGNED 8
 #define SI_TILE_MODE_COLOR_1D 13
-#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SI_TILE_MODE_COLOR_1D_SCANOUT 9
 #define SI_TILE_MODE_COLOR_2D_8BPP 14
 #define SI_TILE_MODE_COLOR_2D_16BPP 15
 #define SI_TILE_MODE_COLOR_2D_32BPP 16
-#define SI_TILE_MODE_COLOR_2D_64BPP 17
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SI_TILE_MODE_COLOR_2D_64BPP 17
 #define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11
 #define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12
 #define SI_TILE_MODE_DEPTH_STENCIL_1D 4
-#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define SI_TILE_MODE_DEPTH_STENCIL_2D 0
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_2AA 3
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA 3
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA 2
-#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5
 #endif
diff --git a/libc/kernel/uapi/linux/pci_regs.h b/libc/kernel/uapi/linux/pci_regs.h
index d191821..3eda5c9 100644
--- a/libc/kernel/uapi/linux/pci_regs.h
+++ b/libc/kernel/uapi/linux/pci_regs.h
@@ -326,626 +326,628 @@
 #define PCI_MSIX_PBA_BIR 0x00000007
 #define PCI_MSIX_PBA_OFFSET 0xfffffff8
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR
 #define PCI_CAP_MSIX_SIZEOF 12
 #define PCI_MSIX_ENTRY_SIZE 16
 #define PCI_MSIX_ENTRY_LOWER_ADDR 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_MSIX_ENTRY_UPPER_ADDR 4
 #define PCI_MSIX_ENTRY_DATA 8
 #define PCI_MSIX_ENTRY_VECTOR_CTRL 12
 #define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
-#define PCI_CHSWP_CSR 2
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_CHSWP_CSR 2
 #define PCI_CHSWP_DHA 0x01
 #define PCI_CHSWP_EIM 0x02
 #define PCI_CHSWP_PIE 0x04
-#define PCI_CHSWP_LOO 0x08
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_CHSWP_LOO 0x08
 #define PCI_CHSWP_PI 0x30
 #define PCI_CHSWP_EXT 0x40
 #define PCI_CHSWP_INS 0x80
-#define PCI_AF_LENGTH 2
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_AF_LENGTH 2
 #define PCI_AF_CAP 3
 #define PCI_AF_CAP_TP 0x01
 #define PCI_AF_CAP_FLR 0x02
-#define PCI_AF_CTRL 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_AF_CTRL 4
 #define PCI_AF_CTRL_FLR 0x01
 #define PCI_AF_STATUS 5
 #define PCI_AF_STATUS_TP 0x01
-#define PCI_CAP_AF_SIZEOF 6
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_CAP_AF_SIZEOF 6
 #define PCI_X_CMD 2
 #define PCI_X_CMD_DPERR_E 0x0001
 #define PCI_X_CMD_ERO 0x0002
-#define PCI_X_CMD_READ_512 0x0000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_CMD_READ_512 0x0000
 #define PCI_X_CMD_READ_1K 0x0004
 #define PCI_X_CMD_READ_2K 0x0008
 #define PCI_X_CMD_READ_4K 0x000c
-#define PCI_X_CMD_MAX_READ 0x000c
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_CMD_MAX_READ 0x000c
 #define PCI_X_CMD_SPLIT_1 0x0000
 #define PCI_X_CMD_SPLIT_2 0x0010
 #define PCI_X_CMD_SPLIT_3 0x0020
-#define PCI_X_CMD_SPLIT_4 0x0030
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_CMD_SPLIT_4 0x0030
 #define PCI_X_CMD_SPLIT_8 0x0040
 #define PCI_X_CMD_SPLIT_12 0x0050
 #define PCI_X_CMD_SPLIT_16 0x0060
-#define PCI_X_CMD_SPLIT_32 0x0070
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_CMD_SPLIT_32 0x0070
 #define PCI_X_CMD_MAX_SPLIT 0x0070
 #define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3)
 #define PCI_X_STATUS 4
-#define PCI_X_STATUS_DEVFN 0x000000ff
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_STATUS_DEVFN 0x000000ff
 #define PCI_X_STATUS_BUS 0x0000ff00
 #define PCI_X_STATUS_64BIT 0x00010000
 #define PCI_X_STATUS_133MHZ 0x00020000
-#define PCI_X_STATUS_SPL_DISC 0x00040000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_STATUS_SPL_DISC 0x00040000
 #define PCI_X_STATUS_UNX_SPL 0x00080000
 #define PCI_X_STATUS_COMPLEX 0x00100000
 #define PCI_X_STATUS_MAX_READ 0x00600000
-#define PCI_X_STATUS_MAX_SPLIT 0x03800000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_STATUS_MAX_SPLIT 0x03800000
 #define PCI_X_STATUS_MAX_CUM 0x1c000000
 #define PCI_X_STATUS_SPL_ERR 0x20000000
 #define PCI_X_STATUS_266MHZ 0x40000000
-#define PCI_X_STATUS_533MHZ 0x80000000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_STATUS_533MHZ 0x80000000
 #define PCI_X_ECC_CSR 8
 #define PCI_CAP_PCIX_SIZEOF_V0 8
 #define PCI_CAP_PCIX_SIZEOF_V1 24
-#define PCI_CAP_PCIX_SIZEOF_V2 PCI_CAP_PCIX_SIZEOF_V1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_CAP_PCIX_SIZEOF_V2 PCI_CAP_PCIX_SIZEOF_V1
 #define PCI_X_BRIDGE_SSTATUS 2
 #define PCI_X_SSTATUS_64BIT 0x0001
 #define PCI_X_SSTATUS_133MHZ 0x0002
-#define PCI_X_SSTATUS_FREQ 0x03c0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_SSTATUS_FREQ 0x03c0
 #define PCI_X_SSTATUS_VERS 0x3000
 #define PCI_X_SSTATUS_V1 0x1000
 #define PCI_X_SSTATUS_V2 0x2000
-#define PCI_X_SSTATUS_266MHZ 0x4000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_X_SSTATUS_266MHZ 0x4000
 #define PCI_X_SSTATUS_533MHZ 0x8000
 #define PCI_X_BRIDGE_STATUS 4
 #define PCI_SSVID_VENDOR_ID 4
-#define PCI_SSVID_DEVICE_ID 6
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SSVID_DEVICE_ID 6
 #define PCI_EXP_FLAGS 2
 #define PCI_EXP_FLAGS_VERS 0x000f
 #define PCI_EXP_FLAGS_TYPE 0x00f0
-#define PCI_EXP_TYPE_ENDPOINT 0x0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_TYPE_ENDPOINT 0x0
 #define PCI_EXP_TYPE_LEG_END 0x1
 #define PCI_EXP_TYPE_ROOT_PORT 0x4
 #define PCI_EXP_TYPE_UPSTREAM 0x5
-#define PCI_EXP_TYPE_DOWNSTREAM 0x6
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6
 #define PCI_EXP_TYPE_PCI_BRIDGE 0x7
 #define PCI_EXP_TYPE_PCIE_BRIDGE 0x8
 #define PCI_EXP_TYPE_RC_END 0x9
-#define PCI_EXP_TYPE_RC_EC 0xa
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_TYPE_RC_EC 0xa
 #define PCI_EXP_FLAGS_SLOT 0x0100
 #define PCI_EXP_FLAGS_IRQ 0x3e00
 #define PCI_EXP_DEVCAP 4
-#define PCI_EXP_DEVCAP_PAYLOAD 0x00000007
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCAP_PAYLOAD 0x00000007
 #define PCI_EXP_DEVCAP_PHANTOM 0x00000018
 #define PCI_EXP_DEVCAP_EXT_TAG 0x00000020
 #define PCI_EXP_DEVCAP_L0S 0x000001c0
-#define PCI_EXP_DEVCAP_L1 0x00000e00
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCAP_L1 0x00000e00
 #define PCI_EXP_DEVCAP_ATN_BUT 0x00001000
 #define PCI_EXP_DEVCAP_ATN_IND 0x00002000
 #define PCI_EXP_DEVCAP_PWR_IND 0x00004000
-#define PCI_EXP_DEVCAP_RBER 0x00008000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCAP_RBER 0x00008000
 #define PCI_EXP_DEVCAP_PWR_VAL 0x03fc0000
 #define PCI_EXP_DEVCAP_PWR_SCL 0x0c000000
 #define PCI_EXP_DEVCAP_FLR 0x10000000
-#define PCI_EXP_DEVCTL 8
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL 8
 #define PCI_EXP_DEVCTL_CERE 0x0001
 #define PCI_EXP_DEVCTL_NFERE 0x0002
 #define PCI_EXP_DEVCTL_FERE 0x0004
-#define PCI_EXP_DEVCTL_URRE 0x0008
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL_URRE 0x0008
 #define PCI_EXP_DEVCTL_RELAX_EN 0x0010
 #define PCI_EXP_DEVCTL_PAYLOAD 0x00e0
 #define PCI_EXP_DEVCTL_EXT_TAG 0x0100
-#define PCI_EXP_DEVCTL_PHANTOM 0x0200
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL_PHANTOM 0x0200
 #define PCI_EXP_DEVCTL_AUX_PME 0x0400
 #define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800
 #define PCI_EXP_DEVCTL_READRQ 0x7000
-#define PCI_EXP_DEVCTL_BCR_FLR 0x8000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL_BCR_FLR 0x8000
 #define PCI_EXP_DEVSTA 10
 #define PCI_EXP_DEVSTA_CED 0x0001
 #define PCI_EXP_DEVSTA_NFED 0x0002
-#define PCI_EXP_DEVSTA_FED 0x0004
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVSTA_FED 0x0004
 #define PCI_EXP_DEVSTA_URD 0x0008
 #define PCI_EXP_DEVSTA_AUXPD 0x0010
 #define PCI_EXP_DEVSTA_TRPND 0x0020
-#define PCI_EXP_LNKCAP 12
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCAP 12
 #define PCI_EXP_LNKCAP_SLS 0x0000000f
 #define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001
 #define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002
-#define PCI_EXP_LNKCAP_MLW 0x000003f0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCAP_MLW 0x000003f0
 #define PCI_EXP_LNKCAP_ASPMS 0x00000c00
 #define PCI_EXP_LNKCAP_L0SEL 0x00007000
 #define PCI_EXP_LNKCAP_L1EL 0x00038000
-#define PCI_EXP_LNKCAP_CLKPM 0x00040000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCAP_CLKPM 0x00040000
 #define PCI_EXP_LNKCAP_SDERC 0x00080000
 #define PCI_EXP_LNKCAP_DLLLARC 0x00100000
 #define PCI_EXP_LNKCAP_LBNC 0x00200000
-#define PCI_EXP_LNKCAP_PN 0xff000000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCAP_PN 0xff000000
 #define PCI_EXP_LNKCTL 16
 #define PCI_EXP_LNKCTL_ASPMC 0x0003
 #define PCI_EXP_LNKCTL_ASPM_L0S 0x0001
-#define PCI_EXP_LNKCTL_ASPM_L1 0x0002
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCTL_ASPM_L1 0x0002
 #define PCI_EXP_LNKCTL_RCB 0x0008
 #define PCI_EXP_LNKCTL_LD 0x0010
 #define PCI_EXP_LNKCTL_RL 0x0020
-#define PCI_EXP_LNKCTL_CCC 0x0040
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCTL_CCC 0x0040
 #define PCI_EXP_LNKCTL_ES 0x0080
 #define PCI_EXP_LNKCTL_CLKREQ_EN 0x0100
 #define PCI_EXP_LNKCTL_HAWD 0x0200
-#define PCI_EXP_LNKCTL_LBMIE 0x0400
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCTL_LBMIE 0x0400
 #define PCI_EXP_LNKCTL_LABIE 0x0800
 #define PCI_EXP_LNKSTA 18
 #define PCI_EXP_LNKSTA_CLS 0x000f
-#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001
 #define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002
 #define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003
 #define PCI_EXP_LNKSTA_NLW 0x03f0
-#define PCI_EXP_LNKSTA_NLW_X1 0x0010
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKSTA_NLW_X1 0x0010
 #define PCI_EXP_LNKSTA_NLW_X2 0x0020
 #define PCI_EXP_LNKSTA_NLW_X4 0x0040
 #define PCI_EXP_LNKSTA_NLW_X8 0x0080
-#define PCI_EXP_LNKSTA_NLW_SHIFT 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKSTA_NLW_SHIFT 4
 #define PCI_EXP_LNKSTA_LT 0x0800
 #define PCI_EXP_LNKSTA_SLC 0x1000
 #define PCI_EXP_LNKSTA_DLLLA 0x2000
-#define PCI_EXP_LNKSTA_LBMS 0x4000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKSTA_LBMS 0x4000
 #define PCI_EXP_LNKSTA_LABS 0x8000
 #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20
 #define PCI_EXP_SLTCAP 20
-#define PCI_EXP_SLTCAP_ABP 0x00000001
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCAP_ABP 0x00000001
 #define PCI_EXP_SLTCAP_PCP 0x00000002
 #define PCI_EXP_SLTCAP_MRLSP 0x00000004
 #define PCI_EXP_SLTCAP_AIP 0x00000008
-#define PCI_EXP_SLTCAP_PIP 0x00000010
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCAP_PIP 0x00000010
 #define PCI_EXP_SLTCAP_HPS 0x00000020
 #define PCI_EXP_SLTCAP_HPC 0x00000040
 #define PCI_EXP_SLTCAP_SPLV 0x00007f80
-#define PCI_EXP_SLTCAP_SPLS 0x00018000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCAP_SPLS 0x00018000
 #define PCI_EXP_SLTCAP_EIP 0x00020000
 #define PCI_EXP_SLTCAP_NCCS 0x00040000
 #define PCI_EXP_SLTCAP_PSN 0xfff80000
-#define PCI_EXP_SLTCTL 24
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCTL 24
 #define PCI_EXP_SLTCTL_ABPE 0x0001
 #define PCI_EXP_SLTCTL_PFDE 0x0002
 #define PCI_EXP_SLTCTL_MRLSCE 0x0004
-#define PCI_EXP_SLTCTL_PDCE 0x0008
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCTL_PDCE 0x0008
 #define PCI_EXP_SLTCTL_CCIE 0x0010
 #define PCI_EXP_SLTCTL_HPIE 0x0020
 #define PCI_EXP_SLTCTL_AIC 0x00c0
-#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040
 #define PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080
 #define PCI_EXP_SLTCTL_ATTN_IND_OFF 0x00c0
 #define PCI_EXP_SLTCTL_PIC 0x0300
-#define PCI_EXP_SLTCTL_PWR_IND_ON 0x0100
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCTL_PWR_IND_ON 0x0100
 #define PCI_EXP_SLTCTL_PWR_IND_BLINK 0x0200
 #define PCI_EXP_SLTCTL_PWR_IND_OFF 0x0300
 #define PCI_EXP_SLTCTL_PCC 0x0400
-#define PCI_EXP_SLTCTL_PWR_ON 0x0000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTCTL_PWR_ON 0x0000
 #define PCI_EXP_SLTCTL_PWR_OFF 0x0400
 #define PCI_EXP_SLTCTL_EIC 0x0800
 #define PCI_EXP_SLTCTL_DLLSCE 0x1000
-#define PCI_EXP_SLTSTA 26
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTSTA 26
 #define PCI_EXP_SLTSTA_ABP 0x0001
 #define PCI_EXP_SLTSTA_PFD 0x0002
 #define PCI_EXP_SLTSTA_MRLSC 0x0004
-#define PCI_EXP_SLTSTA_PDC 0x0008
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTSTA_PDC 0x0008
 #define PCI_EXP_SLTSTA_CC 0x0010
 #define PCI_EXP_SLTSTA_MRLSS 0x0020
 #define PCI_EXP_SLTSTA_PDS 0x0040
-#define PCI_EXP_SLTSTA_EIS 0x0080
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_SLTSTA_EIS 0x0080
 #define PCI_EXP_SLTSTA_DLLSC 0x0100
 #define PCI_EXP_RTCTL 28
 #define PCI_EXP_RTCTL_SECEE 0x0001
-#define PCI_EXP_RTCTL_SENFEE 0x0002
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_RTCTL_SENFEE 0x0002
 #define PCI_EXP_RTCTL_SEFEE 0x0004
 #define PCI_EXP_RTCTL_PMEIE 0x0008
 #define PCI_EXP_RTCTL_CRSSVE 0x0010
-#define PCI_EXP_RTCAP 30
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_RTCAP 30
 #define PCI_EXP_RTCAP_CRSVIS 0x0001
 #define PCI_EXP_RTSTA 32
 #define PCI_EXP_RTSTA_PME 0x00010000
-#define PCI_EXP_RTSTA_PENDING 0x00020000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_RTSTA_PENDING 0x00020000
 #define PCI_EXP_DEVCAP2 36
 #define PCI_EXP_DEVCAP2_ARI 0x00000020
 #define PCI_EXP_DEVCAP2_LTR 0x00000800
-#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000
 #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000
 #define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000
 #define PCI_EXP_DEVCTL2 40
-#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f
 #define PCI_EXP_DEVCTL2_ARI 0x0020
 #define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100
 #define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200
-#define PCI_EXP_DEVCTL2_LTR_EN 0x0400
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVCTL2_LTR_EN 0x0400
 #define PCI_EXP_DEVCTL2_OBFF_MSGA_EN 0x2000
 #define PCI_EXP_DEVCTL2_OBFF_MSGB_EN 0x4000
 #define PCI_EXP_DEVCTL2_OBFF_WAKE_EN 0x6000
-#define PCI_EXP_DEVSTA2 42
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_DEVSTA2 42
 #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 44
 #define PCI_EXP_LNKCAP2 44
 #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002
-#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004
 #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008
 #define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100
 #define PCI_EXP_LNKCTL2 48
-#define PCI_EXP_LNKSTA2 50
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXP_LNKSTA2 50
 #define PCI_EXP_SLTCAP2 52
 #define PCI_EXP_SLTCTL2 56
 #define PCI_EXP_SLTSTA2 58
-#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
 #define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf)
 #define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
 #define PCI_EXT_CAP_ID_ERR 0x01
-#define PCI_EXT_CAP_ID_VC 0x02
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_VC 0x02
 #define PCI_EXT_CAP_ID_DSN 0x03
 #define PCI_EXT_CAP_ID_PWR 0x04
 #define PCI_EXT_CAP_ID_RCLD 0x05
-#define PCI_EXT_CAP_ID_RCILC 0x06
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_RCILC 0x06
 #define PCI_EXT_CAP_ID_RCEC 0x07
 #define PCI_EXT_CAP_ID_MFVC 0x08
 #define PCI_EXT_CAP_ID_VC9 0x09
-#define PCI_EXT_CAP_ID_RCRB 0x0A
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_RCRB 0x0A
 #define PCI_EXT_CAP_ID_VNDR 0x0B
 #define PCI_EXT_CAP_ID_CAC 0x0C
 #define PCI_EXT_CAP_ID_ACS 0x0D
-#define PCI_EXT_CAP_ID_ARI 0x0E
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_ARI 0x0E
 #define PCI_EXT_CAP_ID_ATS 0x0F
 #define PCI_EXT_CAP_ID_SRIOV 0x10
 #define PCI_EXT_CAP_ID_MRIOV 0x11
-#define PCI_EXT_CAP_ID_MCAST 0x12
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_MCAST 0x12
 #define PCI_EXT_CAP_ID_PRI 0x13
 #define PCI_EXT_CAP_ID_AMD_XXX 0x14
 #define PCI_EXT_CAP_ID_REBAR 0x15
-#define PCI_EXT_CAP_ID_DPA 0x16
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_DPA 0x16
 #define PCI_EXT_CAP_ID_TPH 0x17
 #define PCI_EXT_CAP_ID_LTR 0x18
 #define PCI_EXT_CAP_ID_SECPCI 0x19
-#define PCI_EXT_CAP_ID_PMUX 0x1A
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ID_PMUX 0x1A
 #define PCI_EXT_CAP_ID_PASID 0x1B
 #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PASID
 #define PCI_EXT_CAP_DSN_SIZEOF 12
-#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 #define PCI_ERR_UNCOR_STATUS 4
 #define PCI_ERR_UNC_UND 0x00000001
 #define PCI_ERR_UNC_DLP 0x00000010
-#define PCI_ERR_UNC_SURPDN 0x00000020
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_UNC_SURPDN 0x00000020
 #define PCI_ERR_UNC_POISON_TLP 0x00001000
 #define PCI_ERR_UNC_FCP 0x00002000
 #define PCI_ERR_UNC_COMP_TIME 0x00004000
-#define PCI_ERR_UNC_COMP_ABORT 0x00008000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_UNC_COMP_ABORT 0x00008000
 #define PCI_ERR_UNC_UNX_COMP 0x00010000
 #define PCI_ERR_UNC_RX_OVER 0x00020000
 #define PCI_ERR_UNC_MALF_TLP 0x00040000
-#define PCI_ERR_UNC_ECRC 0x00080000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_UNC_ECRC 0x00080000
 #define PCI_ERR_UNC_UNSUP 0x00100000
 #define PCI_ERR_UNC_ACSV 0x00200000
 #define PCI_ERR_UNC_INTN 0x00400000
-#define PCI_ERR_UNC_MCBTLP 0x00800000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_UNC_MCBTLP 0x00800000
 #define PCI_ERR_UNC_ATOMEG 0x01000000
 #define PCI_ERR_UNC_TLPPRE 0x02000000
 #define PCI_ERR_UNCOR_MASK 8
-#define PCI_ERR_UNCOR_SEVER 12
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_UNCOR_SEVER 12
 #define PCI_ERR_COR_STATUS 16
 #define PCI_ERR_COR_RCVR 0x00000001
 #define PCI_ERR_COR_BAD_TLP 0x00000040
-#define PCI_ERR_COR_BAD_DLLP 0x00000080
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_COR_BAD_DLLP 0x00000080
 #define PCI_ERR_COR_REP_ROLL 0x00000100
 #define PCI_ERR_COR_REP_TIMER 0x00001000
 #define PCI_ERR_COR_ADV_NFAT 0x00002000
-#define PCI_ERR_COR_INTERNAL 0x00004000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_COR_INTERNAL 0x00004000
 #define PCI_ERR_COR_LOG_OVER 0x00008000
 #define PCI_ERR_COR_MASK 20
 #define PCI_ERR_CAP 24
-#define PCI_ERR_CAP_FEP(x) ((x) & 31)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_CAP_FEP(x) ((x) & 31)
 #define PCI_ERR_CAP_ECRC_GENC 0x00000020
 #define PCI_ERR_CAP_ECRC_GENE 0x00000040
 #define PCI_ERR_CAP_ECRC_CHKC 0x00000080
-#define PCI_ERR_CAP_ECRC_CHKE 0x00000100
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_CAP_ECRC_CHKE 0x00000100
 #define PCI_ERR_HEADER_LOG 28
 #define PCI_ERR_ROOT_COMMAND 44
 #define PCI_ERR_ROOT_CMD_COR_EN 0x00000001
-#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
 #define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004
 #define PCI_ERR_ROOT_STATUS 48
 #define PCI_ERR_ROOT_COR_RCV 0x00000001
-#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
 #define PCI_ERR_ROOT_UNCOR_RCV 0x00000004
 #define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008
 #define PCI_ERR_ROOT_FIRST_FATAL 0x00000010
-#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020
 #define PCI_ERR_ROOT_FATAL_RCV 0x00000040
 #define PCI_ERR_ROOT_ERR_SRC 52
 #define PCI_VC_PORT_CAP1 4
-#define PCI_VC_CAP1_EVCC 0x00000007
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_CAP1_EVCC 0x00000007
 #define PCI_VC_CAP1_LPEVCC 0x00000070
 #define PCI_VC_CAP1_ARB_SIZE 0x00000c00
 #define PCI_VC_PORT_CAP2 8
-#define PCI_VC_CAP2_32_PHASE 0x00000002
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_CAP2_32_PHASE 0x00000002
 #define PCI_VC_CAP2_64_PHASE 0x00000004
 #define PCI_VC_CAP2_128_PHASE 0x00000008
 #define PCI_VC_CAP2_ARB_OFF 0xff000000
-#define PCI_VC_PORT_CTRL 12
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_PORT_CTRL 12
 #define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001
 #define PCI_VC_PORT_STATUS 14
 #define PCI_VC_PORT_STATUS_TABLE 0x00000001
-#define PCI_VC_RES_CAP 16
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_RES_CAP 16
 #define PCI_VC_RES_CAP_32_PHASE 0x00000002
 #define PCI_VC_RES_CAP_64_PHASE 0x00000004
 #define PCI_VC_RES_CAP_128_PHASE 0x00000008
-#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010
 #define PCI_VC_RES_CAP_256_PHASE 0x00000020
 #define PCI_VC_RES_CAP_ARB_OFF 0xff000000
 #define PCI_VC_RES_CTRL 20
-#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000
 #define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000
 #define PCI_VC_RES_CTRL_ID 0x07000000
 #define PCI_VC_RES_CTRL_ENABLE 0x80000000
-#define PCI_VC_RES_STATUS 26
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VC_RES_STATUS 26
 #define PCI_VC_RES_STATUS_TABLE 0x00000001
 #define PCI_VC_RES_STATUS_NEGO 0x00000002
 #define PCI_CAP_VC_BASE_SIZEOF 0x10
-#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C
 #define PCI_PWR_DSR 4
 #define PCI_PWR_DATA 8
 #define PCI_PWR_DATA_BASE(x) ((x) & 0xff)
-#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3)
 #define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7)
 #define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3)
 #define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7)
-#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7)
 #define PCI_PWR_CAP 12
 #define PCI_PWR_CAP_BUDGET(x) ((x) & 1)
 #define PCI_EXT_CAP_PWR_SIZEOF 16
-#define PCI_VNDR_HEADER 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_VNDR_HEADER 4
 #define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff)
 #define PCI_VNDR_HEADER_REV(x) (((x) >> 16) & 0xf)
 #define PCI_VNDR_HEADER_LEN(x) (((x) >> 20) & 0xfff)
-#define HT_3BIT_CAP_MASK 0xE0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_3BIT_CAP_MASK 0xE0
 #define HT_CAPTYPE_SLAVE 0x00
 #define HT_CAPTYPE_HOST 0x20
 #define HT_5BIT_CAP_MASK 0xF8
-#define HT_CAPTYPE_IRQ 0x80
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_CAPTYPE_IRQ 0x80
 #define HT_CAPTYPE_REMAPPING_40 0xA0
 #define HT_CAPTYPE_REMAPPING_64 0xA2
 #define HT_CAPTYPE_UNITID_CLUMP 0x90
-#define HT_CAPTYPE_EXTCONF 0x98
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_CAPTYPE_EXTCONF 0x98
 #define HT_CAPTYPE_MSI_MAPPING 0xA8
 #define HT_MSI_FLAGS 0x02
 #define HT_MSI_FLAGS_ENABLE 0x1
-#define HT_MSI_FLAGS_FIXED 0x2
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_MSI_FLAGS_FIXED 0x2
 #define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL
 #define HT_MSI_ADDR_LO 0x04
 #define HT_MSI_ADDR_LO_MASK 0xFFF00000
-#define HT_MSI_ADDR_HI 0x08
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_MSI_ADDR_HI 0x08
 #define HT_CAPTYPE_DIRECT_ROUTE 0xB0
 #define HT_CAPTYPE_VCSET 0xB8
 #define HT_CAPTYPE_ERROR_RETRY 0xC0
-#define HT_CAPTYPE_GEN3 0xD0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define HT_CAPTYPE_GEN3 0xD0
 #define HT_CAPTYPE_PM 0xE0
 #define HT_CAP_SIZEOF_LONG 28
 #define HT_CAP_SIZEOF_SHORT 24
-#define PCI_ARI_CAP 0x04
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ARI_CAP 0x04
 #define PCI_ARI_CAP_MFVC 0x0001
 #define PCI_ARI_CAP_ACS 0x0002
 #define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff)
-#define PCI_ARI_CTRL 0x06
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ARI_CTRL 0x06
 #define PCI_ARI_CTRL_MFVC 0x0001
 #define PCI_ARI_CTRL_ACS 0x0002
 #define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7)
-#define PCI_EXT_CAP_ARI_SIZEOF 8
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ARI_SIZEOF 8
 #define PCI_ATS_CAP 0x04
 #define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f)
 #define PCI_ATS_MAX_QDEP 32
-#define PCI_ATS_CTRL 0x06
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ATS_CTRL 0x06
 #define PCI_ATS_CTRL_ENABLE 0x8000
 #define PCI_ATS_CTRL_STU(x) ((x) & 0x1f)
 #define PCI_ATS_MIN_STU 12
-#define PCI_EXT_CAP_ATS_SIZEOF 8
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_ATS_SIZEOF 8
 #define PCI_PRI_CTRL 0x04
 #define PCI_PRI_CTRL_ENABLE 0x01
 #define PCI_PRI_CTRL_RESET 0x02
-#define PCI_PRI_STATUS 0x06
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PRI_STATUS 0x06
 #define PCI_PRI_STATUS_RF 0x001
 #define PCI_PRI_STATUS_UPRGI 0x002
 #define PCI_PRI_STATUS_STOPPED 0x100
-#define PCI_PRI_MAX_REQ 0x08
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PRI_MAX_REQ 0x08
 #define PCI_PRI_ALLOC_REQ 0x0c
 #define PCI_EXT_CAP_PRI_SIZEOF 16
 #define PCI_PASID_CAP 0x04
-#define PCI_PASID_CAP_EXEC 0x02
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PASID_CAP_EXEC 0x02
 #define PCI_PASID_CAP_PRIV 0x04
 #define PCI_PASID_CTRL 0x06
 #define PCI_PASID_CTRL_ENABLE 0x01
-#define PCI_PASID_CTRL_EXEC 0x02
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_PASID_CTRL_EXEC 0x02
 #define PCI_PASID_CTRL_PRIV 0x04
 #define PCI_EXT_CAP_PASID_SIZEOF 8
 #define PCI_SRIOV_CAP 0x04
-#define PCI_SRIOV_CAP_VFM 0x01
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_CAP_VFM 0x01
 #define PCI_SRIOV_CAP_INTR(x) ((x) >> 21)
 #define PCI_SRIOV_CTRL 0x08
 #define PCI_SRIOV_CTRL_VFE 0x01
-#define PCI_SRIOV_CTRL_VFM 0x02
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_CTRL_VFM 0x02
 #define PCI_SRIOV_CTRL_INTR 0x04
 #define PCI_SRIOV_CTRL_MSE 0x08
 #define PCI_SRIOV_CTRL_ARI 0x10
-#define PCI_SRIOV_STATUS 0x0a
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_STATUS 0x0a
 #define PCI_SRIOV_STATUS_VFM 0x01
 #define PCI_SRIOV_INITIAL_VF 0x0c
 #define PCI_SRIOV_TOTAL_VF 0x0e
-#define PCI_SRIOV_NUM_VF 0x10
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_NUM_VF 0x10
 #define PCI_SRIOV_FUNC_LINK 0x12
 #define PCI_SRIOV_VF_OFFSET 0x14
 #define PCI_SRIOV_VF_STRIDE 0x16
-#define PCI_SRIOV_VF_DID 0x1a
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_VF_DID 0x1a
 #define PCI_SRIOV_SUP_PGSIZE 0x1c
 #define PCI_SRIOV_SYS_PGSIZE 0x20
 #define PCI_SRIOV_BAR 0x24
-#define PCI_SRIOV_NUM_BARS 6
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_NUM_BARS 6
 #define PCI_SRIOV_VFM 0x3c
 #define PCI_SRIOV_VFM_BIR(x) ((x) & 7)
 #define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)
-#define PCI_SRIOV_VFM_UA 0x0
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SRIOV_VFM_UA 0x0
 #define PCI_SRIOV_VFM_MI 0x1
 #define PCI_SRIOV_VFM_MO 0x2
 #define PCI_SRIOV_VFM_AV 0x3
-#define PCI_EXT_CAP_SRIOV_SIZEOF 64
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_EXT_CAP_SRIOV_SIZEOF 64
 #define PCI_LTR_MAX_SNOOP_LAT 0x4
 #define PCI_LTR_MAX_NOSNOOP_LAT 0x6
 #define PCI_LTR_VALUE_MASK 0x000003ff
-#define PCI_LTR_SCALE_MASK 0x00001c00
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_LTR_SCALE_MASK 0x00001c00
 #define PCI_LTR_SCALE_SHIFT 10
 #define PCI_EXT_CAP_LTR_SIZEOF 8
 #define PCI_ACS_CAP 0x04
-#define PCI_ACS_SV 0x01
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ACS_SV 0x01
 #define PCI_ACS_TB 0x02
 #define PCI_ACS_RR 0x04
 #define PCI_ACS_CR 0x08
-#define PCI_ACS_UF 0x10
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ACS_UF 0x10
 #define PCI_ACS_EC 0x20
 #define PCI_ACS_DT 0x40
 #define PCI_ACS_EGRESS_BITS 0x05
-#define PCI_ACS_CTRL 0x06
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_ACS_CTRL 0x06
 #define PCI_ACS_EGRESS_CTL_V 0x08
 #define PCI_VSEC_HDR 4
 #define PCI_VSEC_HDR_LEN_SHIFT 20
-#define PCI_SATA_REGS 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SATA_REGS 4
 #define PCI_SATA_REGS_MASK 0xF
 #define PCI_SATA_REGS_INLINE 0xF
 #define PCI_SATA_SIZEOF_SHORT 8
-#define PCI_SATA_SIZEOF_LONG 16
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_SATA_SIZEOF_LONG 16
 #define PCI_REBAR_CTRL 8
 #define PCI_REBAR_CTRL_NBAR_MASK (7 << 5)
 #define PCI_REBAR_CTRL_NBAR_SHIFT 5
-#define PCI_DPA_CAP 4
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_DPA_CAP 4
 #define PCI_DPA_CAP_SUBSTATE_MASK 0x1F
 #define PCI_DPA_BASE_SIZEOF 16
 #define PCI_TPH_CAP 4
-#define PCI_TPH_CAP_LOC_MASK 0x600
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_TPH_CAP_LOC_MASK 0x600
 #define PCI_TPH_LOC_NONE 0x000
 #define PCI_TPH_LOC_CAP 0x200
 #define PCI_TPH_LOC_MSIX 0x400
-#define PCI_TPH_CAP_ST_MASK 0x07FF0000
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define PCI_TPH_CAP_ST_MASK 0x07FF0000
 #define PCI_TPH_CAP_ST_SHIFT 16
 #define PCI_TPH_BASE_SIZEOF 12
 #endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libc/kernel/uapi/linux/udp.h b/libc/kernel/uapi/linux/udp.h
index e1d546c..a3e9e97 100644
--- a/libc/kernel/uapi/linux/udp.h
+++ b/libc/kernel/uapi/linux/udp.h
@@ -19,7 +19,7 @@
 #ifndef _UAPI_LINUX_UDP_H
 #define _UAPI_LINUX_UDP_H
 #include <linux/types.h>
-struct udphdr {
+struct __kernel_udphdr {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
   __be16 source;
   __be16 dest;
diff --git a/libc/kernel/uapi/linux/usbdevice_fs.h b/libc/kernel/uapi/linux/usbdevice_fs.h
index 0aa2062..285b003 100644
--- a/libc/kernel/uapi/linux/usbdevice_fs.h
+++ b/libc/kernel/uapi/linux/usbdevice_fs.h
@@ -118,61 +118,62 @@
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04
 #define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08
+#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10
 #define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01
-#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02
 struct usbdevfs_disconnect_claim {
   unsigned int interface;
   unsigned int flags;
-  char driver[USBDEVFS_MAXDRIVERNAME + 1];
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  char driver[USBDEVFS_MAXDRIVERNAME + 1];
 };
 struct usbdevfs_streams {
   unsigned int num_streams;
-  unsigned int num_eps;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  unsigned int num_eps;
   unsigned char eps[0];
 };
 #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
-#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
 #define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32)
 #define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)
-#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface)
 #define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
 #define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver)
 #define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
-#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)
 #define USBDEVFS_DISCARDURB _IO('U', 11)
 #define USBDEVFS_REAPURB _IOW('U', 12, void *)
 #define USBDEVFS_REAPURB32 _IOW('U', 12, __u32)
-#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)
 #define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32)
 #define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal)
 #define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32)
-#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
 #define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
 #define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo)
 #define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl)
-#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32)
 #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo)
 #define USBDEVFS_RESET _IO('U', 20)
 #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
-#define USBDEVFS_DISCONNECT _IO('U', 22)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_DISCONNECT _IO('U', 22)
 #define USBDEVFS_CONNECT _IO('U', 23)
 #define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int)
 #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int)
-#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32)
 #define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim)
 #define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams)
 #define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams)
-#endif
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/kernel/uapi/linux/version.h b/libc/kernel/uapi/linux/version.h
index a6c6a2f..ddd92c3 100644
--- a/libc/kernel/uapi/linux/version.h
+++ b/libc/kernel/uapi/linux/version.h
@@ -16,5 +16,5 @@
  ***
  ****************************************************************************
  ****************************************************************************/
-#define LINUX_VERSION_CODE 201226
+#define LINUX_VERSION_CODE 201237
 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
diff --git a/libc/libc.map b/libc/libc.arm.brillo.map
similarity index 89%
rename from libc/libc.map
rename to libc/libc.arm.brillo.map
index ffbd29c..4ebdc45 100644
--- a/libc/libc.map
+++ b/libc/libc.arm.brillo.map
@@ -1,3 +1,4 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
@@ -9,44 +10,25 @@
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
-    __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
     __FD_CLR_chk;
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +40,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,26 +63,18 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
     __memrchr_chk;
     __memset_chk;
     __mmap2; # arm x86 mips
-    __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +97,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +113,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +122,6 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +151,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +160,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
     __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +184,37 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +241,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,14 +255,11 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -387,9 +312,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +358,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +389,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +409,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +429,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +440,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +497,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +514,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +566,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +655,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +674,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +692,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +730,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +744,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +752,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +867,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +937,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1009,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1027,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1048,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1079,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1120,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1139,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1187,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,8 +1211,51 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
@@ -1414,8 +1334,29 @@
     __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
+    __cmpdf2; # arm
+    __divdf3; # arm
+    __divdi3; # arm x86 mips
+    __divsf3; # arm
+    __divsi3; # arm
     __dso_handle; # arm
+    __eqdf2; # arm
+    __extendsfdf2; # arm
+    __fixdfsi; # arm
+    __fixsfsi; # arm
+    __fixunssfsi; # arm
+    __floatdidf; # arm
+    __floatdisf; # arm
+    __floatsidf; # arm
+    __floatsisf; # arm
+    __floatundidf; # arm
+    __floatundisf; # arm
+    __floatunsidf; # arm
+    __floatunsisf; # arm
+    __gedf2; # arm
+    __getdents64; # arm x86 mips
+    __gnu_ldivmod_helper; # arm
+    __gnu_uldivmod_helper; # arm
     __gnu_Unwind_Backtrace; # arm
     __gnu_unwind_execute; # arm
     __gnu_Unwind_Find_exidx; # arm
@@ -1434,6 +1375,38 @@
     __gnu_Unwind_Save_VFP_D_16_to_31; # arm
     __gnu_Unwind_Save_WMMXC; # arm
     __gnu_Unwind_Save_WMMXD; # arm
+    __gtdf2; # arm
+    __ledf2; # arm
+    __lshrdi3; # arm
+    __ltdf2; # arm
+    __muldf3; # arm
+    __muldi3; # arm
+    __mulsf3; # arm
+    __nedf2; # arm
+    __popcount_tab; # arm
+    __popcountsi2; # arm x86 mips
+    __restore_core_regs; # arm
+    __sclose; # arm x86 mips
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __subdf3; # arm
+    __subsf3; # arm
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __truncdfsf2; # arm
+    __udivdi3; # arm mips
+    __udivsi3; # arm
+    __unorddf2; # arm
+    __unordsf2; # arm
+    _fwalk; # arm x86 mips
     _Unwind_Backtrace; # arm
     _Unwind_Complete; # arm
     _Unwind_DeleteException; # arm
@@ -1450,11 +1423,10 @@
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
     atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
+    restore_core_regs; # arm
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
     SHA1Transform; # arm x86 mips
diff --git a/libc/libc.map b/libc/libc.arm.map
similarity index 87%
copy from libc/libc.map
copy to libc/libc.arm.map
index ffbd29c..a2fc481 100644
--- a/libc/libc.map
+++ b/libc/libc.arm.map
@@ -1,3 +1,4 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
@@ -9,44 +10,25 @@
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
-    __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
     __FD_CLR_chk;
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +40,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,26 +63,18 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
     __memrchr_chk;
     __memset_chk;
     __mmap2; # arm x86 mips
-    __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +97,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +113,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +122,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +152,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +161,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
     __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +185,37 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +242,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,14 +256,11 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -387,9 +313,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +359,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +390,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +410,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +430,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +441,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +498,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +515,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +567,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +656,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +675,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +693,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +731,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +745,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +753,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +868,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +938,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1010,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1028,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1049,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1080,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1121,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1140,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1188,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,8 +1212,51 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
@@ -1414,8 +1335,33 @@
     __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
+    __cmpdf2; # arm
+    __divdf3; # arm
+    __divdi3; # arm x86 mips
+    __divsf3; # arm
+    __divsi3; # arm
     __dso_handle; # arm
+    __eqdf2; # arm
+    __extendsfdf2; # arm
+    __fixdfsi; # arm
+    __fixsfsi; # arm
+    __fixunssfsi; # arm
+    __floatdidf; # arm
+    __floatdisf; # arm
+    __floatsidf; # arm
+    __floatsisf; # arm
+    __floatundidf; # arm
+    __floatundisf; # arm
+    __floatunsidf; # arm
+    __floatunsisf; # arm
+    __futex_wait; # arm x86 mips nobrillo
+    __futex_wake; # arm x86 mips nobrillo
+    __gedf2; # arm
+    __get_thread; # arm x86 mips nobrillo
+    __get_tls; # arm x86 mips nobrillo
+    __getdents64; # arm x86 mips
+    __gnu_ldivmod_helper; # arm
+    __gnu_uldivmod_helper; # arm
     __gnu_Unwind_Backtrace; # arm
     __gnu_unwind_execute; # arm
     __gnu_Unwind_Find_exidx; # arm
@@ -1434,6 +1380,46 @@
     __gnu_Unwind_Save_VFP_D_16_to_31; # arm
     __gnu_Unwind_Save_WMMXC; # arm
     __gnu_Unwind_Save_WMMXD; # arm
+    __gtdf2; # arm
+    __ledf2; # arm
+    __lshrdi3; # arm
+    __ltdf2; # arm
+    __muldf3; # arm
+    __muldi3; # arm
+    __mulsf3; # arm
+    __nedf2; # arm
+    __open; # arm x86 mips nobrillo
+    __page_shift; # arm x86 mips nobrillo
+    __page_size; # arm x86 mips nobrillo
+    __popcount_tab; # arm
+    __popcountsi2; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
+    __restore_core_regs; # arm
+    __sclose; # arm x86 mips
+    __sdidinit; # arm x86 mips nobrillo
+    __set_errno; # arm x86 mips nobrillo
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __sinit; # arm x86 mips nobrillo
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __subdf3; # arm
+    __subsf3; # arm
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __truncdfsf2; # arm
+    __udivdi3; # arm mips
+    __udivsi3; # arm
+    __unorddf2; # arm
+    __unordsf2; # arm
+    __wait4; # arm x86 mips nobrillo
+    _fwalk; # arm x86 mips
     _Unwind_Backtrace; # arm
     _Unwind_Complete; # arm
     _Unwind_DeleteException; # arm
@@ -1449,14 +1435,40 @@
     _Unwind_VRS_Get; # arm
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
+    arc4random_addrandom; # arm x86 mips nobrillo
+    arc4random_stir; # arm x86 mips nobrillo
     atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
+    bsd_signal; # arm x86 mips nobrillo
+    dlmalloc; # arm x86 mips nobrillo
+    dlmalloc_inspect_all; # arm x86 mips nobrillo
+    dlmalloc_trim; # arm x86 mips nobrillo
+    dlmalloc_usable_size; # arm x86 mips nobrillo
+    endpwent; # arm x86 mips nobrillo
+    fdprintf; # arm x86 mips nobrillo
+    free_malloc_leak_info;
+    ftime; # arm x86 mips nobrillo
+    get_malloc_leak_info;
+    getdents; # arm x86 mips nobrillo
+    getdtablesize; # arm x86 mips nobrillo
     gMallocLeakZygoteChild;
+    index; # arm x86 mips nobrillo
+    issetugid; # arm x86 mips nobrillo
+    memswap; # arm x86 mips nobrillo
+    pthread_attr_getstackaddr; # arm x86 mips nobrillo
+    pthread_attr_setstackaddr; # arm x86 mips nobrillo
+    restore_core_regs; # arm
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
     SHA1Transform; # arm x86 mips
     SHA1Update; # arm x86 mips
+    strntoimax; # arm x86 mips nobrillo
+    strntoumax; # arm x86 mips nobrillo
+    strtotimeval; # arm x86 mips nobrillo
+    sysv_signal; # arm x86 mips nobrillo
+    tkill; # arm x86 mips nobrillo
+    vfdprintf; # arm x86 mips nobrillo
+    wait3; # arm x86 mips nobrillo
+    wcswcs; # arm x86 mips nobrillo
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.arm64.map
similarity index 66%
copy from libc/libc.map
copy to libc/libc.arm64.map
index ffbd29c..dcf1e8f 100644
--- a/libc/libc.map
+++ b/libc/libc.arm64.map
@@ -1,52 +1,25 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
-    __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
-    __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
-    __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
-    __exit; # arm x86 mips
-    __extendsfdf2; # arm
-    __fadvise64; # x86 mips
     __fbufsize;
-    __fcntl64; # arm x86 mips
     __FD_CLR_chk;
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -57,26 +30,11 @@
     __fpurge;
     __freadable;
     __fsetlocking;
-    __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
-    __getcpu; # arm x86 mips
-    __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
-    __getpid; # arm x86 mips
-    __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
-    __ioctl; # arm x86 mips
     __isfinite;
     __isfinitef;
     __isfinitel;
@@ -90,51 +48,17 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
-    __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
     __memrchr_chk;
     __memset_chk;
-    __mmap2; # arm x86 mips
-    __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
-    __ns_format_ttl; # arm x86 mips
-    __ns_get16; # arm x86 mips
-    __ns_get32; # arm x86 mips
-    __ns_initparse; # arm x86 mips
-    __ns_makecanon; # arm x86 mips
-    __ns_msg_getflag; # arm x86 mips
-    __ns_name_compress; # arm x86 mips
-    __ns_name_ntol; # arm x86 mips
-    __ns_name_ntop; # arm x86 mips
-    __ns_name_pack; # arm x86 mips
-    __ns_name_pton; # arm x86 mips
-    __ns_name_rollback; # arm x86 mips
-    __ns_name_skip; # arm x86 mips
-    __ns_name_uncompress; # arm x86 mips
-    __ns_name_unpack; # arm x86 mips
-    __ns_parserr; # arm x86 mips
-    __ns_put16; # arm x86 mips
-    __ns_put32; # arm x86 mips
-    __ns_samename; # arm x86 mips
-    __ns_skiprr; # arm x86 mips
-    __ns_sprintrr; # arm x86 mips
-    __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
-    __openat; # arm x86 mips
     __openat_2;
     __p_cdname;
     __p_cdnname;
@@ -149,27 +73,18 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
-    __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
     __pread_chk;
     __progname;
-    __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
-    __ptrace; # arm x86 mips
     __putlong;
     __putshort;
     __read_chk;
     __readlink_chk;
     __readlinkat_chk;
-    __reboot; # arm x86 mips
     __recvfrom_chk;
     __register_atfork;
     __res_close;
@@ -192,41 +107,14 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
-    __rt_sigaction; # arm x86 mips
-    __rt_sigpending; # arm x86 mips
-    __rt_sigprocmask; # arm x86 mips
-    __rt_sigsuspend; # arm x86 mips
-    __rt_sigtimedwait; # arm x86 mips
     __sched_cpualloc;
     __sched_cpucount;
     __sched_cpufree;
-    __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
-    __set_tid_address; # arm x86 mips
-    __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
-    __sigaction; # arm x86 mips
-    __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
-    __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
-    __statfs64; # arm x86 mips
     __stpcpy_chk;
     __stpncpy_chk;
     __stpncpy_chk2;
@@ -240,51 +128,16 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
-    __timer_create; # arm x86 mips
-    __timer_delete; # arm x86 mips
-    __timer_getoverrun; # arm x86 mips
-    __timer_gettime; # arm x86 mips
-    __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
-    __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -293,9 +146,7 @@
     _resolv_set_nameservers_for_net;
     _setjmp;
     _tolower;
-    _tolower_tab_; # arm x86 mips
     _toupper;
-    _toupper_tab_; # arm x86 mips
     abort;
     abs;
     accept;
@@ -311,13 +162,9 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
-    asctime64; # arm x86 mips
-    asctime64_r; # arm x86 mips
     asctime_r;
     asprintf;
     at_quick_exit;
@@ -326,18 +173,13 @@
     atol;
     atoll;
     basename;
-    basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
-    cacheflush; # arm mips
     calloc;
     capget;
     capset;
@@ -368,8 +210,6 @@
     creat;
     creat64;
     ctime;
-    ctime64; # arm x86 mips
-    ctime64_r; # arm x86 mips
     ctime_r;
     daemon;
     daylight;
@@ -377,7 +217,6 @@
     difftime;
     dirfd;
     dirname;
-    dirname_r; # arm x86 mips
     div;
     dn_expand;
     dprintf;
@@ -387,9 +226,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -421,8 +258,6 @@
     execvpe;
     exit;
     faccessat;
-    fake_gmtime_r; # arm x86 mips
-    fake_localtime_r; # arm x86 mips
     fallocate;
     fallocate64;
     fchdir;
@@ -435,7 +270,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +301,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +321,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +341,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +352,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,14 +409,11 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
     getxattr;
     gmtime;
-    gmtime64; # arm x86 mips
-    gmtime64_r; # arm x86 mips
     gmtime_r;
     grantpt;
     herror;
@@ -598,7 +424,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +476,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -704,8 +528,6 @@
     llistxattr;
     localeconv;
     localtime;
-    localtime64; # arm x86 mips
-    localtime64_r; # arm x86 mips
     localtime_r;
     login_tty;
     longjmp;
@@ -741,7 +563,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -760,8 +581,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -855,7 +674,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,17 +682,12 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
     pthread_cond_init;
     pthread_cond_signal;
     pthread_cond_timedwait;
-    pthread_cond_timedwait_monotonic; # arm x86 mips
-    pthread_cond_timedwait_monotonic_np; # arm x86 mips
-    pthread_cond_timedwait_relative_np; # arm x86 mips
-    pthread_cond_timeout_np; # arm x86 mips
     pthread_cond_wait;
     pthread_condattr_destroy;
     pthread_condattr_getclock;
@@ -898,7 +711,6 @@
     pthread_mutex_destroy;
     pthread_mutex_init;
     pthread_mutex_lock;
-    pthread_mutex_lock_timeout_np; # arm x86 mips
     pthread_mutex_timedlock;
     pthread_mutex_trylock;
     pthread_mutex_unlock;
@@ -939,10 +751,8 @@
     putenv;
     puts;
     pututline;
-    putw; # arm x86 mips
     putwc;
     putwchar;
-    pvalloc; # arm x86 mips
     pwrite;
     pwrite64;
     qsort;
@@ -980,7 +790,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +860,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +932,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +950,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +971,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1185,9 +989,7 @@
     tgkill;
     time;
     timegm;
-    timegm64; # arm x86 mips
     timelocal;
-    timelocal64; # arm x86 mips
     timer_create;
     timer_delete;
     timer_getoverrun;
@@ -1198,7 +1000,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1235,12 +1036,10 @@
     utimensat;
     utimes;
     utmpname;
-    valloc; # arm x86 mips
     vasprintf;
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1059,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1107,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,129 +1131,56 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
-    __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
-    __bionic_brk; # arm x86 mips
-    __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __system_properties_init; # arm64 x86_64 mips64
+    __system_property_add; # arm64 x86_64 mips64
+    __system_property_area__; # arm64 x86_64 mips64
+    __system_property_area_init; # arm64 x86_64 mips64
+    __system_property_area_serial; # arm64 x86_64 mips64
+    __system_property_find; # arm64 x86_64 mips64
+    __system_property_find_nth; # arm64 x86_64 mips64
+    __system_property_foreach; # arm64 x86_64 mips64
+    __system_property_get; # arm64 x86_64 mips64
+    __system_property_read; # arm64 x86_64 mips64
+    __system_property_serial; # arm64 x86_64 mips64
+    __system_property_set; # arm64 x86_64 mips64
+    __system_property_set_filename; # arm64 x86_64 mips64
+    __system_property_update; # arm64 x86_64 mips64
+    __system_property_wait_any; # arm64 x86_64 mips64
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
-    SHA1Final; # arm x86 mips
-    SHA1Init; # arm x86 mips
-    SHA1Transform; # arm x86 mips
-    SHA1Update; # arm x86 mips
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.map.txt
similarity index 85%
copy from libc/libc.map
copy to libc/libc.map.txt
index ffbd29c..8306463 100644
--- a/libc/libc.map
+++ b/libc/libc.map.txt
@@ -9,25 +9,18 @@
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
     __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
@@ -35,18 +28,7 @@
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +40,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,15 +63,12 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
@@ -106,10 +76,6 @@
     __memset_chk;
     __mmap2; # arm x86 mips
     __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +98,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +114,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +123,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +153,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +162,15 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
     __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
     __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +187,39 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
+    __udivdi3; # x86
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
     _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +246,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,14 +260,11 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -387,9 +317,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +363,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +394,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +414,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +434,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +445,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +502,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +519,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +571,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +660,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +679,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -855,7 +772,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +780,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +895,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +965,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1037,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1055,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1076,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1107,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1148,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1167,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1215,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,8 +1239,51 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
@@ -1414,8 +1362,33 @@
     __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
+    __cmpdf2; # arm
+    __divdf3; # arm
+    __divdi3; # arm x86 mips
+    __divsf3; # arm
+    __divsi3; # arm
     __dso_handle; # arm
+    __eqdf2; # arm
+    __extendsfdf2; # arm
+    __fixdfsi; # arm
+    __fixsfsi; # arm
+    __fixunssfsi; # arm
+    __floatdidf; # arm
+    __floatdisf; # arm
+    __floatsidf; # arm
+    __floatsisf; # arm
+    __floatundidf; # arm
+    __floatundisf; # arm
+    __floatunsidf; # arm
+    __floatunsisf; # arm
+    __futex_wait; # arm x86 mips nobrillo
+    __futex_wake; # arm x86 mips nobrillo
+    __gedf2; # arm
+    __get_thread; # arm x86 mips nobrillo
+    __get_tls; # arm x86 mips nobrillo
+    __getdents64; # arm x86 mips
+    __gnu_ldivmod_helper; # arm
+    __gnu_uldivmod_helper; # arm
     __gnu_Unwind_Backtrace; # arm
     __gnu_unwind_execute; # arm
     __gnu_Unwind_Find_exidx; # arm
@@ -1434,6 +1407,62 @@
     __gnu_Unwind_Save_VFP_D_16_to_31; # arm
     __gnu_Unwind_Save_WMMXC; # arm
     __gnu_Unwind_Save_WMMXD; # arm
+    __gtdf2; # arm
+    __ledf2; # arm
+    __lshrdi3; # arm
+    __ltdf2; # arm
+    __muldf3; # arm
+    __muldi3; # arm
+    __mulsf3; # arm
+    __nedf2; # arm
+    __open; # arm x86 mips nobrillo
+    __page_shift; # arm x86 mips nobrillo
+    __page_size; # arm x86 mips nobrillo
+    __popcount_tab; # arm
+    __popcountsi2; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
+    __restore_core_regs; # arm
+    __sclose; # arm x86 mips
+    __sdidinit; # arm x86 mips nobrillo
+    __set_errno; # arm x86 mips nobrillo
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __sinit; # arm x86 mips nobrillo
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __subdf3; # arm
+    __subsf3; # arm
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __system_properties_init; # arm64 x86_64 mips64
+    __system_property_add; # arm64 x86_64 mips64
+    __system_property_area__; # arm64 x86_64 mips64
+    __system_property_area_init; # arm64 x86_64 mips64
+    __system_property_area_serial; # arm64 x86_64 mips64
+    __system_property_find; # arm64 x86_64 mips64
+    __system_property_find_nth; # arm64 x86_64 mips64
+    __system_property_foreach; # arm64 x86_64 mips64
+    __system_property_get; # arm64 x86_64 mips64
+    __system_property_read; # arm64 x86_64 mips64
+    __system_property_serial; # arm64 x86_64 mips64
+    __system_property_set; # arm64 x86_64 mips64
+    __system_property_set_filename; # arm64 x86_64 mips64
+    __system_property_update; # arm64 x86_64 mips64
+    __system_property_wait_any; # arm64 x86_64 mips64
+    __truncdfsf2; # arm
+    __udivdi3; # arm mips
+    __udivsi3; # arm
+    __umoddi3; # x86 mips
+    __unorddf2; # arm
+    __unordsf2; # arm
+    __wait4; # arm x86 mips nobrillo
+    _fwalk; # arm x86 mips
     _Unwind_Backtrace; # arm
     _Unwind_Complete; # arm
     _Unwind_DeleteException; # arm
@@ -1449,14 +1478,40 @@
     _Unwind_VRS_Get; # arm
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
+    arc4random_addrandom; # arm x86 mips nobrillo
+    arc4random_stir; # arm x86 mips nobrillo
     atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
+    bsd_signal; # arm x86 mips nobrillo
+    dlmalloc; # arm x86 mips nobrillo
+    dlmalloc_inspect_all; # arm x86 mips nobrillo
+    dlmalloc_trim; # arm x86 mips nobrillo
+    dlmalloc_usable_size; # arm x86 mips nobrillo
+    endpwent; # arm x86 mips nobrillo
+    fdprintf; # arm x86 mips nobrillo
+    free_malloc_leak_info;
+    ftime; # arm x86 mips nobrillo
+    get_malloc_leak_info;
+    getdents; # arm x86 mips nobrillo
+    getdtablesize; # arm x86 mips nobrillo
     gMallocLeakZygoteChild;
+    index; # arm x86 mips nobrillo
+    issetugid; # arm x86 mips nobrillo
+    memswap; # arm x86 mips nobrillo
+    pthread_attr_getstackaddr; # arm x86 mips nobrillo
+    pthread_attr_setstackaddr; # arm x86 mips nobrillo
+    restore_core_regs; # arm
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
     SHA1Transform; # arm x86 mips
     SHA1Update; # arm x86 mips
+    strntoimax; # arm x86 mips nobrillo
+    strntoumax; # arm x86 mips nobrillo
+    strtotimeval; # arm x86 mips nobrillo
+    sysv_signal; # arm x86 mips nobrillo
+    tkill; # arm x86 mips nobrillo
+    vfdprintf; # arm x86 mips nobrillo
+    wait3; # arm x86 mips nobrillo
+    wcswcs; # arm x86 mips nobrillo
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.mips.brillo.map
similarity index 75%
copy from libc/libc.map
copy to libc/libc.mips.brillo.map
index ffbd29c..e3b5a5e 100644
--- a/libc/libc.map
+++ b/libc/libc.mips.brillo.map
@@ -1,33 +1,23 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
     __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
@@ -35,18 +25,7 @@
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +37,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,15 +60,12 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
@@ -106,10 +73,6 @@
     __memset_chk;
     __mmap2; # arm x86 mips
     __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +95,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +111,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +120,6 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +149,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +158,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
     __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +182,38 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
     _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +240,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,14 +254,11 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -387,9 +311,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +357,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +388,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +408,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +428,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +439,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +496,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +513,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +565,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +654,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +673,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +691,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +729,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +743,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +751,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +866,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +936,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1008,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1026,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1047,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1078,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1119,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1138,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1186,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,126 +1210,64 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
     __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
-    __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __divdi3; # arm x86 mips
+    __getdents64; # arm x86 mips
+    __popcountsi2; # arm x86 mips
+    __sclose; # arm x86 mips
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __udivdi3; # arm mips
+    __umoddi3; # x86 mips
+    _fwalk; # arm x86 mips
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
diff --git a/libc/libc.map b/libc/libc.mips.map
similarity index 75%
copy from libc/libc.map
copy to libc/libc.mips.map
index ffbd29c..4d2f826 100644
--- a/libc/libc.map
+++ b/libc/libc.mips.map
@@ -1,33 +1,23 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
     __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
@@ -35,18 +25,7 @@
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +37,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,15 +60,12 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
@@ -106,10 +73,6 @@
     __memset_chk;
     __mmap2; # arm x86 mips
     __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +95,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +111,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +120,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +150,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +159,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
     __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +183,38 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
     _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +241,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,14 +255,11 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -387,9 +312,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +358,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +389,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +409,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +429,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +440,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +497,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +514,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +566,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +655,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +674,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +692,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +730,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +744,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +752,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +867,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +937,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1009,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1027,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1048,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1079,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1120,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1139,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1187,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,129 +1211,106 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
     __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
-    __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __divdi3; # arm x86 mips
+    __futex_wait; # arm x86 mips nobrillo
+    __futex_wake; # arm x86 mips nobrillo
+    __get_thread; # arm x86 mips nobrillo
+    __get_tls; # arm x86 mips nobrillo
+    __getdents64; # arm x86 mips
+    __open; # arm x86 mips nobrillo
+    __page_shift; # arm x86 mips nobrillo
+    __page_size; # arm x86 mips nobrillo
+    __popcountsi2; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
+    __sclose; # arm x86 mips
+    __sdidinit; # arm x86 mips nobrillo
+    __set_errno; # arm x86 mips nobrillo
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __sinit; # arm x86 mips nobrillo
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __udivdi3; # arm mips
+    __umoddi3; # x86 mips
+    __wait4; # arm x86 mips nobrillo
+    _fwalk; # arm x86 mips
+    arc4random_addrandom; # arm x86 mips nobrillo
+    arc4random_stir; # arm x86 mips nobrillo
+    bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
+    bsd_signal; # arm x86 mips nobrillo
+    dlmalloc; # arm x86 mips nobrillo
+    dlmalloc_inspect_all; # arm x86 mips nobrillo
+    dlmalloc_trim; # arm x86 mips nobrillo
+    dlmalloc_usable_size; # arm x86 mips nobrillo
+    endpwent; # arm x86 mips nobrillo
+    fdprintf; # arm x86 mips nobrillo
+    free_malloc_leak_info;
+    ftime; # arm x86 mips nobrillo
+    get_malloc_leak_info;
+    getdents; # arm x86 mips nobrillo
+    getdtablesize; # arm x86 mips nobrillo
     gMallocLeakZygoteChild;
+    index; # arm x86 mips nobrillo
+    issetugid; # arm x86 mips nobrillo
+    memswap; # arm x86 mips nobrillo
+    pthread_attr_getstackaddr; # arm x86 mips nobrillo
+    pthread_attr_setstackaddr; # arm x86 mips nobrillo
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
     SHA1Transform; # arm x86 mips
     SHA1Update; # arm x86 mips
+    strntoimax; # arm x86 mips nobrillo
+    strntoumax; # arm x86 mips nobrillo
+    strtotimeval; # arm x86 mips nobrillo
+    sysv_signal; # arm x86 mips nobrillo
+    tkill; # arm x86 mips nobrillo
+    vfdprintf; # arm x86 mips nobrillo
+    wait3; # arm x86 mips nobrillo
+    wcswcs; # arm x86 mips nobrillo
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.mips64.map
similarity index 66%
copy from libc/libc.map
copy to libc/libc.mips64.map
index ffbd29c..dcf1e8f 100644
--- a/libc/libc.map
+++ b/libc/libc.mips64.map
@@ -1,52 +1,25 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
-    __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
-    __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
-    __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
-    __exit; # arm x86 mips
-    __extendsfdf2; # arm
-    __fadvise64; # x86 mips
     __fbufsize;
-    __fcntl64; # arm x86 mips
     __FD_CLR_chk;
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -57,26 +30,11 @@
     __fpurge;
     __freadable;
     __fsetlocking;
-    __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
-    __getcpu; # arm x86 mips
-    __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
-    __getpid; # arm x86 mips
-    __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
-    __ioctl; # arm x86 mips
     __isfinite;
     __isfinitef;
     __isfinitel;
@@ -90,51 +48,17 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
-    __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
     __memrchr_chk;
     __memset_chk;
-    __mmap2; # arm x86 mips
-    __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
-    __ns_format_ttl; # arm x86 mips
-    __ns_get16; # arm x86 mips
-    __ns_get32; # arm x86 mips
-    __ns_initparse; # arm x86 mips
-    __ns_makecanon; # arm x86 mips
-    __ns_msg_getflag; # arm x86 mips
-    __ns_name_compress; # arm x86 mips
-    __ns_name_ntol; # arm x86 mips
-    __ns_name_ntop; # arm x86 mips
-    __ns_name_pack; # arm x86 mips
-    __ns_name_pton; # arm x86 mips
-    __ns_name_rollback; # arm x86 mips
-    __ns_name_skip; # arm x86 mips
-    __ns_name_uncompress; # arm x86 mips
-    __ns_name_unpack; # arm x86 mips
-    __ns_parserr; # arm x86 mips
-    __ns_put16; # arm x86 mips
-    __ns_put32; # arm x86 mips
-    __ns_samename; # arm x86 mips
-    __ns_skiprr; # arm x86 mips
-    __ns_sprintrr; # arm x86 mips
-    __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
-    __openat; # arm x86 mips
     __openat_2;
     __p_cdname;
     __p_cdnname;
@@ -149,27 +73,18 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
-    __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
     __pread_chk;
     __progname;
-    __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
-    __ptrace; # arm x86 mips
     __putlong;
     __putshort;
     __read_chk;
     __readlink_chk;
     __readlinkat_chk;
-    __reboot; # arm x86 mips
     __recvfrom_chk;
     __register_atfork;
     __res_close;
@@ -192,41 +107,14 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
-    __rt_sigaction; # arm x86 mips
-    __rt_sigpending; # arm x86 mips
-    __rt_sigprocmask; # arm x86 mips
-    __rt_sigsuspend; # arm x86 mips
-    __rt_sigtimedwait; # arm x86 mips
     __sched_cpualloc;
     __sched_cpucount;
     __sched_cpufree;
-    __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
-    __set_tid_address; # arm x86 mips
-    __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
-    __sigaction; # arm x86 mips
-    __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
-    __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
-    __statfs64; # arm x86 mips
     __stpcpy_chk;
     __stpncpy_chk;
     __stpncpy_chk2;
@@ -240,51 +128,16 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
-    __timer_create; # arm x86 mips
-    __timer_delete; # arm x86 mips
-    __timer_getoverrun; # arm x86 mips
-    __timer_gettime; # arm x86 mips
-    __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
-    __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -293,9 +146,7 @@
     _resolv_set_nameservers_for_net;
     _setjmp;
     _tolower;
-    _tolower_tab_; # arm x86 mips
     _toupper;
-    _toupper_tab_; # arm x86 mips
     abort;
     abs;
     accept;
@@ -311,13 +162,9 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
-    asctime64; # arm x86 mips
-    asctime64_r; # arm x86 mips
     asctime_r;
     asprintf;
     at_quick_exit;
@@ -326,18 +173,13 @@
     atol;
     atoll;
     basename;
-    basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
-    cacheflush; # arm mips
     calloc;
     capget;
     capset;
@@ -368,8 +210,6 @@
     creat;
     creat64;
     ctime;
-    ctime64; # arm x86 mips
-    ctime64_r; # arm x86 mips
     ctime_r;
     daemon;
     daylight;
@@ -377,7 +217,6 @@
     difftime;
     dirfd;
     dirname;
-    dirname_r; # arm x86 mips
     div;
     dn_expand;
     dprintf;
@@ -387,9 +226,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -421,8 +258,6 @@
     execvpe;
     exit;
     faccessat;
-    fake_gmtime_r; # arm x86 mips
-    fake_localtime_r; # arm x86 mips
     fallocate;
     fallocate64;
     fchdir;
@@ -435,7 +270,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +301,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +321,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +341,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +352,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,14 +409,11 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
     getxattr;
     gmtime;
-    gmtime64; # arm x86 mips
-    gmtime64_r; # arm x86 mips
     gmtime_r;
     grantpt;
     herror;
@@ -598,7 +424,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +476,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -704,8 +528,6 @@
     llistxattr;
     localeconv;
     localtime;
-    localtime64; # arm x86 mips
-    localtime64_r; # arm x86 mips
     localtime_r;
     login_tty;
     longjmp;
@@ -741,7 +563,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -760,8 +581,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -855,7 +674,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,17 +682,12 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
     pthread_cond_init;
     pthread_cond_signal;
     pthread_cond_timedwait;
-    pthread_cond_timedwait_monotonic; # arm x86 mips
-    pthread_cond_timedwait_monotonic_np; # arm x86 mips
-    pthread_cond_timedwait_relative_np; # arm x86 mips
-    pthread_cond_timeout_np; # arm x86 mips
     pthread_cond_wait;
     pthread_condattr_destroy;
     pthread_condattr_getclock;
@@ -898,7 +711,6 @@
     pthread_mutex_destroy;
     pthread_mutex_init;
     pthread_mutex_lock;
-    pthread_mutex_lock_timeout_np; # arm x86 mips
     pthread_mutex_timedlock;
     pthread_mutex_trylock;
     pthread_mutex_unlock;
@@ -939,10 +751,8 @@
     putenv;
     puts;
     pututline;
-    putw; # arm x86 mips
     putwc;
     putwchar;
-    pvalloc; # arm x86 mips
     pwrite;
     pwrite64;
     qsort;
@@ -980,7 +790,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +860,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +932,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +950,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +971,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1185,9 +989,7 @@
     tgkill;
     time;
     timegm;
-    timegm64; # arm x86 mips
     timelocal;
-    timelocal64; # arm x86 mips
     timer_create;
     timer_delete;
     timer_getoverrun;
@@ -1198,7 +1000,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1235,12 +1036,10 @@
     utimensat;
     utimes;
     utmpname;
-    valloc; # arm x86 mips
     vasprintf;
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1059,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1107,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,129 +1131,56 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
-    __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
-    __bionic_brk; # arm x86 mips
-    __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __system_properties_init; # arm64 x86_64 mips64
+    __system_property_add; # arm64 x86_64 mips64
+    __system_property_area__; # arm64 x86_64 mips64
+    __system_property_area_init; # arm64 x86_64 mips64
+    __system_property_area_serial; # arm64 x86_64 mips64
+    __system_property_find; # arm64 x86_64 mips64
+    __system_property_find_nth; # arm64 x86_64 mips64
+    __system_property_foreach; # arm64 x86_64 mips64
+    __system_property_get; # arm64 x86_64 mips64
+    __system_property_read; # arm64 x86_64 mips64
+    __system_property_serial; # arm64 x86_64 mips64
+    __system_property_set; # arm64 x86_64 mips64
+    __system_property_set_filename; # arm64 x86_64 mips64
+    __system_property_update; # arm64 x86_64 mips64
+    __system_property_wait_any; # arm64 x86_64 mips64
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
-    SHA1Final; # arm x86 mips
-    SHA1Init; # arm x86 mips
-    SHA1Transform; # arm x86 mips
-    SHA1Update; # arm x86 mips
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.x86.brillo.map
similarity index 75%
copy from libc/libc.map
copy to libc/libc.x86.brillo.map
index ffbd29c..637ad06 100644
--- a/libc/libc.map
+++ b/libc/libc.x86.brillo.map
@@ -1,33 +1,23 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
     __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
@@ -35,18 +25,7 @@
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +37,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,15 +60,12 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
@@ -106,10 +73,6 @@
     __memset_chk;
     __mmap2; # arm x86 mips
     __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +95,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +111,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +120,6 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +149,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +158,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
     __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
-    __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +182,38 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
+    __udivdi3; # x86
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +240,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,17 +254,13 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
-    cacheflush; # arm mips
     calloc;
     capget;
     capset;
@@ -387,9 +310,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +356,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +387,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +407,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +427,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +438,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +495,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +512,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +564,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +653,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +672,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +690,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +728,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +742,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +750,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +865,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +935,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1007,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1025,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1046,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1077,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1118,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1137,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1185,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,126 +1209,64 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
     __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __divdi3; # arm x86 mips
+    __getdents64; # arm x86 mips
+    __popcountsi2; # arm x86 mips
+    __sclose; # arm x86 mips
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __umoddi3; # x86 mips
+    _fwalk; # arm x86 mips
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
diff --git a/libc/libc.map b/libc/libc.x86.map
similarity index 75%
copy from libc/libc.map
copy to libc/libc.x86.map
index ffbd29c..76bf9ea 100644
--- a/libc/libc.map
+++ b/libc/libc.x86.map
@@ -1,33 +1,23 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
     __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
     __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
     __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
     __exit; # arm x86 mips
-    __extendsfdf2; # arm
     __fadvise64; # x86 mips
     __fbufsize;
     __fcntl64; # arm x86 mips
@@ -35,18 +25,7 @@
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -58,23 +37,14 @@
     __freadable;
     __fsetlocking;
     __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
     __getcpu; # arm x86 mips
     __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
     __getpid; # arm x86 mips
     __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
     __ioctl; # arm x86 mips
     __isfinite;
@@ -90,15 +60,12 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
     __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
@@ -106,10 +73,6 @@
     __memset_chk;
     __mmap2; # arm x86 mips
     __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
     __ns_format_ttl; # arm x86 mips
     __ns_get16; # arm x86 mips
     __ns_get32; # arm x86 mips
@@ -132,7 +95,6 @@
     __ns_skiprr; # arm x86 mips
     __ns_sprintrr; # arm x86 mips
     __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
     __openat; # arm x86 mips
     __openat_2;
@@ -149,11 +111,7 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
     __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
@@ -162,7 +120,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -192,7 +150,6 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
     __rt_sigaction; # arm x86 mips
     __rt_sigpending; # arm x86 mips
     __rt_sigprocmask; # arm x86 mips
@@ -202,28 +159,14 @@
     __sched_cpucount;
     __sched_cpufree;
     __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
     __set_thread_area; # x86
     __set_tid_address; # arm x86 mips
-    __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
     __sigaction; # arm x86 mips
     __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
     __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
     __statfs64; # arm x86 mips
@@ -240,51 +183,38 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
+    __system_properties_init; # arm x86 mips
+    __system_property_add; # arm x86 mips
+    __system_property_area__; # arm x86 mips
+    __system_property_area_init; # arm x86 mips
+    __system_property_area_serial; # arm x86 mips
+    __system_property_find; # arm x86 mips
+    __system_property_find_nth; # arm x86 mips
+    __system_property_foreach; # arm x86 mips
+    __system_property_get; # arm x86 mips
+    __system_property_read; # arm x86 mips
+    __system_property_serial; # arm x86 mips
+    __system_property_set; # arm x86 mips
+    __system_property_set_filename; # arm x86 mips
+    __system_property_update; # arm x86 mips
+    __system_property_wait_any; # arm x86 mips
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
+    __udivdi3; # x86
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
     __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -311,9 +241,7 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
     asctime64; # arm x86 mips
@@ -327,17 +255,13 @@
     atoll;
     basename;
     basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
-    cacheflush; # arm mips
     calloc;
     capget;
     capset;
@@ -387,9 +311,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -435,7 +357,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +388,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +408,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +428,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +439,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,7 +496,6 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
@@ -598,7 +513,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +565,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -741,7 +654,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -761,7 +673,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -780,28 +691,6 @@
     nftw64;
     nice;
     nrand48;
-    ns_format_ttl; # arm64 x86_64 mips64
-    ns_get16; # arm64 x86_64 mips64
-    ns_get32; # arm64 x86_64 mips64
-    ns_initparse; # arm64 x86_64 mips64
-    ns_makecanon; # arm64 x86_64 mips64
-    ns_msg_getflag; # arm64 x86_64 mips64
-    ns_name_compress; # arm64 x86_64 mips64
-    ns_name_ntol; # arm64 x86_64 mips64
-    ns_name_ntop; # arm64 x86_64 mips64
-    ns_name_pack; # arm64 x86_64 mips64
-    ns_name_pton; # arm64 x86_64 mips64
-    ns_name_rollback; # arm64 x86_64 mips64
-    ns_name_skip; # arm64 x86_64 mips64
-    ns_name_uncompress; # arm64 x86_64 mips64
-    ns_name_unpack; # arm64 x86_64 mips64
-    ns_parserr; # arm64 x86_64 mips64
-    ns_put16; # arm64 x86_64 mips64
-    ns_put32; # arm64 x86_64 mips64
-    ns_samename; # arm64 x86_64 mips64
-    ns_skiprr; # arm64 x86_64 mips64
-    ns_sprintrr; # arm64 x86_64 mips64
-    ns_sprintrrf; # arm64 x86_64 mips64
     nsdispatch;
     ntohl;
     ntohs;
@@ -840,7 +729,6 @@
     pread;
     pread64;
     printf;
-    prlimit; # arm64 x86_64 mips64
     prlimit64;
     process_vm_readv;
     process_vm_writev;
@@ -855,7 +743,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,7 +751,6 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
@@ -980,7 +866,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +936,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +1008,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +1026,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +1047,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1198,7 +1078,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1240,7 +1119,6 @@
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1138,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1186,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,129 +1210,106 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    prlimit; # arm mips x86
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
     __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
     __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __divdi3; # arm x86 mips
+    __futex_wait; # arm x86 mips nobrillo
+    __futex_wake; # arm x86 mips nobrillo
+    __get_thread; # arm x86 mips nobrillo
+    __get_tls; # arm x86 mips nobrillo
+    __getdents64; # arm x86 mips
+    __open; # arm x86 mips nobrillo
+    __page_shift; # arm x86 mips nobrillo
+    __page_size; # arm x86 mips nobrillo
+    __popcountsi2; # arm x86 mips
+    __pthread_gettid; # arm x86 mips nobrillo
+    __sclose; # arm x86 mips
+    __sdidinit; # arm x86 mips nobrillo
+    __set_errno; # arm x86 mips nobrillo
+    __sflags; # arm x86 mips
+    __sflush; # arm x86 mips
+    __sfp; # arm x86 mips
+    __sglue; # arm x86 mips
+    __sinit; # arm x86 mips nobrillo
+    __smakebuf; # arm x86 mips
+    __sread; # arm x86 mips
+    __srefill; # arm x86 mips
+    __srget; # arm x86 mips
+    __sseek; # arm x86 mips
+    __swbuf; # arm x86 mips
+    __swrite; # arm x86 mips
+    __swsetup; # arm x86 mips
+    __umoddi3; # x86 mips
+    __wait4; # arm x86 mips nobrillo
+    _fwalk; # arm x86 mips
+    arc4random_addrandom; # arm x86 mips nobrillo
+    arc4random_stir; # arm x86 mips nobrillo
+    bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
+    bsd_signal; # arm x86 mips nobrillo
+    dlmalloc; # arm x86 mips nobrillo
+    dlmalloc_inspect_all; # arm x86 mips nobrillo
+    dlmalloc_trim; # arm x86 mips nobrillo
+    dlmalloc_usable_size; # arm x86 mips nobrillo
+    endpwent; # arm x86 mips nobrillo
+    fdprintf; # arm x86 mips nobrillo
+    free_malloc_leak_info;
+    ftime; # arm x86 mips nobrillo
+    get_malloc_leak_info;
+    getdents; # arm x86 mips nobrillo
+    getdtablesize; # arm x86 mips nobrillo
     gMallocLeakZygoteChild;
+    index; # arm x86 mips nobrillo
+    issetugid; # arm x86 mips nobrillo
+    memswap; # arm x86 mips nobrillo
+    pthread_attr_getstackaddr; # arm x86 mips nobrillo
+    pthread_attr_setstackaddr; # arm x86 mips nobrillo
     SHA1Final; # arm x86 mips
     SHA1Init; # arm x86 mips
     SHA1Transform; # arm x86 mips
     SHA1Update; # arm x86 mips
+    strntoimax; # arm x86 mips nobrillo
+    strntoumax; # arm x86 mips nobrillo
+    strtotimeval; # arm x86 mips nobrillo
+    sysv_signal; # arm x86 mips nobrillo
+    tkill; # arm x86 mips nobrillo
+    vfdprintf; # arm x86 mips nobrillo
+    wait3; # arm x86 mips nobrillo
+    wcswcs; # arm x86 mips nobrillo
 } LIBC_N;
diff --git a/libc/libc.map b/libc/libc.x86_64.map
similarity index 66%
copy from libc/libc.map
copy to libc/libc.x86_64.map
index ffbd29c..dcf1e8f 100644
--- a/libc/libc.map
+++ b/libc/libc.x86_64.map
@@ -1,52 +1,25 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __assert;
     __assert2;
-    __atomic_cmpxchg; # arm
-    __atomic_dec; # arm
-    __atomic_inc; # arm
-    __atomic_swap; # arm
     __b64_ntop;
     __b64_pton;
-    __brk; # arm x86 mips
-    __cmpdf2; # arm
     __cmsg_nxthdr;
-    __connect; # arm x86 mips
     __ctype_get_mb_cur_max;
     __cxa_atexit;
     __cxa_finalize;
     __cxa_thread_atexit_impl;
-    __divdf3; # arm
-    __divdi3; # arm x86 mips
-    __divsf3; # arm
-    __divsi3; # arm
     __dn_comp;
     __dn_count_labels;
     __dn_skipname;
-    __epoll_pwait; # arm x86 mips
-    __eqdf2; # arm
     __errno;
-    __exit; # arm x86 mips
-    __extendsfdf2; # arm
-    __fadvise64; # x86 mips
     __fbufsize;
-    __fcntl64; # arm x86 mips
     __FD_CLR_chk;
     __FD_ISSET_chk;
     __FD_SET_chk;
     __fgets_chk;
-    __fixdfsi; # arm
-    __fixsfsi; # arm
-    __fixunssfsi; # arm
     __flbf;
-    __floatdidf; # arm
-    __floatdisf; # arm
-    __floatsidf; # arm
-    __floatsisf; # arm
-    __floatundidf; # arm
-    __floatundisf; # arm
-    __floatunsidf; # arm
-    __floatunsisf; # arm
     __fp_nquery;
     __fp_query;
     __fpclassify;
@@ -57,26 +30,11 @@
     __fpurge;
     __freadable;
     __fsetlocking;
-    __fstatfs64; # arm x86 mips
-    __futex_wait; # arm x86 mips
-    __futex_wake; # arm x86 mips
     __fwritable;
-    __gedf2; # arm
     __get_h_errno;
-    __get_thread; # arm x86 mips
-    __get_tls; # arm x86 mips
-    __getcpu; # arm x86 mips
-    __getcwd; # arm x86 mips
-    __getdents64; # arm x86 mips
-    __getpid; # arm x86 mips
-    __getpriority; # arm x86 mips
     __gnu_basename;
-    __gnu_ldivmod_helper; # arm
     __gnu_strerror_r;
-    __gnu_uldivmod_helper; # arm
-    __gtdf2; # arm
     __hostalias;
-    __ioctl; # arm x86 mips
     __isfinite;
     __isfinitef;
     __isfinitel;
@@ -90,51 +48,17 @@
     __isnormalf;
     __isnormall;
     __isthreaded;
-    __ledf2; # arm
     __libc_current_sigrtmax;
     __libc_current_sigrtmin;
     __libc_init;
-    __llseek; # arm x86 mips
     __loc_aton;
     __loc_ntoa;
-    __lshrdi3; # arm
-    __ltdf2; # arm
     __memchr_chk;
     __memcpy_chk;
     __memmove_chk;
     __memrchr_chk;
     __memset_chk;
-    __mmap2; # arm x86 mips
-    __moddi3; # x86 mips
-    __muldf3; # arm
-    __muldi3; # arm
-    __mulsf3; # arm
-    __nedf2; # arm
-    __ns_format_ttl; # arm x86 mips
-    __ns_get16; # arm x86 mips
-    __ns_get32; # arm x86 mips
-    __ns_initparse; # arm x86 mips
-    __ns_makecanon; # arm x86 mips
-    __ns_msg_getflag; # arm x86 mips
-    __ns_name_compress; # arm x86 mips
-    __ns_name_ntol; # arm x86 mips
-    __ns_name_ntop; # arm x86 mips
-    __ns_name_pack; # arm x86 mips
-    __ns_name_pton; # arm x86 mips
-    __ns_name_rollback; # arm x86 mips
-    __ns_name_skip; # arm x86 mips
-    __ns_name_uncompress; # arm x86 mips
-    __ns_name_unpack; # arm x86 mips
-    __ns_parserr; # arm x86 mips
-    __ns_put16; # arm x86 mips
-    __ns_put32; # arm x86 mips
-    __ns_samename; # arm x86 mips
-    __ns_skiprr; # arm x86 mips
-    __ns_sprintrr; # arm x86 mips
-    __ns_sprintrrf; # arm x86 mips
-    __open; # arm x86 mips
     __open_2;
-    __openat; # arm x86 mips
     __openat_2;
     __p_cdname;
     __p_cdnname;
@@ -149,27 +73,18 @@
     __p_time;
     __p_type;
     __p_type_syms;
-    __page_shift; # arm x86 mips
-    __page_size; # arm x86 mips
     __poll_chk;
-    __popcount_tab; # arm
-    __popcountsi2; # arm x86 mips
-    __ppoll; # arm x86 mips
     __ppoll_chk;
     __pread64_chk;
     __pread_chk;
     __progname;
-    __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
-    __pthread_gettid; # arm x86 mips
-    __ptrace; # arm x86 mips
     __putlong;
     __putshort;
     __read_chk;
     __readlink_chk;
     __readlinkat_chk;
-    __reboot; # arm x86 mips
     __recvfrom_chk;
     __register_atfork;
     __res_close;
@@ -192,41 +107,14 @@
     __res_send;
     __res_send_setqhook;
     __res_send_setrhook;
-    __restore_core_regs; # arm
-    __rt_sigaction; # arm x86 mips
-    __rt_sigpending; # arm x86 mips
-    __rt_sigprocmask; # arm x86 mips
-    __rt_sigsuspend; # arm x86 mips
-    __rt_sigtimedwait; # arm x86 mips
     __sched_cpualloc;
     __sched_cpucount;
     __sched_cpufree;
-    __sched_getaffinity; # arm x86 mips
-    __sclose; # arm x86 mips
-    __sdidinit; # arm x86 mips
-    __set_errno; # arm x86 mips
-    __set_thread_area; # x86
-    __set_tid_address; # arm x86 mips
-    __set_tls; # arm mips
     __sF;
-    __sflags; # arm x86 mips
-    __sflush; # arm x86 mips
-    __sfp; # arm x86 mips
-    __sglue; # arm x86 mips
-    __sigaction; # arm x86 mips
-    __signalfd4; # arm x86 mips
-    __sinit; # arm x86 mips
-    __smakebuf; # arm x86 mips
     __snprintf_chk;
-    __socket; # arm x86 mips
     __sprintf_chk;
-    __sread; # arm x86 mips
-    __srefill; # arm x86 mips
-    __srget; # arm x86 mips
-    __sseek; # arm x86 mips
     __stack_chk_fail;
     __stack_chk_guard;
-    __statfs64; # arm x86 mips
     __stpcpy_chk;
     __stpncpy_chk;
     __stpncpy_chk2;
@@ -240,51 +128,16 @@
     __strncpy_chk;
     __strncpy_chk2;
     __strrchr_chk;
-    __subdf3; # arm
-    __subsf3; # arm
-    __swbuf; # arm x86 mips
-    __swrite; # arm x86 mips
-    __swsetup; # arm x86 mips
     __sym_ntop;
     __sym_ntos;
     __sym_ston;
-    __system_properties_init;
-    __system_property_add;
-    __system_property_area__;
-    __system_property_area_init;
-    __system_property_area_serial;
-    __system_property_find;
-    __system_property_find_nth;
-    __system_property_foreach;
-    __system_property_get;
-    __system_property_read;
-    __system_property_serial;
-    __system_property_set;
-    __system_property_set_filename;
-    __system_property_update;
-    __system_property_wait_any;
-    __timer_create; # arm x86 mips
-    __timer_delete; # arm x86 mips
-    __timer_getoverrun; # arm x86 mips
-    __timer_gettime; # arm x86 mips
-    __timer_settime; # arm x86 mips
-    __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
-    __udivsi3; # arm
     __umask_chk;
-    __umoddi3; # x86 mips
-    __unorddf2; # arm
-    __unordsf2; # arm
     __vsnprintf_chk;
     __vsprintf_chk;
-    __wait4; # arm x86 mips
-    __waitid; # arm x86 mips
     _ctype_;
     _Exit;
     _exit;
-    _flush_cache; # mips
     _flushlbf;
-    _fwalk; # arm x86 mips
     _getlong;
     _getshort;
     _longjmp;
@@ -293,9 +146,7 @@
     _resolv_set_nameservers_for_net;
     _setjmp;
     _tolower;
-    _tolower_tab_; # arm x86 mips
     _toupper;
-    _toupper_tab_; # arm x86 mips
     abort;
     abs;
     accept;
@@ -311,13 +162,9 @@
     android_gethostbynamefornet;
     android_set_abort_message;
     arc4random;
-    arc4random_addrandom; # arm x86 mips
     arc4random_buf;
-    arc4random_stir; # arm x86 mips
     arc4random_uniform;
     asctime;
-    asctime64; # arm x86 mips
-    asctime64_r; # arm x86 mips
     asctime_r;
     asprintf;
     at_quick_exit;
@@ -326,18 +173,13 @@
     atol;
     atoll;
     basename;
-    basename_r; # arm x86 mips
-    bcopy; # arm x86 mips
     bind;
     bindresvport;
     brk;
-    bsd_signal; # arm x86 mips
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
-    cacheflush; # arm mips
     calloc;
     capget;
     capset;
@@ -368,8 +210,6 @@
     creat;
     creat64;
     ctime;
-    ctime64; # arm x86 mips
-    ctime64_r; # arm x86 mips
     ctime_r;
     daemon;
     daylight;
@@ -377,7 +217,6 @@
     difftime;
     dirfd;
     dirname;
-    dirname_r; # arm x86 mips
     div;
     dn_expand;
     dprintf;
@@ -387,9 +226,7 @@
     dup3;
     duplocale;
     endmntent;
-    endpwent;
     endservent;
-    endusershell;
     endutent;
     environ;
     epoll_create;
@@ -421,8 +258,6 @@
     execvpe;
     exit;
     faccessat;
-    fake_gmtime_r; # arm x86 mips
-    fake_localtime_r; # arm x86 mips
     fallocate;
     fallocate64;
     fchdir;
@@ -435,7 +270,6 @@
     fdatasync;
     fdopen;
     fdopendir;
-    fdprintf; # arm x86 mips
     feof;
     feof_unlocked;
     ferror;
@@ -467,7 +301,6 @@
     fputws;
     fread;
     free;
-    free_malloc_leak_info;
     freeaddrinfo;
     freelocale;
     fremovexattr;
@@ -488,7 +321,6 @@
     fsync;
     ftell;
     ftello;
-    ftime; # arm x86 mips
     ftok;
     ftruncate;
     ftruncate64;
@@ -509,7 +341,6 @@
     fwscanf;
     gai_strerror;
     get_avphys_pages;
-    get_malloc_leak_info;
     get_nprocs;
     get_nprocs_conf;
     get_phys_pages;
@@ -521,8 +352,6 @@
     getchar_unlocked;
     getcwd;
     getdelim;
-    getdents; # arm x86 mips
-    getdtablesize; # arm x86 mips
     getegid;
     getenv;
     geteuid;
@@ -580,14 +409,11 @@
     gettid;
     gettimeofday;
     getuid;
-    getusershell;
     getutent;
     getwc;
     getwchar;
     getxattr;
     gmtime;
-    gmtime64; # arm x86 mips
-    gmtime64_r; # arm x86 mips
     gmtime_r;
     grantpt;
     herror;
@@ -598,7 +424,6 @@
     if_nametoindex;
     imaxabs;
     imaxdiv;
-    index; # arm x86 mips
     inet_addr;
     inet_aton;
     inet_lnaof;
@@ -651,7 +476,6 @@
     isprint_l;
     ispunct;
     ispunct_l;
-    issetugid; # arm x86 mips
     isspace;
     isspace_l;
     isupper;
@@ -704,8 +528,6 @@
     llistxattr;
     localeconv;
     localtime;
-    localtime64; # arm x86 mips
-    localtime64_r; # arm x86 mips
     localtime_r;
     login_tty;
     longjmp;
@@ -741,7 +563,6 @@
     mempcpy;
     memrchr;
     memset;
-    memswap; # arm x86 mips
     mincore;
     mkdir;
     mkdirat;
@@ -760,8 +581,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -855,7 +674,6 @@
     pthread_attr_getschedpolicy;
     pthread_attr_getscope;
     pthread_attr_getstack;
-    pthread_attr_getstackaddr; # arm x86 mips
     pthread_attr_getstacksize;
     pthread_attr_init;
     pthread_attr_setdetachstate;
@@ -864,17 +682,12 @@
     pthread_attr_setschedpolicy;
     pthread_attr_setscope;
     pthread_attr_setstack;
-    pthread_attr_setstackaddr; # arm x86 mips
     pthread_attr_setstacksize;
     pthread_cond_broadcast;
     pthread_cond_destroy;
     pthread_cond_init;
     pthread_cond_signal;
     pthread_cond_timedwait;
-    pthread_cond_timedwait_monotonic; # arm x86 mips
-    pthread_cond_timedwait_monotonic_np; # arm x86 mips
-    pthread_cond_timedwait_relative_np; # arm x86 mips
-    pthread_cond_timeout_np; # arm x86 mips
     pthread_cond_wait;
     pthread_condattr_destroy;
     pthread_condattr_getclock;
@@ -898,7 +711,6 @@
     pthread_mutex_destroy;
     pthread_mutex_init;
     pthread_mutex_lock;
-    pthread_mutex_lock_timeout_np; # arm x86 mips
     pthread_mutex_timedlock;
     pthread_mutex_trylock;
     pthread_mutex_unlock;
@@ -939,10 +751,8 @@
     putenv;
     puts;
     pututline;
-    putw; # arm x86 mips
     putwc;
     putwchar;
-    pvalloc; # arm x86 mips
     pwrite;
     pwrite64;
     qsort;
@@ -980,7 +790,6 @@
     res_mkquery;
     res_query;
     res_search;
-    restore_core_regs; # arm
     rewind;
     rewinddir;
     rmdir;
@@ -1051,7 +860,6 @@
     setstate;
     settimeofday;
     setuid;
-    setusershell;
     setutent;
     setvbuf;
     setxattr;
@@ -1124,8 +932,6 @@
     strncpy;
     strndup;
     strnlen;
-    strntoimax; # arm x86 mips
-    strntoumax; # arm x86 mips
     strpbrk;
     strptime;
     strrchr;
@@ -1144,7 +950,6 @@
     strtoll;
     strtoll_l;
     strtoq;
-    strtotimeval; # arm x86 mips
     strtoul;
     strtoull;
     strtoull_l;
@@ -1166,7 +971,6 @@
     sysinfo;
     syslog;
     system;
-    sysv_signal; # arm x86 mips
     tcdrain;
     tcflow;
     tcflush;
@@ -1185,9 +989,7 @@
     tgkill;
     time;
     timegm;
-    timegm64; # arm x86 mips
     timelocal;
-    timelocal64; # arm x86 mips
     timer_create;
     timer_delete;
     timer_getoverrun;
@@ -1198,7 +1000,6 @@
     timerfd_settime;
     times;
     timezone;
-    tkill; # arm x86 mips
     tmpfile;
     tmpnam;
     toascii;
@@ -1235,12 +1036,10 @@
     utimensat;
     utimes;
     utmpname;
-    valloc; # arm x86 mips
     vasprintf;
     vdprintf;
     verr;
     verrx;
-    vfdprintf; # arm x86 mips
     vfork;
     vfprintf;
     vfscanf;
@@ -1260,7 +1059,6 @@
     vwprintf;
     vwscanf;
     wait;
-    wait3; # arm x86 mips
     wait4;
     waitid;
     waitpid;
@@ -1309,7 +1107,6 @@
     wcstoull;
     wcstoull_l;
     wcstoumax;
-    wcswcs; # arm x86 mips
     wcswidth;
     wcsxfrm;
     wcsxfrm_l;
@@ -1334,129 +1131,56 @@
 
 LIBC_N {
   global:
+    __fread_chk;
+    __fwrite_chk;
+    __getcwd_chk;
+    __pwrite_chk;
+    __pwrite64_chk;
+    __write_chk;
+    fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
+    preadv;
+    preadv64;
+    pthread_barrierattr_destroy;
+    pthread_barrierattr_getpshared;
+    pthread_barrierattr_init;
+    pthread_barrierattr_setpshared;
+    pthread_barrier_destroy;
+    pthread_barrier_init;
+    pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
+    pwritev;
+    pwritev64;
+    scandirat;
+    scandirat64;
+    strchrnul;
 } LIBC;
 
 LIBC_PRIVATE {
   global:
-    ___Unwind_Backtrace; # arm
-    ___Unwind_ForcedUnwind; # arm
-    ___Unwind_RaiseException; # arm
-    ___Unwind_Resume; # arm
-    ___Unwind_Resume_or_Rethrow; # arm
-    __accept4; # arm x86 mips
-    __adddf3; # arm
-    __addsf3; # arm
-    __aeabi_atexit; # arm
-    __aeabi_cdcmpeq; # arm
-    __aeabi_cdcmple; # arm
-    __aeabi_cdrcmple; # arm
-    __aeabi_d2f; # arm
-    __aeabi_d2iz; # arm
-    __aeabi_dadd; # arm
-    __aeabi_dcmpeq; # arm
-    __aeabi_dcmpge; # arm
-    __aeabi_dcmpgt; # arm
-    __aeabi_dcmple; # arm
-    __aeabi_dcmplt; # arm
-    __aeabi_dcmpun; # arm
-    __aeabi_ddiv; # arm
-    __aeabi_dmul; # arm
-    __aeabi_drsub; # arm
-    __aeabi_dsub; # arm
-    __aeabi_f2d; # arm
-    __aeabi_f2iz; # arm
-    __aeabi_f2uiz; # arm
-    __aeabi_fadd; # arm
-    __aeabi_fcmpun; # arm
-    __aeabi_fdiv; # arm
-    __aeabi_fmul; # arm
-    __aeabi_frsub; # arm
-    __aeabi_fsub; # arm
-    __aeabi_i2d; # arm
-    __aeabi_i2f; # arm
-    __aeabi_idiv; # arm
-    __aeabi_idiv0; # arm
-    __aeabi_idivmod; # arm
-    __aeabi_l2d; # arm
-    __aeabi_l2f; # arm
-    __aeabi_lasr; # arm
-    __aeabi_ldiv0; # arm
-    __aeabi_ldivmod; # arm
-    __aeabi_llsl; # arm
-    __aeabi_llsr; # arm
-    __aeabi_lmul; # arm
-    __aeabi_memclr; # arm
-    __aeabi_memclr4; # arm
-    __aeabi_memclr8; # arm
-    __aeabi_memcpy; # arm
-    __aeabi_memcpy4; # arm
-    __aeabi_memcpy8; # arm
-    __aeabi_memmove; # arm
-    __aeabi_memmove4; # arm
-    __aeabi_memmove8; # arm
-    __aeabi_memset; # arm
-    __aeabi_memset4; # arm
-    __aeabi_memset8; # arm
-    __aeabi_ui2d; # arm
-    __aeabi_ui2f; # arm
-    __aeabi_uidiv; # arm
-    __aeabi_uidivmod; # arm
-    __aeabi_ul2d; # arm
-    __aeabi_ul2f; # arm
-    __aeabi_uldivmod; # arm
-    __aeabi_unwind_cpp_pr0; # arm
-    __aeabi_unwind_cpp_pr1; # arm
-    __aeabi_unwind_cpp_pr2; # arm
-    __arm_fadvise64_64; # arm
-    __ashldi3; # arm
-    __ashrdi3; # arm
-    __bionic_brk; # arm x86 mips
-    __bionic_libgcc_compat_symbols; # arm x86
-    __bionic_libgcc_unwind_symbols; # arm
-    __dso_handle; # arm
-    __gnu_Unwind_Backtrace; # arm
-    __gnu_unwind_execute; # arm
-    __gnu_Unwind_Find_exidx; # arm
-    __gnu_Unwind_ForcedUnwind; # arm
-    __gnu_unwind_frame; # arm
-    __gnu_Unwind_RaiseException; # arm
-    __gnu_Unwind_Restore_VFP; # arm
-    __gnu_Unwind_Restore_VFP_D; # arm
-    __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Restore_WMMXC; # arm
-    __gnu_Unwind_Restore_WMMXD; # arm
-    __gnu_Unwind_Resume; # arm
-    __gnu_Unwind_Resume_or_Rethrow; # arm
-    __gnu_Unwind_Save_VFP; # arm
-    __gnu_Unwind_Save_VFP_D; # arm
-    __gnu_Unwind_Save_VFP_D_16_to_31; # arm
-    __gnu_Unwind_Save_WMMXC; # arm
-    __gnu_Unwind_Save_WMMXD; # arm
-    _Unwind_Backtrace; # arm
-    _Unwind_Complete; # arm
-    _Unwind_DeleteException; # arm
-    _Unwind_ForcedUnwind; # arm
-    _Unwind_GetCFA; # arm
-    _Unwind_GetDataRelBase; # arm
-    _Unwind_GetLanguageSpecificData; # arm
-    _Unwind_GetRegionStart; # arm
-    _Unwind_GetTextRelBase; # arm
-    _Unwind_RaiseException; # arm
-    _Unwind_Resume; # arm
-    _Unwind_Resume_or_Rethrow; # arm
-    _Unwind_VRS_Get; # arm
-    _Unwind_VRS_Pop; # arm
-    _Unwind_VRS_Set; # arm
-    atexit; # arm
-    dlmalloc; # arm x86 mips
-    dlmalloc_inspect_all;
-    dlmalloc_trim;
-    dlmalloc_usable_size; # arm x86 mips
+    __system_properties_init; # arm64 x86_64 mips64
+    __system_property_add; # arm64 x86_64 mips64
+    __system_property_area__; # arm64 x86_64 mips64
+    __system_property_area_init; # arm64 x86_64 mips64
+    __system_property_area_serial; # arm64 x86_64 mips64
+    __system_property_find; # arm64 x86_64 mips64
+    __system_property_find_nth; # arm64 x86_64 mips64
+    __system_property_foreach; # arm64 x86_64 mips64
+    __system_property_get; # arm64 x86_64 mips64
+    __system_property_read; # arm64 x86_64 mips64
+    __system_property_serial; # arm64 x86_64 mips64
+    __system_property_set; # arm64 x86_64 mips64
+    __system_property_set_filename; # arm64 x86_64 mips64
+    __system_property_update; # arm64 x86_64 mips64
+    __system_property_wait_any; # arm64 x86_64 mips64
+    free_malloc_leak_info;
+    get_malloc_leak_info;
     gMallocLeakZygoteChild;
-    SHA1Final; # arm x86 mips
-    SHA1Init; # arm x86 mips
-    SHA1Transform; # arm x86 mips
-    SHA1Update; # arm x86 mips
 } LIBC_N;
diff --git a/libc/private/KernelArgumentBlock.h b/libc/private/KernelArgumentBlock.h
index c8ea497..68d4999 100644
--- a/libc/private/KernelArgumentBlock.h
+++ b/libc/private/KernelArgumentBlock.h
@@ -38,32 +38,25 @@
     argv = reinterpret_cast<char**>(args + 1);
     envp = argv + argc + 1;
 
-    // Skip over all environment variable definitions to find aux vector.
-    // The end of the environment block is marked by two NULL pointers.
+    // Skip over all environment variable definitions to find the aux vector.
+    // The end of the environment block is marked by a NULL pointer.
     char** p = envp;
     while (*p != NULL) {
       ++p;
     }
-    ++p; // Skip second NULL;
+    ++p; // Skip the NULL itself.
 
     auxv = reinterpret_cast<ElfW(auxv_t)*>(p);
   }
 
   // Similar to ::getauxval but doesn't require the libc global variables to be set up,
-  // so it's safe to call this really early on. This function also lets you distinguish
-  // between the inability to find the given type and its value just happening to be 0.
-  unsigned long getauxval(unsigned long type, bool* found_match = NULL) {
+  // so it's safe to call this really early on.
+  unsigned long getauxval(unsigned long type) {
     for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) {
       if (v->a_type == type) {
-        if (found_match != NULL) {
-            *found_match = true;
-        }
         return v->a_un.a_val;
       }
     }
-    if (found_match != NULL) {
-      *found_match = false;
-    }
     return 0;
   }
 
diff --git a/libc/private/ScopedPthreadMutexLocker.h b/libc/private/ScopedPthreadMutexLocker.h
index 43dbdc1..58462e3 100644
--- a/libc/private/ScopedPthreadMutexLocker.h
+++ b/libc/private/ScopedPthreadMutexLocker.h
@@ -34,7 +34,7 @@
  private:
   pthread_mutex_t* mu_;
 
-  DISALLOW_COPY_AND_ASSIGN(ScopedPthreadMutexLocker);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPthreadMutexLocker);
 };
 
 #endif // SCOPED_PTHREAD_MUTEX_LOCKER_H
diff --git a/libc/private/ScopedReaddir.h b/libc/private/ScopedReaddir.h
index 84c1b93..3d77a40 100644
--- a/libc/private/ScopedReaddir.h
+++ b/libc/private/ScopedReaddir.h
@@ -23,8 +23,11 @@
 
 class ScopedReaddir {
  public:
-  ScopedReaddir(const char* path) {
-    dir_ = opendir(path);
+  ScopedReaddir(const char* path) : ScopedReaddir(opendir(path)) {
+  }
+
+  ScopedReaddir(DIR* dir) {
+    dir_ = dir;
   }
 
   ~ScopedReaddir() {
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
new file mode 100644
index 0000000..1133e2a
--- /dev/null
+++ b/libc/private/WriteProtected.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef _PRIVATE_WRITEPROTECTED_H
+#define _PRIVATE_WRITEPROTECTED_H
+
+#include <errno.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+
+#include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
+#include "private/libc_logging.h"
+
+template <typename T>
+union WriteProtectedContents {
+  T value;
+  char padding[PAGE_SIZE];
+
+  WriteProtectedContents() = default;
+  DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
+} __attribute__((aligned(PAGE_SIZE)));
+
+// Write protected wrapper class that aligns its contents to a page boundary,
+// and sets the memory protection to be non-writable, except when being modified
+// explicitly.
+template <typename T>
+class WriteProtected {
+  static_assert(sizeof(T) < PAGE_SIZE,
+                "WriteProtected only supports contents up to PAGE_SIZE");
+  static_assert(__is_pod(T), "WriteProtected only supports POD contents");
+
+  WriteProtectedContents<T> contents;
+
+ public:
+  WriteProtected() = default;
+  DISALLOW_COPY_AND_ASSIGN(WriteProtected);
+
+  void initialize() {
+    // Not strictly necessary, but this will hopefully segfault if we initialize
+    // multiple times by accident.
+    memset(&contents, 0, sizeof(contents));
+
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
+      __libc_fatal("failed to make WriteProtected nonwritable in initialize");
+    }
+  }
+
+  const T* operator->() {
+    return &contents.value;
+  }
+
+  const T& operator*() {
+    return contents.value;
+  }
+
+  template <typename Mutator>
+  void mutate(Mutator mutator) {
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+      __libc_fatal("failed to make WriteProtected writable in mutate: %s",
+                   strerror(errno));
+    }
+    mutator(&contents.value);
+    if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
+      __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s",
+                   strerror(errno));
+    }
+  }
+};
+
+#endif
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 5fca222..e2084d4 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -38,25 +38,36 @@
 
 #include <machine/asm.h>
 
-#define ENTRY(f) \
+#define ENTRY_NO_DWARF(f) \
     .text; \
     .globl f; \
     .align __bionic_asm_align; \
     .type f, __bionic_asm_function_type; \
     f: \
     __bionic_asm_custom_entry(f); \
+
+#define ENTRY(f) \
+    ENTRY_NO_DWARF(f) \
     .cfi_startproc \
 
+#define END_NO_DWARF(f) \
+    .size f, .-f; \
+    __bionic_asm_custom_end(f) \
+
 #define END(f) \
     .cfi_endproc; \
-    .size f, .-f; \
-    __bionic_asm_custom_end(f) \
+    END_NO_DWARF(f) \
 
 /* Like ENTRY, but with hidden visibility. */
 #define ENTRY_PRIVATE(f) \
     ENTRY(f); \
     .hidden f \
 
+/* Like ENTRY_NO_DWARF, but with hidden visibility. */
+#define ENTRY_PRIVATE_NO_DWARF(f) \
+    ENTRY_NO_DWARF(f); \
+    .hidden f \
+
 #define ALIAS_SYMBOL(alias, original) \
     .globl alias; \
     .equ alias, original
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 401577a..946d9dd 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -40,10 +40,12 @@
 
 struct timespec;
 
-static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) {
+static inline __always_inline int __futex(volatile void* ftx, int op, int value,
+                                          const struct timespec* timeout,
+                                          int bitset) {
   // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
   int saved_errno = errno;
-  int result = syscall(__NR_futex, ftx, op, value, timeout);
+  int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
   if (__predict_false(result == -1)) {
     result = -errno;
     errno = saved_errno;
@@ -52,19 +54,22 @@
 }
 
 static inline int __futex_wake(volatile void* ftx, int count) {
-  return __futex(ftx, FUTEX_WAKE, count, NULL);
+  return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
 }
 
 static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
-  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL);
+  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
 }
 
 static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
-  return __futex(ftx, FUTEX_WAIT, value, timeout);
+  return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
 }
 
-static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) {
-  return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout);
+static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
+                                  bool use_realtime_clock, const struct timespec* abs_timeout) {
+  return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
+                 (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
+                 FUTEX_BITSET_MATCH_ANY);
 }
 
 __END_DECLS
diff --git a/libc/private/bionic_time.h b/libc/private/bionic_globals.h
similarity index 63%
copy from libc/private/bionic_time.h
copy to libc/private/bionic_globals.h
index 030dcfd..a671d77 100644
--- a/libc/private/bionic_time.h
+++ b/libc/private/bionic_globals.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,26 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _BIONIC_TIME_H
-#define _BIONIC_TIME_H
+#ifndef _PRIVATE_BIONIC_GLOBALS_H
+#define _PRIVATE_BIONIC_GLOBALS_H
 
-#include <time.h>
 #include <sys/cdefs.h>
+#include "private/bionic_malloc_dispatch.h"
+#include "private/bionic_vdso.h"
+#include "private/WriteProtected.h"
 
-__BEGIN_DECLS
+struct libc_globals {
+  vdso_entry vdso[VDSO_END];
+  long setjmp_cookie;
+  MallocDebug malloc_dispatch;
+};
 
-// We can't remove this (and this file) until we fix MtpUtils.cpp.
-time_t mktime_tz(struct tm* const, char const*);
+__LIBC_HIDDEN__ extern WriteProtected<libc_globals> __libc_globals;
 
-__END_DECLS
-
-#endif /* _BIONIC_TIME_H */
+class KernelArgumentBlock;
+__LIBC_HIDDEN__ void __libc_init_vdso(libc_globals* globals,
+                                      KernelArgumentBlock& args);
+__LIBC_HIDDEN__ void __libc_init_setjmp_cookie(libc_globals* globals,
+                                               KernelArgumentBlock& args);
+__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals);
+#endif
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index 6a0fd06..3dbafe0 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -30,7 +30,10 @@
 
 #include <stdatomic.h>
 #include "private/bionic_futex.h"
+#include "private/bionic_macros.h"
 
+// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
+// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
 class Lock {
  private:
   enum LockState {
@@ -42,15 +45,17 @@
   bool process_shared;
 
  public:
-  Lock(bool process_shared = false) {
-    init(process_shared);
-  }
-
   void init(bool process_shared) {
     atomic_init(&state, Unlocked);
     this->process_shared = process_shared;
   }
 
+  bool trylock() {
+    LockState old_state = Unlocked;
+    return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
+                        LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
+  }
+
   void lock() {
     LockState old_state = Unlocked;
     if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
@@ -59,7 +64,7 @@
     }
     while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
       // TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
-      __futex_wait_ex(&state, process_shared, LockedWithWaiter, NULL);
+      __futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
     }
     return;
   }
diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h
index 4f3cf89..4969bd9 100644
--- a/libc/private/bionic_macros.h
+++ b/libc/private/bionic_macros.h
@@ -42,8 +42,8 @@
   (((value) + (alignment) - 1) & ~((alignment) - 1))
 
 #define BIONIC_ROUND_UP_POWER_OF_2(value) \
-  (sizeof(value) == 8) \
+  ((sizeof(value) == 8) \
     ? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
-    : (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value))))
+    : (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
 
 #endif // _BIONIC_MACROS_H_
diff --git a/libc/private/bionic_malloc_dispatch.h b/libc/private/bionic_malloc_dispatch.h
new file mode 100644
index 0000000..34fb898
--- /dev/null
+++ b/libc/private/bionic_malloc_dispatch.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef _PRIVATE_BIONIC_MALLOC_DISPATCH_H
+#define _PRIVATE_BIONIC_MALLOC_DISPATCH_H
+
+#include <stddef.h>
+#include "private/bionic_config.h"
+
+/* Entry in malloc dispatch table. */
+typedef void* (*MallocDebugCalloc)(size_t, size_t);
+typedef void (*MallocDebugFree)(void*);
+typedef struct mallinfo (*MallocDebugMallinfo)();
+typedef void* (*MallocDebugMalloc)(size_t);
+typedef size_t (*MallocDebugMallocUsableSize)(const void*);
+typedef void* (*MallocDebugMemalign)(size_t, size_t);
+typedef int (*MallocDebugPosixMemalign)(void**, size_t, size_t);
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+typedef void* (*MallocDebugPvalloc)(size_t);
+#endif
+typedef void* (*MallocDebugRealloc)(void*, size_t);
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+typedef void* (*MallocDebugValloc)(size_t);
+#endif
+
+struct MallocDebug {
+  MallocDebugCalloc calloc;
+  MallocDebugFree free;
+  MallocDebugMallinfo mallinfo;
+  MallocDebugMalloc malloc;
+  MallocDebugMallocUsableSize malloc_usable_size;
+  MallocDebugMemalign memalign;
+  MallocDebugPosixMemalign posix_memalign;
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+  MallocDebugPvalloc pvalloc;
+#endif
+  MallocDebugRealloc realloc;
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+  MallocDebugValloc valloc;
+#endif
+} __attribute__((aligned(32)));
+
+#endif
diff --git a/libc/private/bionic_page.h b/libc/private/bionic_page.h
new file mode 100644
index 0000000..0beb708
--- /dev/null
+++ b/libc/private/bionic_page.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef _BIONIC_PAGE_H_
+#define _BIONIC_PAGE_H_
+
+// Get PAGE_SIZE and PAGE_MASK.
+#include <sys/user.h>
+
+// Returns the address of the page containing address 'x'.
+#define PAGE_START(x) ((x) & PAGE_MASK)
+
+// Returns the offset of address 'x' in its page.
+#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
+
+// Returns the address of the next page after address 'x', unless 'x' is
+// itself at the start of a page.
+#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1))
+
+#endif // _BIONIC_PAGE_H_
diff --git a/libc/private/bionic_time_conversions.h b/libc/private/bionic_time_conversions.h
index cf0046a..a834843 100644
--- a/libc/private/bionic_time_conversions.h
+++ b/libc/private/bionic_time_conversions.h
@@ -29,9 +29,12 @@
 #ifndef _BIONIC_TIME_CONVERSIONS_H
 #define _BIONIC_TIME_CONVERSIONS_H
 
+#include <errno.h>
 #include <time.h>
 #include <sys/cdefs.h>
 
+#include "private/bionic_constants.h"
+
 __BEGIN_DECLS
 
 __LIBC_HIDDEN__ bool timespec_from_timeval(timespec& ts, const timeval& tv);
@@ -39,8 +42,24 @@
 
 __LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
 
-__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
+__LIBC_HIDDEN__ void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts,
+                                                     clockid_t clock);
 
 __END_DECLS
 
+static inline int check_timespec(const timespec* ts, bool null_allowed) {
+  if (null_allowed && ts == nullptr) {
+    return 0;
+  }
+  // glibc just segfaults if you pass a null timespec.
+  // That seems a lot more likely to catch bad code than returning EINVAL.
+  if (ts->tv_nsec < 0 || ts->tv_nsec >= NS_PER_S) {
+    return EINVAL;
+  }
+  if (ts->tv_sec < 0) {
+    return ETIMEDOUT;
+  }
+  return 0;
+}
+
 #endif
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 30dc0eb..9d3f4c5 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -67,6 +67,13 @@
   TLS_SLOT_STACK_GUARD = 5, // GCC requires this specific slot for x86.
   TLS_SLOT_DLERROR,
 
+  // Fast storage for Thread::Current() in ART.
+  TLS_SLOT_ART_THREAD_SELF,
+
+  // Lets TSAN avoid using pthread_getspecific for finding the current thread
+  // state.
+  TLS_SLOT_TSAN,
+
   BIONIC_TLS_SLOTS // Must come last!
 };
 
@@ -114,7 +121,7 @@
 
 #if defined(__cplusplus)
 class KernelArgumentBlock;
-extern __LIBC_HIDDEN__ void __libc_init_tls(KernelArgumentBlock& args);
+extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock&);
 #endif
 
 #endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
diff --git a/libc/private/bionic_time.h b/libc/private/bionic_vdso.h
similarity index 66%
copy from libc/private/bionic_time.h
copy to libc/private/bionic_vdso.h
index 030dcfd..5400de5 100644
--- a/libc/private/bionic_time.h
+++ b/libc/private/bionic_vdso.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,31 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _BIONIC_TIME_H
-#define _BIONIC_TIME_H
+#ifndef _PRIVATE_BIONIC_VDSO_H
+#define _PRIVATE_BIONIC_VDSO_H
 
 #include <time.h>
-#include <sys/cdefs.h>
 
-__BEGIN_DECLS
+#if defined(__aarch64__)
+#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
+#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
+#elif defined(__x86_64__) || defined(__i386__)
+#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
+#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
+#endif
 
-// We can't remove this (and this file) until we fix MtpUtils.cpp.
-time_t mktime_tz(struct tm* const, char const*);
+extern "C" int __clock_gettime(int, timespec*);
+extern "C" int __gettimeofday(timeval*, struct timezone*);
 
-__END_DECLS
+struct vdso_entry {
+  const char* name;
+  void* fn;
+};
 
-#endif /* _BIONIC_TIME_H */
+enum {
+  VDSO_CLOCK_GETTIME = 0,
+  VDSO_GETTIMEOFDAY,
+  VDSO_END
+};
+
+#endif  // _PRIVATE_BIONIC_VDSO_H
diff --git a/libc/include/sys/shm.h b/libc/private/get_cpu_count_from_string.h
similarity index 69%
copy from libc/include/sys/shm.h
copy to libc/private/get_cpu_count_from_string.h
index c691c29..a0cb95d 100644
--- a/libc/include/sys/shm.h
+++ b/libc/private/get_cpu_count_from_string.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,28 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_SHM_H_
-#define _SYS_SHM_H_
+#include <ctype.h>
+#include <stdlib.h>
 
-#include <linux/shm.h>
-
-#endif /* _SYS_SHM_H_ */
+// Parse a string like: 0, 2-4, 6.
+static int GetCpuCountFromString(const char* s) {
+  int cpu_count = 0;
+  int last_cpu = -1;
+  while (*s != '\0') {
+    if (isdigit(*s)) {
+      int cpu = static_cast<int>(strtol(s, const_cast<char**>(&s), 10));
+      if (last_cpu != -1) {
+        cpu_count += cpu - last_cpu;
+      } else {
+        cpu_count++;
+      }
+      last_cpu = cpu;
+    } else {
+      if (*s == ',') {
+        last_cpu = -1;
+      }
+      s++;
+    }
+  }
+  return cpu_count;
+}
diff --git a/libc/stdio/fileext.h b/libc/stdio/fileext.h
deleted file mode 100644
index 6cacc0f..0000000
--- a/libc/stdio/fileext.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*	$OpenBSD: fileext.h,v 1.2 2005/06/17 20:40:32 espie Exp $	*/
-/* $NetBSD: fileext.h,v 1.5 2003/07/18 21:46:41 nathanw Exp $ */
-
-/*-
- * Copyright (c)2001 Citrus 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Citrus$
- */
-
-#ifndef _FILEEXT_H_
-#define _FILEEXT_H_
-
-#include <pthread.h>
-#include <stdbool.h>
-
-__BEGIN_DECLS
-
-/*
- * file extension
- */
-struct __sfileext {
-	struct	__sbuf _ub;		/* ungetc buffer */
-	struct wchar_io_data _wcio;	/* wide char io status */
-	pthread_mutex_t _lock;		/* file lock */
-	bool _stdio_handles_locking;	/* __fsetlocking support */
-};
-
-#if defined(__cplusplus)
-#define _EXT(fp) reinterpret_cast<__sfileext*>((fp)->_ext._base)
-#else
-#define _EXT(fp) ((struct __sfileext *)((fp)->_ext._base))
-#endif
-
-#define _UB(fp) _EXT(fp)->_ub
-#define _FLOCK(fp)  _EXT(fp)->_lock
-
-#define _FILEEXT_INIT(fp) \
-do { \
-	_UB(fp)._base = NULL; \
-	_UB(fp)._size = 0; \
-	WCIO_INIT(fp); \
-	pthread_mutexattr_t attr; \
-	pthread_mutexattr_init(&attr); \
-	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
-	pthread_mutex_init(&_FLOCK(fp), &attr); \
-	pthread_mutexattr_destroy(&attr); \
-	_EXT(fp)->_stdio_handles_locking = true; \
-} while (0)
-
-#define _FILEEXT_SETUP(f, fext) \
-do { \
-	(f)->_ext._base = (unsigned char *)(fext); \
-	_FILEEXT_INIT(f); \
-} while (0)
-
-__END_DECLS
-
-#endif /* _FILEEXT_H_ */
diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c
index 5e51198..6e20562 100644
--- a/libc/stdio/findfp.c
+++ b/libc/stdio/findfp.c
@@ -44,31 +44,43 @@
 #define ALIGNBYTES (sizeof(uintptr_t) - 1)
 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
 
-int	__sdidinit;
-
 #define	NDYNAMIC 10		/* add ten more whenever necessary */
 
 #define	std(flags, file) \
 	{0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
 	    {(unsigned char *)(__sFext+file), 0},NULL,0,{0},{0},{0,0},0,0}
 
-				/* the usual - (stdin + stdout + stderr) */
-static FILE usual[FOPEN_MAX - 3];
-static struct __sfileext usualext[FOPEN_MAX - 3];
-static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
-static struct glue *lastglue = &uglue;
 _THREAD_PRIVATE_MUTEX(__sfp_mutex);
 
-static struct __sfileext __sFext[3];
-FILE __sF[3] = {
-	std(__SRD, STDIN_FILENO),		/* stdin */
-	std(__SWR, STDOUT_FILENO),		/* stdout */
-	std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */
+// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
+#define SBUF_INIT {0,0}
+#if defined(__LP64__)
+#define MBSTATE_T_INIT {{0},{0}}
+#else
+#define MBSTATE_T_INIT {{0}}
+#endif
+#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
+
+static struct __sfileext __sFext[3] = {
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
 };
+
+// __sF is exported for backwards compatibility. Until M, we didn't have symbols
+// for stdin/stdout/stderr; they were macros accessing __sF.
+FILE __sF[3] = {
+  std(__SRD, STDIN_FILENO),
+  std(__SWR, STDOUT_FILENO),
+  std(__SWR|__SNBF, STDERR_FILENO),
+};
+
 FILE* stdin = &__sF[0];
 FILE* stdout = &__sF[1];
 FILE* stderr = &__sF[2];
-struct glue __sglue = { &uglue, 3, __sF };
+
+struct glue __sglue = { NULL, 3, __sF };
+static struct glue* lastglue = &__sglue;
 
 static struct glue *
 moreglue(int n)
@@ -109,9 +121,6 @@
 	int n;
 	struct glue *g;
 
-	if (!__sdidinit)
-		__sinit();
-
 	_THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
 	for (g = &__sglue; g != NULL; g = g->next) {
 		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
@@ -144,48 +153,7 @@
 	return (fp);
 }
 
-/*
- * exit() and abort() call _cleanup() through the callback registered
- * with __atexit_register_cleanup(), set whenever we open or buffer a
- * file. This chicanery is done so that programs that do not use stdio
- * need not link it all in.
- *
- * The name `_cleanup' is, alas, fairly well known outside stdio.
- */
-void
-_cleanup(void)
-{
+__LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
 	/* (void) _fwalk(fclose); */
 	(void) _fwalk(__sflush);		/* `cheating' */
 }
-
-/*
- * __sinit() is called whenever stdio's internal variables must be set up.
- */
-void
-__sinit(void)
-{
-	_THREAD_PRIVATE_MUTEX(__sinit_mutex);
-
-	_THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex);
-	if (__sdidinit) {
-		/* bail out if caller lost the race */
-		_THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
-		return;
-	}
-
-	/* Initialize stdin/stdout/stderr (for the recursive mutex). http://b/18208568. */
-	for (size_t i = 0; i < 3; ++i) {
-		_FILEEXT_SETUP(__sF+i, __sFext+i);
-	}
-	/* Initialize the pre-allocated (but initially unused) streams. */
-	for (size_t i = 0; i < FOPEN_MAX - 3; ++i) {
-		_FILEEXT_SETUP(usual+i, usualext+i);
-	}
-
-	/* make sure we clean up on exit */
-	__atexit_register_cleanup(_cleanup); /* conservative */
-	__sdidinit = 1;
-
-	_THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
-}
diff --git a/libc/stdio/glue.h b/libc/stdio/glue.h
index a9e5d10..cb1d182 100644
--- a/libc/stdio/glue.h
+++ b/libc/stdio/glue.h
@@ -47,6 +47,6 @@
 };
 
 /* This was referenced by a couple of different pieces of middleware and the Crystax NDK. */
-__LIBC64_HIDDEN__ extern struct glue __sglue;
+__LIBC32_LEGACY_PUBLIC__ extern struct glue __sglue;
 
 __END_DECLS
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index ce04141..6dcd3ae 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -32,48 +32,142 @@
  * SUCH DAMAGE.
  */
 
+#ifndef __BIONIC_STDIO_LOCAL_H__
+#define __BIONIC_STDIO_LOCAL_H__
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <wchar.h>
+#include "wcio.h"
+
 /*
  * Information local to this implementation of stdio,
  * in particular, macros and private variables.
  */
 
-#include <wchar.h>
-#include "wcio.h"
-#include "fileext.h"
-
 __BEGIN_DECLS
 
+struct __sbuf {
+  unsigned char* _base;
+#if defined(__LP64__)
+  size_t _size;
+#else
+  int _size;
+#endif
+};
+
+struct __sFILE {
+	unsigned char *_p;	/* current position in (some) buffer */
+	int	_r;		/* read space left for getc() */
+	int	_w;		/* write space left for putc() */
+#if defined(__LP64__)
+	int	_flags;		/* flags, below; this FILE is free if 0 */
+	int	_file;		/* fileno, if Unix descriptor, else -1 */
+#else
+	short	_flags;		/* flags, below; this FILE is free if 0 */
+	short	_file;		/* fileno, if Unix descriptor, else -1 */
+#endif
+	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
+	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
+
+	/* operations */
+	void	*_cookie;	/* cookie passed to io functions */
+	int	(*_close)(void *);
+	int	(*_read)(void *, char *, int);
+	fpos_t	(*_seek)(void *, fpos_t, int);
+	int	(*_write)(void *, const char *, int);
+
+	/* extension data, to avoid further ABI breakage */
+	struct	__sbuf _ext;
+	/* data for long sequences of ungetc() */
+	unsigned char *_up;	/* saved _p when _p is doing ungetc data */
+	int	_ur;		/* saved _r when _r is counting ungetc data */
+
+	/* tricks to meet minimum requirements even when malloc() fails */
+	unsigned char _ubuf[3];	/* guarantee an ungetc() buffer */
+	unsigned char _nbuf[1];	/* guarantee a getc() buffer */
+
+	/* separate buffer for fgetln() when line crosses buffer boundary */
+	struct	__sbuf _lb;	/* buffer for fgetln() */
+
+	/* Unix stdio files get aligned to block boundaries on fseek() */
+	int	_blksize;	/* stat.st_blksize (may be != _bf._size) */
+	fpos_t	_offset;	/* current lseek offset */
+};
+
+/*
+ * file extension
+ */
+struct __sfileext {
+  /* ungetc buffer */
+  struct __sbuf _ub;
+
+  /* wide char io status */
+  struct wchar_io_data _wcio;
+
+  /* file lock */
+  pthread_mutex_t _lock;
+
+  /* __fsetlocking support */
+  bool _caller_handles_locking;
+};
+
+#if defined(__cplusplus)
+#define _EXT(fp) reinterpret_cast<__sfileext*>((fp)->_ext._base)
+#else
+#define _EXT(fp) ((struct __sfileext *)((fp)->_ext._base))
+#endif
+
+#define _UB(fp) _EXT(fp)->_ub
+#define _FLOCK(fp)  _EXT(fp)->_lock
+
+#define _FILEEXT_INIT(fp) \
+do { \
+	_UB(fp)._base = NULL; \
+	_UB(fp)._size = 0; \
+	WCIO_INIT(fp); \
+	pthread_mutexattr_t attr; \
+	pthread_mutexattr_init(&attr); \
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+	pthread_mutex_init(&_FLOCK(fp), &attr); \
+	pthread_mutexattr_destroy(&attr); \
+	_EXT(fp)->_caller_handles_locking = false; \
+} while (0)
+
+#define _FILEEXT_SETUP(f, fext) \
+do { \
+	(f)->_ext._base = (unsigned char *)(fext); \
+	_FILEEXT_INIT(f); \
+} while (0)
+
 /*
  * Android <= KitKat had getc/putc macros in <stdio.h> that referred
  * to __srget/__swbuf, so those symbols need to be public for LP32
  * but can be hidden for LP64.
  */
-__LIBC64_HIDDEN__ int __srget(FILE*);
-__LIBC64_HIDDEN__ int __swbuf(int, FILE*);
-__LIBC64_HIDDEN__ int __srefill(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __srget(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __swbuf(int, FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __srefill(FILE*);
 
 /* This was referenced by the apportable middleware for LP32. */
-__LIBC64_HIDDEN__ int __swsetup(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __swsetup(FILE*);
 
 /* These were referenced by a couple of different pieces of middleware and the Crystax NDK. */
-__LIBC64_HIDDEN__ extern int __sdidinit;
-__LIBC64_HIDDEN__ int __sflags(const char*, int*);
-__LIBC64_HIDDEN__ FILE* __sfp(void);
-__LIBC64_HIDDEN__ void __sinit(void);
-__LIBC64_HIDDEN__ void __smakebuf(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __sflags(const char*, int*);
+__LIBC32_LEGACY_PUBLIC__ FILE* __sfp(void);
+__LIBC32_LEGACY_PUBLIC__ void __smakebuf(FILE*);
 
 /* These are referenced by the Greed for Glory franchise. */
-__LIBC64_HIDDEN__ int __sflush(FILE *);
-__LIBC64_HIDDEN__ int __sread(void *, char *, int);
-__LIBC64_HIDDEN__ int __swrite(void *, const char *, int);
-__LIBC64_HIDDEN__ fpos_t __sseek(void *, fpos_t, int);
-__LIBC64_HIDDEN__ int __sclose(void *);
-__LIBC64_HIDDEN__ int _fwalk(int (*)(FILE *));
+__LIBC32_LEGACY_PUBLIC__ int __sflush(FILE *);
+__LIBC32_LEGACY_PUBLIC__ int __sread(void *, char *, int);
+__LIBC32_LEGACY_PUBLIC__ int __swrite(void *, const char *, int);
+__LIBC32_LEGACY_PUBLIC__ fpos_t __sseek(void *, fpos_t, int);
+__LIBC32_LEGACY_PUBLIC__ int __sclose(void *);
+__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE *));
 
 #pragma GCC visibility push(hidden)
 
 int	__sflush_locked(FILE *);
-void	_cleanup(void);
 int	__swhatbuf(FILE *, size_t *, int *);
 wint_t __fgetwc_unlock(FILE *);
 wint_t	__ungetwc(wint_t, FILE *);
@@ -82,8 +176,6 @@
 int	__vfwprintf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 int	__vfwscanf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 
-extern void __atexit_register_cleanup(void (*)(void));
-
 /*
  * Return true if the given FILE cannot be written now.
  */
@@ -111,8 +203,8 @@
 	(fp)->_lb._base = NULL; \
 }
 
-#define FLOCKFILE(fp)   if (_EXT(fp)->_stdio_handles_locking) flockfile(fp)
-#define FUNLOCKFILE(fp) if (_EXT(fp)->_stdio_handles_locking) funlockfile(fp)
+#define FLOCKFILE(fp)   if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
+#define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
 
 #define FLOATING_POINT
 #define PRINTF_WIDE_CHAR
@@ -140,6 +232,12 @@
 extern int __sfvwrite(FILE *, struct __suio *);
 wint_t __fputwc_unlock(wchar_t wc, FILE *fp);
 
+/* Remove the if (!__sdidinit) __sinit() idiom from untouched upstream stdio code. */
+extern void __sinit(void); // Not actually implemented.
+#define __sdidinit 1
+
 #pragma GCC visibility pop
 
 __END_DECLS
+
+#endif
diff --git a/libc/upstream-openbsd/lib/libc/stdio/refill.c b/libc/stdio/refill.c
similarity index 97%
rename from libc/upstream-openbsd/lib/libc/stdio/refill.c
rename to libc/stdio/refill.c
index 165c72a..5b0811f 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/refill.c
+++ b/libc/stdio/refill.c
@@ -51,16 +51,13 @@
 int
 __srefill(FILE *fp)
 {
-
-	/* make sure stdio is set up */
-	if (!__sdidinit)
-		__sinit();
-
 	fp->_r = 0;		/* largely a convenience for callers */
 
+#if !defined(__ANDROID__)
 	/* SysV does not make this test; take it out for compatibility */
 	if (fp->_flags & __SEOF)
 		return (EOF);
+#endif
 
 	/* if not already reading, have to be reading and writing */
 	if ((fp->_flags & __SRD) == 0) {
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index fea44f6..f273d45 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -74,7 +74,7 @@
 }
 
 int __fsetlocking(FILE* fp, int type) {
-  int old_state = _EXT(fp)->_stdio_handles_locking ? FSETLOCKING_INTERNAL : FSETLOCKING_BYCALLER;
+  int old_state = _EXT(fp)->_caller_handles_locking ? FSETLOCKING_BYCALLER : FSETLOCKING_INTERNAL;
   if (type == FSETLOCKING_QUERY) {
     return old_state;
   }
@@ -84,7 +84,7 @@
     __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
   }
 
-  _EXT(fp)->_stdio_handles_locking = (type == FSETLOCKING_INTERNAL);
+  _EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
   return old_state;
 }
 
@@ -99,3 +99,7 @@
 int ferror_unlocked(FILE* fp) {
   return __sferror(fp);
 }
+
+int fileno_unlocked(FILE* fp) {
+  return __sfileno(fp);
+}
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index a6970dd..c817b63 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -37,6 +37,10 @@
 #include "atexit.h"
 #include "private/thread_private.h"
 
+/* BEGIN android-changed */
+#include "private/bionic_prctl.h"
+/* END android-changed */
+
 struct atexit {
 	struct atexit *next;		/* next in list */
 	int ind;			/* next index in this table */
@@ -95,6 +99,10 @@
 		    MAP_ANON | MAP_PRIVATE, -1, 0);
 		if (p == MAP_FAILED)
 			goto unlock;
+/* BEGIN android-changed */
+		prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
+		    "atexit handlers");
+/* END android-changed */
 		if (__atexit == NULL) {
 			memset(&p->fns[0], 0, sizeof(p->fns[0]));
 			p->ind = 1;
@@ -177,47 +185,12 @@
 	}
 	_ATEXIT_UNLOCK();
 
+  extern void __libc_stdio_cleanup(void);
+  __libc_stdio_cleanup();
+
   /* BEGIN android-changed: call __unregister_atfork if dso is not null */
   if (dso != NULL) {
     __unregister_atfork(dso);
   }
   /* END android-changed */
 }
-
-/*
- * Register the cleanup function
- */
-void
-__atexit_register_cleanup(void (*func)(void))
-{
-	struct atexit *p;
-	size_t pgsize = getpagesize();
-
-	if (pgsize < sizeof(*p))
-		return;
-	_ATEXIT_LOCK();
-	p = __atexit;
-	while (p != NULL && p->next != NULL)
-		p = p->next;
-	if (p == NULL) {
-		p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
-		    MAP_ANON | MAP_PRIVATE, -1, 0);
-		if (p == MAP_FAILED)
-			goto unlock;
-		p->ind = 1;
-		p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
-		    sizeof(p->fns[0]);
-		p->next = NULL;
-		__atexit = p;
-	} else {
-		if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
-			goto unlock;
-	}
-	p->fns[0].fn_ptr = (void (*)(void *))func;
-	p->fns[0].fn_arg = NULL;
-	p->fns[0].fn_dso = NULL;
-	mprotect(p, pgsize, PROT_READ);
-	restartloop = 1;
-unlock:
-	_ATEXIT_UNLOCK();
-}
diff --git a/libc/tools/check-symbols.py b/libc/tools/check-symbols.py
index a217ff7..a6cf50c 100755
--- a/libc/tools/check-symbols.py
+++ b/libc/tools/check-symbols.py
@@ -13,9 +13,21 @@
 sys.stderr.write('Checking symbols for arch "%s"...\n' % arch)
 
 def GetSymbols(library, functions_or_variables):
+  global api
+  global arch
+
   api = '9'
   if library == 'libm' and arch == 'arm':
     api = '3'
+
+  # There were no 64-bit ABIs before API level 21.
+  if '64' in arch:
+    api = '21'
+
+  # What GCC calls aarch64, Android calls arm64.
+  if arch == 'aarch64':
+    arch = 'arm64'
+
   path = '%s/development/ndk/platforms/android-%s/arch-%s/symbols/%s.so.%s.txt' % (os.environ['ANDROID_BUILD_TOP'], api, arch, library, functions_or_variables)
   symbols = set()
   for line in open(path, 'r'):
@@ -26,7 +38,11 @@
 def CheckSymbols(library, functions_or_variables):
   expected_symbols = GetSymbols(library, functions_or_variables)
 
-  so_file = '%s/system/lib/%s.so' % (os.environ['ANDROID_PRODUCT_OUT'], library)
+  lib_dir = 'lib'
+  if '64' in arch:
+    lib_dir = 'lib64'
+
+  so_file = '%s/system/%s/%s.so' % (os.environ['ANDROID_PRODUCT_OUT'], lib_dir, library)
 
   # Example readelf output:
   #   264: 0001623c     4 FUNC    GLOBAL DEFAULT    8 cabsf
@@ -38,7 +54,7 @@
   r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)')
 
   actual_symbols = set()
-  for line in subprocess.check_output(['readelf', '--dyn-syms', so_file]).split('\n'):
+  for line in subprocess.check_output(['readelf', '-W', '--dyn-syms', so_file]).split('\n'):
     m = r.match(line)
     if m:
       symbol = string.split(m.group(2), '@')[0]
@@ -55,6 +71,12 @@
     for miss in sorted(missing):
       sys.stderr.write('  %s\n' % miss)
 
+  extra = actual_symbols - expected_symbols
+  if len(extra) > 0:
+    sys.stderr.write('%d extra %s in %s for %s:\n' % (len(extra), functions_or_variables, library, arch))
+    for s in sorted(extra):
+      sys.stderr.write('  %s\n' % s)
+
   return len(missing) == 0
 
 CheckSymbols("libc", "functions")
diff --git a/libc/tools/genversion-scripts.py b/libc/tools/genversion-scripts.py
new file mode 100755
index 0000000..e15c04e
--- /dev/null
+++ b/libc/tools/genversion-scripts.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+
+# This tool is used to generate the version scripts for libc and libm
+# for every architecture.
+
+import atexit
+import os.path
+import shutil
+import tempfile
+
+
+all_arches = ["arm", "arm64", "mips", "mips64", "x86", "x86_64"]
+bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
+bionic_libm_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libm")
+bionic_libdl_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libdl")
+libc_script = os.path.join(bionic_libc_root, "libc.map.txt")
+libm_script = os.path.join(bionic_libm_root, "libm.map.txt")
+libdl_script = os.path.join(bionic_libdl_root, "libdl.map.txt")
+
+# TODO (dimity): generate architecture-specific version scripts as part of build
+
+# temp directory where we store all intermediate files
+bionic_temp = tempfile.mkdtemp(prefix="bionic_genversionscripts")
+# Make sure the directory is deleted when the script exits.
+atexit.register(shutil.rmtree, bionic_temp)
+
+bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
+
+warning = "Generated by genversionscripts.py. Do not edit."
+
+
+class VersionScriptGenerator(object):
+
+  def run(self):
+    for script in [libc_script, libm_script, libdl_script]:
+      basename = os.path.basename(script)
+      dirname = os.path.dirname(script)
+      for arch in all_arches:
+        for brillo in [False, True]:
+          has_nobrillo = False
+          name = basename.split(".")[0] + "." + arch + (".brillo" if brillo else "") + ".map"
+          tmp_path = os.path.join(bionic_temp, name)
+          dest_path = os.path.join(dirname, name)
+          with open(tmp_path, "w") as fout:
+            with open(script, "r") as fin:
+              fout.write("# %s\n" % warning)
+              for line in fin:
+                index = line.find("#")
+                if index != -1:
+                  tags = line[index+1:].split()
+                  if arch not in tags:
+                    continue
+                  if brillo and "nobrillo" in tags:
+                    has_nobrillo = True
+                    continue
+                fout.write(line)
+          if not brillo or has_nobrillo:
+            shutil.copyfile(tmp_path, dest_path)
+
+
+generator = VersionScriptGenerator()
+generator.run()
+
diff --git a/libc/tools/zoneinfo/ZoneCompactor.java b/libc/tools/zoneinfo/ZoneCompactor.java
deleted file mode 100644
index 2d598fe..0000000
--- a/libc/tools/zoneinfo/ZoneCompactor.java
+++ /dev/null
@@ -1,192 +0,0 @@
-
-import java.io.*;
-import java.util.*;
-
-// usage: java ZoneCompiler <setup file> <data directory> <output directory> <tzdata version>
-//
-// Compile a set of tzfile-formatted files into a single file containing an index.
-//
-// The compilation is controlled by a setup file, which is provided as a
-// command-line argument.  The setup file has the form:
-//
-// Link <toName> <fromName>
-// ...
-// <zone filename>
-// ...
-//
-// Note that the links must be declared prior to the zone names.
-// A zone name is a filename relative to the source directory such as
-// 'GMT', 'Africa/Dakar', or 'America/Argentina/Jujuy'.
-//
-// Use the 'zic' command-line tool to convert from flat files
-// (such as 'africa' or 'northamerica') to a directory
-// hierarchy suitable for this tool (containing files such as 'data/Africa/Abidjan').
-//
-
-public class ZoneCompactor {
-  // Maximum number of characters in a zone name, including '\0' terminator.
-  private static final int MAXNAME = 40;
-
-  // Zone name synonyms.
-  private Map<String,String> links = new HashMap<String,String>();
-
-  // File offsets by zone name.
-  private Map<String,Integer> offsets = new HashMap<String,Integer>();
-
-  // File lengths by zone name.
-  private Map<String,Integer> lengths = new HashMap<String,Integer>();
-
-  // Concatenate the contents of 'inFile' onto 'out'.
-  private static void copyFile(File inFile, OutputStream out) throws Exception {
-    byte[] ret = new byte[0];
-
-    InputStream in = new FileInputStream(inFile);
-    byte[] buf = new byte[8192];
-    while (true) {
-      int nbytes = in.read(buf);
-      if (nbytes == -1) {
-        break;
-      }
-      out.write(buf, 0, nbytes);
-
-      byte[] nret = new byte[ret.length + nbytes];
-      System.arraycopy(ret, 0, nret, 0, ret.length);
-      System.arraycopy(buf, 0, nret, ret.length, nbytes);
-      ret = nret;
-    }
-    out.flush();
-  }
-
-  public ZoneCompactor(String setupFile, String dataDirectory, String zoneTabFile, String outputDirectory, String version) throws Exception {
-    // Read the setup file and concatenate all the data.
-    ByteArrayOutputStream allData = new ByteArrayOutputStream();
-    BufferedReader reader = new BufferedReader(new FileReader(setupFile));
-    String s;
-    int offset = 0;
-    while ((s = reader.readLine()) != null) {
-      s = s.trim();
-      if (s.startsWith("Link")) {
-        StringTokenizer st = new StringTokenizer(s);
-        st.nextToken();
-        String to = st.nextToken();
-        String from = st.nextToken();
-        links.put(from, to);
-      } else {
-        String link = links.get(s);
-        if (link == null) {
-          File sourceFile = new File(dataDirectory, s);
-          long length = sourceFile.length();
-          offsets.put(s, offset);
-          lengths.put(s, (int) length);
-
-          offset += length;
-          copyFile(sourceFile, allData);
-        }
-      }
-    }
-    reader.close();
-
-    // Fill in fields for links.
-    Iterator<String> it = links.keySet().iterator();
-    while (it.hasNext()) {
-      String from = it.next();
-      String to = links.get(from);
-
-      offsets.put(from, offsets.get(to));
-      lengths.put(from, lengths.get(to));
-    }
-
-    // Create/truncate the destination file.
-    RandomAccessFile f = new RandomAccessFile(new File(outputDirectory, "tzdata"), "rw");
-    f.setLength(0);
-
-    // Write the header.
-
-    // byte[12] tzdata_version -- 'tzdata2012f\0'
-    // int index_offset -- so we can slip in extra header fields in a backwards-compatible way
-    // int data_offset
-    // int zonetab_offset
-
-    // tzdata_version
-    f.write(toAscii(new byte[12], version));
-
-    // Write dummy values for the three offsets, and remember where we need to seek back to later
-    // when we have the real values.
-    int index_offset_offset = (int) f.getFilePointer();
-    f.writeInt(0);
-    int data_offset_offset = (int) f.getFilePointer();
-    f.writeInt(0);
-    int zonetab_offset_offset = (int) f.getFilePointer();
-    f.writeInt(0);
-
-    int index_offset = (int) f.getFilePointer();
-
-    // Write the index.
-    ArrayList<String> sortedOlsonIds = new ArrayList<String>();
-    sortedOlsonIds.addAll(offsets.keySet());
-    Collections.sort(sortedOlsonIds);
-    it = sortedOlsonIds.iterator();
-    while (it.hasNext()) {
-      String zoneName = it.next();
-      if (zoneName.length() >= MAXNAME) {
-        throw new RuntimeException("zone filename too long: " + zoneName.length());
-      }
-
-      // Follow the chain of links to work out where the real data for this zone lives.
-      String actualZoneName = zoneName;
-      while (links.get(actualZoneName) != null) {
-        actualZoneName = links.get(actualZoneName);
-      }
-
-      f.write(toAscii(new byte[MAXNAME], zoneName));
-      f.writeInt(offsets.get(actualZoneName));
-      f.writeInt(lengths.get(actualZoneName));
-      f.writeInt(0); // Used to be raw GMT offset. No longer used.
-    }
-
-    int data_offset = (int) f.getFilePointer();
-
-    // Write the data.
-    f.write(allData.toByteArray());
-
-    int zonetab_offset = (int) f.getFilePointer();
-
-    // Copy the zone.tab.
-    reader = new BufferedReader(new FileReader(zoneTabFile));
-    while ((s = reader.readLine()) != null) {
-      if (!s.startsWith("#")) {
-        f.writeBytes(s);
-        f.write('\n');
-      }
-    }
-    reader.close();
-
-    // Go back and fix up the offsets in the header.
-    f.seek(index_offset_offset);
-    f.writeInt(index_offset);
-    f.seek(data_offset_offset);
-    f.writeInt(data_offset);
-    f.seek(zonetab_offset_offset);
-    f.writeInt(zonetab_offset);
-
-    f.close();
-  }
-
-  private static byte[] toAscii(byte[] dst, String src) {
-    for (int i = 0; i < src.length(); ++i) {
-      if (src.charAt(i) > '~') {
-        throw new RuntimeException("non-ASCII string: " + src);
-      }
-      dst[i] = (byte) src.charAt(i);
-    }
-    return dst;
-  }
-
-  public static void main(String[] args) throws Exception {
-    if (args.length != 5) {
-      System.err.println("usage: java ZoneCompactor <setup file> <data directory> <zone.tab file> <output directory> <tzdata version>");
-      System.exit(0);
-    }
-    new ZoneCompactor(args[0], args[1], args[2], args[3], args[4]);
-  }
-}
diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py
deleted file mode 100755
index 68a5ff5..0000000
--- a/libc/tools/zoneinfo/update-tzdata.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/python
-
-"""Updates the timezone data held in bionic and ICU."""
-
-import ftplib
-import glob
-import httplib
-import os
-import re
-import shutil
-import subprocess
-import sys
-import tarfile
-import tempfile
-
-regions = ['africa', 'antarctica', 'asia', 'australasia',
-           'etcetera', 'europe', 'northamerica', 'southamerica',
-           # These two deliberately come last so they override what came
-           # before (and each other).
-           'backward', 'backzone' ]
-
-def CheckDirExists(dir, dirname):
-  if not os.path.isdir(dir):
-    print "Couldn't find %s (%s)!" % (dirname, dir)
-    sys.exit(1)
-
-bionic_libc_tools_zoneinfo_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
-
-# Find the bionic directory, searching upward from this script.
-bionic_dir = os.path.realpath('%s/../../..' % bionic_libc_tools_zoneinfo_dir)
-bionic_libc_zoneinfo_dir = '%s/libc/zoneinfo' % bionic_dir
-CheckDirExists(bionic_libc_zoneinfo_dir, 'bionic/libc/zoneinfo')
-CheckDirExists(bionic_libc_tools_zoneinfo_dir, 'bionic/libc/tools/zoneinfo')
-print 'Found bionic in %s ...' % bionic_dir
-
-# Find the icu directory.
-icu_dir = os.path.realpath('%s/../external/icu' % bionic_dir)
-icu4c_dir = os.path.realpath('%s/icu4c/source' % icu_dir)
-icu4j_dir = os.path.realpath('%s/icu4j' % icu_dir)
-CheckDirExists(icu4c_dir, 'external/icu/icu4c/source')
-CheckDirExists(icu4j_dir, 'external/icu/icu4j')
-print 'Found icu in %s ...' % icu_dir
-
-
-def GetCurrentTzDataVersion():
-  return open('%s/tzdata' % bionic_libc_zoneinfo_dir).read().split('\x00', 1)[0]
-
-
-def WriteSetupFile():
-  """Writes the list of zones that ZoneCompactor should process."""
-  links = []
-  zones = []
-  for region in regions:
-    for line in open('extracted/%s' % region):
-      fields = line.split()
-      if fields:
-        if fields[0] == 'Link':
-          links.append('%s %s %s' % (fields[0], fields[1], fields[2]))
-          zones.append(fields[2])
-        elif fields[0] == 'Zone':
-          zones.append(fields[1])
-  zones.sort()
-
-  setup = open('setup', 'w')
-  for link in sorted(set(links)):
-    setup.write('%s\n' % link)
-  for zone in sorted(set(zones)):
-    setup.write('%s\n' % zone)
-  setup.close()
-
-
-def SwitchToNewTemporaryDirectory():
-  tmp_dir = tempfile.mkdtemp('-tzdata')
-  os.chdir(tmp_dir)
-  print 'Created temporary directory "%s"...' % tmp_dir
-
-
-def FtpRetrieveFile(ftp, filename):
-  ftp.retrbinary('RETR %s' % filename, open(filename, 'wb').write)
-
-
-def FtpRetrieveFileAndSignature(ftp, data_filename):
-  """Downloads and repackages the given data from the given FTP server."""
-  print 'Downloading data...'
-  FtpRetrieveFile(ftp, data_filename)
-
-  print 'Downloading signature...'
-  signature_filename = '%s.asc' % data_filename
-  FtpRetrieveFile(ftp, signature_filename)
-
-
-def HttpRetrieveFile(http, path, output_filename):
-  http.request("GET", path)
-  f = open(output_filename, 'wb')
-  f.write(http.getresponse().read())
-  f.close()
-
-
-def HttpRetrieveFileAndSignature(http, data_filename):
-  """Downloads and repackages the given data from the given HTTP server."""
-  path = "/time-zones/repository/releases/%s" % data_filename
-
-  print 'Downloading data...'
-  HttpRetrieveFile(http, path, data_filename)
-
-  print 'Downloading signature...'
-  signature_filename = '%s.asc' % data_filename
-  HttpRetrievefile(http, "%s.asc" % path, signature_filename)
-
-
-def BuildIcuToolsAndData(data_filename):
-  # Keep track of the original cwd so we can go back to it at the end.
-  original_working_dir = os.getcwd()
-
-  # Create a directory to run 'make' from.
-  icu_working_dir = '%s/icu' % original_working_dir
-  os.mkdir(icu_working_dir)
-  os.chdir(icu_working_dir)
-
-  # Build the ICU tools.
-  print 'Configuring ICU tools...'
-  subprocess.check_call(['%s/runConfigureICU' % icu4c_dir, 'Linux'])
-
-  # Run the ICU tools.
-  os.chdir('tools/tzcode')
-
-  # The tz2icu tool only picks up icuregions and icuzones in they are in the CWD
-  for icu_data_file in [ 'icuregions', 'icuzones']:
-    icu_data_file_source = '%s/tools/tzcode/%s' % (icu4c_dir, icu_data_file)
-    icu_data_file_symlink = './%s' % icu_data_file
-    os.symlink(icu_data_file_source, icu_data_file_symlink)
-
-  shutil.copyfile('%s/%s' % (original_working_dir, data_filename), data_filename)
-  print 'Making ICU data...'
-  # The Makefile assumes the existence of the bin directory.
-  os.mkdir('%s/bin' % icu_working_dir)
-  subprocess.check_call(['make'])
-
-  # Copy the source file to its ultimate destination.
-  icu_txt_data_dir = '%s/data/misc' % icu4c_dir
-  print 'Copying zoneinfo64.txt to %s ...' % icu_txt_data_dir
-  shutil.copy('zoneinfo64.txt', icu_txt_data_dir)
-
-  # Regenerate the .dat file.
-  os.chdir(icu_working_dir)
-  subprocess.check_call(['make', 'INCLUDE_UNI_CORE_DATA=1', '-j32'])
-
-  # Copy the .dat file to its ultimate destination.
-  icu_dat_data_dir = '%s/stubdata' % icu4c_dir
-  datfiles = glob.glob('data/out/tmp/icudt??l.dat')
-  if len(datfiles) != 1:
-    print 'ERROR: Unexpectedly found %d .dat files (%s). Halting.' % (len(datfiles), datfiles)
-    sys.exit(1)
-  datfile = datfiles[0]
-  print 'Copying %s to %s ...' % (datfile, icu_dat_data_dir)
-  shutil.copy(datfile, icu_dat_data_dir)
-
-  # Generate the ICU4J .jar files
-  os.chdir('%s/data' % icu_working_dir)
-  subprocess.check_call(['make', 'icu4j-data'])
-
-  # Copy the ICU4J .jar files to their ultimate destination.
-  icu_jar_data_dir = '%s/main/shared/data' % icu4j_dir
-  jarfiles = glob.glob('out/icu4j/*.jar')
-  if len(jarfiles) != 2:
-    print 'ERROR: Unexpectedly found %d .jar files (%s). Halting.' % (len(jarfiles), jarfiles)
-    sys.exit(1)
-  for jarfile in jarfiles:
-    print 'Copying %s to %s ...' % (jarfile, icu_jar_data_dir)
-    shutil.copy(jarfile, icu_jar_data_dir)
-
-  # Switch back to the original working cwd.
-  os.chdir(original_working_dir)
-
-
-def CheckSignature(data_filename):
-  signature_filename = '%s.asc' % data_filename
-  print 'Verifying signature...'
-  # If this fails for you, you probably need to import Paul Eggert's public key:
-  # gpg --recv-keys ED97E90E62AA7E34
-  subprocess.check_call(['gpg', '--trusted-key=ED97E90E62AA7E34', '--verify',
-                         signature_filename, data_filename])
-
-
-def BuildBionicToolsAndData(data_filename):
-  new_version = re.search('(tzdata.+)\\.tar\\.gz', data_filename).group(1)
-
-  print 'Extracting...'
-  os.mkdir('extracted')
-  tar = tarfile.open(data_filename, 'r')
-  tar.extractall('extracted')
-
-  print 'Calling zic(1)...'
-  os.mkdir('data')
-  zic_inputs = [ 'extracted/%s' % x for x in regions ]
-  zic_cmd = ['zic', '-d', 'data' ]
-  zic_cmd.extend(zic_inputs)
-  subprocess.check_call(zic_cmd)
-
-  WriteSetupFile()
-
-  print 'Calling ZoneCompactor to update bionic to %s...' % new_version
-  subprocess.check_call(['javac', '-d', '.',
-                         '%s/ZoneCompactor.java' % bionic_libc_tools_zoneinfo_dir])
-  subprocess.check_call(['java', 'ZoneCompactor',
-                         'setup', 'data', 'extracted/zone.tab',
-                         bionic_libc_zoneinfo_dir, new_version])
-
-
-# Run with no arguments from any directory, with no special setup required.
-# See http://www.iana.org/time-zones/ for more about the source of this data.
-def main():
-  print 'Looking for new tzdata...'
-
-  tzdata_filenames = []
-
-  # The FTP server lets you download intermediate releases, and also lets you
-  # download the signatures for verification, so it's your best choice.
-  use_ftp = True
-
-  if use_ftp:
-    ftp = ftplib.FTP('ftp.iana.org')
-    ftp.login()
-    ftp.cwd('tz/releases')
-    for filename in ftp.nlst():
-      if filename.startswith('tzdata20') and filename.endswith('.tar.gz'):
-        tzdata_filenames.append(filename)
-    tzdata_filenames.sort()
-  else:
-    http = httplib.HTTPConnection('www.iana.org')
-    http.request("GET", "/time-zones")
-    index_lines = http.getresponse().read().split('\n')
-    for line in index_lines:
-      m = re.compile('.*href="/time-zones/repository/releases/(tzdata20\d\d\c\.tar\.gz)".*').match(line)
-      if m:
-        tzdata_filenames.append(m.group(1))
-
-  # If you're several releases behind, we'll walk you through the upgrades
-  # one by one.
-  current_version = GetCurrentTzDataVersion()
-  current_filename = '%s.tar.gz' % current_version
-  for filename in tzdata_filenames:
-    if filename > current_filename:
-      print 'Found new tzdata: %s' % filename
-      SwitchToNewTemporaryDirectory()
-      if use_ftp:
-        FtpRetrieveFileAndSignature(ftp, filename)
-      else:
-        HttpRetrieveFileAndSignature(http, filename)
-
-      CheckSignature(filename)
-      BuildIcuToolsAndData(filename)
-      BuildBionicToolsAndData(filename)
-      print 'Look in %s and %s for new data files' % (bionic_dir, icu_dir)
-      sys.exit(0)
-
-  print 'You already have the latest tzdata (%s)!' % current_version
-  sys.exit(0)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/libc/tzcode/asctime.c b/libc/tzcode/asctime.c
index fea24e4..337a313 100644
--- a/libc/tzcode/asctime.c
+++ b/libc/tzcode/asctime.c
@@ -55,7 +55,7 @@
 ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
 ** (two three-character abbreviations, five strings denoting integers,
 ** seven explicit spaces, two explicit colons, a newline,
-** and a trailing ASCII nul).
+** and a trailing NUL byte).
 ** The values above are for systems where an int is 32 bits and are provided
 ** as an example; the define below calculates the maximum for the system at
 ** hand.
@@ -99,11 +99,11 @@
 	** Assume that strftime is unaffected by other out-of-range members
 	** (e.g., timeptr->tm_mday) when processing "%Y".
 	*/
-	(void) strftime(year, sizeof year, "%Y", timeptr);
+	strftime(year, sizeof year, "%Y", timeptr);
 	/*
 	** We avoid using snprintf since it's not available on all systems.
 	*/
-	(void) snprintf(result, sizeof(result), /* Android change: use snprintf. */
+	snprintf(result, sizeof(result), /* Android change: use snprintf. */
 		((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
 		wn, mn,
 		timeptr->tm_mday, timeptr->tm_hour,
@@ -112,11 +112,7 @@
 	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
 		return strcpy(buf, result);
 	else {
-#ifdef EOVERFLOW
 		errno = EOVERFLOW;
-#else /* !defined EOVERFLOW */
-		errno = EINVAL;
-#endif /* !defined EOVERFLOW */
 		return NULL;
 	}
 }
diff --git a/libc/tzcode/difftime.c b/libc/tzcode/difftime.c
index 449cdf0..ba2fd03 100644
--- a/libc/tzcode/difftime.c
+++ b/libc/tzcode/difftime.c
@@ -7,42 +7,52 @@
 
 #include "private.h"	/* for time_t and TYPE_SIGNED */
 
+/* Return -X as a double.  Using this avoids casting to 'double'.  */
+static double
+dminus(double x)
+{
+  return -x;
+}
+
 double ATTRIBUTE_CONST
-difftime(const time_t time1, const time_t time0)
+difftime(time_t time1, time_t time0)
 {
 	/*
-	** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
+	** If double is large enough, simply convert and subtract
 	** (assuming that the larger type has more precision).
 	*/
-	if (sizeof (double) > sizeof (time_t))
-		return (double) time1 - (double) time0;
-	if (!TYPE_SIGNED(time_t)) {
-		/*
-		** The difference of two unsigned values can't overflow
-		** if the minuend is greater than or equal to the subtrahend.
-		*/
-		if (time1 >= time0)
-			return            time1 - time0;
-		else	return -(double) (time0 - time1);
+	if (sizeof (time_t) < sizeof (double)) {
+	  double t1 = time1, t0 = time0;
+	  return t1 - t0;
 	}
+
+	/*
+	** The difference of two unsigned values can't overflow
+	** if the minuend is greater than or equal to the subtrahend.
+	*/
+	if (!TYPE_SIGNED(time_t))
+	  return time0 <= time1 ? time1 - time0 : dminus(time0 - time1);
+
+	/* Use uintmax_t if wide enough.  */
+	if (sizeof (time_t) <= sizeof (uintmax_t)) {
+	  uintmax_t t1 = time1, t0 = time0;
+	  return time0 <= time1 ? t1 - t0 : dminus(t0 - t1);
+	}
+
 	/*
 	** Handle cases where both time1 and time0 have the same sign
 	** (meaning that their difference cannot overflow).
 	*/
 	if ((time1 < 0) == (time0 < 0))
-		return time1 - time0;
+	  return time1 - time0;
+
 	/*
-	** time1 and time0 have opposite signs.
-	** Punt if uintmax_t is too narrow.
+	** The values have opposite signs and uintmax_t is too narrow.
 	** This suffers from double rounding; attempt to lessen that
 	** by using long double temporaries.
 	*/
-	if (sizeof (uintmax_t) < sizeof (time_t))
-		return (long double) time1 - (long double) time0;
-	/*
-	** Stay calm...decent optimizers will eliminate the complexity below.
-	*/
-	if (time1 >= 0 /* && time0 < 0 */)
-		return    (uintmax_t) time1 + (uintmax_t) (-1 - time0) + 1;
-	return -(double) ((uintmax_t) time0 + (uintmax_t) (-1 - time1) + 1);
+	{
+	  long double t1 = time1, t0 = time0;
+	  return t1 - t0;
+	}
 }
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index bf09c5e..f370e87 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -10,10 +10,30 @@
 
 /*LINTLIBRARY*/
 
+#define LOCALTIME_IMPLEMENTATION
 #include "private.h"
+
 #include "tzfile.h"
 #include "fcntl.h"
 
+#if THREAD_SAFE
+# include <pthread.h>
+static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
+#else
+static int lock(void) { return 0; }
+static void unlock(void) { }
+#endif
+
+/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
+   NETBSD_INSPIRED is defined, and are private otherwise.  */
+#if NETBSD_INSPIRED
+# define NETBSD_INSPIRED_EXTERN
+#else
+# define NETBSD_INSPIRED_EXTERN static
+#endif
+
 #ifndef TZ_ABBR_MAX_LEN
 #define TZ_ABBR_MAX_LEN 16
 #endif /* !defined TZ_ABBR_MAX_LEN */
@@ -38,19 +58,6 @@
 #define OPEN_MODE   O_RDONLY
 #endif /* !defined O_BINARY */
 
-#if 0
-#  define  XLOG(xx)  printf xx , fflush(stdout)
-#else
-#  define  XLOG(x)   do{}while (0)
-#endif
-
-/* BEGIN android-added: thread-safety. */
-#include <pthread.h>
-static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
-static inline void _tzLock(void) { pthread_mutex_lock(&_tzMutex); }
-static inline void _tzUnlock(void) { pthread_mutex_unlock(&_tzMutex); }
-/* END android-added */
-
 #ifndef WILDABBR
 /*
 ** Someone might make incorrect use of a time zone abbreviation:
@@ -91,10 +98,10 @@
 
 struct ttinfo {              /* time type information */
     int_fast32_t tt_gmtoff;  /* UT offset in seconds */
-    int          tt_isdst;   /* used to set tm_isdst */
+    bool         tt_isdst;   /* used to set tm_isdst */
     int          tt_abbrind; /* abbreviation list index */
-    int          tt_ttisstd; /* TRUE if transition is std time */
-    int          tt_ttisgmt; /* TRUE if transition is UT */
+    bool         tt_ttisstd; /* transition is std time */
+    bool         tt_ttisgmt; /* transition is UT */
 };
 
 struct lsinfo {              /* leap second information */
@@ -102,6 +109,7 @@
     int_fast64_t ls_corr;    /* correction to apply */
 };
 
+#define SMALLEST(a, b)	(((a) < (b)) ? (a) : (b))
 #define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
 
 #ifdef TZNAME_MAX
@@ -116,8 +124,8 @@
     int           timecnt;
     int           typecnt;
     int           charcnt;
-    int           goback;
-    int           goahead;
+    bool          goback;
+    bool          goahead;
     time_t        ats[TZ_MAX_TIMES];
     unsigned char types[TZ_MAX_TIMES];
     struct ttinfo ttis[TZ_MAX_TYPES];
@@ -127,74 +135,29 @@
     int           defaulttype; /* for early times or if no transitions */
 };
 
+enum r_type {
+  JULIAN_DAY,		/* Jn = Julian day */
+  DAY_OF_YEAR,		/* n = day of year */
+  MONTH_NTH_DAY_OF_WEEK	/* Mm.n.d = month, week, day of week */
+};
+
 struct rule {
-    int          r_type; /* type of rule; see below */
+	enum r_type	r_type;		/* type of rule */
     int          r_day;  /* day number of rule */
     int          r_week; /* week number of rule */
     int          r_mon;  /* month number of rule */
     int_fast32_t r_time; /* transition time of rule */
 };
 
-#define JULIAN_DAY             0       /* Jn = Julian day */
-#define DAY_OF_YEAR            1       /* n = day of year */
-#define MONTH_NTH_DAY_OF_WEEK  2       /* Mm.n.d = month, week, day of week */
-
-/*
-** Prototypes for static functions.
-*/
-
-/* NOTE: all internal functions assume that _tzLock() was already called */
-
-static int __bionic_open_tzdata(const char*, int*);
-static int_fast32_t detzcode(const char * codep);
-static int_fast64_t detzcode64(const char * codep);
-static int      differ_by_repeat(time_t t1, time_t t0);
-static const char * getzname(const char * strp) ATTRIBUTE_PURE;
-static const char * getqzname(const char * strp, const int delim)
-        ATTRIBUTE_PURE;
-static const char * getnum(const char * strp, int * nump, int min,
-                int max);
-static const char * getsecs(const char * strp, int_fast32_t * secsp);
-static const char * getoffset(const char * strp, int_fast32_t * offsetp);
-static const char * getrule(const char * strp, struct rule * rulep);
-static void     gmtload(struct state * sp);
-static struct tm *  gmtsub(const time_t * timep, int_fast32_t offset,
-                struct tm * tmp, struct state * sp); // android-changed: added sp.
-static struct tm *  localsub(const time_t * timep, int_fast32_t offset,
-                struct tm * tmp, struct state * sp); // android-changed: added sp.
-static int      increment_overflow(int * number, int delta);
-static int      leaps_thru_end_of(int y) ATTRIBUTE_PURE;
-static int      increment_overflow32(int_fast32_t * number, int delta);
-static int      increment_overflow_time(time_t *t, int_fast32_t delta);
-static int      normalize_overflow32(int_fast32_t * tensptr,
-                int * unitsptr, int base);
-static int      normalize_overflow(int * tensptr, int * unitsptr,
-                int base);
-static void     settzname(void);
-static time_t       time1(struct tm * tmp,
-                struct tm * (*funcp)(const time_t *,
-                int_fast32_t, struct tm *, struct state *), // android-changed: added state*.
-                int_fast32_t, struct state * sp); // android-changed: added sp.
-static time_t       time2(struct tm * tmp,
-                struct tm * (*funcp)(const time_t *,
-                int_fast32_t, struct tm*, struct state *), // android-changed: added state*.
-                int_fast32_t offset, int * okayp, struct state * sp); // android-changed: added sp.
-static time_t       time2sub(struct tm *tmp,
-                struct tm * (*funcp) (const time_t *,
-                int_fast32_t, struct tm*, struct state *), // android-changed: added state*.
-                int_fast32_t offset, int * okayp, int do_norm_secs, struct state * sp); // android-change: added sp.
-static struct tm *  timesub(const time_t * timep, int_fast32_t offset,
-                const struct state * sp, struct tm * tmp);
-static int      tmcomp(const struct tm * atmp,
-                const struct tm * btmp);
-static int_fast32_t transtime(int year, const struct rule * rulep,
-                int_fast32_t offset)
-        ATTRIBUTE_PURE;
-static int      typesequiv(const struct state * sp, int a, int b);
-static int      tzload(const char * name, struct state * sp,
-                int doextend);
-static int      tzparse(const char * name, struct state * sp,
-                int lastditch);
+static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
+			 struct tm *);
+static bool increment_overflow(int *, int);
+static bool increment_overflow_time(time_t *, int_fast32_t);
+static bool normalize_overflow32(int_fast32_t *, int *, int);
+static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
+			  struct tm *);
+static bool typesequiv(struct state const *, int, int);
+static bool tzparse(char const *, struct state *, bool);
 
 #ifdef ALL_STATE
 static struct state * lclptr;
@@ -214,7 +177,6 @@
 
 static char lcl_TZname[TZ_STRLEN_MAX + 1];
 static int  lcl_is_set;
-static int  gmt_is_set;
 
 char * tzname[2] = {
     (char *) wildabbr,
@@ -229,427 +191,539 @@
 ** Thanks to Paul Eggert for noting this.
 */
 
-static struct tm    tmGlobal;
+static struct tm	tm;
 
 #ifdef USG_COMPAT
-long                timezone = 0;
-int                 daylight = 0;
+long			timezone;
+int			daylight;
 #endif /* defined USG_COMPAT */
 
 #ifdef ALTZONE
-long                altzone = 0;
+long			altzone;
 #endif /* defined ALTZONE */
 
+/* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND.  */
+static void
+init_ttinfo(struct ttinfo *s, int_fast32_t gmtoff, bool isdst, int abbrind)
+{
+  s->tt_gmtoff = gmtoff;
+  s->tt_isdst = isdst;
+  s->tt_abbrind = abbrind;
+  s->tt_ttisstd = false;
+  s->tt_ttisgmt = false;
+}
+
 static int_fast32_t
 detzcode(const char *const codep)
 {
-    register int_fast32_t result;
-    register int          i;
+	register int_fast32_t	result;
+	register int		i;
+	int_fast32_t one = 1;
+	int_fast32_t halfmaxval = one << (32 - 2);
+	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
+	int_fast32_t minval = -1 - maxval;
 
-    result = (codep[0] & 0x80) ? -1 : 0;
-    for (i = 0; i < 4; ++i)
-        result = (result << 8) | (codep[i] & 0xff);
-    return result;
+	result = codep[0] & 0x7f;
+	for (i = 1; i < 4; ++i)
+		result = (result << 8) | (codep[i] & 0xff);
+
+	if (codep[0] & 0x80) {
+	  /* Do two's-complement negation even on non-two's-complement machines.
+	     If the result would be minval - 1, return minval.  */
+	  result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
+	  result += minval;
+	}
+	return result;
 }
 
 static int_fast64_t
 detzcode64(const char *const codep)
 {
-    register int_fast64_t result;
-    register int          i;
+	register uint_fast64_t result;
+	register int	i;
+	int_fast64_t one = 1;
+	int_fast64_t halfmaxval = one << (64 - 2);
+	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
+	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
 
-    result = (codep[0] & 0x80) ? -1 : 0;
-    for (i = 0; i < 8; ++i)
-        result = (result << 8) | (codep[i] & 0xff);
-    return result;
+	result = codep[0] & 0x7f;
+	for (i = 1; i < 8; ++i)
+		result = (result << 8) | (codep[i] & 0xff);
+
+	if (codep[0] & 0x80) {
+	  /* Do two's-complement negation even on non-two's-complement machines.
+	     If the result would be minval - 1, return minval.  */
+	  result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
+	  result += minval;
+	}
+	return result;
+}
+
+static void
+update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
+{
+  tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+  if (!ttisp->tt_isdst)
+    timezone = - ttisp->tt_gmtoff;
+#endif
+#ifdef ALTZONE
+  if (ttisp->tt_isdst)
+    altzone = - ttisp->tt_gmtoff;
+#endif
 }
 
 static void
 settzname(void)
 {
-    register struct state * const sp = lclptr;
-    register int                  i;
+	register struct state * const	sp = lclptr;
+	register int			i;
 
-    tzname[0] = tzname[1] = (char *) wildabbr;
+	tzname[0] = tzname[1] = (char *) wildabbr;
 #ifdef USG_COMPAT
-    daylight = 0;
-    timezone = 0;
+	daylight = 0;
+	timezone = 0;
 #endif /* defined USG_COMPAT */
 #ifdef ALTZONE
-    altzone = 0;
+	altzone = 0;
 #endif /* defined ALTZONE */
-    if (sp == NULL) {
-        tzname[0] = tzname[1] = (char *) gmt;
-        return;
-    }
-    /*
-    ** And to get the latest zone names into tzname. . .
-    */
-    for (i = 0; i < sp->typecnt; ++i) {
-        register const struct ttinfo * const    ttisp = &sp->ttis[i];
-
-        tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
-    }
-    for (i = 0; i < sp->timecnt; ++i) {
-        register const struct ttinfo * const    ttisp =
-                            &sp->ttis[
-                                sp->types[i]];
-
-        tzname[ttisp->tt_isdst] =
-            &sp->chars[ttisp->tt_abbrind];
+	if (sp == NULL) {
+		tzname[0] = tzname[1] = (char *) gmt;
+		return;
+	}
+	/*
+	** And to get the latest zone names into tzname. . .
+	*/
+	for (i = 0; i < sp->typecnt; ++i) {
+		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+		update_tzname_etc(sp, ttisp);
+	}
+	for (i = 0; i < sp->timecnt; ++i) {
+		register const struct ttinfo * const	ttisp =
+							&sp->ttis[
+								sp->types[i]];
+		update_tzname_etc(sp, ttisp);
 #ifdef USG_COMPAT
-        if (ttisp->tt_isdst)
-            daylight = 1;
-        if (!ttisp->tt_isdst)
-            timezone = -(ttisp->tt_gmtoff);
+		if (ttisp->tt_isdst)
+			daylight = 1;
 #endif /* defined USG_COMPAT */
-#ifdef ALTZONE
-        if (ttisp->tt_isdst)
-            altzone = -(ttisp->tt_gmtoff);
-#endif /* defined ALTZONE */
-    }
-    /*
-    ** Finally, scrub the abbreviations.
-    ** First, replace bogus characters.
-    */
-    for (i = 0; i < sp->charcnt; ++i)
-        if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
-            sp->chars[i] = TZ_ABBR_ERR_CHAR;
-    /*
-    ** Second, truncate long abbreviations.
-    */
-    for (i = 0; i < sp->typecnt; ++i) {
-        register const struct ttinfo * const    ttisp = &sp->ttis[i];
-        register char *             cp = &sp->chars[ttisp->tt_abbrind];
-
-        if (strlen(cp) > TZ_ABBR_MAX_LEN &&
-            strcmp(cp, GRANDPARENTED) != 0)
-                *(cp + TZ_ABBR_MAX_LEN) = '\0';
-    }
+	}
 }
 
-static int
-differ_by_repeat(const time_t t1 __unused, const time_t t0 __unused)
+static void
+scrub_abbrs(struct state *sp)
+{
+	int i;
+	/*
+	** First, replace bogus characters.
+	*/
+	for (i = 0; i < sp->charcnt; ++i)
+		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+			sp->chars[i] = TZ_ABBR_ERR_CHAR;
+	/*
+	** Second, truncate long abbreviations.
+	*/
+	for (i = 0; i < sp->typecnt; ++i) {
+		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+		register char *				cp = &sp->chars[ttisp->tt_abbrind];
+
+		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+			strcmp(cp, GRANDPARENTED) != 0)
+				*(cp + TZ_ABBR_MAX_LEN) = '\0';
+	}
+}
+
+static bool
+differ_by_repeat(const time_t t1, const time_t t0)
 {
     if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
         return 0;
-#if defined(__LP64__) // 32-bit Android only has a signed 32-bit time_t; 64-bit Android is fixed.
+#if defined(__LP64__) // 32-bit Android/glibc has a signed 32-bit time_t; 64-bit doesn't.
     return t1 - t0 == SECSPERREPEAT;
 #endif
 }
 
-static int
-tzload(register const char* name, register struct state* const sp,
-       register const int doextend)
-{
-    register const char * p;
-    register int          i;
-    register int          fid;
-    register int          stored;
-    register int          nread;
-    typedef union {
-        struct tzhead tzhead;
-        char          buf[2 * sizeof(struct tzhead) +
-                      2 * sizeof *sp +
-                      4 * TZ_MAX_TIMES];
-    } u_t;
-    union local_storage {
-        /*
-        ** Section 4.9.1 of the C standard says that
-        ** "FILENAME_MAX expands to an integral constant expression
-        ** that is the size needed for an array of char large enough
-        ** to hold the longest file name string that the implementation
-        ** guarantees can be opened."
-        */
-        //char            fullname[FILENAME_MAX + 1];
+/* Input buffer for data read from a compiled tz file.  */
+union input_buffer {
+  /* The first part of the buffer, interpreted as a header.  */
+  struct tzhead tzhead;
 
-        /* The main part of the storage for this function.  */
-        struct {
-            u_t u;
-            struct state st;
-        } u;
-    };
-    //register char *fullname;
-    register u_t *up;
-    register union local_storage *lsp;
-#ifdef ALL_STATE
-    lsp = malloc(sizeof *lsp);
-    if (!lsp)
-        return -1;
-#else /* !defined ALL_STATE */
-    union local_storage ls;
-    lsp = &ls;
-#endif /* !defined ALL_STATE */
-    //fullname = lsp->fullname;
-    up = &lsp->u.u;
-
-    sp->goback = sp->goahead = FALSE;
-
-    if (! name) {
-        name = TZDEFAULT;
-        if (! name)
-            goto oops;
-    }
-
-    int toread;
-    fid = __bionic_open_tzdata(name, &toread);
-    if (fid < 0)
-        goto oops;
-
-    nread = read(fid, up->buf, sizeof up->buf);
-    if (close(fid) < 0 || nread <= 0)
-        goto oops;
-    for (stored = 4; stored <= 8; stored *= 2) {
-        int ttisstdcnt;
-        int ttisgmtcnt;
-        int timecnt;
-
-        ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
-        ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
-        sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
-        sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
-        sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
-        sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
-        p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
-        if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
-            sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
-            sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
-            sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
-            (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
-            (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
-                goto oops;
-        if (nread - (p - up->buf) <
-            sp->timecnt * stored +       /* ats */
-            sp->timecnt +                /* types */
-            sp->typecnt * 6 +            /* ttinfos */
-            sp->charcnt +                /* chars */
-            sp->leapcnt * (stored + 4) + /* lsinfos */
-            ttisstdcnt +                 /* ttisstds */
-            ttisgmtcnt)                  /* ttisgmts */
-                goto oops;
-        timecnt = 0;
-        for (i = 0; i < sp->timecnt; ++i) {
-            int_fast64_t at
-              = stored == 4 ? detzcode(p) : detzcode64(p);
-            sp->types[i] = ((TYPE_SIGNED(time_t)
-                     ? time_t_min <= at
-                     : 0 <= at)
-                    && at <= time_t_max);
-            if (sp->types[i]) {
-                if (i && !timecnt && at != time_t_min) {
-                    /*
-                    ** Keep the earlier record, but tweak
-                    ** it so that it starts with the
-                    ** minimum time_t value.
-                    */
-                    sp->types[i - 1] = 1;
-                    sp->ats[timecnt++] = time_t_min;
-                }
-                sp->ats[timecnt++] = at;
-            }
-            p += stored;
-        }
-        timecnt = 0;
-        for (i = 0; i < sp->timecnt; ++i) {
-            unsigned char typ = *p++;
-            if (sp->typecnt <= typ)
-                goto oops;
-            if (sp->types[i])
-                sp->types[timecnt++] = typ;
-        }
-        sp->timecnt = timecnt;
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            ttisp->tt_gmtoff = detzcode(p);
-            p += 4;
-            ttisp->tt_isdst = (unsigned char) *p++;
-            if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
-                goto oops;
-            ttisp->tt_abbrind = (unsigned char) *p++;
-            if (ttisp->tt_abbrind < 0 ||
-                ttisp->tt_abbrind > sp->charcnt)
-                    goto oops;
-        }
-        for (i = 0; i < sp->charcnt; ++i)
-            sp->chars[i] = *p++;
-        sp->chars[i] = '\0';    /* ensure '\0' at end */
-        for (i = 0; i < sp->leapcnt; ++i) {
-            register struct lsinfo *    lsisp;
-
-            lsisp = &sp->lsis[i];
-            lsisp->ls_trans = (stored == 4) ?
-                detzcode(p) : detzcode64(p);
-            p += stored;
-            lsisp->ls_corr = detzcode(p);
-            p += 4;
-        }
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            if (ttisstdcnt == 0)
-                ttisp->tt_ttisstd = FALSE;
-            else {
-                ttisp->tt_ttisstd = *p++;
-                if (ttisp->tt_ttisstd != TRUE &&
-                    ttisp->tt_ttisstd != FALSE)
-                        goto oops;
-            }
-        }
-        for (i = 0; i < sp->typecnt; ++i) {
-            register struct ttinfo *    ttisp;
-
-            ttisp = &sp->ttis[i];
-            if (ttisgmtcnt == 0)
-                ttisp->tt_ttisgmt = FALSE;
-            else {
-                ttisp->tt_ttisgmt = *p++;
-                if (ttisp->tt_ttisgmt != TRUE &&
-                    ttisp->tt_ttisgmt != FALSE)
-                        goto oops;
-            }
-        }
-        /*
-        ** If this is an old file, we're done.
-        */
-        if (up->tzhead.tzh_version[0] == '\0')
-            break;
-        nread -= p - up->buf;
-        for (i = 0; i < nread; ++i)
-            up->buf[i] = p[i];
-        /*
-        ** If this is a signed narrow time_t system, we're done.
-        */
-        if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
-            break;
-    }
-    if (doextend && nread > 2 &&
-        up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
-        sp->typecnt + 2 <= TZ_MAX_TYPES) {
-            struct state    *ts = &lsp->u.st;
-            register int result;
-
-            up->buf[nread - 1] = '\0';
-            result = tzparse(&up->buf[1], ts, FALSE);
-            if (result == 0 && ts->typecnt == 2 &&
-                sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
-                    for (i = 0; i < 2; ++i)
-                        ts->ttis[i].tt_abbrind +=
-                            sp->charcnt;
-                    for (i = 0; i < ts->charcnt; ++i)
-                        sp->chars[sp->charcnt++] =
-                            ts->chars[i];
-                    i = 0;
-                    while (i < ts->timecnt &&
-                        ts->ats[i] <=
-                        sp->ats[sp->timecnt - 1])
-                            ++i;
-                    while (i < ts->timecnt &&
-                        sp->timecnt < TZ_MAX_TIMES) {
-                        sp->ats[sp->timecnt] =
-                            ts->ats[i];
-                        sp->types[sp->timecnt] =
-                            sp->typecnt +
-                            ts->types[i];
-                        ++sp->timecnt;
-                        ++i;
-                    }
-                    sp->ttis[sp->typecnt++] = ts->ttis[0];
-                    sp->ttis[sp->typecnt++] = ts->ttis[1];
-            }
-    }
-    if (sp->timecnt > 1) {
-        for (i = 1; i < sp->timecnt; ++i)
-            if (typesequiv(sp, sp->types[i], sp->types[0]) &&
-                    differ_by_repeat(sp->ats[i], sp->ats[0])) {
-                sp->goback = TRUE;
-                break;
-            }
-            for (i = sp->timecnt - 2; i >= 0; --i)
-                if (typesequiv(sp, sp->types[sp->timecnt - 1],
-                               sp->types[i]) &&
-                        differ_by_repeat(sp->ats[sp->timecnt - 1],
-                                         sp->ats[i])) {
-                    sp->goahead = TRUE;
-                    break;
-            }
-        }
-        /*
-        ** If type 0 is is unused in transitions,
-        ** it's the type to use for early times.
-        */
-        for (i = 0; i < sp->typecnt; ++i)
-            if (sp->types[i] == 0)
-                break;
-        i = (i >= sp->typecnt) ? 0 : -1;
-        /*
-        ** Absent the above,
-        ** if there are transition times
-        ** and the first transition is to a daylight time
-        ** find the standard type less than and closest to
-        ** the type of the first transition.
-        */
-        if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
-            i = sp->types[0];
-            while (--i >= 0)
-                if (!sp->ttis[i].tt_isdst)
-                    break;
-        }
-        /*
-        ** If no result yet, find the first standard type.
-        ** If there is none, punt to type zero.
-        */
-        if (i < 0) {
-            i = 0;
-            while (sp->ttis[i].tt_isdst)
-                if (++i >= sp->typecnt) {
-                    i = 0;
-                    break;
-                }
-        }
-        sp->defaulttype = i;
-#ifdef ALL_STATE
-        free(up);
-#endif /* defined ALL_STATE */
-        return 0;
-oops:
-#ifdef ALL_STATE
-        free(up);
-#endif /* defined ALL_STATE */
-        return -1;
-}
-
-static int
-typesequiv(const struct state *const sp, const int a, const int b)
-{
-    register int result;
-
-    if (sp == NULL ||
-        a < 0 || a >= sp->typecnt ||
-        b < 0 || b >= sp->typecnt)
-            result = FALSE;
-    else {
-        register const struct ttinfo *  ap = &sp->ttis[a];
-        register const struct ttinfo *  bp = &sp->ttis[b];
-        result = ap->tt_gmtoff == bp->tt_gmtoff &&
-            ap->tt_isdst == bp->tt_isdst &&
-            ap->tt_ttisstd == bp->tt_ttisstd &&
-            ap->tt_ttisgmt == bp->tt_ttisgmt &&
-            strcmp(&sp->chars[ap->tt_abbrind],
-            &sp->chars[bp->tt_abbrind]) == 0;
-    }
-    return result;
-}
-
-static const int mon_lengths[2][MONSPERYEAR] = {
-    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+  /* The entire buffer.  */
+  char buf[2 * sizeof(struct tzhead) + 2 * sizeof (struct state)
+	   + 4 * TZ_MAX_TIMES];
 };
 
-static const int year_lengths[2] = {
-    DAYSPERNYEAR, DAYSPERLYEAR
+/* Local storage needed for 'tzloadbody'.  */
+union local_storage {
+  /* The file name to be opened.  */
+  char fullname[FILENAME_MAX + 1];
+
+  /* The results of analyzing the file's contents after it is opened.  */
+  struct {
+    /* The input buffer.  */
+    union input_buffer u;
+
+    /* A temporary state used for parsing a TZ string in the file.  */
+    struct state st;
+  } u;
+};
+
+static int __bionic_open_tzdata(const char*);
+
+/* Load tz data from the file named NAME into *SP.  Read extended
+   format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
+   success, an errno value on failure.  */
+static int
+tzloadbody(char const *name, struct state *sp, bool doextend,
+	   union local_storage *lsp)
+{
+	register int			i;
+	register int			fid;
+	register int			stored;
+	register ssize_t		nread;
+#if !defined(__ANDROID__)
+	register bool doaccess;
+	register char *fullname = lsp->fullname;
+#endif
+	register union input_buffer *up = &lsp->u.u;
+	register int tzheadsize = sizeof (struct tzhead);
+
+	sp->goback = sp->goahead = false;
+
+	if (! name) {
+		name = TZDEFAULT;
+		if (! name)
+		  return EINVAL;
+	}
+
+#if defined(__ANDROID__)
+	fid = __bionic_open_tzdata(name);
+#else
+	if (name[0] == ':')
+		++name;
+	doaccess = name[0] == '/';
+	if (!doaccess) {
+		char const *p = TZDIR;
+		if (! p)
+		  return EINVAL;
+		if (sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
+		  return ENAMETOOLONG;
+		strcpy(fullname, p);
+		strcat(fullname, "/");
+		strcat(fullname, name);
+		/* Set doaccess if '.' (as in "../") shows up in name.  */
+		if (strchr(name, '.'))
+			doaccess = true;
+		name = fullname;
+	}
+	if (doaccess && access(name, R_OK) != 0)
+	  return errno;
+	fid = open(name, OPEN_MODE);
+#endif
+	if (fid < 0)
+	  return errno;
+
+	nread = read(fid, up->buf, sizeof up->buf);
+	if (nread < tzheadsize) {
+	  int err = nread < 0 ? errno : EINVAL;
+	  close(fid);
+	  return err;
+	}
+	if (close(fid) < 0)
+	  return errno;
+	for (stored = 4; stored <= 8; stored *= 2) {
+		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
+		int_fast32_t ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt);
+		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
+		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
+		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
+		int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
+		char const *p = up->buf + tzheadsize;
+		if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
+		       && 0 < typecnt && typecnt < TZ_MAX_TYPES
+		       && 0 <= timecnt && timecnt < TZ_MAX_TIMES
+		       && 0 <= charcnt && charcnt < TZ_MAX_CHARS
+		       && (ttisstdcnt == typecnt || ttisstdcnt == 0)
+		       && (ttisgmtcnt == typecnt || ttisgmtcnt == 0)))
+		  return EINVAL;
+		if (nread
+		    < (tzheadsize		/* struct tzhead */
+		       + timecnt * stored	/* ats */
+		       + timecnt		/* types */
+		       + typecnt * 6		/* ttinfos */
+		       + charcnt		/* chars */
+		       + leapcnt * (stored + 4)	/* lsinfos */
+		       + ttisstdcnt		/* ttisstds */
+		       + ttisgmtcnt))		/* ttisgmts */
+		  return EINVAL;
+		sp->leapcnt = leapcnt;
+		sp->timecnt = timecnt;
+		sp->typecnt = typecnt;
+		sp->charcnt = charcnt;
+
+		/* Read transitions, discarding those out of time_t range.
+		   But pretend the last transition before time_t_min
+		   occurred at time_t_min.  */
+		timecnt = 0;
+		for (i = 0; i < sp->timecnt; ++i) {
+			int_fast64_t at
+			  = stored == 4 ? detzcode(p) : detzcode64(p);
+			sp->types[i] = at <= time_t_max;
+			if (sp->types[i]) {
+			  time_t attime
+			    = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
+			       ? time_t_min : at);
+			  if (timecnt && attime <= sp->ats[timecnt - 1]) {
+			    if (attime < sp->ats[timecnt - 1])
+			      return EINVAL;
+			    sp->types[i - 1] = 0;
+			    timecnt--;
+			  }
+			  sp->ats[timecnt++] = attime;
+			}
+			p += stored;
+		}
+
+		timecnt = 0;
+		for (i = 0; i < sp->timecnt; ++i) {
+			unsigned char typ = *p++;
+			if (sp->typecnt <= typ)
+			  return EINVAL;
+			if (sp->types[i])
+				sp->types[timecnt++] = typ;
+		}
+		sp->timecnt = timecnt;
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+			unsigned char isdst, abbrind;
+
+			ttisp = &sp->ttis[i];
+			ttisp->tt_gmtoff = detzcode(p);
+			p += 4;
+			isdst = *p++;
+			if (! (isdst < 2))
+			  return EINVAL;
+			ttisp->tt_isdst = isdst;
+			abbrind = *p++;
+			if (! (abbrind < sp->charcnt))
+			  return EINVAL;
+			ttisp->tt_abbrind = abbrind;
+		}
+		for (i = 0; i < sp->charcnt; ++i)
+			sp->chars[i] = *p++;
+		sp->chars[i] = '\0';	/* ensure '\0' at end */
+
+		/* Read leap seconds, discarding those out of time_t range.  */
+		leapcnt = 0;
+		for (i = 0; i < sp->leapcnt; ++i) {
+		  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
+		  int_fast32_t corr = detzcode(p + stored);
+		  p += stored + 4;
+		  if (tr <= time_t_max) {
+		    time_t trans
+		      = ((TYPE_SIGNED(time_t) ? tr < time_t_min : tr < 0)
+			 ? time_t_min : tr);
+		    if (leapcnt && trans <= sp->lsis[leapcnt - 1].ls_trans) {
+		      if (trans < sp->lsis[leapcnt - 1].ls_trans)
+			return EINVAL;
+		      leapcnt--;
+		    }
+		    sp->lsis[leapcnt].ls_trans = trans;
+		    sp->lsis[leapcnt].ls_corr = corr;
+		    leapcnt++;
+		  }
+		}
+		sp->leapcnt = leapcnt;
+
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+
+			ttisp = &sp->ttis[i];
+			if (ttisstdcnt == 0)
+				ttisp->tt_ttisstd = false;
+			else {
+				if (*p != true && *p != false)
+				  return EINVAL;
+				ttisp->tt_ttisstd = *p++;
+			}
+		}
+		for (i = 0; i < sp->typecnt; ++i) {
+			register struct ttinfo *	ttisp;
+
+			ttisp = &sp->ttis[i];
+			if (ttisgmtcnt == 0)
+				ttisp->tt_ttisgmt = false;
+			else {
+				if (*p != true && *p != false)
+						return EINVAL;
+				ttisp->tt_ttisgmt = *p++;
+			}
+		}
+		/*
+		** If this is an old file, we're done.
+		*/
+		if (up->tzhead.tzh_version[0] == '\0')
+			break;
+		nread -= p - up->buf;
+		memmove(up->buf, p, nread);
+	}
+	if (doextend && nread > 2 &&
+		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
+		sp->typecnt + 2 <= TZ_MAX_TYPES) {
+			struct state	*ts = &lsp->u.st;
+
+			up->buf[nread - 1] = '\0';
+			if (tzparse(&up->buf[1], ts, false)
+			    && ts->typecnt == 2) {
+
+			  /* Attempt to reuse existing abbreviations.
+			     Without this, America/Anchorage would stop
+			     working after 2037 when TZ_MAX_CHARS is 50, as
+			     sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST
+			     AHDT YST AKDT AKST) and ts->charcnt equals 10
+			     (for AKST AKDT).  Reusing means sp->charcnt can
+			     stay 42 in this example.  */
+			  int gotabbr = 0;
+			  int charcnt = sp->charcnt;
+			  for (i = 0; i < 2; i++) {
+			    char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind;
+			    int j;
+			    for (j = 0; j < charcnt; j++)
+			      if (strcmp(sp->chars + j, tsabbr) == 0) {
+				ts->ttis[i].tt_abbrind = j;
+				gotabbr++;
+				break;
+			      }
+			    if (! (j < charcnt)) {
+			      int tsabbrlen = strlen(tsabbr);
+			      if (j + tsabbrlen < TZ_MAX_CHARS) {
+				strcpy(sp->chars + j, tsabbr);
+				charcnt = j + tsabbrlen + 1;
+				ts->ttis[i].tt_abbrind = j;
+				gotabbr++;
+			      }
+			    }
+			  }
+			  if (gotabbr == 2) {
+			    sp->charcnt = charcnt;
+			    for (i = 0; i < ts->timecnt; i++)
+			      if (sp->ats[sp->timecnt - 1] < ts->ats[i])
+				break;
+			    while (i < ts->timecnt
+				   && sp->timecnt < TZ_MAX_TIMES) {
+			      sp->ats[sp->timecnt] = ts->ats[i];
+			      sp->types[sp->timecnt] = (sp->typecnt
+							+ ts->types[i]);
+			      sp->timecnt++;
+			      i++;
+			    }
+			    sp->ttis[sp->typecnt++] = ts->ttis[0];
+			    sp->ttis[sp->typecnt++] = ts->ttis[1];
+			  }
+			}
+	}
+	if (sp->timecnt > 1) {
+		for (i = 1; i < sp->timecnt; ++i)
+			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
+				differ_by_repeat(sp->ats[i], sp->ats[0])) {
+					sp->goback = true;
+					break;
+				}
+		for (i = sp->timecnt - 2; i >= 0; --i)
+			if (typesequiv(sp, sp->types[sp->timecnt - 1],
+				sp->types[i]) &&
+				differ_by_repeat(sp->ats[sp->timecnt - 1],
+				sp->ats[i])) {
+					sp->goahead = true;
+					break;
+		}
+	}
+	/*
+	** If type 0 is is unused in transitions,
+	** it's the type to use for early times.
+	*/
+	for (i = 0; i < sp->timecnt; ++i)
+		if (sp->types[i] == 0)
+			break;
+	i = i < sp->timecnt ? -1 : 0;
+	/*
+	** Absent the above,
+	** if there are transition times
+	** and the first transition is to a daylight time
+	** find the standard type less than and closest to
+	** the type of the first transition.
+	*/
+	if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
+		i = sp->types[0];
+		while (--i >= 0)
+			if (!sp->ttis[i].tt_isdst)
+				break;
+	}
+	/*
+	** If no result yet, find the first standard type.
+	** If there is none, punt to type zero.
+	*/
+	if (i < 0) {
+		i = 0;
+		while (sp->ttis[i].tt_isdst)
+			if (++i >= sp->typecnt) {
+				i = 0;
+				break;
+			}
+	}
+	sp->defaulttype = i;
+	return 0;
+}
+
+/* Load tz data from the file named NAME into *SP.  Read extended
+   format if DOEXTEND.  Return 0 on success, an errno value on failure.  */
+static int
+tzload(char const *name, struct state *sp, bool doextend)
+{
+#ifdef ALL_STATE
+  union local_storage *lsp = malloc(sizeof *lsp);
+  if (!lsp)
+    return errno;
+  else {
+    int err = tzloadbody(name, sp, doextend, lsp);
+    free(lsp);
+    return err;
+  }
+#else
+  union local_storage ls;
+  return tzloadbody(name, sp, doextend, &ls);
+#endif
+}
+
+static bool
+typesequiv(const struct state *sp, int a, int b)
+{
+	register bool result;
+
+	if (sp == NULL ||
+		a < 0 || a >= sp->typecnt ||
+		b < 0 || b >= sp->typecnt)
+			result = false;
+	else {
+		register const struct ttinfo *	ap = &sp->ttis[a];
+		register const struct ttinfo *	bp = &sp->ttis[b];
+		result = ap->tt_gmtoff == bp->tt_gmtoff &&
+			ap->tt_isdst == bp->tt_isdst &&
+			ap->tt_ttisstd == bp->tt_ttisstd &&
+			ap->tt_ttisgmt == bp->tt_ttisgmt &&
+			strcmp(&sp->chars[ap->tt_abbrind],
+			&sp->chars[bp->tt_abbrind]) == 0;
+	}
+	return result;
+}
+
+static const int	mon_lengths[2][MONSPERYEAR] = {
+	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int	year_lengths[2] = {
+	DAYSPERNYEAR, DAYSPERLYEAR
 };
 
 /*
@@ -658,15 +732,15 @@
 ** character.
 */
 
-static const char *
-getzname(register const char * strp)
+static const char * ATTRIBUTE_PURE
+getzname(register const char *strp)
 {
-    register char   c;
+	register char	c;
 
-    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
-        c != '+')
-            ++strp;
-    return strp;
+	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+		c != '+')
+			++strp;
+	return strp;
 }
 
 /*
@@ -678,14 +752,14 @@
 ** We don't do any checking here; checking is done later in common-case code.
 */
 
-static const char *
+static const char * ATTRIBUTE_PURE
 getqzname(register const char *strp, const int delim)
 {
-    register int c;
+	register int	c;
 
-    while ((c = *strp) != '\0' && c != delim)
-        ++strp;
-    return strp;
+	while ((c = *strp) != '\0' && c != delim)
+		++strp;
+	return strp;
 }
 
 /*
@@ -696,24 +770,24 @@
 */
 
 static const char *
-getnum(register const char * strp, int * const nump, const int min, const int max)
+getnum(register const char *strp, int *const nump, const int min, const int max)
 {
-    register char c;
-    register int  num;
+	register char	c;
+	register int	num;
 
-    if (strp == NULL || !is_digit(c = *strp))
-        return NULL;
-    num = 0;
-    do {
-        num = num * 10 + (c - '0');
-        if (num > max)
-            return NULL;    /* illegal value */
-        c = *++strp;
-    } while (is_digit(c));
-    if (num < min)
-        return NULL;        /* illegal value */
-    *nump = num;
-    return strp;
+	if (strp == NULL || !is_digit(c = *strp))
+		return NULL;
+	num = 0;
+	do {
+		num = num * 10 + (c - '0');
+		if (num > max)
+			return NULL;	/* illegal value */
+		c = *++strp;
+	} while (is_digit(c));
+	if (num < min)
+		return NULL;		/* illegal value */
+	*nump = num;
+	return strp;
 }
 
 /*
@@ -727,34 +801,34 @@
 static const char *
 getsecs(register const char *strp, int_fast32_t *const secsp)
 {
-    int num;
+	int	num;
 
-    /*
-    ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
-    ** "M10.4.6/26", which does not conform to Posix,
-    ** but which specifies the equivalent of
-    ** "02:00 on the first Sunday on or after 23 Oct".
-    */
-    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
-    if (strp == NULL)
-        return NULL;
-    *secsp = num * (int_fast32_t) SECSPERHOUR;
-    if (*strp == ':') {
-        ++strp;
-        strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
-        if (strp == NULL)
-            return NULL;
-        *secsp += num * SECSPERMIN;
-        if (*strp == ':') {
-            ++strp;
-            /* 'SECSPERMIN' allows for leap seconds. */
-            strp = getnum(strp, &num, 0, SECSPERMIN);
-            if (strp == NULL)
-                return NULL;
-            *secsp += num;
-        }
-    }
-    return strp;
+	/*
+	** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+	** "M10.4.6/26", which does not conform to Posix,
+	** but which specifies the equivalent of
+	** "02:00 on the first Sunday on or after 23 Oct".
+	*/
+	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+	if (strp == NULL)
+		return NULL;
+	*secsp = num * (int_fast32_t) SECSPERHOUR;
+	if (*strp == ':') {
+		++strp;
+		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+		if (strp == NULL)
+			return NULL;
+		*secsp += num * SECSPERMIN;
+		if (*strp == ':') {
+			++strp;
+			/* 'SECSPERMIN' allows for leap seconds.  */
+			strp = getnum(strp, &num, 0, SECSPERMIN);
+			if (strp == NULL)
+				return NULL;
+			*secsp += num;
+		}
+	}
+	return strp;
 }
 
 /*
@@ -767,19 +841,19 @@
 static const char *
 getoffset(register const char *strp, int_fast32_t *const offsetp)
 {
-    register int neg = 0;
+	register bool neg = false;
 
-    if (*strp == '-') {
-        neg = 1;
-        ++strp;
-    } else if (*strp == '+')
-        ++strp;
-    strp = getsecs(strp, offsetp);
-    if (strp == NULL)
-        return NULL;        /* illegal time */
-    if (neg)
-        *offsetp = -*offsetp;
-    return strp;
+	if (*strp == '-') {
+		neg = true;
+		++strp;
+	} else if (*strp == '+')
+		++strp;
+	strp = getsecs(strp, offsetp);
+	if (strp == NULL)
+		return NULL;		/* illegal time */
+	if (neg)
+		*offsetp = -*offsetp;
+	return strp;
 }
 
 /*
@@ -790,49 +864,49 @@
 */
 
 static const char *
-getrule(const char * strp, register struct rule * const rulep)
+getrule(const char *strp, register struct rule *const rulep)
 {
-    if (*strp == 'J') {
-        /*
-        ** Julian day.
-        */
-        rulep->r_type = JULIAN_DAY;
-        ++strp;
-        strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
-    } else if (*strp == 'M') {
-        /*
-        ** Month, week, day.
-        */
-        rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
-        ++strp;
-        strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
-        if (strp == NULL)
-            return NULL;
-        if (*strp++ != '.')
-            return NULL;
-        strp = getnum(strp, &rulep->r_week, 1, 5);
-        if (strp == NULL)
-            return NULL;
-        if (*strp++ != '.')
-            return NULL;
-        strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
-    } else if (is_digit(*strp)) {
-        /*
-        ** Day of year.
-        */
-        rulep->r_type = DAY_OF_YEAR;
-        strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
-    } else  return NULL;        /* invalid format */
-    if (strp == NULL)
-        return NULL;
-    if (*strp == '/') {
-        /*
-        ** Time specified.
-        */
-        ++strp;
-        strp = getoffset(strp, &rulep->r_time);
-    } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
-    return strp;
+	if (*strp == 'J') {
+		/*
+		** Julian day.
+		*/
+		rulep->r_type = JULIAN_DAY;
+		++strp;
+		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+	} else if (*strp == 'M') {
+		/*
+		** Month, week, day.
+		*/
+		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+		++strp;
+		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+		if (strp == NULL)
+			return NULL;
+		if (*strp++ != '.')
+			return NULL;
+		strp = getnum(strp, &rulep->r_week, 1, 5);
+		if (strp == NULL)
+			return NULL;
+		if (*strp++ != '.')
+			return NULL;
+		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+	} else if (is_digit(*strp)) {
+		/*
+		** Day of year.
+		*/
+		rulep->r_type = DAY_OF_YEAR;
+		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+	} else	return NULL;		/* invalid format */
+	if (strp == NULL)
+		return NULL;
+	if (*strp == '/') {
+		/*
+		** Time specified.
+		*/
+		++strp;
+		strp = getoffset(strp, &rulep->r_time);
+	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
+	return strp;
 }
 
 /*
@@ -840,11 +914,11 @@
 ** effect, calculate the year-relative time that rule takes effect.
 */
 
-static int_fast32_t
+static int_fast32_t ATTRIBUTE_PURE
 transtime(const int year, register const struct rule *const rulep,
           const int_fast32_t offset)
 {
-    register int          leapyear;
+    register bool         leapyear;
     register int_fast32_t value;
     register int          i;
     int d, m1, yy0, yy1, yy2, dow;
@@ -931,457 +1005,542 @@
 ** appropriate.
 */
 
-static int
-tzparse(const char * name, register struct state * const sp,
-        const int lastditch)
+static bool
+tzparse(const char *name, struct state *sp, bool lastditch)
 {
-    const char *         stdname;
-    const char *         dstname;
-    size_t               stdlen;
-    size_t               dstlen;
-    int_fast32_t         stdoffset;
-    int_fast32_t         dstoffset;
-    register char *      cp;
-    register int         load_result;
-    static struct ttinfo zttinfo;
+	const char *			stdname;
+	const char *			dstname;
+	size_t				stdlen;
+	size_t				dstlen;
+	size_t				charcnt;
+	int_fast32_t			stdoffset;
+	int_fast32_t			dstoffset;
+	register char *			cp;
+	register bool			load_ok;
 
-    stdname = name;
-    if (lastditch) {
-        stdlen = strlen(name);  /* length of standard zone name */
-        name += stdlen;
-        if (stdlen >= sizeof sp->chars)
-            stdlen = (sizeof sp->chars) - 1;
-        stdoffset = 0;
-    } else {
-        if (*name == '<') {
-            name++;
-            stdname = name;
-            name = getqzname(name, '>');
-            if (*name != '>')
-                return (-1);
-            stdlen = name - stdname;
-            name++;
-        } else {
-            name = getzname(name);
-            stdlen = name - stdname;
-        }
-        if (*name == '\0')
-            return -1;
-        name = getoffset(name, &stdoffset);
-        if (name == NULL)
-            return -1;
-    }
-    load_result = tzload(TZDEFRULES, sp, FALSE);
-    if (load_result != 0)
-        sp->leapcnt = 0;        /* so, we're off a little */
-    if (*name != '\0') {
-        if (*name == '<') {
-            dstname = ++name;
-            name = getqzname(name, '>');
-            if (*name != '>')
-                return -1;
-            dstlen = name - dstname;
-            name++;
-        } else {
-            dstname = name;
-            name = getzname(name);
-            dstlen = name - dstname; /* length of DST zone name */
-        }
-        if (*name != '\0' && *name != ',' && *name != ';') {
-            name = getoffset(name, &dstoffset);
-            if (name == NULL)
-                return -1;
-        } else  dstoffset = stdoffset - SECSPERHOUR;
-        if (*name == '\0' && load_result != 0)
-            name = TZDEFRULESTRING;
-        if (*name == ',' || *name == ';') {
-            struct rule  start;
-            struct rule  end;
-            register int year;
-            register int yearlim;
-            register int timecnt;
-            time_t       janfirst;
+	stdname = name;
+	if (lastditch) {
+		stdlen = sizeof gmt - 1;
+		name += stdlen;
+		stdoffset = 0;
+	} else {
+		if (*name == '<') {
+			name++;
+			stdname = name;
+			name = getqzname(name, '>');
+			if (*name != '>')
+			  return false;
+			stdlen = name - stdname;
+			name++;
+		} else {
+			name = getzname(name);
+			stdlen = name - stdname;
+		}
+		if (!stdlen)
+		  return false;
+		name = getoffset(name, &stdoffset);
+		if (name == NULL)
+		  return false;
+	}
+	charcnt = stdlen + 1;
+	if (sizeof sp->chars < charcnt)
+	  return false;
+	load_ok = tzload(TZDEFRULES, sp, false) == 0;
+	if (!load_ok)
+		sp->leapcnt = 0;		/* so, we're off a little */
+	if (*name != '\0') {
+		if (*name == '<') {
+			dstname = ++name;
+			name = getqzname(name, '>');
+			if (*name != '>')
+			  return false;
+			dstlen = name - dstname;
+			name++;
+		} else {
+			dstname = name;
+			name = getzname(name);
+			dstlen = name - dstname; /* length of DST zone name */
+		}
+		if (!dstlen)
+		  return false;
+		charcnt += dstlen + 1;
+		if (sizeof sp->chars < charcnt)
+		  return false;
+		if (*name != '\0' && *name != ',' && *name != ';') {
+			name = getoffset(name, &dstoffset);
+			if (name == NULL)
+			  return false;
+		} else	dstoffset = stdoffset - SECSPERHOUR;
+		if (*name == '\0' && !load_ok)
+			name = TZDEFRULESTRING;
+		if (*name == ',' || *name == ';') {
+			struct rule	start;
+			struct rule	end;
+			register int	year;
+			register int	yearlim;
+			register int	timecnt;
+			time_t		janfirst;
 
-            ++name;
-            if ((name = getrule(name, &start)) == NULL)
-                return -1;
-            if (*name++ != ',')
-                return -1;
-            if ((name = getrule(name, &end)) == NULL)
-                return -1;
-            if (*name != '\0')
-                return -1;
-            sp->typecnt = 2;    /* standard time and DST */
-            /*
-            ** Two transitions per year, from EPOCH_YEAR forward.
-            */
-            sp->ttis[0] = sp->ttis[1] = zttinfo;
-            sp->ttis[0].tt_gmtoff = -dstoffset;
-            sp->ttis[0].tt_isdst = 1;
-            sp->ttis[0].tt_abbrind = stdlen + 1;
-            sp->ttis[1].tt_gmtoff = -stdoffset;
-            sp->ttis[1].tt_isdst = 0;
-            sp->ttis[1].tt_abbrind = 0;
-            sp->defaulttype = 0;
-            timecnt = 0;
-            janfirst = 0;
-            yearlim = EPOCH_YEAR + YEARSPERREPEAT;
-            for (year = EPOCH_YEAR; year < yearlim; year++) {
-                int_fast32_t
-                  starttime = transtime(year, &start, stdoffset),
-                  endtime = transtime(year, &end, dstoffset);
-                int_fast32_t
-                yearsecs = (year_lengths[isleap(year)]
-                            * SECSPERDAY);
-                int reversed = endtime < starttime;
-                if (reversed) {
-                    int_fast32_t swap = starttime;
-                    starttime = endtime;
-                    endtime = swap;
-                }
-                if (reversed
-                    || (starttime < endtime
-                        && (endtime - starttime
-                            < (yearsecs
-                               + (stdoffset - dstoffset))))) {
-                    if (TZ_MAX_TIMES - 2 < timecnt)
-                        break;
-                    yearlim = year + YEARSPERREPEAT + 1;
-                    sp->ats[timecnt] = janfirst;
-                    if (increment_overflow_time
-                        (&sp->ats[timecnt], starttime))
-                        break;
-                    sp->types[timecnt++] = reversed;
-                    sp->ats[timecnt] = janfirst;
-                    if (increment_overflow_time
-                        (&sp->ats[timecnt], endtime))
-                        break;
-                    sp->types[timecnt++] = !reversed;
-                    }
-                if (increment_overflow_time(&janfirst, yearsecs))
-                    break;
-            }
-            sp->timecnt = timecnt;
-            if (!timecnt)
-                sp->typecnt = 1;    /* Perpetual DST.  */
-        } else {
-            register int_fast32_t   theirstdoffset;
-            register int_fast32_t   theirdstoffset;
-            register int_fast32_t   theiroffset;
-            register int    isdst;
-            register int    i;
-            register int    j;
+			++name;
+			if ((name = getrule(name, &start)) == NULL)
+			  return false;
+			if (*name++ != ',')
+			  return false;
+			if ((name = getrule(name, &end)) == NULL)
+			  return false;
+			if (*name != '\0')
+			  return false;
+			sp->typecnt = 2;	/* standard time and DST */
+			/*
+			** Two transitions per year, from EPOCH_YEAR forward.
+			*/
+			init_ttinfo(&sp->ttis[0], -dstoffset, true, stdlen + 1);
+			init_ttinfo(&sp->ttis[1], -stdoffset, false, 0);
+			sp->defaulttype = 0;
+			timecnt = 0;
+			janfirst = 0;
+			yearlim = EPOCH_YEAR + YEARSPERREPEAT;
+			for (year = EPOCH_YEAR; year < yearlim; year++) {
+				int_fast32_t
+				  starttime = transtime(year, &start, stdoffset),
+				  endtime = transtime(year, &end, dstoffset);
+				int_fast32_t
+				  yearsecs = (year_lengths[isleap(year)]
+					      * SECSPERDAY);
+				bool reversed = endtime < starttime;
+				if (reversed) {
+					int_fast32_t swap = starttime;
+					starttime = endtime;
+					endtime = swap;
+				}
+				if (reversed
+				    || (starttime < endtime
+					&& (endtime - starttime
+					    < (yearsecs
+					       + (stdoffset - dstoffset))))) {
+					if (TZ_MAX_TIMES - 2 < timecnt)
+						break;
+					yearlim = year + YEARSPERREPEAT + 1;
+					sp->ats[timecnt] = janfirst;
+					if (increment_overflow_time
+					    (&sp->ats[timecnt], starttime))
+						break;
+					sp->types[timecnt++] = reversed;
+					sp->ats[timecnt] = janfirst;
+					if (increment_overflow_time
+					    (&sp->ats[timecnt], endtime))
+						break;
+					sp->types[timecnt++] = !reversed;
+				}
+				if (increment_overflow_time(&janfirst, yearsecs))
+					break;
+			}
+			sp->timecnt = timecnt;
+			if (!timecnt)
+				sp->typecnt = 1;	/* Perpetual DST.  */
+		} else {
+			register int_fast32_t	theirstdoffset;
+			register int_fast32_t	theirdstoffset;
+			register int_fast32_t	theiroffset;
+			register bool		isdst;
+			register int		i;
+			register int		j;
 
-            if (*name != '\0')
-                return -1;
-            /*
-            ** Initial values of theirstdoffset and theirdstoffset.
-            */
-            theirstdoffset = 0;
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                if (!sp->ttis[j].tt_isdst) {
-                    theirstdoffset =
-                        -sp->ttis[j].tt_gmtoff;
-                    break;
-                }
-            }
-            theirdstoffset = 0;
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                if (sp->ttis[j].tt_isdst) {
-                    theirdstoffset =
-                        -sp->ttis[j].tt_gmtoff;
-                    break;
-                }
-            }
-            /*
-            ** Initially we're assumed to be in standard time.
-            */
-            isdst = FALSE;
-            theiroffset = theirstdoffset;
-            /*
-            ** Now juggle transition times and types
-            ** tracking offsets as you do.
-            */
-            for (i = 0; i < sp->timecnt; ++i) {
-                j = sp->types[i];
-                sp->types[i] = sp->ttis[j].tt_isdst;
-                if (sp->ttis[j].tt_ttisgmt) {
-                    /* No adjustment to transition time */
-                } else {
-                    /*
-                    ** If summer time is in effect, and the
-                    ** transition time was not specified as
-                    ** standard time, add the summer time
-                    ** offset to the transition time;
-                    ** otherwise, add the standard time
-                    ** offset to the transition time.
-                    */
-                    /*
-                    ** Transitions from DST to DDST
-                    ** will effectively disappear since
-                    ** POSIX provides for only one DST
-                    ** offset.
-                    */
-                    if (isdst && !sp->ttis[j].tt_ttisstd) {
-                        sp->ats[i] += dstoffset -
-                            theirdstoffset;
-                    } else {
-                        sp->ats[i] += stdoffset -
-                            theirstdoffset;
-                    }
-                }
-                theiroffset = -sp->ttis[j].tt_gmtoff;
-                if (sp->ttis[j].tt_isdst)
-                    theirdstoffset = theiroffset;
-                else    theirstdoffset = theiroffset;
-            }
-            /*
-            ** Finally, fill in ttis.
-            */
-            sp->ttis[0] = sp->ttis[1] = zttinfo;
-            sp->ttis[0].tt_gmtoff = -stdoffset;
-            sp->ttis[0].tt_isdst = FALSE;
-            sp->ttis[0].tt_abbrind = 0;
-            sp->ttis[1].tt_gmtoff = -dstoffset;
-            sp->ttis[1].tt_isdst = TRUE;
-            sp->ttis[1].tt_abbrind = stdlen + 1;
-            sp->typecnt = 2;
-            sp->defaulttype = 0;
-        }
-    } else {
-        dstlen = 0;
-        sp->typecnt = 1;        /* only standard time */
-        sp->timecnt = 0;
-        sp->ttis[0] = zttinfo;
-        sp->ttis[0].tt_gmtoff = -stdoffset;
-        sp->ttis[0].tt_isdst = 0;
-        sp->ttis[0].tt_abbrind = 0;
-        sp->defaulttype = 0;
-    }
-    sp->charcnt = stdlen + 1;
-    if (dstlen != 0)
-        sp->charcnt += dstlen + 1;
-    if ((size_t) sp->charcnt > sizeof sp->chars)
-        return -1;
-    cp = sp->chars;
-    (void) strncpy(cp, stdname, stdlen);
-    cp += stdlen;
-    *cp++ = '\0';
-    if (dstlen != 0) {
-        (void) strncpy(cp, dstname, dstlen);
-        *(cp + dstlen) = '\0';
-    }
-    return 0;
+			if (*name != '\0')
+			  return false;
+			/*
+			** Initial values of theirstdoffset and theirdstoffset.
+			*/
+			theirstdoffset = 0;
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				if (!sp->ttis[j].tt_isdst) {
+					theirstdoffset =
+						-sp->ttis[j].tt_gmtoff;
+					break;
+				}
+			}
+			theirdstoffset = 0;
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				if (sp->ttis[j].tt_isdst) {
+					theirdstoffset =
+						-sp->ttis[j].tt_gmtoff;
+					break;
+				}
+			}
+			/*
+			** Initially we're assumed to be in standard time.
+			*/
+			isdst = false;
+			theiroffset = theirstdoffset;
+			/*
+			** Now juggle transition times and types
+			** tracking offsets as you do.
+			*/
+			for (i = 0; i < sp->timecnt; ++i) {
+				j = sp->types[i];
+				sp->types[i] = sp->ttis[j].tt_isdst;
+				if (sp->ttis[j].tt_ttisgmt) {
+					/* No adjustment to transition time */
+				} else {
+					/*
+					** If summer time is in effect, and the
+					** transition time was not specified as
+					** standard time, add the summer time
+					** offset to the transition time;
+					** otherwise, add the standard time
+					** offset to the transition time.
+					*/
+					/*
+					** Transitions from DST to DDST
+					** will effectively disappear since
+					** POSIX provides for only one DST
+					** offset.
+					*/
+					if (isdst && !sp->ttis[j].tt_ttisstd) {
+						sp->ats[i] += dstoffset -
+							theirdstoffset;
+					} else {
+						sp->ats[i] += stdoffset -
+							theirstdoffset;
+					}
+				}
+				theiroffset = -sp->ttis[j].tt_gmtoff;
+				if (sp->ttis[j].tt_isdst)
+					theirdstoffset = theiroffset;
+				else	theirstdoffset = theiroffset;
+			}
+			/*
+			** Finally, fill in ttis.
+			*/
+			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
+			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
+			sp->typecnt = 2;
+			sp->defaulttype = 0;
+		}
+	} else {
+		dstlen = 0;
+		sp->typecnt = 1;		/* only standard time */
+		sp->timecnt = 0;
+		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
+		sp->defaulttype = 0;
+	}
+	sp->charcnt = charcnt;
+	cp = sp->chars;
+	memcpy(cp, stdname, stdlen);
+	cp += stdlen;
+	*cp++ = '\0';
+	if (dstlen != 0) {
+		memcpy(cp, dstname, dstlen);
+		*(cp + dstlen) = '\0';
+	}
+	return true;
 }
 
 static void
-gmtload(struct state * const sp)
+gmtload(struct state *const sp)
 {
-    if (tzload(gmt, sp, TRUE) != 0)
-        (void) tzparse(gmt, sp, TRUE);
+	if (tzload(gmt, sp, true) != 0)
+		tzparse(gmt, sp, true);
 }
 
-#ifndef STD_INSPIRED
-/*
-** A non-static declaration of tzsetwall in a system header file
-** may cause a warning about this upcoming static declaration...
-*/
-static
-#endif /* !defined STD_INSPIRED */
+/* Initialize *SP to a value appropriate for the TZ setting NAME.
+   Return 0 on success, an errno value on failure.  */
+static int
+zoneinit(struct state *sp, char const *name)
+{
+  if (name && ! name[0]) {
+    /*
+    ** User wants it fast rather than right.
+    */
+    sp->leapcnt = 0;		/* so, we're off a little */
+    sp->timecnt = 0;
+    sp->typecnt = 0;
+    sp->charcnt = 0;
+    sp->goback = sp->goahead = false;
+    init_ttinfo(&sp->ttis[0], 0, false, 0);
+    strcpy(sp->chars, gmt);
+    sp->defaulttype = 0;
+    return 0;
+  } else {
+    int err = tzload(name, sp, true);
+    if (err != 0 && name && name[0] != ':' && tzparse(name, sp, false))
+      err = 0;
+    if (err == 0)
+      scrub_abbrs(sp);
+    return err;
+  }
+}
+
+static void
+tzsetlcl(char const *name)
+{
+  struct state *sp = lclptr;
+  int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
+  if (lcl < 0
+      ? lcl_is_set < 0
+      : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
+    return;
+#ifdef ALL_STATE
+  if (! sp)
+    lclptr = sp = malloc(sizeof *lclptr);
+#endif /* defined ALL_STATE */
+  if (sp) {
+    if (zoneinit(sp, name) != 0)
+      zoneinit(sp, "");
+    if (0 < lcl)
+      strcpy(lcl_TZname, name);
+  }
+  settzname();
+  lcl_is_set = lcl;
+}
+
+#ifdef STD_INSPIRED
 void
 tzsetwall(void)
 {
-    if (lcl_is_set < 0)
-        return;
-    lcl_is_set = -1;
-
-#ifdef ALL_STATE
-    if (lclptr == NULL) {
-        lclptr = malloc(sizeof *lclptr);
-        if (lclptr == NULL) {
-            settzname();    /* all we can do */
-            return;
-        }
-    }
-#endif /* defined ALL_STATE */
-    if (tzload(NULL, lclptr, TRUE) != 0)
-        gmtload(lclptr);
-    settzname();
+  if (lock() != 0)
+    return;
+  tzsetlcl(NULL);
+  unlock();
 }
+#endif
 
-#include <sys/system_properties.h> // For __system_property_get.
+#if defined(__ANDROID__)
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h> // For __system_property_serial.
+#endif
 
 static void
-tzset_locked(void)
+tzset_unlocked(void)
 {
-    register const char * name;
+#if defined(__ANDROID__)
+  // The TZ environment variable is meant to override the system-wide setting.
+  const char * name = getenv("TZ");
 
-    name = getenv("TZ");
+  // If that's not set, look at the "persist.sys.timezone" system property.
+  if (name == NULL) {
+    static const prop_info *pi;
 
-    // try the "persist.sys.timezone" system property first
-    static char buf[PROP_VALUE_MAX];
-    if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) {
+    if (!pi) {
+      pi = __system_property_find("persist.sys.timezone");
+    }
+    if (pi) {
+      static char buf[PROP_VALUE_MAX];
+      static uint32_t s = -1;
+      static bool ok = false;
+      uint32_t serial = __system_property_serial(pi);
+      if (serial != s) {
+        ok = __system_property_read(pi, 0, buf) > 0;
+        s = serial;
+      }
+      if (ok) {
         name = buf;
+      }
     }
+  }
 
-    if (name == NULL) {
-        tzsetwall();
-        return;
-    }
+  // If that's not available (because you're running AOSP on a WiFi-only
+  // device, say), fall back to GMT.
+  if (name == NULL) name = gmt;
 
-    if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
-        return;
-    lcl_is_set = strlen(name) < sizeof lcl_TZname;
-    if (lcl_is_set)
-        (void) strcpy(lcl_TZname, name);
-
-#ifdef ALL_STATE
-    if (lclptr == NULL) {
-        lclptr = malloc(sizeof *lclptr);
-        if (lclptr == NULL) {
-            settzname();    /* all we can do */
-            return;
-        }
-    }
-#endif /* defined ALL_STATE */
-    if (*name == '\0') {
-        /*
-        ** User wants it fast rather than right.
-        */
-        lclptr->leapcnt = 0;        /* so, we're off a little */
-        lclptr->timecnt = 0;
-        lclptr->typecnt = 0;
-        lclptr->ttis[0].tt_isdst = 0;
-        lclptr->ttis[0].tt_gmtoff = 0;
-        lclptr->ttis[0].tt_abbrind = 0;
-        (void) strcpy(lclptr->chars, gmt);
-        lclptr->defaulttype = 0;
-    } else if (tzload(name, lclptr, TRUE) != 0)
-        if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
-            (void) gmtload(lclptr);
-    settzname();
+  tzsetlcl(name);
+#else
+  tzsetlcl(getenv("TZ"));
+#endif
 }
 
 void
 tzset(void)
 {
-    _tzLock();
-    tzset_locked();
-    _tzUnlock();
+  if (lock() != 0)
+    return;
+  tzset_unlocked();
+  unlock();
+}
+
+static void
+gmtcheck(void)
+{
+  static bool gmt_is_set;
+  if (lock() != 0)
+    return;
+  if (! gmt_is_set) {
+#ifdef ALL_STATE
+    gmtptr = malloc(sizeof *gmtptr);
+#endif
+    if (gmtptr)
+      gmtload(gmtptr);
+    gmt_is_set = true;
+  }
+  unlock();
+}
+
+#if NETBSD_INSPIRED
+
+timezone_t
+tzalloc(char const *name)
+{
+  timezone_t sp = malloc(sizeof *sp);
+  if (sp) {
+    int err = zoneinit(sp, name);
+    if (err != 0) {
+      free(sp);
+      errno = err;
+      return NULL;
+    }
+  }
+  return sp;
+}
+
+void
+tzfree(timezone_t sp)
+{
+  free(sp);
 }
 
 /*
+** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
+** ctime_r are obsolescent and have potential security problems that
+** ctime_rz would share.  Callers can instead use localtime_rz + strftime.
+**
+** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
+** in zones with three or more time zone abbreviations.
+** Callers can instead use localtime_rz + strftime.
+*/
+
+#endif
+
+/*
 ** The easy way to behave "as if no library function calls" localtime
-** is to not call it--so we drop its guts into "localsub", which can be
-** freely called. (And no, the PANS doesn't require the above behavior--
+** is to not call it, so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior,
 ** but it *is* desirable.)
 **
-** The unused offset argument is for the benefit of mktime variants.
+** If successful and SETNAME is nonzero,
+** set the applicable parts of tzname, timezone and altzone;
+** however, it's OK to omit this step if the time zone is POSIX-compatible,
+** since in that case tzset should have already done this step correctly.
+** SETNAME's type is intfast32_t for compatibility with gmtsub,
+** but it is actually a boolean and its value should be 0 or 1.
 */
 
 /*ARGSUSED*/
 static struct tm *
-localsub(const time_t * const timep, const int_fast32_t offset,
-         struct tm * const tmp, struct state * sp) // android-changed: added sp.
+localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
+	 struct tm *const tmp)
 {
-    register const struct ttinfo * ttisp;
-    register int         i;
-    register struct tm * result;
-    const time_t         t = *timep;
+	register const struct ttinfo *	ttisp;
+	register int			i;
+	register struct tm *		result;
+	const time_t			t = *timep;
 
-    // BEGIN android-changed: support user-supplied sp.
-    if (sp == NULL) {
-        sp = lclptr;
-    }
-    // END android-changed
-    if (sp == NULL)
-        return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
-    if ((sp->goback && t < sp->ats[0]) ||
-        (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
-            time_t          newt = t;
-            register time_t seconds;
-            register time_t years;
+	if (sp == NULL) {
+	  /* Don't bother to set tzname etc.; tzset has already done it.  */
+	  return gmtsub(gmtptr, timep, 0, tmp);
+	}
+	if ((sp->goback && t < sp->ats[0]) ||
+		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+			time_t			newt = t;
+			register time_t		seconds;
+			register time_t		years;
 
-            if (t < sp->ats[0])
-                seconds = sp->ats[0] - t;
-            else    seconds = t - sp->ats[sp->timecnt - 1];
-            --seconds;
-            years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
-            seconds = years * AVGSECSPERYEAR;
-            if (t < sp->ats[0])
-                newt += seconds;
-            else    newt -= seconds;
-            if (newt < sp->ats[0] ||
-                newt > sp->ats[sp->timecnt - 1])
-                    return NULL;    /* "cannot happen" */
-            result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
-            if (result == tmp) {
-                register time_t newy;
+			if (t < sp->ats[0])
+				seconds = sp->ats[0] - t;
+			else	seconds = t - sp->ats[sp->timecnt - 1];
+			--seconds;
+			years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
+			seconds = years * AVGSECSPERYEAR;
+			if (t < sp->ats[0])
+				newt += seconds;
+			else	newt -= seconds;
+			if (newt < sp->ats[0] ||
+				newt > sp->ats[sp->timecnt - 1])
+					return NULL;	/* "cannot happen" */
+			result = localsub(sp, &newt, setname, tmp);
+			if (result) {
+				register int_fast64_t newy;
 
-                newy = tmp->tm_year;
-                if (t < sp->ats[0])
-                    newy -= years;
-                else    newy += years;
-                tmp->tm_year = newy;
-                if (tmp->tm_year != newy)
-                    return NULL;
-            }
-            return result;
-    }
-    if (sp->timecnt == 0 || t < sp->ats[0]) {
-        i = sp->defaulttype;
-    } else {
-        register int lo = 1;
-        register int hi = sp->timecnt;
+				newy = result->tm_year;
+				if (t < sp->ats[0])
+					newy -= years;
+				else	newy += years;
+				if (! (INT_MIN <= newy && newy <= INT_MAX))
+					return NULL;
+				result->tm_year = newy;
+			}
+			return result;
+	}
+	if (sp->timecnt == 0 || t < sp->ats[0]) {
+		i = sp->defaulttype;
+	} else {
+		register int	lo = 1;
+		register int	hi = sp->timecnt;
 
-        while (lo < hi) {
-            register int    mid = (lo + hi) >> 1;
+		while (lo < hi) {
+			register int	mid = (lo + hi) >> 1;
 
-            if (t < sp->ats[mid])
-                hi = mid;
-            else    lo = mid + 1;
-        }
-        i = (int) sp->types[lo - 1];
-    }
-    ttisp = &sp->ttis[i];
-    /*
-    ** To get (wrong) behavior that's compatible with System V Release 2.0
-    ** you'd replace the statement below with
-    **  t += ttisp->tt_gmtoff;
-    **  timesub(&t, 0L, sp, tmp);
-    */
-    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
-    tmp->tm_isdst = ttisp->tt_isdst;
-    tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+			if (t < sp->ats[mid])
+				hi = mid;
+			else	lo = mid + 1;
+		}
+		i = (int) sp->types[lo - 1];
+	}
+	ttisp = &sp->ttis[i];
+	/*
+	** To get (wrong) behavior that's compatible with System V Release 2.0
+	** you'd replace the statement below with
+	**	t += ttisp->tt_gmtoff;
+	**	timesub(&t, 0L, sp, tmp);
+	*/
+	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+	if (result) {
+	  result->tm_isdst = ttisp->tt_isdst;
 #ifdef TM_ZONE
-    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+	  result->TM_ZONE = (char *) &sp->chars[ttisp->tt_abbrind];
 #endif /* defined TM_ZONE */
-    return result;
+	  if (setname)
+	    update_tzname_etc(sp, ttisp);
+	}
+	return result;
+}
+
+#if NETBSD_INSPIRED
+
+struct tm *
+localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
+{
+  return localsub(sp, timep, 0, tmp);
+}
+
+#endif
+
+static struct tm *
+localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
+{
+  int err = lock();
+  if (err) {
+    errno = err;
+    return NULL;
+  }
+  if (setname || !lcl_is_set)
+    tzset_unlocked();
+  tmp = localsub(lclptr, timep, setname, tmp);
+  unlock();
+  return tmp;
 }
 
 struct tm *
-localtime(const time_t * const timep)
+localtime(const time_t *timep)
 {
-    return localtime_r(timep, &tmGlobal);
+  return localtime_tzset(timep, &tm, true);
 }
 
-/*
-** Re-entrant version of localtime.
-*/
-
 struct tm *
-localtime_r(const time_t * const timep, struct tm * tmp)
+localtime_r(const time_t *timep, struct tm *tmp)
 {
-    struct tm* result;
-
-    _tzLock();
-    tzset_locked();
-    result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+  return localtime_tzset(timep, tmp, false);
 }
 
 /*
@@ -1389,37 +1548,22 @@
 */
 
 static struct tm *
-gmtsub(const time_t * const timep, const int_fast32_t offset,
-       struct tm *const tmp, struct state * sp __unused) // android-changed: added sp.
+gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
+       struct tm *tmp)
 {
-    register struct tm * result;
+	register struct tm *	result;
 
-    if (!gmt_is_set) {
-#ifdef ALL_STATE
-        gmtptr = malloc(sizeof *gmtptr);
-        gmt_is_set = gmtptr != NULL;
-#else
-        gmt_is_set = TRUE;
-#endif /* defined ALL_STATE */
-        if (gmt_is_set)
-            gmtload(gmtptr);
-    }
-    result = timesub(timep, offset, gmtptr, tmp);
+	result = timesub(timep, offset, gmtptr, tmp);
 #ifdef TM_ZONE
-    /*
-    ** Could get fancy here and deliver something such as
-    ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
-    ** but this is no time for a treasure hunt.
-    */
-    tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt;
+	/*
+	** Could get fancy here and deliver something such as
+	** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
+	** but this is no time for a treasure hunt.
+	*/
+	tmp->TM_ZONE = ((char *)
+			(offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
 #endif /* defined TM_ZONE */
-    return result;
-}
-
-struct tm *
-gmtime(const time_t * const timep)
-{
-    return gmtime_r(timep, &tmGlobal);
+	return result;
 }
 
 /*
@@ -1427,23 +1571,25 @@
 */
 
 struct tm *
-gmtime_r(const time_t * const timep, struct tm * tmp)
+gmtime_r(const time_t *timep, struct tm *tmp)
 {
-    struct tm* result;
+  gmtcheck();
+  return gmtsub(gmtptr, timep, 0, tmp);
+}
 
-    _tzLock();
-    result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+struct tm *
+gmtime(const time_t *timep)
+{
+  return gmtime_r(timep, &tm);
 }
 
 #ifdef STD_INSPIRED
 
 struct tm *
-offtime(const time_t *const timep, const long offset)
+offtime(const time_t *timep, long offset)
 {
-    return gmtsub(timep, offset, &tmGlobal, NULL); // android-changed: extra parameter.
+  gmtcheck();
+  return gmtsub(gmtptr, timep, offset, &tm);
 }
 
 #endif /* defined STD_INSPIRED */
@@ -1453,597 +1599,610 @@
 ** where, to make the math easy, the answer for year zero is defined as zero.
 */
 
-static int
+static int ATTRIBUTE_PURE
 leaps_thru_end_of(register const int y)
 {
-    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
-        -(leaps_thru_end_of(-(y + 1)) + 1);
+	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+		-(leaps_thru_end_of(-(y + 1)) + 1);
 }
 
 static struct tm *
-timesub(const time_t *const timep, const int_fast32_t offset,
-        register const struct state *const sp,
-        register struct tm *const tmp)
+timesub(const time_t *timep, int_fast32_t offset,
+	const struct state *sp, struct tm *tmp)
 {
-    register const struct lsinfo * lp;
-    register time_t       tdays;
-    register int          idays;  /* unsigned would be so 2003 */
-    register int_fast64_t rem;
-    int                   y;
-    register const int *  ip;
-    register int_fast64_t corr;
-    register int          hit;
-    register int          i;
+	register const struct lsinfo *	lp;
+	register time_t			tdays;
+	register int			idays;	/* unsigned would be so 2003 */
+	register int_fast64_t		rem;
+	int				y;
+	register const int *		ip;
+	register int_fast64_t		corr;
+	register bool			hit;
+	register int			i;
 
-    corr = 0;
-    hit = 0;
-    i = (sp == NULL) ? 0 : sp->leapcnt;
-    while (--i >= 0) {
-        lp = &sp->lsis[i];
-        if (*timep >= lp->ls_trans) {
-            if (*timep == lp->ls_trans) {
-                hit = ((i == 0 && lp->ls_corr > 0) ||
-                    lp->ls_corr > sp->lsis[i - 1].ls_corr);
-                if (hit)
-                    while (i > 0 &&
-                        sp->lsis[i].ls_trans ==
-                        sp->lsis[i - 1].ls_trans + 1 &&
-                        sp->lsis[i].ls_corr ==
-                        sp->lsis[i - 1].ls_corr + 1) {
-                            ++hit;
-                            --i;
-                    }
-            }
-            corr = lp->ls_corr;
-            break;
-        }
-    }
-    y = EPOCH_YEAR;
-    tdays = *timep / SECSPERDAY;
-    rem = *timep - tdays * SECSPERDAY;
-    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
-        int     newy;
-        register time_t tdelta;
-        register int    idelta;
-        register int    leapdays;
+	corr = 0;
+	hit = false;
+	i = (sp == NULL) ? 0 : sp->leapcnt;
+	while (--i >= 0) {
+		lp = &sp->lsis[i];
+		if (*timep >= lp->ls_trans) {
+			if (*timep == lp->ls_trans) {
+				hit = ((i == 0 && lp->ls_corr > 0) ||
+					lp->ls_corr > sp->lsis[i - 1].ls_corr);
+				if (hit)
+					while (i > 0 &&
+						sp->lsis[i].ls_trans ==
+						sp->lsis[i - 1].ls_trans + 1 &&
+						sp->lsis[i].ls_corr ==
+						sp->lsis[i - 1].ls_corr + 1) {
+							++hit;
+							--i;
+					}
+			}
+			corr = lp->ls_corr;
+			break;
+		}
+	}
+	y = EPOCH_YEAR;
+	tdays = *timep / SECSPERDAY;
+	rem = *timep % SECSPERDAY;
+	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
+		int		newy;
+		register time_t	tdelta;
+		register int	idelta;
+		register int	leapdays;
 
-        tdelta = tdays / DAYSPERLYEAR;
-        if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
-               && tdelta <= INT_MAX))
-                return NULL;
-        idelta = tdelta;
-        if (idelta == 0)
-            idelta = (tdays < 0) ? -1 : 1;
-        newy = y;
-        if (increment_overflow(&newy, idelta))
-            return NULL;
-        leapdays = leaps_thru_end_of(newy - 1) -
-            leaps_thru_end_of(y - 1);
-        tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
-        tdays -= leapdays;
-        y = newy;
-    }
-    {
-        register int_fast32_t   seconds;
-
-        seconds = tdays * SECSPERDAY;
-        tdays = seconds / SECSPERDAY;
-        rem += seconds - tdays * SECSPERDAY;
-    }
-    /*
-    ** Given the range, we can now fearlessly cast...
-    */
-    idays = tdays;
-    rem += offset - corr;
-    while (rem < 0) {
-        rem += SECSPERDAY;
-        --idays;
-    }
-    while (rem >= SECSPERDAY) {
-        rem -= SECSPERDAY;
-        ++idays;
-    }
-    while (idays < 0) {
-        if (increment_overflow(&y, -1))
-            return NULL;
-        idays += year_lengths[isleap(y)];
-    }
-    while (idays >= year_lengths[isleap(y)]) {
-        idays -= year_lengths[isleap(y)];
-        if (increment_overflow(&y, 1))
-            return NULL;
-    }
-    tmp->tm_year = y;
-    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
-        return NULL;
-    tmp->tm_yday = idays;
-    /*
-    ** The "extra" mods below avoid overflow problems.
-    */
-    tmp->tm_wday = EPOCH_WDAY +
-        ((y - EPOCH_YEAR) % DAYSPERWEEK) *
-        (DAYSPERNYEAR % DAYSPERWEEK) +
-        leaps_thru_end_of(y - 1) -
-        leaps_thru_end_of(EPOCH_YEAR - 1) +
-        idays;
-    tmp->tm_wday %= DAYSPERWEEK;
-    if (tmp->tm_wday < 0)
-        tmp->tm_wday += DAYSPERWEEK;
-    tmp->tm_hour = (int) (rem / SECSPERHOUR);
-    rem %= SECSPERHOUR;
-    tmp->tm_min = (int) (rem / SECSPERMIN);
-    /*
-    ** A positive leap second requires a special
-    ** representation. This uses "... ??:59:60" et seq.
-    */
-    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
-    ip = mon_lengths[isleap(y)];
-    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
-        idays -= ip[tmp->tm_mon];
-    tmp->tm_mday = (int) (idays + 1);
-    tmp->tm_isdst = 0;
+		tdelta = tdays / DAYSPERLYEAR;
+		if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
+		       && tdelta <= INT_MAX))
+		  goto out_of_range;
+		idelta = tdelta;
+		if (idelta == 0)
+			idelta = (tdays < 0) ? -1 : 1;
+		newy = y;
+		if (increment_overflow(&newy, idelta))
+		  goto out_of_range;
+		leapdays = leaps_thru_end_of(newy - 1) -
+			leaps_thru_end_of(y - 1);
+		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
+		tdays -= leapdays;
+		y = newy;
+	}
+	/*
+	** Given the range, we can now fearlessly cast...
+	*/
+	idays = tdays;
+	rem += offset - corr;
+	while (rem < 0) {
+		rem += SECSPERDAY;
+		--idays;
+	}
+	while (rem >= SECSPERDAY) {
+		rem -= SECSPERDAY;
+		++idays;
+	}
+	while (idays < 0) {
+		if (increment_overflow(&y, -1))
+		  goto out_of_range;
+		idays += year_lengths[isleap(y)];
+	}
+	while (idays >= year_lengths[isleap(y)]) {
+		idays -= year_lengths[isleap(y)];
+		if (increment_overflow(&y, 1))
+		  goto out_of_range;
+	}
+	tmp->tm_year = y;
+	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+	  goto out_of_range;
+	tmp->tm_yday = idays;
+	/*
+	** The "extra" mods below avoid overflow problems.
+	*/
+	tmp->tm_wday = EPOCH_WDAY +
+		((y - EPOCH_YEAR) % DAYSPERWEEK) *
+		(DAYSPERNYEAR % DAYSPERWEEK) +
+		leaps_thru_end_of(y - 1) -
+		leaps_thru_end_of(EPOCH_YEAR - 1) +
+		idays;
+	tmp->tm_wday %= DAYSPERWEEK;
+	if (tmp->tm_wday < 0)
+		tmp->tm_wday += DAYSPERWEEK;
+	tmp->tm_hour = (int) (rem / SECSPERHOUR);
+	rem %= SECSPERHOUR;
+	tmp->tm_min = (int) (rem / SECSPERMIN);
+	/*
+	** A positive leap second requires a special
+	** representation. This uses "... ??:59:60" et seq.
+	*/
+	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+	ip = mon_lengths[isleap(y)];
+	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
+		idays -= ip[tmp->tm_mon];
+	tmp->tm_mday = (int) (idays + 1);
+	tmp->tm_isdst = 0;
 #ifdef TM_GMTOFF
-    tmp->TM_GMTOFF = offset;
+	tmp->TM_GMTOFF = offset;
 #endif /* defined TM_GMTOFF */
-    return tmp;
+	return tmp;
+
+ out_of_range:
+	errno = EOVERFLOW;
+	return NULL;
 }
 
 char *
-ctime(const time_t * const timep)
+ctime(const time_t *timep)
 {
 /*
 ** Section 4.12.3.2 of X3.159-1989 requires that
-**  The ctime function converts the calendar time pointed to by timer
-**  to local time in the form of a string. It is equivalent to
-**      asctime(localtime(timer))
+**	The ctime function converts the calendar time pointed to by timer
+**	to local time in the form of a string. It is equivalent to
+**		asctime(localtime(timer))
 */
-    return asctime(localtime(timep));
+  struct tm *tmp = localtime(timep);
+  return tmp ? asctime(tmp) : NULL;
 }
 
 char *
-ctime_r(const time_t * const timep, char * buf)
+ctime_r(const time_t *timep, char *buf)
 {
-    struct tm   mytm;
-
-    return asctime_r(localtime_r(timep, &mytm), buf);
+  struct tm mytm;
+  struct tm *tmp = localtime_r(timep, &mytm);
+  return tmp ? asctime_r(tmp, buf) : NULL;
 }
 
 /*
 ** Adapted from code provided by Robert Elz, who writes:
-**  The "best" way to do mktime I think is based on an idea of Bob
-**  Kridle's (so its said...) from a long time ago.
-**  It does a binary search of the time_t space. Since time_t's are
-**  just 32 bits, its a max of 32 iterations (even at 64 bits it
-**  would still be very reasonable).
+**	The "best" way to do mktime I think is based on an idea of Bob
+**	Kridle's (so its said...) from a long time ago.
+**	It does a binary search of the time_t space. Since time_t's are
+**	just 32 bits, its a max of 32 iterations (even at 64 bits it
+**	would still be very reasonable).
 */
 
 #ifndef WRONG
-#define WRONG   (-1)
+#define WRONG	(-1)
 #endif /* !defined WRONG */
 
 /*
 ** Normalize logic courtesy Paul Eggert.
 */
 
-static int
-increment_overflow(int *const ip, int j)
+static bool
+increment_overflow(int *ip, int j)
 {
-    register int const i = *ip;
+	register int const	i = *ip;
 
-    /*
-    ** If i >= 0 there can only be overflow if i + j > INT_MAX
-    ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
-    ** If i < 0 there can only be overflow if i + j < INT_MIN
-    ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
-    */
-    if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
-        return TRUE;
-    *ip += j;
-    return FALSE;
+	/*
+	** If i >= 0 there can only be overflow if i + j > INT_MAX
+	** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
+	** If i < 0 there can only be overflow if i + j < INT_MIN
+	** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
+	*/
+	if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
+		return true;
+	*ip += j;
+	return false;
 }
 
-static int
+static bool
 increment_overflow32(int_fast32_t *const lp, int const m)
 {
-    register int_fast32_t const l = *lp;
+	register int_fast32_t const	l = *lp;
 
-    if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
-        return TRUE;
-    *lp += m;
-    return FALSE;
+	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
+		return true;
+	*lp += m;
+	return false;
 }
 
-static int
+static bool
 increment_overflow_time(time_t *tp, int_fast32_t j)
 {
-    /*
-    ** This is like
-    ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
-    ** except that it does the right thing even if *tp + j would overflow.
-    */
-    if (! (j < 0
-           ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
-           : *tp <= time_t_max - j))
-        return TRUE;
-    *tp += j;
-    return FALSE;
+	/*
+	** This is like
+	** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
+	** except that it does the right thing even if *tp + j would overflow.
+	*/
+	if (! (j < 0
+	       ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
+	       : *tp <= time_t_max - j))
+		return true;
+	*tp += j;
+	return false;
 }
 
-static int
+static bool
 normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
 {
-    register int tensdelta;
+	register int	tensdelta;
 
-    tensdelta = (*unitsptr >= 0) ?
-        (*unitsptr / base) :
-        (-1 - (-1 - *unitsptr) / base);
-    *unitsptr -= tensdelta * base;
-    return increment_overflow(tensptr, tensdelta);
+	tensdelta = (*unitsptr >= 0) ?
+		(*unitsptr / base) :
+		(-1 - (-1 - *unitsptr) / base);
+	*unitsptr -= tensdelta * base;
+	return increment_overflow(tensptr, tensdelta);
+}
+
+static bool
+normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
+{
+	register int	tensdelta;
+
+	tensdelta = (*unitsptr >= 0) ?
+		(*unitsptr / base) :
+		(-1 - (-1 - *unitsptr) / base);
+	*unitsptr -= tensdelta * base;
+	return increment_overflow32(tensptr, tensdelta);
 }
 
 static int
-normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
-             const int base)
+tmcomp(register const struct tm *const atmp,
+       register const struct tm *const btmp)
 {
-    register int tensdelta;
+	register int	result;
 
-    tensdelta = (*unitsptr >= 0) ?
-        (*unitsptr / base) :
-        (-1 - (-1 - *unitsptr) / base);
-    *unitsptr -= tensdelta * base;
-    return increment_overflow32(tensptr, tensdelta);
-}
-
-static int
-tmcomp(register const struct tm * const atmp,
-       register const struct tm * const btmp)
-{
-    register int result;
-
-    if (atmp->tm_year != btmp->tm_year)
-        return atmp->tm_year < btmp->tm_year ? -1 : 1;
-    if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
-        (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
-        (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
-        (result = (atmp->tm_min - btmp->tm_min)) == 0)
-            result = atmp->tm_sec - btmp->tm_sec;
-    return result;
+	if (atmp->tm_year != btmp->tm_year)
+		return atmp->tm_year < btmp->tm_year ? -1 : 1;
+	if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+		(result = (atmp->tm_min - btmp->tm_min)) == 0)
+			result = atmp->tm_sec - btmp->tm_sec;
+	return result;
 }
 
 static time_t
-time2sub(struct tm * const tmp,
-         struct tm *(*const funcp)(const time_t*, int_fast32_t, struct tm*, struct state*),
-         const int_fast32_t offset,
-         int * const okayp,
-         const int do_norm_secs, struct state * sp) // android-changed: added sp
+time2sub(struct tm *const tmp,
+	 struct tm *(*funcp)(struct state const *, time_t const *,
+			     int_fast32_t, struct tm *),
+	 struct state const *sp,
+	 const int_fast32_t offset,
+	 bool *okayp,
+	 bool do_norm_secs)
 {
-    register int          dir;
-    register int          i, j;
-    register int          saved_seconds;
-    register int_fast32_t li;
-    register time_t       lo;
-    register time_t       hi;
-    int_fast32_t          y;
-    time_t                newt;
-    time_t                t;
-    struct tm             yourtm, mytm;
+	register int			dir;
+	register int			i, j;
+	register int			saved_seconds;
+	register int_fast32_t		li;
+	register time_t			lo;
+	register time_t			hi;
+	int_fast32_t			y;
+	time_t				newt;
+	time_t				t;
+	struct tm			yourtm, mytm;
 
-    *okayp = FALSE;
-    yourtm = *tmp;
-    if (do_norm_secs) {
-        if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
-            SECSPERMIN))
-                return WRONG;
-    }
-    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
-        return WRONG;
-    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
-        return WRONG;
-    y = yourtm.tm_year;
-    if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
-        return WRONG;
-    /*
-    ** Turn y into an actual year number for now.
-    ** It is converted back to an offset from TM_YEAR_BASE later.
-    */
-    if (increment_overflow32(&y, TM_YEAR_BASE))
-        return WRONG;
-    while (yourtm.tm_mday <= 0) {
-        if (increment_overflow32(&y, -1))
-            return WRONG;
-        li = y + (1 < yourtm.tm_mon);
-        yourtm.tm_mday += year_lengths[isleap(li)];
-    }
-    while (yourtm.tm_mday > DAYSPERLYEAR) {
-        li = y + (1 < yourtm.tm_mon);
-        yourtm.tm_mday -= year_lengths[isleap(li)];
-        if (increment_overflow32(&y, 1))
-            return WRONG;
-    }
-    for ( ; ; ) {
-        i = mon_lengths[isleap(y)][yourtm.tm_mon];
-        if (yourtm.tm_mday <= i)
-            break;
-        yourtm.tm_mday -= i;
-        if (++yourtm.tm_mon >= MONSPERYEAR) {
-            yourtm.tm_mon = 0;
-            if (increment_overflow32(&y, 1))
-                return WRONG;
-        }
-    }
-    if (increment_overflow32(&y, -TM_YEAR_BASE))
-        return WRONG;
-    yourtm.tm_year = y;
-    if (yourtm.tm_year != y)
-        return WRONG;
-    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
-        saved_seconds = 0;
-    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
-        /*
-        ** We can't set tm_sec to 0, because that might push the
-        ** time below the minimum representable time.
-        ** Set tm_sec to 59 instead.
-        ** This assumes that the minimum representable time is
-        ** not in the same minute that a leap second was deleted from,
-        ** which is a safer assumption than using 58 would be.
-        */
-        if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
-            return WRONG;
-        saved_seconds = yourtm.tm_sec;
-        yourtm.tm_sec = SECSPERMIN - 1;
-    } else {
-        saved_seconds = yourtm.tm_sec;
-        yourtm.tm_sec = 0;
-    }
-    /*
-    ** Do a binary search (this works whatever time_t's type is).
-    */
-    if (!TYPE_SIGNED(time_t)) {
-        lo = 0;
-        hi = lo - 1;
-    } else {
-        lo = 1;
-        for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
-            lo *= 2;
-        hi = -(lo + 1);
-    }
-    for ( ; ; ) {
-        t = lo / 2 + hi / 2;
-        if (t < lo)
-            t = lo;
-        else if (t > hi)
-            t = hi;
-        if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
-            /*
-            ** Assume that t is too extreme to be represented in
-            ** a struct tm; arrange things so that it is less
-            ** extreme on the next pass.
-            */
-            dir = (t > 0) ? 1 : -1;
-        } else  dir = tmcomp(&mytm, &yourtm);
-        if (dir != 0) {
-            if (t == lo) {
-                if (t == time_t_max)
-                    return WRONG;
-                ++t;
-                ++lo;
-            } else if (t == hi) {
-                if (t == time_t_min)
-                    return WRONG;
-                --t;
-                --hi;
-            }
-            if (lo > hi)
-                return WRONG;
-            if (dir > 0)
-                hi = t;
-            else    lo = t;
-            continue;
-        }
-        if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
-            break;
-        /*
-        ** Right time, wrong type.
-        ** Hunt for right time, right type.
-        ** It's okay to guess wrong since the guess
-        ** gets checked.
-        */
-        // BEGIN android-changed: support user-supplied sp
-        if (sp == NULL) {
-            sp = (struct state *)
-                ((funcp == localsub) ? lclptr : gmtptr);
-        }
-        // END android-changed
-        if (sp == NULL)
-            return WRONG;
-        for (i = sp->typecnt - 1; i >= 0; --i) {
-            if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
-                continue;
-            for (j = sp->typecnt - 1; j >= 0; --j) {
-                if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
-                    continue;
-                newt = t + sp->ttis[j].tt_gmtoff -
-                    sp->ttis[i].tt_gmtoff;
-                if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
-                    continue;
-                if (tmcomp(&mytm, &yourtm) != 0)
-                    continue;
-                if (mytm.tm_isdst != yourtm.tm_isdst)
-                    continue;
-                /*
-                ** We have a match.
-                */
-                t = newt;
-                goto label;
-            }
-        }
-        return WRONG;
-    }
+	*okayp = false;
+	yourtm = *tmp;
+	if (do_norm_secs) {
+		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+			SECSPERMIN))
+				return WRONG;
+	}
+	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+		return WRONG;
+	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+		return WRONG;
+	y = yourtm.tm_year;
+	if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
+		return WRONG;
+	/*
+	** Turn y into an actual year number for now.
+	** It is converted back to an offset from TM_YEAR_BASE later.
+	*/
+	if (increment_overflow32(&y, TM_YEAR_BASE))
+		return WRONG;
+	while (yourtm.tm_mday <= 0) {
+		if (increment_overflow32(&y, -1))
+			return WRONG;
+		li = y + (1 < yourtm.tm_mon);
+		yourtm.tm_mday += year_lengths[isleap(li)];
+	}
+	while (yourtm.tm_mday > DAYSPERLYEAR) {
+		li = y + (1 < yourtm.tm_mon);
+		yourtm.tm_mday -= year_lengths[isleap(li)];
+		if (increment_overflow32(&y, 1))
+			return WRONG;
+	}
+	for ( ; ; ) {
+		i = mon_lengths[isleap(y)][yourtm.tm_mon];
+		if (yourtm.tm_mday <= i)
+			break;
+		yourtm.tm_mday -= i;
+		if (++yourtm.tm_mon >= MONSPERYEAR) {
+			yourtm.tm_mon = 0;
+			if (increment_overflow32(&y, 1))
+				return WRONG;
+		}
+	}
+	if (increment_overflow32(&y, -TM_YEAR_BASE))
+		return WRONG;
+	if (! (INT_MIN <= y && y <= INT_MAX))
+		return WRONG;
+	yourtm.tm_year = y;
+	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+		saved_seconds = 0;
+	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
+		/*
+		** We can't set tm_sec to 0, because that might push the
+		** time below the minimum representable time.
+		** Set tm_sec to 59 instead.
+		** This assumes that the minimum representable time is
+		** not in the same minute that a leap second was deleted from,
+		** which is a safer assumption than using 58 would be.
+		*/
+		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+			return WRONG;
+		saved_seconds = yourtm.tm_sec;
+		yourtm.tm_sec = SECSPERMIN - 1;
+	} else {
+		saved_seconds = yourtm.tm_sec;
+		yourtm.tm_sec = 0;
+	}
+	/*
+	** Do a binary search (this works whatever time_t's type is).
+	*/
+	lo = time_t_min;
+	hi = time_t_max;
+	for ( ; ; ) {
+		t = lo / 2 + hi / 2;
+		if (t < lo)
+			t = lo;
+		else if (t > hi)
+			t = hi;
+		if (! funcp(sp, &t, offset, &mytm)) {
+			/*
+			** Assume that t is too extreme to be represented in
+			** a struct tm; arrange things so that it is less
+			** extreme on the next pass.
+			*/
+			dir = (t > 0) ? 1 : -1;
+		} else	dir = tmcomp(&mytm, &yourtm);
+		if (dir != 0) {
+			if (t == lo) {
+				if (t == time_t_max)
+					return WRONG;
+				++t;
+				++lo;
+			} else if (t == hi) {
+				if (t == time_t_min)
+					return WRONG;
+				--t;
+				--hi;
+			}
+			if (lo > hi)
+				return WRONG;
+			if (dir > 0)
+				hi = t;
+			else	lo = t;
+			continue;
+		}
+#if defined TM_GMTOFF && ! UNINIT_TRAP
+		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
+		    && (yourtm.TM_GMTOFF < 0
+			? (-SECSPERDAY <= yourtm.TM_GMTOFF
+			   && (mytm.TM_GMTOFF <=
+			       (SMALLEST (INT_FAST32_MAX, LONG_MAX)
+				+ yourtm.TM_GMTOFF)))
+			: (yourtm.TM_GMTOFF <= SECSPERDAY
+			   && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
+				+ yourtm.TM_GMTOFF)
+			       <= mytm.TM_GMTOFF)))) {
+		  /* MYTM matches YOURTM except with the wrong UTC offset.
+		     YOURTM.TM_GMTOFF is plausible, so try it instead.
+		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
+		     since the guess gets checked.  */
+		  time_t altt = t;
+		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
+		  if (!increment_overflow_time(&altt, diff)) {
+		    struct tm alttm;
+		    if (funcp(sp, &altt, offset, &alttm)
+			&& alttm.tm_isdst == mytm.tm_isdst
+			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
+			&& tmcomp(&alttm, &yourtm) == 0) {
+		      t = altt;
+		      mytm = alttm;
+		    }
+		  }
+		}
+#endif
+		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+			break;
+		/*
+		** Right time, wrong type.
+		** Hunt for right time, right type.
+		** It's okay to guess wrong since the guess
+		** gets checked.
+		*/
+		if (sp == NULL)
+			return WRONG;
+		for (i = sp->typecnt - 1; i >= 0; --i) {
+			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+				continue;
+			for (j = sp->typecnt - 1; j >= 0; --j) {
+				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+					continue;
+				newt = t + sp->ttis[j].tt_gmtoff -
+					sp->ttis[i].tt_gmtoff;
+				if (! funcp(sp, &newt, offset, &mytm))
+					continue;
+				if (tmcomp(&mytm, &yourtm) != 0)
+					continue;
+				if (mytm.tm_isdst != yourtm.tm_isdst)
+					continue;
+				/*
+				** We have a match.
+				*/
+				t = newt;
+				goto label;
+			}
+		}
+		return WRONG;
+	}
 label:
-    newt = t + saved_seconds;
-    if ((newt < t) != (saved_seconds < 0))
-        return WRONG;
-    t = newt;
-    if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
-        *okayp = TRUE;
-    return t;
+	newt = t + saved_seconds;
+	if ((newt < t) != (saved_seconds < 0))
+		return WRONG;
+	t = newt;
+	if (funcp(sp, &t, offset, tmp))
+		*okayp = true;
+	return t;
 }
 
 static time_t
-time2(struct tm * const tmp,
-      struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *, struct state *), // android-changed: added sp.
+time2(struct tm * const	tmp,
+      struct tm *(*funcp)(struct state const *, time_t const *,
+			  int_fast32_t, struct tm *),
+      struct state const *sp,
       const int_fast32_t offset,
-      int *const okayp, struct state* sp) // android-changed: added sp.
+      bool *okayp)
 {
-    time_t t;
+	time_t	t;
 
-    /*
-    ** First try without normalization of seconds
-    ** (in case tm_sec contains a value associated with a leap second).
-    ** If that fails, try with normalization of seconds.
-    */
-    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
-    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
+	/*
+	** First try without normalization of seconds
+	** (in case tm_sec contains a value associated with a leap second).
+	** If that fails, try with normalization of seconds.
+	*/
+	t = time2sub(tmp, funcp, sp, offset, okayp, false);
+	return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
 }
 
 static time_t
-time1(struct tm * const tmp,
-      struct tm * (* const funcp) (const time_t *, int_fast32_t, struct tm *, struct state *), // android-changed: added sp.
-      const int_fast32_t offset, struct state * sp) // android-changed: added sp.
+time1(struct tm *const tmp,
+      struct tm *(*funcp) (struct state const *, time_t const *,
+			   int_fast32_t, struct tm *),
+      struct state const *sp,
+      const int_fast32_t offset)
 {
-    register time_t t;
-    register int    samei, otheri;
-    register int    sameind, otherind;
-    register int    i;
-    register int    nseen;
-    char            seen[TZ_MAX_TYPES];
-    unsigned char   types[TZ_MAX_TYPES];
-    int             okay;
+	register time_t			t;
+	register int			samei, otheri;
+	register int			sameind, otherind;
+	register int			i;
+	register int			nseen;
+	char				seen[TZ_MAX_TYPES];
+	unsigned char			types[TZ_MAX_TYPES];
+	bool				okay;
 
-    if (tmp == NULL) {
-        errno = EINVAL;
-        return WRONG;
-    }
-    if (tmp->tm_isdst > 1)
-        tmp->tm_isdst = 1;
-    t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
-    if (okay)
-        return t;
-    if (tmp->tm_isdst < 0)
+	if (tmp == NULL) {
+		errno = EINVAL;
+		return WRONG;
+	}
+	if (tmp->tm_isdst > 1)
+		tmp->tm_isdst = 1;
+	t = time2(tmp, funcp, sp, offset, &okay);
+	if (okay)
+		return t;
+	if (tmp->tm_isdst < 0)
 #ifdef PCTS
-        /*
-        ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
-        */
-        tmp->tm_isdst = 0;  /* reset to std and try again */
+		/*
+		** POSIX Conformance Test Suite code courtesy Grant Sullivan.
+		*/
+		tmp->tm_isdst = 0;	/* reset to std and try again */
 #else
-        return t;
+		return t;
 #endif /* !defined PCTS */
-    /*
-    ** We're supposed to assume that somebody took a time of one type
-    ** and did some math on it that yielded a "struct tm" that's bad.
-    ** We try to divine the type they started from and adjust to the
-    ** type they need.
-    */
-    // BEGIN android-changed: support user-supplied sp.
-    if (sp == NULL) {
-        sp = (struct state *) ((funcp == localsub) ?  lclptr : gmtptr);
-    }
-    // BEGIN android-changed
-    if (sp == NULL)
-        return WRONG;
-    for (i = 0; i < sp->typecnt; ++i)
-        seen[i] = FALSE;
-    nseen = 0;
-    for (i = sp->timecnt - 1; i >= 0; --i)
-        if (!seen[sp->types[i]]) {
-            seen[sp->types[i]] = TRUE;
-            types[nseen++] = sp->types[i];
-        }
-    for (sameind = 0; sameind < nseen; ++sameind) {
-        samei = types[sameind];
-        if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
-            continue;
-        for (otherind = 0; otherind < nseen; ++otherind) {
-            otheri = types[otherind];
-            if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
-                continue;
-            tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
-                    sp->ttis[samei].tt_gmtoff;
-            tmp->tm_isdst = !tmp->tm_isdst;
-            t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
-            if (okay)
-                return t;
-            tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
-                    sp->ttis[samei].tt_gmtoff;
-            tmp->tm_isdst = !tmp->tm_isdst;
-        }
-    }
-    return WRONG;
+	/*
+	** We're supposed to assume that somebody took a time of one type
+	** and did some math on it that yielded a "struct tm" that's bad.
+	** We try to divine the type they started from and adjust to the
+	** type they need.
+	*/
+	if (sp == NULL)
+		return WRONG;
+	for (i = 0; i < sp->typecnt; ++i)
+		seen[i] = false;
+	nseen = 0;
+	for (i = sp->timecnt - 1; i >= 0; --i)
+		if (!seen[sp->types[i]]) {
+			seen[sp->types[i]] = true;
+			types[nseen++] = sp->types[i];
+		}
+	for (sameind = 0; sameind < nseen; ++sameind) {
+		samei = types[sameind];
+		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+			continue;
+		for (otherind = 0; otherind < nseen; ++otherind) {
+			otheri = types[otherind];
+			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+				continue;
+			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+					sp->ttis[samei].tt_gmtoff;
+			tmp->tm_isdst = !tmp->tm_isdst;
+			t = time2(tmp, funcp, sp, offset, &okay);
+			if (okay)
+				return t;
+			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+					sp->ttis[samei].tt_gmtoff;
+			tmp->tm_isdst = !tmp->tm_isdst;
+		}
+	}
+	return WRONG;
 }
 
+static time_t
+mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
+{
+  if (sp)
+    return time1(tmp, localsub, sp, setname);
+  else {
+    gmtcheck();
+    return time1(tmp, gmtsub, gmtptr, 0);
+  }
+}
+
+#if NETBSD_INSPIRED
+
 time_t
-mktime(struct tm * const tmp)
+mktime_z(struct state *sp, struct tm *tmp)
 {
-    _tzLock();
-    tzset_locked();
-    time_t result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-    return result;
+  return mktime_tzname(sp, tmp, false);
+}
+
+#endif
+
+time_t
+mktime(struct tm *tmp)
+{
+  time_t t;
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  tzset_unlocked();
+  t = mktime_tzname(lclptr, tmp, true);
+  unlock();
+  return t;
 }
 
 #ifdef STD_INSPIRED
 
 time_t
-timelocal(struct tm * const tmp)
+timelocal(struct tm *tmp)
 {
-    if (tmp != NULL)
-        tmp->tm_isdst = -1; /* in case it wasn't initialized */
-    return mktime(tmp);
+	if (tmp != NULL)
+		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
+	return mktime(tmp);
 }
 
 time_t
-timegm(struct tm * const tmp)
+timegm(struct tm *tmp)
 {
-    time_t result;
-
-    if (tmp != NULL)
-        tmp->tm_isdst = 0;
-    _tzLock();
-    result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
-    _tzUnlock();
-
-    return result;
+  return timeoff(tmp, 0);
 }
 
 time_t
-timeoff(struct tm *const tmp, const long offset)
+timeoff(struct tm *tmp, long offset)
 {
-    if (tmp != NULL)
-        tmp->tm_isdst = 0;
-    return time1(tmp, gmtsub, offset, NULL); // android-changed: extra parameter.
+  if (tmp)
+    tmp->tm_isdst = 0;
+  gmtcheck();
+  return time1(tmp, gmtsub, gmtptr, offset);
 }
 
 #endif /* defined STD_INSPIRED */
 
-#ifdef CMUCS
-
-/*
-** The following is supplied for compatibility with
-** previous versions of the CMUCS runtime library.
-*/
-
-long
-gtime(struct tm * const tmp)
-{
-    const time_t t = mktime(tmp);
-
-    if (t == WRONG)
-        return -1;
-    return t;
-}
-
-#endif /* defined CMUCS */
-
 /*
 ** XXX--is the below the right way to conditionalize??
 */
@@ -2059,64 +2218,105 @@
 */
 
 static int_fast64_t
-leapcorr(time_t * timep)
+leapcorr(struct state const *sp, time_t t)
 {
-    register struct state *  sp;
-    register struct lsinfo * lp;
-    register int             i;
+	register struct lsinfo const *	lp;
+	register int			i;
 
-    sp = lclptr;
-    i = sp->leapcnt;
-    while (--i >= 0) {
-        lp = &sp->lsis[i];
-        if (*timep >= lp->ls_trans)
-            return lp->ls_corr;
-    }
-    return 0;
+	i = sp->leapcnt;
+	while (--i >= 0) {
+		lp = &sp->lsis[i];
+		if (t >= lp->ls_trans)
+			return lp->ls_corr;
+	}
+	return 0;
+}
+
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+time2posix_z(struct state *sp, time_t t)
+{
+  return t - leapcorr(sp, t);
 }
 
 time_t
 time2posix(time_t t)
 {
-    tzset();
-    return t - leapcorr(&t);
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  if (!lcl_is_set)
+    tzset_unlocked();
+  if (lclptr)
+    t = time2posix_z(lclptr, t);
+  unlock();
+  return t;
+}
+
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+posix2time_z(struct state *sp, time_t t)
+{
+	time_t	x;
+	time_t	y;
+	/*
+	** For a positive leap second hit, the result
+	** is not unique. For a negative leap second
+	** hit, the corresponding time doesn't exist,
+	** so we return an adjacent second.
+	*/
+	x = t + leapcorr(sp, t);
+	y = x - leapcorr(sp, x);
+	if (y < t) {
+		do {
+			x++;
+			y = x - leapcorr(sp, x);
+		} while (y < t);
+		x -= y != t;
+	} else if (y > t) {
+		do {
+			--x;
+			y = x - leapcorr(sp, x);
+		} while (y > t);
+		x += y != t;
+	}
+	return x;
 }
 
 time_t
 posix2time(time_t t)
 {
-    time_t x;
-    time_t y;
-
-    tzset();
-    /*
-    ** For a positive leap second hit, the result
-    ** is not unique. For a negative leap second
-    ** hit, the corresponding time doesn't exist,
-    ** so we return an adjacent second.
-    */
-    x = t + leapcorr(&t);
-    y = x - leapcorr(&x);
-    if (y < t) {
-        do {
-            x++;
-            y = x - leapcorr(&x);
-        } while (y < t);
-        if (t != y)
-            return x - 1;
-    } else if (y > t) {
-        do {
-            --x;
-            y = x - leapcorr(&x);
-        } while (y > t);
-        if (t != y)
-            return x + 1;
-    }
-    return x;
+  int err = lock();
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  if (!lcl_is_set)
+    tzset_unlocked();
+  if (lclptr)
+    t = posix2time_z(lclptr, t);
+  unlock();
+  return t;
 }
 
 #endif /* defined STD_INSPIRED */
 
+#ifdef time_tz
+
+/* Convert from the underlying system's time_t to the ersatz time_tz,
+   which is called 'time_t' in this file.  */
+
+time_t
+time(time_t *p)
+{
+  time_t r = sys_time(0);
+  if (p)
+    *p = r;
+  return r;
+}
+
+#endif
+
 // BEGIN android-added
 
 #include <assert.h>
@@ -2124,7 +2324,7 @@
 #include <arpa/inet.h> // For ntohl(3).
 
 static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
-                                     const char* olson_id, int* data_size) {
+                                     const char* olson_id) {
   const char* path_prefix = getenv(path_prefix_variable);
   if (path_prefix == NULL) {
     fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
@@ -2139,7 +2339,6 @@
   snprintf(path, path_length, "%s/%s", path_prefix, path_suffix);
   int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
   if (fd == -1) {
-    XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
     free(path);
     return -2; // Distinguish failure to find any data from failure to find a specific id.
   }
@@ -2223,7 +2422,6 @@
 
     if (strcmp(this_id, olson_id) == 0) {
       specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
-      *data_size = ntohl(entry->length);
       break;
     }
 
@@ -2232,7 +2430,6 @@
   free(index);
 
   if (specific_zone_offset == -1) {
-    XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
     free(path);
     close(fd);
     return -1;
@@ -2252,10 +2449,10 @@
   return fd;
 }
 
-static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
-  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id, data_size);
+static int __bionic_open_tzdata(const char* olson_id) {
+  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id);
   if (fd < 0) {
-    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size);
+    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id);
     if (fd == -2) {
       // The first thing that 'recovery' does is try to format the current time. It doesn't have
       // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
@@ -2265,50 +2462,4 @@
   return fd;
 }
 
-// Caches the most recent timezone (http://b/8270865).
-static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
-  _tzLock();
-
-  // Our single-item cache.
-  static char* g_cached_time_zone_name;
-  static struct state g_cached_time_zone;
-
-  // Do we already have this timezone cached?
-  if (g_cached_time_zone_name != NULL && strcmp(name, g_cached_time_zone_name) == 0) {
-    *sp = g_cached_time_zone;
-    _tzUnlock();
-    return 0;
-  }
-
-  // Can we load it?
-  int rc = tzload(name, sp, doextend);
-  if (rc == 0) {
-    // Update the cache.
-    free(g_cached_time_zone_name);
-    g_cached_time_zone_name = strdup(name);
-    g_cached_time_zone = *sp;
-  }
-
-  _tzUnlock();
-  return rc;
-}
-
-// Non-standard API: mktime(3) but with an explicit timezone parameter.
-// This can't actually be hidden/removed until we fix MtpUtils.cpp
-__attribute__((visibility("default"))) time_t mktime_tz(struct tm* const tmp, const char* tz) {
-  struct state* st = malloc(sizeof(*st));
-  time_t return_value;
-
-  if (st == NULL)
-    return 0;
-  if (__bionic_tzload_cached(tz, st, TRUE) != 0) {
-    // TODO: not sure what's best here, but for now, we fall back to gmt.
-    gmtload(st);
-  }
-
-  return_value = time1(tmp, localsub, 0L, st);
-  free(st);
-  return return_value;
-}
-
 // END android-added
diff --git a/libc/tzcode/private.h b/libc/tzcode/private.h
index c30c711..1c176e6 100644
--- a/libc/tzcode/private.h
+++ b/libc/tzcode/private.h
@@ -19,13 +19,9 @@
 
 /*
 ** Defaults for preprocessor symbols.
-** You can override these in your C compiler options, e.g. '-DHAVE_ADJTIME=0'.
+** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
 */
 
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME		1
-#endif /* !defined HAVE_ADJTIME */
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT		0
 #endif /* !defined HAVE_GETTEXT */
@@ -38,9 +34,9 @@
 #define HAVE_LINK		1
 #endif /* !defined HAVE_LINK */
 
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY	3
-#endif /* !defined HAVE_SETTIMEOFDAY */
+#ifndef HAVE_STRDUP
+#define HAVE_STRDUP 1
+#endif
 
 #ifndef HAVE_SYMLINK
 #define HAVE_SYMLINK		1
@@ -59,32 +55,61 @@
 #endif /* !defined HAVE_UNISTD_H */
 
 #ifndef HAVE_UTMPX_H
-#define HAVE_UTMPX_H		0
+#define HAVE_UTMPX_H		1
 #endif /* !defined HAVE_UTMPX_H */
 
-#if !defined(__ANDROID__)
-#ifndef LOCALE_HOME
-#define LOCALE_HOME		"/usr/lib/locale"
-#endif /* !defined LOCALE_HOME */
-#endif // __ANDROID__
+#ifndef NETBSD_INSPIRED
+# define NETBSD_INSPIRED 1
+#endif
 
 #if HAVE_INCOMPATIBLE_CTIME_R
 #define asctime_r _incompatible_asctime_r
 #define ctime_r _incompatible_ctime_r
 #endif /* HAVE_INCOMPATIBLE_CTIME_R */
 
+/* Enable tm_gmtoff and tm_zone on GNUish systems.  */
+#define _GNU_SOURCE 1
+/* Fix asctime_r on Solaris 10.  */
+#define _POSIX_PTHREAD_SEMANTICS 1
+/* Enable strtoimax on Solaris 10.  */
+#define __EXTENSIONS__ 1
+
 /*
 ** Nested includes
 */
 
+/* Avoid clashes with NetBSD by renaming NetBSD's declarations.  */
+#define localtime_rz sys_localtime_rz
+#define mktime_z sys_mktime_z
+#define posix2time_z sys_posix2time_z
+#define time2posix_z sys_time2posix_z
+#define timezone_t sys_timezone_t
+#define tzalloc sys_tzalloc
+#define tzfree sys_tzfree
+#include <time.h>
+#undef localtime_rz
+#undef mktime_z
+#undef posix2time_z
+#undef time2posix_z
+#undef timezone_t
+#undef tzalloc
+#undef tzfree
+
 #include "sys/types.h"	/* for time_t */
 #include "stdio.h"
-#include "errno.h"
 #include "string.h"
 #include "limits.h"	/* for CHAR_BIT et al. */
-#include "time.h"
 #include "stdlib.h"
 
+#include "errno.h"
+
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG EINVAL
+#endif
+#ifndef EOVERFLOW
+# define EOVERFLOW EINVAL
+#endif
+
 #if HAVE_GETTEXT
 #include "libintl.h"
 #endif /* HAVE_GETTEXT */
@@ -104,6 +129,14 @@
 #include "unistd.h"	/* for F_OK, R_OK, and other POSIX goodness */
 #endif /* HAVE_UNISTD_H */
 
+#ifndef HAVE_STRFTIME_L
+# if _POSIX_VERSION < 200809
+#  define HAVE_STRFTIME_L 0
+# else
+#  define HAVE_STRFTIME_L 1
+# endif
+#endif
+
 #ifndef F_OK
 #define F_OK	0
 #endif /* !defined F_OK */
@@ -138,65 +171,98 @@
 # include <inttypes.h>
 #endif
 
-#ifndef INT_FAST64_MAX
 /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX.  */
-#if defined LLONG_MAX || defined __LONG_LONG_MAX__
-typedef long long	int_fast64_t;
+#ifdef __LONG_LONG_MAX__
+# ifndef LLONG_MAX
+#  define LLONG_MAX __LONG_LONG_MAX__
+# endif
+# ifndef LLONG_MIN
+#  define LLONG_MIN (-1 - LLONG_MAX)
+# endif
+#endif
+
+#ifndef INT_FAST64_MAX
 # ifdef LLONG_MAX
+typedef long long	int_fast64_t;
 #  define INT_FAST64_MIN LLONG_MIN
 #  define INT_FAST64_MAX LLONG_MAX
 # else
-#  define INT_FAST64_MIN __LONG_LONG_MIN__
-#  define INT_FAST64_MAX __LONG_LONG_MAX__
-# endif
-# define SCNdFAST64 "lld"
-#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#if (LONG_MAX >> 31) < 0xffffffff
+#  if LONG_MAX >> 31 < 0xffffffff
 Please use a compiler that supports a 64-bit integer type (or wider);
 you may need to compile with "-DHAVE_STDINT_H".
-#endif /* (LONG_MAX >> 31) < 0xffffffff */
+#  endif
 typedef long		int_fast64_t;
-# define INT_FAST64_MIN LONG_MIN
-# define INT_FAST64_MAX LONG_MAX
-# define SCNdFAST64 "ld"
-#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#endif /* !defined INT_FAST64_MAX */
+#  define INT_FAST64_MIN LONG_MIN
+#  define INT_FAST64_MAX LONG_MAX
+# endif
+#endif
+
+#ifndef SCNdFAST64
+# if INT_FAST64_MAX == LLONG_MAX
+#  define SCNdFAST64 "lld"
+# else
+#  define SCNdFAST64 "ld"
+# endif
+#endif
 
 #ifndef INT_FAST32_MAX
 # if INT_MAX >> 31 == 0
 typedef long int_fast32_t;
+#  define INT_FAST32_MAX LONG_MAX
+#  define INT_FAST32_MIN LONG_MIN
 # else
 typedef int int_fast32_t;
+#  define INT_FAST32_MAX INT_MAX
+#  define INT_FAST32_MIN INT_MIN
 # endif
 #endif
 
 #ifndef INTMAX_MAX
-# if defined LLONG_MAX || defined __LONG_LONG_MAX__
+# ifdef LLONG_MAX
 typedef long long intmax_t;
 #  define strtoimax strtoll
-#  define PRIdMAX "lld"
-#  ifdef LLONG_MAX
-#   define INTMAX_MAX LLONG_MAX
-#   define INTMAX_MIN LLONG_MIN
-#  else
-#   define INTMAX_MAX __LONG_LONG_MAX__
-#   define INTMAX_MIN __LONG_LONG_MIN__
-#  endif
+#  define INTMAX_MAX LLONG_MAX
+#  define INTMAX_MIN LLONG_MIN
 # else
 typedef long intmax_t;
 #  define strtoimax strtol
-#  define PRIdMAX "ld"
 #  define INTMAX_MAX LONG_MAX
 #  define INTMAX_MIN LONG_MIN
 # endif
 #endif
 
+#ifndef PRIdMAX
+# if INTMAX_MAX == LLONG_MAX
+#  define PRIdMAX "lld"
+# else
+#  define PRIdMAX "ld"
+# endif
+#endif
+
+#ifndef UINT_FAST64_MAX
+# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
+typedef unsigned long long uint_fast64_t;
+# else
+#  if ULONG_MAX >> 31 >> 1 < 0xffffffff
+Please use a compiler that supports a 64-bit integer type (or wider);
+you may need to compile with "-DHAVE_STDINT_H".
+#  endif
+typedef unsigned long	uint_fast64_t;
+# endif
+#endif
+
 #ifndef UINTMAX_MAX
 # if defined ULLONG_MAX || defined __LONG_LONG_MAX__
 typedef unsigned long long uintmax_t;
-#  define PRIuMAX "llu"
 # else
 typedef unsigned long uintmax_t;
+# endif
+#endif
+
+#ifndef PRIuMAX
+# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
+#  define PRIuMAX "llu"
+# else
 #  define PRIuMAX "lu"
 # endif
 #endif
@@ -239,16 +305,6 @@
 */
 
 /*
-** Some time.h implementations don't declare asctime_r.
-** Others might define it as a macro.
-** Fix the former without affecting the latter.
-*/
-
-#ifndef asctime_r
-extern char *	asctime_r(struct tm const *, char *);
-#endif
-
-/*
 ** Compile with -Dtime_tz=T to build the tz package with a private
 ** time_t type equivalent to T rather than the system-supplied time_t.
 ** This debugging feature can test unusual design decisions
@@ -256,7 +312,11 @@
 ** typical platforms.
 */
 #ifdef time_tz
+# ifdef LOCALTIME_IMPLEMENTATION
 static time_t sys_time(time_t *x) { return time(x); }
+# endif
+
+typedef time_tz tz_time_t;
 
 # undef  ctime
 # define ctime tz_ctime
@@ -272,14 +332,40 @@
 # define localtime tz_localtime
 # undef  localtime_r
 # define localtime_r tz_localtime_r
+# undef  localtime_rz
+# define localtime_rz tz_localtime_rz
 # undef  mktime
 # define mktime tz_mktime
+# undef  mktime_z
+# define mktime_z tz_mktime_z
+# undef  offtime
+# define offtime tz_offtime
+# undef  posix2time
+# define posix2time tz_posix2time
+# undef  posix2time_z
+# define posix2time_z tz_posix2time_z
 # undef  time
 # define time tz_time
+# undef  time2posix
+# define time2posix tz_time2posix
+# undef  time2posix_z
+# define time2posix_z tz_time2posix_z
 # undef  time_t
 # define time_t tz_time_t
-
-typedef time_tz time_t;
+# undef  timegm
+# define timegm tz_timegm
+# undef  timelocal
+# define timelocal tz_timelocal
+# undef  timeoff
+# define timeoff tz_timeoff
+# undef  tzalloc
+# define tzalloc tz_tzalloc
+# undef  tzfree
+# define tzfree tz_tzfree
+# undef  tzset
+# define tzset tz_tzset
+# undef  tzsetwall
+# define tzsetwall tz_tzsetwall
 
 char *ctime(time_t const *);
 char *ctime_r(time_t const *, char *);
@@ -289,36 +375,111 @@
 struct tm *localtime(time_t const *);
 struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
 time_t mktime(struct tm *);
-
-static time_t
-time(time_t *p)
-{
-	time_t r = sys_time(0);
-	if (p)
-		*p = r;
-	return r;
-}
+time_t time(time_t *);
+void tzset(void);
 #endif
 
 /*
-** Private function declarations.
+** Some time.h implementations don't declare asctime_r.
+** Others might define it as a macro.
+** Fix the former without affecting the latter.
+** Similarly for timezone, daylight, and altzone.
 */
 
-char *		icatalloc(char * old, const char * new);
-char *		icpyalloc(const char * string);
-const char *	scheck(const char * string, const char * format);
+#ifndef asctime_r
+extern char *	asctime_r(struct tm const *restrict, char *restrict);
+#endif
+
+#ifdef USG_COMPAT
+# ifndef timezone
+extern long timezone;
+# endif
+# ifndef daylight
+extern int daylight;
+# endif
+#endif
+#if defined ALTZONE && !defined altzone
+extern long altzone;
+#endif
+
+/*
+** The STD_INSPIRED functions are similar, but most also need
+** declarations if time_tz is defined.
+*/
+
+#ifdef STD_INSPIRED
+# if !defined tzsetwall || defined time_tz
+void tzsetwall(void);
+# endif
+# if !defined offtime || defined time_tz
+struct tm *offtime(time_t const *, long);
+# endif
+# if !defined timegm || defined time_tz
+time_t timegm(struct tm *);
+# endif
+# if !defined timelocal || defined time_tz
+time_t timelocal(struct tm *);
+# endif
+# if !defined timeoff || defined time_tz
+time_t timeoff(struct tm *, long);
+# endif
+# if !defined time2posix || defined time_tz
+time_t time2posix(time_t);
+# endif
+# if !defined posix2time || defined time_tz
+time_t posix2time(time_t);
+# endif
+#endif
+
+/* Infer TM_ZONE on systems where this information is known, but suppress
+   guessing if NO_TM_ZONE is defined.  Similarly for TM_GMTOFF.  */
+#if (defined __GLIBC__ \
+     || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
+     || (defined __APPLE__ && defined __MACH__))
+# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
+#  define TM_GMTOFF tm_gmtoff
+# endif
+# if !defined TM_ZONE && !defined NO_TM_ZONE
+#  define TM_ZONE tm_zone
+# endif
+#endif
+
+/*
+** Define functions that are ABI compatible with NetBSD but have
+** better prototypes.  NetBSD 6.1.4 defines a pointer type timezone_t
+** and labors under the misconception that 'const timezone_t' is a
+** pointer to a constant.  This use of 'const' is ineffective, so it
+** is not done here.  What we call 'struct state' NetBSD calls
+** 'struct __state', but this is a private name so it doesn't matter.
+*/
+#if NETBSD_INSPIRED
+typedef struct state *timezone_t;
+struct tm *localtime_rz(timezone_t restrict, time_t const *restrict,
+			struct tm *restrict);
+time_t mktime_z(timezone_t restrict, struct tm *restrict);
+timezone_t tzalloc(char const *);
+void tzfree(timezone_t);
+# ifdef STD_INSPIRED
+#  if !defined posix2time_z || defined time_tz
+time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_PURE;
+#  endif
+#  if !defined time2posix_z || defined time_tz
+time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
+#  endif
+# endif
+#endif
 
 /*
 ** Finally, some convenience items.
 */
 
-#ifndef TRUE
-#define TRUE	1
-#endif /* !defined TRUE */
-
-#ifndef FALSE
-#define FALSE	0
-#endif /* !defined FALSE */
+#if __STDC_VERSION__ < 199901
+# define true 1
+# define false 0
+# define bool int
+#else
+# include <stdbool.h>
+#endif
 
 #ifndef TYPE_BIT
 #define TYPE_BIT(type)	(sizeof (type) * CHAR_BIT)
@@ -328,15 +489,20 @@
 #define TYPE_SIGNED(type) (((type) -1) < 0)
 #endif /* !defined TYPE_SIGNED */
 
-/* The minimum and maximum finite time values.  */
-static time_t const time_t_min =
-  (TYPE_SIGNED(time_t)
-   ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
-   : 0);
-static time_t const time_t_max =
-  (TYPE_SIGNED(time_t)
-   ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
-   : -1);
+#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
+
+/* Max and min values of the integer type T, of which only the bottom
+   B bits are used, and where the highest-order used bit is considered
+   to be a sign bit if T is signed.  */
+#define MAXVAL(t, b)						\
+  ((t) (((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))			\
+	- 1 + ((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))))
+#define MINVAL(t, b)						\
+  ((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
+
+/* The minimum and maximum finite time values.  This assumes no padding.  */
+static time_t const time_t_min = MINVAL(time_t, TYPE_BIT(time_t));
+static time_t const time_t_max = MAXVAL(time_t, TYPE_BIT(time_t));
 
 #ifndef INT_STRLEN_MAXIMUM
 /*
@@ -360,6 +526,10 @@
 # define INITIALIZE(x)
 #endif
 
+#ifndef UNINIT_TRAP
+# define UNINIT_TRAP 0
+#endif
+
 /*
 ** For the benefit of GNU folk...
 ** '_(MSGID)' uses the current locale's message library string for MSGID.
@@ -374,7 +544,7 @@
 #endif /* !HAVE_GETTEXT */
 #endif /* !defined _ */
 
-#if !defined TZ_DOMAIN && defined TZ_DOMAINDIR
+#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
 # define TZ_DOMAIN "tz"
 #endif
 
@@ -405,8 +575,4 @@
 #define SECSPERREPEAT_BITS	34	/* ceil(log2(SECSPERREPEAT)) */
 #endif /* !defined SECSPERREPEAT_BITS */
 
-/*
-** UNIX was a registered trademark of The Open Group in 2003.
-*/
-
 #endif /* !defined PRIVATE_H */
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index 4328b4c..4349cf6 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -55,15 +55,7 @@
     const char *    date_fmt;
 };
 
-#ifdef LOCALE_HOME
-#include "sys/stat.h"
-static struct lc_time_T                localebuf;
-static struct lc_time_T *      _loc(void);
-#define Locale _loc()
-#endif /* defined LOCALE_HOME */
-#ifndef LOCALE_HOME
 #define Locale  (&C_time_locale)
-#endif /* !defined LOCALE_HOME */
 
 static const struct lc_time_T   C_time_locale = {
     {
@@ -115,7 +107,7 @@
 static char *   _conv(int, const char *, char *, const char *);
 static char *   _fmt(const char *, const struct tm *, char *, const char *,
             int *);
-static char *   _yconv(int, int, int, int, char *, const char *, int);
+static char *   _yconv(int, int, bool, bool, char *, const char *, int);
 static char *   getformat(int, char *, char *, char *, char *);
 
 extern char *   tzname[];
@@ -132,32 +124,28 @@
 #define FORCE_LOWER_CASE 0x100
 
 size_t
-strftime(char * const s, const size_t maxsize, const char *const format,
-        const struct tm *const t)
+strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
 {
     char *  p;
     int warn;
 
     tzset();
-#ifdef LOCALE_HOME
-    localebuf.mon[0] = 0;
-#endif /* defined LOCALE_HOME */
     warn = IN_NONE;
     p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
     if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
-        (void) fprintf(stderr, "\n");
+        fprintf(stderr, "\n");
         if (format == NULL)
-            (void) fprintf(stderr, "NULL strftime format ");
-        else    (void) fprintf(stderr, "strftime format \"%s\" ",
+            fprintf(stderr, "NULL strftime format ");
+        else    fprintf(stderr, "strftime format \"%s\" ",
                 format);
-        (void) fprintf(stderr, "yields only two digits of years in ");
+        fprintf(stderr, "yields only two digits of years in ");
         if (warn == IN_SOME)
-            (void) fprintf(stderr, "some locales");
+            fprintf(stderr, "some locales");
         else if (warn == IN_THIS)
-            (void) fprintf(stderr, "the current locale");
-        else    (void) fprintf(stderr, "all locales");
-        (void) fprintf(stderr, "\n");
+            fprintf(stderr, "the current locale");
+        else    fprintf(stderr, "all locales");
+        fprintf(stderr, "\n");
     }
 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
     if (p == s + maxsize)
@@ -171,20 +159,17 @@
     switch (modifier) {
     case '_':
         return underscore;
-
     case '-':
         return dash;
-
     case '0':
         return zero;
     }
-
     return normal;
 }
 
 static char *
-_fmt(const char *format, const struct tm *const t, char * pt,
-        const char *const ptlim, int *warnp)
+_fmt(const char *format, const struct tm *t, char *pt,
+        const char *ptlim, int *warnp)
 {
     for ( ; *format; ++format) {
         if (*format == '%') {
@@ -227,8 +212,8 @@
                 ** something completely different.
                 ** (ado, 1993-05-24)
                 */
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
-                    pt, ptlim, modifier);
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    true, false, pt, ptlim, modifier);
                 continue;
             case 'c':
                 {
@@ -245,10 +230,7 @@
                                 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
                 continue;
             case 'd':
-                                pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                                pt = _conv(t->tm_mday, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'E':
             case 'O':
@@ -270,31 +252,21 @@
                 modifier = *format;
                 goto label;
             case 'e':
-                pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_mday, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'F':
                 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
                 continue;
             case 'H':
-                pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_hour, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'I':
                 pt = _conv((t->tm_hour % 12) ?
                     (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'j':
-                pt = _conv(t->tm_yday + 1,
-                           getformat(modifier, "%03d", "%3d", "%d", "%03d"),
-                           pt, ptlim);
+                pt = _conv(t->tm_yday + 1, getformat(modifier, "%03d", "%3d", "%d", "%03d"), pt, ptlim);
                 continue;
             case 'k':
                 /*
@@ -307,10 +279,7 @@
                 ** "%l" have been swapped.
                 ** (ado, 1993-05-24)
                 */
-                pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_hour, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
 #ifdef KITCHEN_SINK
             case 'K':
@@ -332,36 +301,23 @@
                 */
                 pt = _conv((t->tm_hour % 12) ?
                     (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%2d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'M':
-                pt = _conv(t->tm_min,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_min, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'm':
-                pt = _conv(t->tm_mon + 1,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_mon + 1, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'n':
                 pt = _add("\n", pt, ptlim, modifier);
                 continue;
+            case 'P':
             case 'p':
                 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
                     Locale->pm :
                     Locale->am,
-                    pt, ptlim, modifier);
-                continue;
-            case 'P':
-                pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-                    Locale->pm :
-                    Locale->am,
-                    pt, ptlim, FORCE_LOWER_CASE);
+                    pt, ptlim, (*format == 'P') ? FORCE_LOWER_CASE : modifier);
                 continue;
             case 'R':
                 pt = _fmt("%H:%M", t, pt, ptlim, warnp);
@@ -370,10 +326,7 @@
                 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
                 continue;
             case 'S':
-                pt = _conv(t->tm_sec,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
+                pt = _conv(t->tm_sec, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 's':
                 {
@@ -385,10 +338,10 @@
                     tm = *t;
                     mkt = mktime64(&tm);
                     if (TYPE_SIGNED(time64_t))
-                        (void) snprintf(buf, sizeof(buf), "%lld",
-                            (long long) mkt);
-                    else    (void) snprintf(buf, sizeof(buf), "%llu",
-                            (unsigned long long) mkt);
+                        snprintf(buf, sizeof(buf), "%"PRIdMAX,
+                                 (intmax_t) mkt);
+                    else    snprintf(buf, sizeof(buf), "%"PRIuMAX,
+                                     (uintmax_t) mkt);
                     pt = _add(buf, pt, ptlim, modifier);
                 }
                 continue;
@@ -401,9 +354,7 @@
             case 'U':
                 pt = _conv((t->tm_yday + DAYSPERWEEK -
                     t->tm_wday) / DAYSPERWEEK,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'u':
                 /*
@@ -413,7 +364,8 @@
                 ** (ado, 1993-05-24)
                 */
                 pt = _conv((t->tm_wday == 0) ?
-                    DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
+                    DAYSPERWEEK : t->tm_wday,
+                    "%d", pt, ptlim);
                 continue;
             case 'V':   /* ISO 8601 week number */
             case 'G':   /* ISO 8601 year (four digits) */
@@ -493,14 +445,15 @@
                             w = 53;
 #endif /* defined XPG4_1994_04_09 */
                     if (*format == 'V')
-                        pt = _conv(w,
-                                getformat(modifier, "%02d", "%2d", "%d", "%02d"),
+                        pt = _conv(w, getformat(modifier, "%02d", "%2d", "%d", "%02d"),
                                pt, ptlim);
                     else if (*format == 'g') {
                         *warnp = IN_ALL;
-                        pt = _yconv(year, base, 0, 1,
+                        pt = _yconv(year, base,
+                            false, true,
                             pt, ptlim, modifier);
-                    } else  pt = _yconv(year, base, 1, 1,
+                    } else  pt = _yconv(year, base,
+                            true, true,
                             pt, ptlim, modifier);
                 }
                 continue;
@@ -517,9 +470,7 @@
                     (t->tm_wday ?
                     (t->tm_wday - 1) :
                     (DAYSPERWEEK - 1))) / DAYSPERWEEK,
-                    getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
+                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
                 continue;
             case 'w':
                 pt = _conv(t->tm_wday, "%d", pt, ptlim);
@@ -540,23 +491,39 @@
                 continue;
             case 'y':
                 *warnp = IN_ALL;
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    false, true,
                     pt, ptlim, modifier);
                 continue;
             case 'Y':
-                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+                pt = _yconv(t->tm_year, TM_YEAR_BASE,
+                    true, true,
                     pt, ptlim, modifier);
                 continue;
             case 'Z':
 #ifdef TM_ZONE
-                if (t->TM_ZONE != NULL)
-                    pt = _add(t->TM_ZONE, pt, ptlim,
-                                                  modifier);
-                else
-#endif /* defined TM_ZONE */
+                // BEGIN: Android-changed.
+                {
+                    const char* zone = t->TM_ZONE;
+                    if (!zone || !*zone) {
+                        // "The value of tm_isdst shall be positive if Daylight Savings Time is
+                        // in effect, 0 if Daylight Savings Time is not in effect, and negative
+                        // if the information is not available."
+                        if (t->tm_isdst == 0) zone = tzname[0];
+                        else if (t->tm_isdst > 0) zone = tzname[1];
+
+                        // "Replaced by the timezone name or abbreviation, or by no bytes if no
+                        // timezone information exists."
+                        if (!zone || !*zone) zone = "";
+                    }
+                    pt = _add(zone, pt, ptlim, modifier);
+                }
+                // END: Android-changed.
+#else
                 if (t->tm_isdst >= 0)
                     pt = _add(tzname[t->tm_isdst != 0],
-                        pt, ptlim, modifier);
+                        pt, ptlim);
+#endif
                 /*
                 ** C99 says that %Z must be replaced by the
                 ** empty string if the time zone is not
@@ -613,10 +580,7 @@
                 diff /= SECSPERMIN;
                 diff = (diff / MINSPERHOUR) * 100 +
                     (diff % MINSPERHOUR);
-                pt = _conv(diff,
-                                           getformat(modifier, "%04d",
-                                                     "%4d", "%d", "%04d"),
-                                           pt, ptlim);
+                pt = _conv(diff, getformat(modifier, "%04d", "%4d", "%d", "%04d"), pt, ptlim);
                 }
                 continue;
             case '+':
@@ -641,13 +605,12 @@
 }
 
 static char *
-_conv(const int n, const char *const format, char *const pt,
-        const char *const ptlim)
+_conv(int n, const char *format, char *pt, const char *ptlim)
 {
-    char    buf[INT_STRLEN_MAXIMUM(int) + 1];
+	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
 
-    (void) snprintf(buf, sizeof(buf), format, n);
-    return _add(buf, pt, ptlim, 0);
+	snprintf(buf, sizeof(buf), format, n);
+	return _add(buf, pt, ptlim, 0);
 }
 
 static char *
@@ -699,8 +662,8 @@
 */
 
 static char *
-_yconv(const int a, const int b, const int convert_top, const int convert_yy,
-        char *pt, const char *const ptlim, int modifier)
+_yconv(int a, int b, bool convert_top, bool convert_yy,
+       char *pt, const char *ptlim, int modifier)
 {
     register int    lead;
     register int    trail;
diff --git a/libc/tzcode/tzfile.h b/libc/tzcode/tzfile.h
index 529650d..ebecd68 100644
--- a/libc/tzcode/tzfile.h
+++ b/libc/tzcode/tzfile.h
@@ -40,7 +40,7 @@
 struct tzhead {
 	char	tzh_magic[4];		/* TZ_MAGIC */
 	char	tzh_version[1];		/* '\0' or '2' or '3' as of 2013 */
-	char	tzh_reserved[15];	/* reserved--must be zero */
+	char	tzh_reserved[15];	/* reserved; must be zero */
 	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
 	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
 	char	tzh_leapcnt[4];		/* coded number of leap seconds */
@@ -62,13 +62,13 @@
 **	tzh_leapcnt repetitions of
 **		one (char [4])		coded leap second transition times
 **		one (char [4])		total correction after above
-**	tzh_ttisstdcnt (char)s		indexed by type; if TRUE, transition
-**					time is standard time, if FALSE,
+**	tzh_ttisstdcnt (char)s		indexed by type; if 1, transition
+**					time is standard time, if 0,
 **					transition time is wall clock time
 **					if absent, transition times are
 **					assumed to be wall clock time
-**	tzh_ttisgmtcnt (char)s		indexed by type; if TRUE, transition
-**					time is UT, if FALSE,
+**	tzh_ttisgmtcnt (char)s		indexed by type; if 1, transition
+**					time is UT, if 0,
 **					transition time is local time
 **					if absent, transition times are
 **					assumed to be local time
@@ -97,7 +97,7 @@
 */
 
 #ifndef TZ_MAX_TIMES
-#define TZ_MAX_TIMES	1200
+#define TZ_MAX_TIMES	2000
 #endif /* !defined TZ_MAX_TIMES */
 
 #ifndef TZ_MAX_TYPES
diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c
index 3c9d36b..a61c0da 100644
--- a/libc/upstream-dlmalloc/malloc.c
+++ b/libc/upstream-dlmalloc/malloc.c
@@ -4822,8 +4822,13 @@
       req = MAX_SIZE_T; /* force downstream failure on overflow */
   }
   mem = dlmalloc(req);
-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
-    memset(mem, 0, req);
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    if (calloc_must_clear(p)) {
+      /* Make sure to clear all of the buffer, not just the requested size. */
+      memset(mem, 0, chunksize(p) - overhead_for(p));
+    }
+  }
   return mem;
 }
 
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c b/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c
deleted file mode 100644
index 35e3dee..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/imaxabs.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <inttypes.h>
-
-intmax_t
-imaxabs(intmax_t j)
-{
-	return (j < 0 ? -j : j);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c b/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c
deleted file mode 100644
index 7dae467..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/imaxdiv.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <inttypes.h>
-
-/* See comments in div.c for implementation details. */
-imaxdiv_t
-imaxdiv(intmax_t numer, intmax_t denom)
-{
-	imaxdiv_t retval;
-
-	retval.quot = numer / denom;
-	retval.rem = numer % denom;
-	if (numer >= 0 && retval.rem < 0) {
-		retval.quot++;
-		retval.rem -= denom;
-	}
-	return (retval);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/llabs.c b/libc/upstream-freebsd/lib/libc/stdlib/llabs.c
deleted file mode 100644
index 2bfbada..0000000
--- a/libc/upstream-freebsd/lib/libc/stdlib/llabs.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <stdlib.h>
-
-long long
-llabs(long long j)
-{
-	return (j < 0 ? -j : j);
-}
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 8d1c46b..0212d16 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -32,6 +32,6 @@
 #define __unlockenv() 0
 
 #include <stddef.h>
-__LIBC_HIDDEN__ int reallocarr(void*, size_t, size_t);
+int reallocarr(void*, size_t, size_t);
 
 #endif
diff --git a/libc/upstream-openbsd/android/include/arc4random.h b/libc/upstream-openbsd/android/include/arc4random.h
index c07257d..96d9c9a 100644
--- a/libc/upstream-openbsd/android/include/arc4random.h
+++ b/libc/upstream-openbsd/android/include/arc4random.h
@@ -27,6 +27,8 @@
 #include <pthread.h>
 #include <signal.h>
 
+#include "private/bionic_prctl.h"
+
 // Android gets these from "thread_private.h".
 #include "thread_private.h"
 //static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
@@ -76,12 +78,18 @@
 	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
 		return (-1);
 
+	prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsp, sizeof(**rsp),
+	    "arc4random _rs structure");
+
 	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
 	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
 		munmap(*rsxp, sizeof(**rsxp));
 		return (-1);
 	}
 
+	prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *rsxp, sizeof(**rsxp),
+	    "arc4random _rsx structure");
+
 	_ARC4_ATFORK(_rs_forkhandler);
 	return (0);
 }
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 47bacc3..b07f55d 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -71,8 +71,8 @@
 __LIBC_HIDDEN__ void* reallocarray(void*, size_t, size_t);
 
 /* LP32 NDK ctype.h contained references to these. */
-__LIBC64_HIDDEN__ extern const short* _tolower_tab_;
-__LIBC64_HIDDEN__ extern const short* _toupper_tab_;
+__LIBC32_LEGACY_PUBLIC__ extern const short* _tolower_tab_;
+__LIBC32_LEGACY_PUBLIC__ extern const short* _toupper_tab_;
 
 __LIBC_HIDDEN__ extern const char _C_ctype_[];
 __LIBC_HIDDEN__ extern const short _C_toupper_[];
diff --git a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
index 2c860f7..0d0f18f 100644
--- a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
+++ b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fnmatch.c,v 1.17 2013/11/24 23:51:29 deraadt Exp $	*/
+/*	$OpenBSD: fnmatch.c,v 1.19 2015/08/01 18:11:08 millert Exp $	*/
 
 /* Copyright (c) 2011, VMware, Inc.
  * All rights reserved.
@@ -88,7 +88,6 @@
 #include <fnmatch.h>
 #include <string.h>
 #include <ctype.h>
-#include <limits.h>
 
 #include "charclass.h"
 
@@ -193,6 +192,8 @@
                 result = 0;
                 continue;
             }
+            if (!**pattern)
+                break;
 
 leadingclosebrace:
             /* Look at only well-formed range patterns; 
@@ -294,10 +295,6 @@
     const char *mismatch = NULL;
     int matchlen = 0;
 
-    if (strnlen(pattern, PATH_MAX) == PATH_MAX ||
-        strnlen(string, PATH_MAX) == PATH_MAX)
-            return (FNM_NOMATCH);
-
     if (*pattern == '*')
         goto firstsegment;
 
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_addr.c b/libc/upstream-openbsd/lib/libc/net/inet_addr.c
deleted file mode 100644
index 18762ab..0000000
--- a/libc/upstream-openbsd/lib/libc/net/inet_addr.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*	$OpenBSD: inet_addr.c,v 1.10 2013/11/24 23:51:28 deraadt Exp $	*/
-
-/*
- * ++Copyright++ 1983, 1990, 1993
- * -
- * Copyright (c) 1983, 1990, 1993
- *    The Regents of the University of California.  All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- * 
- * 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, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION 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--
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-
-/*
- * Ascii internet address interpretation routine.
- * The value returned is in network order.
- */
-in_addr_t
-inet_addr(const char *cp)
-{
-	struct in_addr val;
-
-	if (inet_aton(cp, &val))
-		return (val.s_addr);
-	return (INADDR_NONE);
-}
-
-/* 
- * Check whether "cp" is a valid ascii representation
- * of an Internet address and convert to a binary address.
- * Returns 1 if the address is valid, 0 if not.
- * This replaces inet_addr, the return value from which
- * cannot distinguish between failure and a local broadcast address.
- */
-int
-inet_aton(const char *cp, struct in_addr *addr)
-{
-	in_addr_t val;
-	int base, n;
-	char c;
-	u_int parts[4];
-	u_int *pp = parts;
-
-	c = *cp;
-	for (;;) {
-		/*
-		 * Collect number up to ``.''.
-		 * Values are specified as for C:
-		 * 0x=hex, 0=octal, isdigit=decimal.
-		 */
-		if (!isdigit((unsigned char)c))
-			return (0);
-		val = 0; base = 10;
-		if (c == '0') {
-			c = *++cp;
-			if (c == 'x' || c == 'X')
-				base = 16, c = *++cp;
-			else
-				base = 8;
-		}
-		for (;;) {
-			if (isascii((unsigned char)c) &&
-			    isdigit((unsigned char)c)) {
-				val = (val * base) + (c - '0');
-				c = *++cp;
-			} else if (base == 16 &&
-			    isascii((unsigned char)c) &&
-			    isxdigit((unsigned char)c)) {
-				val = (val << 4) |
-				    (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
-				c = *++cp;
-			} else
-				break;
-		}
-		if (c == '.') {
-			/*
-			 * Internet format:
-			 *	a.b.c.d
-			 *	a.b.c	(with c treated as 16 bits)
-			 *	a.b	(with b treated as 24 bits)
-			 */
-			if (pp >= parts + 3)
-				return (0);
-			*pp++ = val;
-			c = *++cp;
-		} else
-			break;
-	}
-	/*
-	 * Check for trailing characters.
-	 */
-	if (c != '\0' &&
-	    (!isascii((unsigned char)c) || !isspace((unsigned char)c)))
-		return (0);
-	/*
-	 * Concoct the address according to
-	 * the number of parts specified.
-	 */
-	n = pp - parts + 1;
-	switch (n) {
-
-	case 0:
-		return (0);		/* initial nondigit */
-
-	case 1:				/* a -- 32 bits */
-		break;
-
-	case 2:				/* a.b -- 8.24 bits */
-		if ((val > 0xffffff) || (parts[0] > 0xff))
-			return (0);
-		val |= parts[0] << 24;
-		break;
-
-	case 3:				/* a.b.c -- 8.8.16 bits */
-		if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
-			return (0);
-		val |= (parts[0] << 24) | (parts[1] << 16);
-		break;
-
-	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
-		if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
-			return (0);
-		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
-		break;
-	}
-	if (addr)
-		addr->s_addr = htonl(val);
-	return (1);
-}
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_network.c b/libc/upstream-openbsd/lib/libc/net/inet_network.c
deleted file mode 100644
index ecf554e..0000000
--- a/libc/upstream-openbsd/lib/libc/net/inet_network.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*	$OpenBSD: inet_network.c,v 1.11 2013/11/25 17:29:19 deraadt Exp $ */
-/*
- * Copyright (c) 1983, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-
-/*
- * Internet network address interpretation routine.
- * The library routines call this routine to interpret
- * network numbers.
- */
-in_addr_t
-inet_network(const char *cp)
-{
-	in_addr_t val, base, n;
-	u_char c;
-	in_addr_t parts[4], *pp = parts;
-	int i;
-
-again:
-	val = 0; base = 10;
-	if (*cp == '0')
-		base = 8, cp++;
-	if (*cp == 'x' || *cp == 'X')
-		base = 16, cp++;
-	while ((c = *cp)) {
-		if (isdigit(c)) {
-			val = (val * base) + (c - '0');
-			cp++;
-			continue;
-		}
-		if (base == 16 && isxdigit(c)) {
-			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
-			cp++;
-			continue;
-		}
-		break;
-	}
-	if (*cp == '.') {
-		if (pp >= parts + 3)
-			return (INADDR_NONE);
-		*pp++ = val, cp++;
-		goto again;
-	}
-	if (*cp && !isspace(*cp))
-		return (INADDR_NONE);
-	*pp++ = val;
-	n = pp - parts;
-	for (val = 0, i = 0; i < 4; i++) {
-		val <<= 8;
-		if (i < n)
-			val |= parts[i] & 0xff;
-	}
-	return (val);
-}
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/labs.c b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
similarity index 83%
rename from libc/upstream-freebsd/lib/libc/stdlib/labs.c
rename to libc/upstream-openbsd/lib/libc/stdlib/abs.c
index 816370e..5d2fbae 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/labs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
@@ -1,6 +1,7 @@
+/*	$OpenBSD: abs.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +28,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)labs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
-long
-labs(j)
-	long j;
+int
+abs(int j)
 {
 	return(j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
similarity index 81%
rename from libc/upstream-freebsd/lib/libc/stdlib/abs.c
rename to libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
index 8758947..b7e910e 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c
@@ -1,6 +1,8 @@
+/*	$OpenBSD: imaxabs.c,v 1.1 2006/01/13 17:58:09 millert Exp $	*/
+
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +29,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)abs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#include <inttypes.h>
 
-#include <stdlib.h>
-
-int
-abs(j)
-	int j;
+intmax_t
+imaxabs(intmax_t j)
 {
-	return(j < 0 ? -j : j);
+	return (j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/labs.c b/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
similarity index 74%
copy from libc/upstream-freebsd/lib/libc/stdlib/labs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
index 816370e..0515a94 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/labs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c
@@ -1,6 +1,10 @@
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+/*	$OpenBSD: imaxdiv.c,v 1.1 2006/01/13 17:58:09 millert Exp $	*/
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +31,20 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)labs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#include <inttypes.h>		/* imaxdiv_t */
 
-#include <stdlib.h>
-
-long
-labs(j)
-	long j;
+imaxdiv_t
+imaxdiv(intmax_t num, intmax_t denom)
 {
-	return(j < 0 ? -j : j);
+	imaxdiv_t r;
+
+	/* see div.c for comments */
+
+	r.quot = num / denom;
+	r.rem = num % denom;
+	if (num >= 0 && r.rem < 0) {
+		r.quot++;
+		r.rem -= denom;
+	}
+	return (r);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/labs.c b/libc/upstream-openbsd/lib/libc/stdlib/labs.c
similarity index 83%
copy from libc/upstream-freebsd/lib/libc/stdlib/labs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/labs.c
index 816370e..ca60b9a 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/labs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/labs.c
@@ -1,6 +1,7 @@
+/*	$OpenBSD: labs.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +28,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)labs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
 long
-labs(j)
-	long j;
+labs(long j)
 {
 	return(j < 0 ? -j : j);
 }
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/labs.c b/libc/upstream-openbsd/lib/libc/stdlib/llabs.c
similarity index 82%
copy from libc/upstream-freebsd/lib/libc/stdlib/labs.c
copy to libc/upstream-openbsd/lib/libc/stdlib/llabs.c
index 816370e..fc2cd82 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/labs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/llabs.c
@@ -1,6 +1,8 @@
+/*	$OpenBSD: llabs.c,v 1.3 2007/01/08 19:39:25 deraadt Exp $	*/
+
 /*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +29,10 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)labs.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <stdlib.h>
 
-long
-labs(j)
-	long j;
+long long
+llabs(long long j)
 {
-	return(j < 0 ? -j : j);
+	return (j < 0 ? -j : j);
 }
diff --git a/libdl/Android.bp b/libdl/Android.bp
new file mode 100644
index 0000000..2aa9b68
--- /dev/null
+++ b/libdl/Android.bp
@@ -0,0 +1,60 @@
+//
+// libdl
+//
+cc_library {
+
+    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
+    // libgcc.a are made static to libdl.so.  This in turn ensures that libraries that
+    // a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
+    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
+    // we use this property to make sure libc.so has its own copy of the code from
+    // libgcc.a it uses.
+    //
+    // DO NOT REMOVE --exclude-libs!
+
+    ldflags: ["-Wl,--exclude-libs=libgcc.a"],
+
+    // for x86, exclude libgcc_eh.a for the same reasons as above
+    arch: {
+        arm: {
+            version_script: "libdl.arm.map",
+        },
+        arm64: {
+            version_script: "libdl.arm64.map",
+        },
+        mips: {
+            version_script: "libdl.mips.map",
+        },
+        mips64: {
+            version_script: "libdl.mips64.map",
+        },
+        x86: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+            version_script: "libdl.x86.map",
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+            version_script: "libdl.x86_64.map",
+        },
+    },
+    srcs: ["libdl.c"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+    stl: "none",
+
+    name: "libdl",
+
+    // NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
+    // few symbols from libc. Using --no-undefined here results in having to link
+    // against libc creating a circular dependency which is removed and we end up
+    // with missing symbols. Since this library is just a bunch of stubs, we set
+    // LOCAL_ALLOW_UNDEFINED_SYMBOLS to remove --no-undefined from the linker flags.
+    allow_undefined_symbols: true,
+    system_shared_libs: [],
+
+    sanitize: ["never"],
+}
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 7b97dc4..1ea5dc7 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -15,18 +15,31 @@
 #
 # DO NOT REMOVE --exclude-libs!
 
-LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a -Wl,--version-script=$(LOCAL_PATH)/libdl.map
+LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a
 
 # for x86, exclude libgcc_eh.a for the same reasons as above
 LOCAL_LDFLAGS_x86 := -Wl,--exclude-libs=libgcc_eh.a
 LOCAL_LDFLAGS_x86_64 := $(LOCAL_LDFLAGS_x86)
 
+LOCAL_LDFLAGS_arm    += -Wl,--version-script=$(LOCAL_PATH)/libdl.arm.map
+LOCAL_LDFLAGS_arm64  += -Wl,--version-script=$(LOCAL_PATH)/libdl.arm64.map
+LOCAL_LDFLAGS_mips   += -Wl,--version-script=$(LOCAL_PATH)/libdl.mips.map
+LOCAL_LDFLAGS_mips64 += -Wl,--version-script=$(LOCAL_PATH)/libdl.mips64.map
+LOCAL_LDFLAGS_x86    += -Wl,--version-script=$(LOCAL_PATH)/libdl.x86.map
+LOCAL_LDFLAGS_x86_64 += -Wl,--version-script=$(LOCAL_PATH)/libdl.x86_64.map
+
 LOCAL_SRC_FILES:= libdl.c
 LOCAL_CFLAGS := -Wall -Wextra -Wunused -Werror
 LOCAL_CXX_STL := none
 
 LOCAL_MODULE := libdl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk \
+                                 $(LOCAL_PATH)/libdl.arm.map \
+                                 $(LOCAL_PATH)/libdl.arm64.map \
+                                 $(LOCAL_PATH)/libdl.mips.map \
+                                 $(LOCAL_PATH)/libdl.mips64.map \
+                                 $(LOCAL_PATH)/libdl.x86.map \
+                                 $(LOCAL_PATH)/libdl.x86_64.map \
 
 # NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
 # few symbols from libc. Using --no-undefined here results in having to link
@@ -36,7 +49,7 @@
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 include $(BUILD_SHARED_LIBRARY)
 
 # A dummy libdl.a. Need for static executables using the LLVM unwinder. Most
@@ -49,5 +62,5 @@
 
 LOCAL_MODULE := libdl
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libdl/NOTICE b/libdl/NOTICE
index 77b5743..7940d04 100644
--- a/libdl/NOTICE
+++ b/libdl/NOTICE
@@ -14,3 +14,19 @@
 
 -------------------------------------------------------------------
 
+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.
+
+-------------------------------------------------------------------
+
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
new file mode 100644
index 0000000..b9e494a
--- /dev/null
+++ b/libdl/libdl.arm.map
@@ -0,0 +1,30 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dl_unwind_find_exidx; # arm
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
new file mode 100644
index 0000000..a8c98da
--- /dev/null
+++ b/libdl/libdl.arm64.map
@@ -0,0 +1,29 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 9a858a3..fa5237f 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -24,21 +24,48 @@
 // in the dynamic linker and hijacked at runtime.
 
 void* dlopen(const char* filename __unused, int flag __unused) { return 0; }
+
 const char* dlerror(void) { return 0; }
+
 void* dlsym(void* handle __unused, const char* symbol __unused) { return 0; }
+
+void* dlvsym(void* handle __unused, const char* symbol __unused, const char* version __unused) {
+  return 0;
+}
+
 int dladdr(const void* addr __unused, Dl_info* info __unused) { return 0; }
+
 int dlclose(void* handle __unused) { return 0; }
 
 #if defined(__arm__)
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc __unused, int* pcount __unused) { return 0; }
 #endif
 
-int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data) __unused, void* data __unused) { return 0; }
+int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data) __unused,
+                    void* data __unused) {
+  return 0;
+}
 
 void android_get_LD_LIBRARY_PATH(char* buffer __unused, size_t buffer_size __unused) { }
 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_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; }
+
+bool android_init_namespaces(const char* public_ns_sonames __unused,
+                             const char* anon_ns_library_path __unused) {
+  return false;
+}
+
+struct android_namespace_t* android_create_namespace(const char* name __unused,
+                                                     const char* ld_library_path __unused,
+                                                     const char* default_library_path __unused,
+                                                     uint64_t type __unused,
+                                                     const char* permitted_when_isolated_path __unused) {
+  return 0;
+}
diff --git a/libdl/libdl.map b/libdl/libdl.map.txt
similarity index 87%
rename from libdl/libdl.map
rename to libdl/libdl.map.txt
index a911cb6..55a03cb 100644
--- a/libdl/libdl.map
+++ b/libdl/libdl.map.txt
@@ -18,9 +18,7 @@
   global:
     android_dlopen_ext;
     dl_iterate_phdr;
-# begin arm-only
-    dl_unwind_find_exidx;
-# end arm-only
+    dl_unwind_find_exidx; # arm
     dladdr;
     dlclose;
     dlerror;
@@ -30,10 +28,17 @@
     *;
 };
 
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
 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;
+} LIBC_N;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
new file mode 100644
index 0000000..a8c98da
--- /dev/null
+++ b/libdl/libdl.mips.map
@@ -0,0 +1,29 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
new file mode 100644
index 0000000..a8c98da
--- /dev/null
+++ b/libdl/libdl.mips64.map
@@ -0,0 +1,29 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
new file mode 100644
index 0000000..a8c98da
--- /dev/null
+++ b/libdl/libdl.x86.map
@@ -0,0 +1,29 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
new file mode 100644
index 0000000..a8c98da
--- /dev/null
+++ b/libdl/libdl.x86_64.map
@@ -0,0 +1,29 @@
+# Generated by genversionscripts.py. Do not edit.
+
+LIBC {
+  global:
+    android_dlopen_ext;
+    dl_iterate_phdr;
+    dladdr;
+    dlclose;
+    dlerror;
+    dlopen;
+    dlsym;
+  local:
+    *;
+};
+
+LIBC_N {
+  global:
+    android_init_namespaces;
+    android_create_namespace;
+    dlvsym;
+} LIBC;
+
+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_N;
diff --git a/libm/Android.bp b/libm/Android.bp
new file mode 100644
index 0000000..081a139
--- /dev/null
+++ b/libm/Android.bp
@@ -0,0 +1,520 @@
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// ifneq ($(TARGET_USE_PRIVATE_LIBM),true)
+
+bionic_coverage = false
+
+libm_common_src_files = [
+    "upstream-freebsd/lib/msun/bsdsrc/b_exp.c",
+    "upstream-freebsd/lib/msun/bsdsrc/b_log.c",
+    "upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c",
+    "upstream-freebsd/lib/msun/src/catrig.c",
+    "upstream-freebsd/lib/msun/src/catrigf.c",
+    "upstream-freebsd/lib/msun/src/e_acos.c",
+    "upstream-freebsd/lib/msun/src/e_acosf.c",
+    "upstream-freebsd/lib/msun/src/e_acosh.c",
+    "upstream-freebsd/lib/msun/src/e_acoshf.c",
+    "upstream-freebsd/lib/msun/src/e_asin.c",
+    "upstream-freebsd/lib/msun/src/e_asinf.c",
+    "upstream-freebsd/lib/msun/src/e_atan2.c",
+    "upstream-freebsd/lib/msun/src/e_atan2f.c",
+    "upstream-freebsd/lib/msun/src/e_atanh.c",
+    "upstream-freebsd/lib/msun/src/e_atanhf.c",
+    "upstream-freebsd/lib/msun/src/e_cosh.c",
+    "upstream-freebsd/lib/msun/src/e_coshf.c",
+    "upstream-freebsd/lib/msun/src/e_exp.c",
+    "upstream-freebsd/lib/msun/src/e_expf.c",
+    "upstream-freebsd/lib/msun/src/e_fmod.c",
+    "upstream-freebsd/lib/msun/src/e_fmodf.c",
+    "upstream-freebsd/lib/msun/src/e_gamma.c",
+    "upstream-freebsd/lib/msun/src/e_gammaf.c",
+    "upstream-freebsd/lib/msun/src/e_gammaf_r.c",
+    "upstream-freebsd/lib/msun/src/e_gamma_r.c",
+    "upstream-freebsd/lib/msun/src/e_hypot.c",
+    "upstream-freebsd/lib/msun/src/e_hypotf.c",
+    "upstream-freebsd/lib/msun/src/e_j0.c",
+    "upstream-freebsd/lib/msun/src/e_j0f.c",
+    "upstream-freebsd/lib/msun/src/e_j1.c",
+    "upstream-freebsd/lib/msun/src/e_j1f.c",
+    "upstream-freebsd/lib/msun/src/e_jn.c",
+    "upstream-freebsd/lib/msun/src/e_jnf.c",
+    "upstream-freebsd/lib/msun/src/e_lgamma.c",
+    "upstream-freebsd/lib/msun/src/e_lgammaf.c",
+    "upstream-freebsd/lib/msun/src/e_lgammaf_r.c",
+    "upstream-freebsd/lib/msun/src/e_lgamma_r.c",
+    "upstream-freebsd/lib/msun/src/e_log10.c",
+    "upstream-freebsd/lib/msun/src/e_log10f.c",
+    "upstream-freebsd/lib/msun/src/e_log2.c",
+    "upstream-freebsd/lib/msun/src/e_log2f.c",
+    "upstream-freebsd/lib/msun/src/e_log.c",
+    "upstream-freebsd/lib/msun/src/e_logf.c",
+    "upstream-freebsd/lib/msun/src/e_pow.c",
+    "upstream-freebsd/lib/msun/src/e_powf.c",
+    "upstream-freebsd/lib/msun/src/e_remainder.c",
+    "upstream-freebsd/lib/msun/src/e_remainderf.c",
+    "upstream-freebsd/lib/msun/src/e_rem_pio2.c",
+    "upstream-freebsd/lib/msun/src/e_rem_pio2f.c",
+    "upstream-freebsd/lib/msun/src/e_scalb.c",
+    "upstream-freebsd/lib/msun/src/e_scalbf.c",
+    "upstream-freebsd/lib/msun/src/e_sinh.c",
+    "upstream-freebsd/lib/msun/src/e_sinhf.c",
+    "upstream-freebsd/lib/msun/src/e_sqrt.c",
+    "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+    "upstream-freebsd/lib/msun/src/imprecise.c",
+    "upstream-freebsd/lib/msun/src/k_cos.c",
+    "upstream-freebsd/lib/msun/src/k_cosf.c",
+    "upstream-freebsd/lib/msun/src/k_exp.c",
+    "upstream-freebsd/lib/msun/src/k_expf.c",
+    "upstream-freebsd/lib/msun/src/k_rem_pio2.c",
+    "upstream-freebsd/lib/msun/src/k_sin.c",
+    "upstream-freebsd/lib/msun/src/k_sinf.c",
+    "upstream-freebsd/lib/msun/src/k_tan.c",
+    "upstream-freebsd/lib/msun/src/k_tanf.c",
+    "upstream-freebsd/lib/msun/src/s_asinh.c",
+    "upstream-freebsd/lib/msun/src/s_asinhf.c",
+    "upstream-freebsd/lib/msun/src/s_atan.c",
+    "upstream-freebsd/lib/msun/src/s_atanf.c",
+    "upstream-freebsd/lib/msun/src/s_carg.c",
+    "upstream-freebsd/lib/msun/src/s_cargf.c",
+    "upstream-freebsd/lib/msun/src/s_cargl.c",
+    "upstream-freebsd/lib/msun/src/s_cbrt.c",
+    "upstream-freebsd/lib/msun/src/s_cbrtf.c",
+    "upstream-freebsd/lib/msun/src/s_ccosh.c",
+    "upstream-freebsd/lib/msun/src/s_ccoshf.c",
+    "upstream-freebsd/lib/msun/src/s_ceil.c",
+    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+    "upstream-freebsd/lib/msun/src/s_cexp.c",
+    "upstream-freebsd/lib/msun/src/s_cexpf.c",
+    "upstream-freebsd/lib/msun/src/s_cimag.c",
+    "upstream-freebsd/lib/msun/src/s_cimagf.c",
+    "upstream-freebsd/lib/msun/src/s_cimagl.c",
+    "upstream-freebsd/lib/msun/src/s_conj.c",
+    "upstream-freebsd/lib/msun/src/s_conjf.c",
+    "upstream-freebsd/lib/msun/src/s_conjl.c",
+    "upstream-freebsd/lib/msun/src/s_copysign.c",
+    "upstream-freebsd/lib/msun/src/s_copysignf.c",
+    "upstream-freebsd/lib/msun/src/s_cos.c",
+    "upstream-freebsd/lib/msun/src/s_cosf.c",
+    "upstream-freebsd/lib/msun/src/s_cproj.c",
+    "upstream-freebsd/lib/msun/src/s_cprojf.c",
+    "upstream-freebsd/lib/msun/src/s_cprojl.c",
+    "upstream-freebsd/lib/msun/src/s_creal.c",
+    "upstream-freebsd/lib/msun/src/s_crealf.c",
+    "upstream-freebsd/lib/msun/src/s_creall.c",
+    "upstream-freebsd/lib/msun/src/s_csinh.c",
+    "upstream-freebsd/lib/msun/src/s_csinhf.c",
+    "upstream-freebsd/lib/msun/src/s_csqrt.c",
+    "upstream-freebsd/lib/msun/src/s_csqrtf.c",
+    "upstream-freebsd/lib/msun/src/s_csqrtl.c",
+    "upstream-freebsd/lib/msun/src/s_ctanh.c",
+    "upstream-freebsd/lib/msun/src/s_ctanhf.c",
+    "upstream-freebsd/lib/msun/src/s_erf.c",
+    "upstream-freebsd/lib/msun/src/s_erff.c",
+    "upstream-freebsd/lib/msun/src/s_exp2.c",
+    "upstream-freebsd/lib/msun/src/s_exp2f.c",
+    "upstream-freebsd/lib/msun/src/s_expm1.c",
+    "upstream-freebsd/lib/msun/src/s_expm1f.c",
+    "upstream-freebsd/lib/msun/src/s_fdim.c",
+    "upstream-freebsd/lib/msun/src/s_finite.c",
+    "upstream-freebsd/lib/msun/src/s_finitef.c",
+    "upstream-freebsd/lib/msun/src/s_floor.c",
+    "upstream-freebsd/lib/msun/src/s_floorf.c",
+    "upstream-freebsd/lib/msun/src/s_fma.c",
+    "upstream-freebsd/lib/msun/src/s_fmaf.c",
+    "upstream-freebsd/lib/msun/src/s_fmax.c",
+    "upstream-freebsd/lib/msun/src/s_fmaxf.c",
+    "upstream-freebsd/lib/msun/src/s_fmin.c",
+    "upstream-freebsd/lib/msun/src/s_fminf.c",
+    "upstream-freebsd/lib/msun/src/s_frexp.c",
+    "upstream-freebsd/lib/msun/src/s_frexpf.c",
+    "upstream-freebsd/lib/msun/src/s_ilogb.c",
+    "upstream-freebsd/lib/msun/src/s_ilogbf.c",
+    "upstream-freebsd/lib/msun/src/s_llrint.c",
+    "upstream-freebsd/lib/msun/src/s_llrintf.c",
+    "upstream-freebsd/lib/msun/src/s_llround.c",
+    "upstream-freebsd/lib/msun/src/s_llroundf.c",
+    "upstream-freebsd/lib/msun/src/s_log1p.c",
+    "upstream-freebsd/lib/msun/src/s_log1pf.c",
+    "upstream-freebsd/lib/msun/src/s_logb.c",
+    "upstream-freebsd/lib/msun/src/s_logbf.c",
+    "upstream-freebsd/lib/msun/src/s_lrint.c",
+    "upstream-freebsd/lib/msun/src/s_lrintf.c",
+    "upstream-freebsd/lib/msun/src/s_lround.c",
+    "upstream-freebsd/lib/msun/src/s_lroundf.c",
+    "upstream-freebsd/lib/msun/src/s_modf.c",
+    "upstream-freebsd/lib/msun/src/s_modff.c",
+    "upstream-freebsd/lib/msun/src/s_nan.c",
+    "upstream-freebsd/lib/msun/src/s_nearbyint.c",
+    "upstream-freebsd/lib/msun/src/s_nextafter.c",
+    "upstream-freebsd/lib/msun/src/s_nextafterf.c",
+    "upstream-freebsd/lib/msun/src/s_remquo.c",
+    "upstream-freebsd/lib/msun/src/s_remquof.c",
+    "upstream-freebsd/lib/msun/src/s_rint.c",
+    "upstream-freebsd/lib/msun/src/s_rintf.c",
+    "upstream-freebsd/lib/msun/src/s_round.c",
+    "upstream-freebsd/lib/msun/src/s_roundf.c",
+    "upstream-freebsd/lib/msun/src/s_scalbln.c",
+    "upstream-freebsd/lib/msun/src/s_scalbn.c",
+    "upstream-freebsd/lib/msun/src/s_scalbnf.c",
+    "upstream-freebsd/lib/msun/src/s_signgam.c",
+    "upstream-freebsd/lib/msun/src/s_significand.c",
+    "upstream-freebsd/lib/msun/src/s_significandf.c",
+    "upstream-freebsd/lib/msun/src/s_sin.c",
+    "upstream-freebsd/lib/msun/src/s_sinf.c",
+    "upstream-freebsd/lib/msun/src/s_tan.c",
+    "upstream-freebsd/lib/msun/src/s_tanf.c",
+    "upstream-freebsd/lib/msun/src/s_tanh.c",
+    "upstream-freebsd/lib/msun/src/s_tanhf.c",
+    "upstream-freebsd/lib/msun/src/s_tgammaf.c",
+    "upstream-freebsd/lib/msun/src/s_trunc.c",
+    "upstream-freebsd/lib/msun/src/s_truncf.c",
+    "upstream-freebsd/lib/msun/src/w_cabs.c",
+    "upstream-freebsd/lib/msun/src/w_cabsf.c",
+    "upstream-freebsd/lib/msun/src/w_cabsl.c",
+    "upstream-freebsd/lib/msun/src/w_drem.c",
+    "upstream-freebsd/lib/msun/src/w_dremf.c",
+]
+
+libm_common_src_files += [
+    // TODO: this comes from from upstream's libc, not libm, but it's an
+    // implementation detail that should have hidden visibility, so it needs
+    // to be in whatever library the math code is in.
+    "digittoint.c",
+
+    // Functionality not in the BSDs.
+    "significandl.c",
+    "sincos.c",
+
+    // Modified versions of BSD code.
+    "signbit.c",
+
+    // Home-grown stuff.
+    "fabs.cpp",
+]
+
+libm_ld128_src_files = [
+    "upstream-freebsd/lib/msun/src/e_acosl.c",
+    "upstream-freebsd/lib/msun/src/e_acoshl.c",
+    "upstream-freebsd/lib/msun/src/e_asinl.c",
+    "upstream-freebsd/lib/msun/src/e_atan2l.c",
+    "upstream-freebsd/lib/msun/src/e_atanhl.c",
+    "upstream-freebsd/lib/msun/src/e_fmodl.c",
+    "upstream-freebsd/lib/msun/src/e_hypotl.c",
+    "upstream-freebsd/lib/msun/src/e_lgammal.c",
+    "upstream-freebsd/lib/msun/src/e_remainderl.c",
+    "upstream-freebsd/lib/msun/src/e_sqrtl.c",
+    "upstream-freebsd/lib/msun/src/s_asinhl.c",
+    "upstream-freebsd/lib/msun/src/s_atanl.c",
+    "upstream-freebsd/lib/msun/src/s_cbrtl.c",
+    "upstream-freebsd/lib/msun/src/s_ceill.c",
+    "upstream-freebsd/lib/msun/src/s_copysignl.c",
+    "upstream-freebsd/lib/msun/src/e_coshl.c",
+    "upstream-freebsd/lib/msun/src/s_cosl.c",
+    "upstream-freebsd/lib/msun/src/s_floorl.c",
+    "upstream-freebsd/lib/msun/src/s_fmal.c",
+    "upstream-freebsd/lib/msun/src/s_fmaxl.c",
+    "upstream-freebsd/lib/msun/src/s_fminl.c",
+    "upstream-freebsd/lib/msun/src/s_modfl.c",
+    "upstream-freebsd/lib/msun/src/s_frexpl.c",
+    "upstream-freebsd/lib/msun/src/s_ilogbl.c",
+    "upstream-freebsd/lib/msun/src/s_llrintl.c",
+    "upstream-freebsd/lib/msun/src/s_llroundl.c",
+    "upstream-freebsd/lib/msun/src/s_logbl.c",
+    "upstream-freebsd/lib/msun/src/s_lrintl.c",
+    "upstream-freebsd/lib/msun/src/s_lroundl.c",
+    "upstream-freebsd/lib/msun/src/s_nextafterl.c",
+    "upstream-freebsd/lib/msun/src/s_nexttoward.c",
+    "upstream-freebsd/lib/msun/src/s_nexttowardf.c",
+    "upstream-freebsd/lib/msun/src/s_remquol.c",
+    "upstream-freebsd/lib/msun/src/s_rintl.c",
+    "upstream-freebsd/lib/msun/src/s_roundl.c",
+    "upstream-freebsd/lib/msun/src/s_scalbnl.c",
+    "upstream-freebsd/lib/msun/src/e_sinhl.c",
+    "upstream-freebsd/lib/msun/src/s_sinl.c",
+    "upstream-freebsd/lib/msun/src/s_tanhl.c",
+    "upstream-freebsd/lib/msun/src/s_tanl.c",
+    "upstream-freebsd/lib/msun/src/s_truncl.c",
+]
+
+libm_ld128_src_files += [
+    "upstream-freebsd/lib/msun/ld128/invtrig.c",
+    "upstream-freebsd/lib/msun/ld128/e_lgammal_r.c",
+    "upstream-freebsd/lib/msun/ld128/k_cosl.c",
+    "upstream-freebsd/lib/msun/ld128/k_sinl.c",
+    "upstream-freebsd/lib/msun/ld128/k_tanl.c",
+    "upstream-freebsd/lib/msun/ld128/s_erfl.c",
+    "upstream-freebsd/lib/msun/ld128/s_exp2l.c",
+    "upstream-freebsd/lib/msun/ld128/s_expl.c",
+    "upstream-freebsd/lib/msun/ld128/s_logl.c",
+    "upstream-freebsd/lib/msun/ld128/s_nanl.c",
+]
+
+// TODO: re-enable i387/e_sqrtf.S for x86, and maybe others.
+
+libm_common_cflags = [
+    "-D__BIONIC_NO_MATH_INLINES",
+    "-DFLT_EVAL_METHOD=0",
+    "-include freebsd-compat.h",
+    "-Werror",
+    "-Wno-missing-braces",
+    "-Wno-parentheses",
+    "-Wno-sign-compare",
+    "-Wno-uninitialized",
+    "-Wno-unknown-pragmas",
+    "-fvisibility=hidden",
+]
+
+// Workaround the GCC "(long)fn -> lfn" optimization bug which will result in
+// self recursions for lrint, lrintf, and lrintl.
+// BUG: 14225968
+libm_common_cflags += [
+    "-fno-builtin-rint",
+    "-fno-builtin-rintf",
+    "-fno-builtin-rintl",
+]
+
+libm_common_local_includes = ["upstream-freebsd/lib/msun/src/"]
+
+libm_ld_local_includes = ["upstream-freebsd/lib/msun/ld128/"]
+
+//
+// libm.so and libm.a for target.
+//
+cc_library {
+    name: "libm",
+
+    cflags: libm_common_cflags,
+    include_dirs: ["bionic/libc"],
+    local_include_dirs: libm_common_local_includes,
+    srcs: libm_common_src_files,
+    system_shared_libs: ["libc"],
+
+    native_coverage: bionic_coverage,
+    sanitize: ["never"],
+
+    multilib: {
+        lib32: {
+            srcs: ["fake_long_double.c"],
+        },
+        lib64: {
+            srcs: libm_ld128_src_files,
+            local_include_dirs: libm_ld_local_includes,
+            // 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.
+            ldflags: ["-Wl,--exclude-libs,libgcc.a"],
+        },
+    },
+
+    // arch-specific settings
+    arch: {
+        arm: {
+            srcs: [
+                "arm/fenv.c",
+            ],
+            armv7_a_neon: {
+                srcs: [
+                    "arm/sqrt.S",
+                    "arm/floor.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                    "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                ],
+            },
+            instruction_set: "arm",
+            ldflags: ["-Wl,--hash-style=both"],
+            version_script: "libm.arm.map",
+        },
+
+        arm64: {
+            srcs: [
+                "arm64/ceil.S",
+                "arm64/fenv.c",
+                "arm64/fma.S",
+                "arm64/floor.S",
+                "arm64/lrint.S",
+                "arm64/rint.S",
+                "arm64/sqrt.S",
+                "arm64/trunc.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_ceil.c",
+                "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                "upstream-freebsd/lib/msun/src/s_fma.c",
+                "upstream-freebsd/lib/msun/src/s_fmaf.c",
+                "upstream-freebsd/lib/msun/src/s_floor.c",
+                "upstream-freebsd/lib/msun/src/s_floorf.c",
+                "upstream-freebsd/lib/msun/src/s_llrint.c",
+                "upstream-freebsd/lib/msun/src/s_llrintf.c",
+                "upstream-freebsd/lib/msun/src/s_lrint.c",
+                "upstream-freebsd/lib/msun/src/s_lrintf.c",
+                "upstream-freebsd/lib/msun/src/s_rint.c",
+                "upstream-freebsd/lib/msun/src/s_rintf.c",
+                "upstream-freebsd/lib/msun/src/s_trunc.c",
+                "upstream-freebsd/lib/msun/src/s_truncf.c",
+            ],
+            version_script: "libm.arm64.map",
+        },
+
+        mips: {
+            srcs: ["mips/fenv.c"],
+            version_script: "libm.mips.map",
+        },
+
+        mips64: {
+            srcs: ["mips/fenv.c"],
+            version_script: "libm.mips64.map",
+        },
+
+        x86: {
+            srcs: [
+                "i387/fenv.c",
+                "x86/sqrt.S",
+                "x86/sqrtf.S",
+                "x86/e_acos.S",
+                "x86/e_asin.S",
+                "x86/e_atan2.S",
+                "x86/e_cosh.S",
+                "x86/e_exp.S",
+                "x86/e_hypot.S",
+                "x86/e_log10.S",
+                "x86/e_log.S",
+                "x86/e_pow.S",
+                "x86/e_sinh.S",
+                "x86/libm_reduce_pi04l.S",
+                "x86/libm_sincos_huge.S",
+                "x86/libm_tancot_huge.S",
+                "x86/s_atan.S",
+                "x86/s_cbrt.S",
+                "x86/s_cos.S",
+                "x86/s_expm1.S",
+                "x86/s_log1p.S",
+                "x86/s_sin.S",
+                "x86/s_tanh.S",
+                "x86/s_tan.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_acos.c",
+                "upstream-freebsd/lib/msun/src/e_asin.c",
+                "upstream-freebsd/lib/msun/src/e_atan2.c",
+                "upstream-freebsd/lib/msun/src/e_cosh.c",
+                "upstream-freebsd/lib/msun/src/e_exp.c",
+                "upstream-freebsd/lib/msun/src/e_hypot.c",
+                "upstream-freebsd/lib/msun/src/e_log.c",
+                "upstream-freebsd/lib/msun/src/e_log10.c",
+                "upstream-freebsd/lib/msun/src/e_pow.c",
+                "upstream-freebsd/lib/msun/src/e_sinh.c",
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_atan.c",
+                "upstream-freebsd/lib/msun/src/s_cbrt.c",
+                "upstream-freebsd/lib/msun/src/s_cos.c",
+                "upstream-freebsd/lib/msun/src/s_expm1.c",
+                "upstream-freebsd/lib/msun/src/s_log1p.c",
+                "upstream-freebsd/lib/msun/src/s_sin.c",
+                "upstream-freebsd/lib/msun/src/s_tan.c",
+                "upstream-freebsd/lib/msun/src/s_tanh.c",
+            ],
+            sse4_1: {
+                srcs: [
+                    "x86/ceil.S",
+                    "x86/ceilf.S",
+                    "x86/floor.S",
+                    "x86/floorf.S",
+                    "x86/trunc.S",
+                    "x86/truncf.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/s_ceil.c",
+                    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                    "upstream-freebsd/lib/msun/src/s_floorf.c",
+                    "upstream-freebsd/lib/msun/src/s_trunc.c",
+                    "upstream-freebsd/lib/msun/src/s_truncf.c",
+                ],
+            },
+            local_include_dirs: ["i387"],
+            // Clang has wrong long double sizes for x86.
+            clang: false,
+            ldflags: ["-Wl,--hash-style=both"],
+            version_script: "libm.x86.map",
+        },
+
+        x86_64: {
+            srcs: [
+                "amd64/fenv.c",
+                "x86_64/sqrt.S",
+                "x86_64/sqrtf.S",
+                "x86_64/e_acos.S",
+                "x86_64/e_asin.S",
+                "x86_64/e_atan2.S",
+                "x86_64/e_cosh.S",
+                "x86_64/e_exp.S",
+                "x86_64/e_hypot.S",
+                "x86_64/e_log10.S",
+                "x86_64/e_log.S",
+                "x86_64/e_pow.S",
+                "x86_64/e_sinh.S",
+                "x86_64/s_atan.S",
+                "x86_64/s_cbrt.S",
+                "x86_64/s_cos.S",
+                "x86_64/s_expm1.S",
+                "x86_64/s_log1p.S",
+                "x86_64/s_sin.S",
+                "x86_64/s_tanh.S",
+                "x86_64/s_tan.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_acos.c",
+                "upstream-freebsd/lib/msun/src/e_asin.c",
+                "upstream-freebsd/lib/msun/src/e_atan2.c",
+                "upstream-freebsd/lib/msun/src/e_cosh.c",
+                "upstream-freebsd/lib/msun/src/e_exp.c",
+                "upstream-freebsd/lib/msun/src/e_hypot.c",
+                "upstream-freebsd/lib/msun/src/e_log.c",
+                "upstream-freebsd/lib/msun/src/e_log10.c",
+                "upstream-freebsd/lib/msun/src/e_pow.c",
+                "upstream-freebsd/lib/msun/src/e_sinh.c",
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_atan.c",
+                "upstream-freebsd/lib/msun/src/s_cbrt.c",
+                "upstream-freebsd/lib/msun/src/s_cos.c",
+                "upstream-freebsd/lib/msun/src/s_expm1.c",
+                "upstream-freebsd/lib/msun/src/s_log1p.c",
+                "upstream-freebsd/lib/msun/src/s_sin.c",
+                "upstream-freebsd/lib/msun/src/s_tan.c",
+                "upstream-freebsd/lib/msun/src/s_tanh.c",
+            ],
+            sse4_1: {
+                srcs: [
+                    "x86_64/ceil.S",
+                    "x86_64/ceilf.S",
+                    "x86_64/floor.S",
+                    "x86_64/floorf.S",
+                    "x86_64/trunc.S",
+                    "x86_64/truncf.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/s_ceil.c",
+                    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                    "upstream-freebsd/lib/msun/src/s_floorf.c",
+                    "upstream-freebsd/lib/msun/src/s_trunc.c",
+                    "upstream-freebsd/lib/msun/src/s_truncf.c",
+                ],
+            },
+            // Clang has wrong long double sizes for x86.
+            clang: false,
+            version_script: "libm.x86_64.map",
+        },
+    },
+
+    stl: "none",
+}
+
+// ANDROIDMK TRANSLATION ERROR: unsupported directive
+// endif
diff --git a/libm/Android.mk b/libm/Android.mk
index e919129..faf3c50 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -3,8 +3,9 @@
 
 bionic_coverage := false
 
-ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
-# Clang has wrong long double sizes for x86.
+# Clang/llvm has incompatible long double (fp128) for x86_64.
+# https://llvm.org/bugs/show_bug.cgi?id=23897
+ifeq ($(TARGET_ARCH),x86_64)
 libm_clang := false
 endif
 
@@ -21,14 +22,19 @@
     upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c \
     upstream-freebsd/lib/msun/src/catrig.c \
     upstream-freebsd/lib/msun/src/catrigf.c \
+    upstream-freebsd/lib/msun/src/e_acos.c \
     upstream-freebsd/lib/msun/src/e_acosf.c \
     upstream-freebsd/lib/msun/src/e_acosh.c \
     upstream-freebsd/lib/msun/src/e_acoshf.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
     upstream-freebsd/lib/msun/src/e_asinf.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
     upstream-freebsd/lib/msun/src/e_atan2f.c \
     upstream-freebsd/lib/msun/src/e_atanh.c \
     upstream-freebsd/lib/msun/src/e_atanhf.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
     upstream-freebsd/lib/msun/src/e_coshf.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
     upstream-freebsd/lib/msun/src/e_expf.c \
     upstream-freebsd/lib/msun/src/e_fmod.c \
     upstream-freebsd/lib/msun/src/e_fmodf.c \
@@ -36,6 +42,7 @@
     upstream-freebsd/lib/msun/src/e_gammaf.c \
     upstream-freebsd/lib/msun/src/e_gammaf_r.c \
     upstream-freebsd/lib/msun/src/e_gamma_r.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
     upstream-freebsd/lib/msun/src/e_hypotf.c \
     upstream-freebsd/lib/msun/src/e_j0.c \
     upstream-freebsd/lib/msun/src/e_j0f.c \
@@ -47,10 +54,13 @@
     upstream-freebsd/lib/msun/src/e_lgammaf.c \
     upstream-freebsd/lib/msun/src/e_lgammaf_r.c \
     upstream-freebsd/lib/msun/src/e_lgamma_r.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
     upstream-freebsd/lib/msun/src/e_log10f.c \
     upstream-freebsd/lib/msun/src/e_log2.c \
     upstream-freebsd/lib/msun/src/e_log2f.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
     upstream-freebsd/lib/msun/src/e_logf.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
     upstream-freebsd/lib/msun/src/e_powf.c \
     upstream-freebsd/lib/msun/src/e_remainder.c \
     upstream-freebsd/lib/msun/src/e_remainderf.c \
@@ -58,7 +68,10 @@
     upstream-freebsd/lib/msun/src/e_rem_pio2f.c \
     upstream-freebsd/lib/msun/src/e_scalb.c \
     upstream-freebsd/lib/msun/src/e_scalbf.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
     upstream-freebsd/lib/msun/src/e_sinhf.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
     upstream-freebsd/lib/msun/src/imprecise.c \
     upstream-freebsd/lib/msun/src/k_cos.c \
     upstream-freebsd/lib/msun/src/k_cosf.c \
@@ -71,13 +84,17 @@
     upstream-freebsd/lib/msun/src/k_tanf.c \
     upstream-freebsd/lib/msun/src/s_asinh.c \
     upstream-freebsd/lib/msun/src/s_asinhf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
     upstream-freebsd/lib/msun/src/s_atanf.c \
     upstream-freebsd/lib/msun/src/s_carg.c \
     upstream-freebsd/lib/msun/src/s_cargf.c \
     upstream-freebsd/lib/msun/src/s_cargl.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
     upstream-freebsd/lib/msun/src/s_cbrtf.c \
     upstream-freebsd/lib/msun/src/s_ccosh.c \
     upstream-freebsd/lib/msun/src/s_ccoshf.c \
+    upstream-freebsd/lib/msun/src/s_ceil.c \
+    upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_cexp.c \
     upstream-freebsd/lib/msun/src/s_cexpf.c \
     upstream-freebsd/lib/msun/src/s_cimag.c \
@@ -88,6 +105,7 @@
     upstream-freebsd/lib/msun/src/s_conjl.c \
     upstream-freebsd/lib/msun/src/s_copysign.c \
     upstream-freebsd/lib/msun/src/s_copysignf.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
     upstream-freebsd/lib/msun/src/s_cosf.c \
     upstream-freebsd/lib/msun/src/s_cproj.c \
     upstream-freebsd/lib/msun/src/s_cprojf.c \
@@ -106,12 +124,15 @@
     upstream-freebsd/lib/msun/src/s_erff.c \
     upstream-freebsd/lib/msun/src/s_exp2.c \
     upstream-freebsd/lib/msun/src/s_exp2f.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
     upstream-freebsd/lib/msun/src/s_expm1f.c \
-    upstream-freebsd/lib/msun/src/s_fabs.c \
-    upstream-freebsd/lib/msun/src/s_fabsf.c \
     upstream-freebsd/lib/msun/src/s_fdim.c \
     upstream-freebsd/lib/msun/src/s_finite.c \
     upstream-freebsd/lib/msun/src/s_finitef.c \
+    upstream-freebsd/lib/msun/src/s_floor.c \
+    upstream-freebsd/lib/msun/src/s_floorf.c \
+    upstream-freebsd/lib/msun/src/s_fma.c \
+    upstream-freebsd/lib/msun/src/s_fmaf.c \
     upstream-freebsd/lib/msun/src/s_fmax.c \
     upstream-freebsd/lib/msun/src/s_fmaxf.c \
     upstream-freebsd/lib/msun/src/s_fmin.c \
@@ -120,11 +141,16 @@
     upstream-freebsd/lib/msun/src/s_frexpf.c \
     upstream-freebsd/lib/msun/src/s_ilogb.c \
     upstream-freebsd/lib/msun/src/s_ilogbf.c \
+    upstream-freebsd/lib/msun/src/s_llrint.c \
+    upstream-freebsd/lib/msun/src/s_llrintf.c \
     upstream-freebsd/lib/msun/src/s_llround.c \
     upstream-freebsd/lib/msun/src/s_llroundf.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
     upstream-freebsd/lib/msun/src/s_log1pf.c \
     upstream-freebsd/lib/msun/src/s_logb.c \
     upstream-freebsd/lib/msun/src/s_logbf.c \
+    upstream-freebsd/lib/msun/src/s_lrint.c \
+    upstream-freebsd/lib/msun/src/s_lrintf.c \
     upstream-freebsd/lib/msun/src/s_lround.c \
     upstream-freebsd/lib/msun/src/s_lroundf.c \
     upstream-freebsd/lib/msun/src/s_modf.c \
@@ -135,6 +161,8 @@
     upstream-freebsd/lib/msun/src/s_nextafterf.c \
     upstream-freebsd/lib/msun/src/s_remquo.c \
     upstream-freebsd/lib/msun/src/s_remquof.c \
+    upstream-freebsd/lib/msun/src/s_rint.c \
+    upstream-freebsd/lib/msun/src/s_rintf.c \
     upstream-freebsd/lib/msun/src/s_round.c \
     upstream-freebsd/lib/msun/src/s_roundf.c \
     upstream-freebsd/lib/msun/src/s_scalbln.c \
@@ -143,10 +171,15 @@
     upstream-freebsd/lib/msun/src/s_signgam.c \
     upstream-freebsd/lib/msun/src/s_significand.c \
     upstream-freebsd/lib/msun/src/s_significandf.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
     upstream-freebsd/lib/msun/src/s_sinf.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
     upstream-freebsd/lib/msun/src/s_tanf.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
     upstream-freebsd/lib/msun/src/s_tanhf.c \
     upstream-freebsd/lib/msun/src/s_tgammaf.c \
+    upstream-freebsd/lib/msun/src/s_trunc.c \
+    upstream-freebsd/lib/msun/src/s_truncf.c \
     upstream-freebsd/lib/msun/src/w_cabs.c \
     upstream-freebsd/lib/msun/src/w_cabsf.c \
     upstream-freebsd/lib/msun/src/w_cabsl.c \
@@ -174,7 +207,6 @@
     upstream-freebsd/lib/msun/src/s_copysignl.c \
     upstream-freebsd/lib/msun/src/e_coshl.c \
     upstream-freebsd/lib/msun/src/s_cosl.c \
-    upstream-freebsd/lib/msun/src/s_fabsl.c \
     upstream-freebsd/lib/msun/src/s_floorl.c \
     upstream-freebsd/lib/msun/src/s_fmal.c \
     upstream-freebsd/lib/msun/src/s_fmaxl.c \
@@ -227,6 +259,10 @@
 LOCAL_SRC_FILES += \
     signbit.c \
 
+# Home-grown stuff.
+LOCAL_SRC_FILES += \
+    fabs.cpp \
+
 # Arch specific optimizations.
 
 # -----------------------------------------------------------------------------
@@ -234,37 +270,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_arm += \
     arm/fenv.c \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_ceil.c \
-    upstream-freebsd/lib/msun/src/s_ceilf.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_floorf.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
-    upstream-freebsd/lib/msun/src/s_trunc.c \
-    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 # s_floor.S requires neon instructions.
 ifdef TARGET_2ND_ARCH
@@ -274,18 +279,16 @@
 endif
 
 # Use the C version on armv7-a since it doesn't support neon instructions.
-ifeq ($(arch_variant),armv7-a)
+ifneq ($(arch_variant),armv7-a)
 LOCAL_SRC_FILES_arm += \
+    arm/sqrt.S \
+    arm/floor.S \
+
+LOCAL_SRC_FILES_EXCLUDE_arm += \
     upstream-freebsd/lib/msun/src/e_sqrt.c \
     upstream-freebsd/lib/msun/src/e_sqrtf.c \
     upstream-freebsd/lib/msun/src/s_floor.c \
 
-else
-LOCAL_SRC_FILES_arm += \
-    arm/e_sqrt.S \
-    arm/e_sqrtf.S \
-    arm/s_floor.S \
-
 endif
 
 # -----------------------------------------------------------------------------
@@ -300,64 +303,30 @@
     arm64/rint.S \
     arm64/sqrt.S \
     arm64/trunc.S \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
+
+LOCAL_SRC_FILES_EXCLUDE_arm64 += \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_ceil.c \
+    upstream-freebsd/lib/msun/src/s_ceilf.c \
+    upstream-freebsd/lib/msun/src/s_fma.c \
+    upstream-freebsd/lib/msun/src/s_fmaf.c \
+    upstream-freebsd/lib/msun/src/s_floor.c \
+    upstream-freebsd/lib/msun/src/s_floorf.c \
+    upstream-freebsd/lib/msun/src/s_llrint.c \
+    upstream-freebsd/lib/msun/src/s_llrintf.c \
+    upstream-freebsd/lib/msun/src/s_lrint.c \
+    upstream-freebsd/lib/msun/src/s_lrintf.c \
+    upstream-freebsd/lib/msun/src/s_rint.c \
+    upstream-freebsd/lib/msun/src/s_rintf.c \
+    upstream-freebsd/lib/msun/src/s_trunc.c \
+    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 # -----------------------------------------------------------------------------
 # mips
 # -----------------------------------------------------------------------------
 libm_mips_arch_files := \
     mips/fenv.c \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/e_sqrt.c \
-    upstream-freebsd/lib/msun/src/e_sqrtf.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_ceil.c \
-    upstream-freebsd/lib/msun/src/s_ceilf.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_floor.c \
-    upstream-freebsd/lib/msun/src/s_floorf.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
-    upstream-freebsd/lib/msun/src/s_trunc.c \
-    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 LOCAL_SRC_FILES_mips += $(libm_mips_arch_files)
 LOCAL_SRC_FILES_mips64 += $(libm_mips_arch_files)
@@ -367,14 +336,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_x86 += \
     i387/fenv.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
     x86/sqrt.S \
     x86/sqrtf.S \
     x86/e_acos.S \
@@ -399,6 +360,28 @@
     x86/s_tanh.S \
     x86/s_tan.S \
 
+LOCAL_SRC_FILES_EXCLUDE_x86 += \
+    upstream-freebsd/lib/msun/src/e_acos.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
+
 ifeq ($(ARCH_X86_HAVE_SSE4_1),true)
 LOCAL_SRC_FILES_x86 += \
     x86/ceil.S \
@@ -408,8 +391,7 @@
     x86/trunc.S \
     x86/truncf.S \
 
-else
-LOCAL_SRC_FILES_x86 += \
+LOCAL_SRC_FILES_EXCLUDE_x86 += \
     upstream-freebsd/lib/msun/src/s_ceil.c \
     upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_floor.c \
@@ -424,14 +406,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_x86_64 += \
     amd64/fenv.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
     x86_64/sqrt.S \
     x86_64/sqrtf.S \
     x86_64/e_acos.S \
@@ -453,6 +427,28 @@
     x86_64/s_tanh.S \
     x86_64/s_tan.S \
 
+LOCAL_SRC_FILES_EXCLUDE_x86_64 += \
+    upstream-freebsd/lib/msun/src/e_acos.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
+
 ifeq ($(ARCH_X86_HAVE_SSE4_1),true)
 LOCAL_SRC_FILES_x86_64 += \
     x86_64/ceil.S \
@@ -462,8 +458,7 @@
     x86_64/trunc.S \
     x86_64/truncf.S \
 
-else
-LOCAL_SRC_FILES_x86_64 += \
+LOCAL_SRC_FILES_EXCLUDE_x86_64 += \
     upstream-freebsd/lib/msun/src/s_ceil.c \
     upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_floor.c \
@@ -481,8 +476,10 @@
 LOCAL_CLANG := $(libm_clang)
 LOCAL_ARM_MODE := arm
 LOCAL_CFLAGS := \
+    -D__BIONIC_NO_MATH_INLINES \
     -DFLT_EVAL_METHOD=0 \
     -include $(LOCAL_PATH)/freebsd-compat.h \
+    -Werror \
     -Wno-missing-braces \
     -Wno-parentheses \
     -Wno-sign-compare \
@@ -501,11 +498,8 @@
     -fno-builtin-rintf \
     -fno-builtin-rintl \
 
-LOCAL_CONLY_FLAGS := \
-    -std=c99 \
-
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 include $(BUILD_STATIC_LIBRARY)
 
 # -----------------------------------------------------------------------------
@@ -513,13 +507,25 @@
 # -----------------------------------------------------------------------------
 include $(CLEAR_VARS)
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/libm.map
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(LOCAL_PATH)/libm.arm.map \
+    $(LOCAL_PATH)/libm.arm64.map \
+    $(LOCAL_PATH)/libm.mips.map \
+    $(LOCAL_PATH)/libm.mips64.map \
+    $(LOCAL_PATH)/libm.x86.map \
+    $(LOCAL_PATH)/libm.x86_64.map \
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
 
-LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/libm.map
+LOCAL_LDFLAGS_arm    += -Wl,--version-script,$(LOCAL_PATH)/libm.arm.map
+LOCAL_LDFLAGS_arm64  += -Wl,--version-script,$(LOCAL_PATH)/libm.arm64.map
+LOCAL_LDFLAGS_mips   += -Wl,--version-script,$(LOCAL_PATH)/libm.mips.map
+LOCAL_LDFLAGS_mips64 += -Wl,--version-script,$(LOCAL_PATH)/libm.mips64.map
+LOCAL_LDFLAGS_x86    += -Wl,--version-script,$(LOCAL_PATH)/libm.x86.map
+LOCAL_LDFLAGS_x86_64 += -Wl,--version-script,$(LOCAL_PATH)/libm.x86_64.map
+
 
 LOCAL_MODULE := libm
 LOCAL_CLANG := $(libm_clang)
@@ -527,7 +533,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := libm
 
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 
 LOCAL_CXX_STL := none
 
diff --git a/libm/NOTICE b/libm/NOTICE
index a2cfad3..c254c08 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -181,6 +181,22 @@
 
 -------------------------------------------------------------------
 
+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) 1985, 1993
    The Regents of the University of California.  All rights reserved.
 
@@ -1003,37 +1019,6 @@
 -------------------------------------------------------------------
 
 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>
 
diff --git a/libm/arm/e_sqrtf.S b/libm/arm/e_sqrtf.S
deleted file mode 100644
index ddefb22..0000000
--- a/libm/arm/e_sqrtf.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY(sqrtf)
-    vmov.f32    s0, r0
-    vsqrt.f32   s0, s0
-    vmov.f32    r0, s0
-    bx          lr
-END(sqrtf)
diff --git a/libm/arm/s_floor.S b/libm/arm/floor.S
similarity index 100%
rename from libm/arm/s_floor.S
rename to libm/arm/floor.S
diff --git a/libm/arm/e_sqrt.S b/libm/arm/sqrt.S
similarity index 94%
rename from libm/arm/e_sqrt.S
rename to libm/arm/sqrt.S
index 17312f5..f2981f4 100644
--- a/libm/arm/e_sqrt.S
+++ b/libm/arm/sqrt.S
@@ -39,4 +39,11 @@
     bx          lr
 END(sqrt)
 
+ENTRY(sqrtf)
+    vmov.f32    s0, r0
+    vsqrt.f32   s0, s0
+    vmov.f32    r0, s0
+    bx          lr
+END(sqrtf)
+
 ALIAS_SYMBOL(sqrtl, sqrt);
diff --git a/libm/arm64/fenv.c b/libm/arm64/fenv.c
index ce560a7..19a2393 100644
--- a/libm/arm64/fenv.c
+++ b/libm/arm64/fenv.c
@@ -26,6 +26,7 @@
  * $FreeBSD: libm/aarch64/fenv.c $
  */
 
+#include <stdint.h>
 #include <fenv.h>
 
 #define FPCR_EXCEPT_SHIFT 8
@@ -38,10 +39,20 @@
 typedef __uint32_t fpu_control_t;   // FPCR, Floating-point Control Register.
 typedef __uint32_t fpu_status_t;    // FPSR, Floating-point Status Register.
 
-#define __get_fpcr(__fpcr) __asm__ __volatile__("mrs %0,fpcr" : "=r" (__fpcr))
-#define __get_fpsr(__fpsr) __asm__ __volatile__("mrs %0,fpsr" : "=r" (__fpsr))
-#define __set_fpcr(__fpcr) __asm__ __volatile__("msr fpcr,%0" : :"ri" (__fpcr))
-#define __set_fpsr(__fpsr) __asm__ __volatile__("msr fpsr,%0" : :"ri" (__fpsr))
+#define __get(REGISTER, __value) { \
+  uint64_t __value64; \
+  __asm__ __volatile__("mrs %0," REGISTER : "=r" (__value64)); \
+  __value = (__uint32_t) __value64; \
+}
+#define __get_fpcr(__fpcr) __get("fpcr", __fpcr)
+#define __get_fpsr(__fpsr) __get("fpsr", __fpsr)
+
+#define __set(REGISTER, __value) { \
+  uint64_t __value64 = __value; \
+  __asm__ __volatile__("msr " REGISTER ",%0" : : "ri" (__value64)); \
+}
+#define __set_fpcr(__fpcr) __set("fpcr", __fpcr)
+#define __set_fpsr(__fpsr) __set("fpsr", __fpsr)
 
 int fegetenv(fenv_t* envp) {
   __get_fpcr(envp->__control);
diff --git a/libm/fabs.cpp b/libm/fabs.cpp
new file mode 100644
index 0000000..add73fe
--- /dev/null
+++ b/libm/fabs.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <math.h>
+
+#include "fpmath.h"
+
+double fabs(double x) {
+#if __arm__
+  // Both Clang and GCC insist on moving r0/r1 into a double register
+  // and using fabs where bit-twiddling would be a better choice.
+  // They get fabsf right, but we need to be careful in fabsl too.
+  IEEEd2bits u;
+  u.d = x;
+  u.bits.sign = 0;
+  return u.d;
+#else
+  return __builtin_fabs(x);
+#endif
+}
+
+float fabsf(float x) {
+  return __builtin_fabsf(x);
+}
+
+#if defined(__LP64__)
+long double fabsl(long double x) { return __builtin_fabsl(x); }
+#else
+long double fabsl(long double x) {
+  // Don't use __builtin_fabs here because of ARM. (See fabs above.)
+  return fabs(x);
+}
+#endif
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index 317a115..5edf839 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -25,7 +25,6 @@
  */
 
 long double copysignl(long double a1, long double a2) { return copysign(a1, a2); }
-long double fabsl(long double a1) { return fabs(a1); }
 long double fmaxl(long double a1, long double a2) { return fmax(a1, a2); }
 long double fmodl(long double a1, long double a2) { return fmod(a1, a2); }
 long double fminl(long double a1, long double a2) { return fmin(a1, a2); }
diff --git a/libm/include/math.h b/libm/include/math.h
index 1542374..ce8e3b2 100644
--- a/libm/include/math.h
+++ b/libm/include/math.h
@@ -15,116 +15,70 @@
  */
 
 #ifndef _MATH_H_
-#define	_MATH_H_
+#define _MATH_H_
 
 #include <sys/cdefs.h>
 #include <limits.h>
 
+#if !defined(__BIONIC_NO_MATH_INLINES)
+#define __BIONIC_MATH_INLINE(__def) extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__)) __def
+#else
+#define __BIONIC_MATH_INLINE(__def)
+#endif
+
 __BEGIN_DECLS
 #pragma GCC visibility push(default)
 
-/*
- * ANSI/POSIX
- */
-extern const union __infinity_un {
-	unsigned char	__uc[8];
-	double		__ud;
-} __infinity;
-
-extern const union __nan_un {
-	unsigned char	__uc[sizeof(float)];
-	float		__uf;
-} __nan;
-
-#if __GNUC_PREREQ(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
-#define	__MATH_BUILTIN_CONSTANTS
-#endif
-
-#if __GNUC_PREREQ(3, 0) && !defined(__INTEL_COMPILER)
-#define	__MATH_BUILTIN_RELOPS
-#endif
-
-#ifdef __MATH_BUILTIN_CONSTANTS
-#define	HUGE_VAL	__builtin_huge_val()
-#else
-#define	HUGE_VAL	(__infinity.__ud)
-#endif
+#define HUGE_VAL	__builtin_huge_val()
 
 #if __ISO_C_VISIBLE >= 1999
-#define	FP_ILOGB0	(-INT_MAX) /* Android-changed */
-#define	FP_ILOGBNAN	INT_MAX /* Android-changed */
+#define FP_ILOGB0	(-INT_MAX)
+#define FP_ILOGBNAN	INT_MAX
 
-#ifdef __MATH_BUILTIN_CONSTANTS
-#define	HUGE_VALF	__builtin_huge_valf()
-#define	HUGE_VALL	__builtin_huge_vall()
-#define	INFINITY	__builtin_inff()
-#define	NAN		__builtin_nanf("")
-#else
-#define	HUGE_VALF	(float)HUGE_VAL
-#define	HUGE_VALL	(long double)HUGE_VAL
-#define	INFINITY	HUGE_VALF
-#define	NAN		(__nan.__uf)
-#endif /* __MATH_BUILTIN_CONSTANTS */
+#define HUGE_VALF	__builtin_huge_valf()
+#define HUGE_VALL	__builtin_huge_vall()
+#define INFINITY	__builtin_inff()
+#define NAN		__builtin_nanf("")
 
-#define	MATH_ERRNO	1
-#define	MATH_ERREXCEPT	2
-#define	math_errhandling	MATH_ERREXCEPT
+#define MATH_ERRNO	1
+#define MATH_ERREXCEPT	2
+#define math_errhandling	MATH_ERREXCEPT
 
-#define	FP_FAST_FMAF	1
-#ifdef __ia64__
-#define	FP_FAST_FMA	1
-#define	FP_FAST_FMAL	1
+#if defined(__FP_FAST_FMA)
+#define FP_FAST_FMA 1
+#endif
+#if defined(__FP_FAST_FMAF)
+#define FP_FAST_FMAF 1
+#endif
+#if defined(__FP_FAST_FMAL)
+#define FP_FAST_FMAL 1
 #endif
 
 /* Symbolic constants to classify floating point numbers. */
-#define	FP_INFINITE	0x01
-#define	FP_NAN		0x02
-#define	FP_NORMAL	0x04
-#define	FP_SUBNORMAL	0x08
-#define	FP_ZERO		0x10
-#define	fpclassify(x) \
-    ((sizeof (x) == sizeof (float)) ? __fpclassifyf(x) \
-    : (sizeof (x) == sizeof (double)) ? __fpclassifyd(x) \
-    : __fpclassifyl(x))
+#define FP_INFINITE	0x01
+#define FP_NAN		0x02
+#define FP_NORMAL	0x04
+#define FP_SUBNORMAL	0x08
+#define FP_ZERO		0x10
+#define fpclassify(x) \
+    __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x)
 
-#define	isfinite(x)					\
-    ((sizeof (x) == sizeof (float)) ? __isfinitef(x)	\
-    : (sizeof (x) == sizeof (double)) ? __isfinite(x)	\
-    : __isfinitel(x))
-#define	isinf(x)					\
-    ((sizeof (x) == sizeof (float)) ? __isinff(x)	\
-    : (sizeof (x) == sizeof (double)) ? isinf(x)	\
-    : __isinfl(x))
-#define	isnan(x)					\
-    ((sizeof (x) == sizeof (float)) ? __isnanf(x)	\
-    : (sizeof (x) == sizeof (double)) ? isnan(x)	\
-    : __isnanl(x))
-#define	isnormal(x)					\
-    ((sizeof (x) == sizeof (float)) ? __isnormalf(x)	\
-    : (sizeof (x) == sizeof (double)) ? __isnormal(x)	\
-    : __isnormall(x))
+#define isfinite(x) __builtin_isfinite(x)
+#define isinf(x) __builtin_isinf(x)
+#define isnan(x) __builtin_isnan(x)
+#define isnormal(x) __builtin_isnormal(x)
 
-#ifdef __MATH_BUILTIN_RELOPS
-#define	isgreater(x, y)		__builtin_isgreater((x), (y))
-#define	isgreaterequal(x, y)	__builtin_isgreaterequal((x), (y))
-#define	isless(x, y)		__builtin_isless((x), (y))
-#define	islessequal(x, y)	__builtin_islessequal((x), (y))
-#define	islessgreater(x, y)	__builtin_islessgreater((x), (y))
-#define	isunordered(x, y)	__builtin_isunordered((x), (y))
-#else
-#define	isgreater(x, y)		(!isunordered((x), (y)) && (x) > (y))
-#define	isgreaterequal(x, y)	(!isunordered((x), (y)) && (x) >= (y))
-#define	isless(x, y)		(!isunordered((x), (y)) && (x) < (y))
-#define	islessequal(x, y)	(!isunordered((x), (y)) && (x) <= (y))
-#define	islessgreater(x, y)	(!isunordered((x), (y)) && \
-					((x) > (y) || (y) > (x)))
-#define	isunordered(x, y)	(isnan(x) || isnan(y))
-#endif /* __MATH_BUILTIN_RELOPS */
+#define isgreater(x, y) __builtin_isgreater((x), (y))
+#define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y))
+#define isless(x, y) __builtin_isless((x), (y))
+#define islessequal(x, y) __builtin_islessequal((x), (y))
+#define islessgreater(x, y) __builtin_islessgreater((x), (y))
+#define isunordered(x, y) __builtin_isunordered((x), (y))
 
-#define	signbit(x)					\
-    ((sizeof (x) == sizeof (float)) ? __signbitf(x)	\
-    : (sizeof (x) == sizeof (double)) ? __signbit(x)	\
-    : __signbitl(x))
+#define signbit(x) \
+    ((sizeof(x) == sizeof(float)) ? __builtin_signbitf(x) \
+    : (sizeof(x) == sizeof(double)) ? __builtin_signbit(x) \
+    : __builtin_signbitl(x))
 
 typedef double __double_t;
 typedef __double_t double_t;
@@ -213,6 +167,7 @@
 
 double	ceil(double);
 double	fabs(double) __pure2;
+__BIONIC_MATH_INLINE(double fabs(double x) { return __builtin_fabs(x); })
 double	floor(double);
 double	fmod(double, double);
 
@@ -331,6 +286,7 @@
 
 float	ceilf(float);
 float	fabsf(float) __pure2;
+__BIONIC_MATH_INLINE(float fabsf(float x) { return __builtin_fabsf(x); })
 float	floorf(float);
 float	fmodf(float, float);
 float	roundf(float);
@@ -418,6 +374,7 @@
 long double	expl(long double);
 long double	expm1l(long double);
 long double	fabsl(long double) __pure2;
+__BIONIC_MATH_INLINE(long double fabsl(long double x) { return __builtin_fabsl(x); })
 long double	fdiml(long double, long double);
 long double	floorl(long double);
 long double	fmal(long double, long double, long double);
diff --git a/libm/libm.map b/libm/libm.arm.map
similarity index 97%
copy from libm/libm.map
copy to libm/libm.arm.map
index 7f02f42..e781f2d 100644
--- a/libm/libm.map
+++ b/libm/libm.arm.map
@@ -1,3 +1,4 @@
+# Generated by genversionscripts.py. Do not edit.
 LIBC {
   global:
     __fe_dfl_env;
@@ -271,8 +272,8 @@
     *;
 };
 
-LIBC_PRIVATE {
-  global:
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
     ___Unwind_RaiseException; # arm
@@ -353,7 +354,6 @@
     __lesf2; # arm
     __ltdf2; # arm
     __ltsf2; # arm
-    __muldc3; # arm x86 mips
     __muldf3; # arm
     __nedf2; # arm
     __nesf2; # arm
@@ -375,4 +375,4 @@
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
     restore_core_regs; # arm
-} LIBC;
+} LIBC; # arm mips
diff --git a/libm/libm.arm64.map b/libm/libm.arm64.map
new file mode 100644
index 0000000..1623ea0
--- /dev/null
+++ b/libm/libm.arm64.map
@@ -0,0 +1,274 @@
+# Generated by genversionscripts.py. Do not edit.
+LIBC {
+  global:
+    __fe_dfl_env;
+    __signbit;
+    __signbitf;
+    __signbitl;
+    acos;
+    acosf;
+    acosh;
+    acoshf;
+    acoshl;
+    acosl;
+    asin;
+    asinf;
+    asinh;
+    asinhf;
+    asinhl;
+    asinl;
+    atan;
+    atan2;
+    atan2f;
+    atan2l;
+    atanf;
+    atanh;
+    atanhf;
+    atanhl;
+    atanl;
+    cabs;
+    cabsf;
+    cabsl;
+    cacos;
+    cacosf;
+    cacosh;
+    cacoshf;
+    carg;
+    cargf;
+    cargl;
+    casin;
+    casinf;
+    casinh;
+    casinhf;
+    catan;
+    catanf;
+    catanh;
+    catanhf;
+    cbrt;
+    cbrtf;
+    cbrtl;
+    ccos;
+    ccosf;
+    ccosh;
+    ccoshf;
+    ceil;
+    ceilf;
+    ceill;
+    cexp;
+    cexpf;
+    cimag;
+    cimagf;
+    cimagl;
+    conj;
+    conjf;
+    conjl;
+    copysign;
+    copysignf;
+    copysignl;
+    cos;
+    cosf;
+    cosh;
+    coshf;
+    coshl;
+    cosl;
+    cproj;
+    cprojf;
+    cprojl;
+    creal;
+    crealf;
+    creall;
+    csin;
+    csinf;
+    csinh;
+    csinhf;
+    csqrt;
+    csqrtf;
+    csqrtl;
+    ctan;
+    ctanf;
+    ctanh;
+    ctanhf;
+    drem;
+    dremf;
+    erf;
+    erfc;
+    erfcf;
+    erfcl;
+    erff;
+    erfl;
+    exp;
+    exp2;
+    exp2f;
+    exp2l;
+    expf;
+    expl;
+    expm1;
+    expm1f;
+    expm1l;
+    fabs;
+    fabsf;
+    fabsl;
+    fdim;
+    fdimf;
+    fdiml;
+    feclearexcept;
+    fedisableexcept;
+    feenableexcept;
+    fegetenv;
+    fegetexcept;
+    fegetexceptflag;
+    fegetround;
+    feholdexcept;
+    feraiseexcept;
+    fesetenv;
+    fesetexceptflag;
+    fesetround;
+    fetestexcept;
+    feupdateenv;
+    finite;
+    finitef;
+    floor;
+    floorf;
+    floorl;
+    fma;
+    fmaf;
+    fmal;
+    fmax;
+    fmaxf;
+    fmaxl;
+    fmin;
+    fminf;
+    fminl;
+    fmod;
+    fmodf;
+    fmodl;
+    frexp;
+    frexpf;
+    frexpl;
+    gamma;
+    gamma_r;
+    gammaf;
+    gammaf_r;
+    hypot;
+    hypotf;
+    hypotl;
+    ilogb;
+    ilogbf;
+    ilogbl;
+    j0;
+    j0f;
+    j1;
+    j1f;
+    jn;
+    jnf;
+    ldexpf;
+    ldexpl;
+    lgamma;
+    lgamma_r;
+    lgammaf;
+    lgammaf_r;
+    lgammal;
+    lgammal_r;
+    llrint;
+    llrintf;
+    llrintl;
+    llround;
+    llroundf;
+    llroundl;
+    log;
+    log10;
+    log10f;
+    log10l;
+    log1p;
+    log1pf;
+    log1pl;
+    log2;
+    log2f;
+    log2l;
+    logb;
+    logbf;
+    logbl;
+    logf;
+    logl;
+    lrint;
+    lrintf;
+    lrintl;
+    lround;
+    lroundf;
+    lroundl;
+    modf;
+    modff;
+    modfl;
+    nan;
+    nanf;
+    nanl;
+    nearbyint;
+    nearbyintf;
+    nearbyintl;
+    nextafter;
+    nextafterf;
+    nextafterl;
+    nexttoward;
+    nexttowardf;
+    nexttowardl;
+    pow;
+    powf;
+    powl;
+    remainder;
+    remainderf;
+    remainderl;
+    remquo;
+    remquof;
+    remquol;
+    rint;
+    rintf;
+    rintl;
+    round;
+    roundf;
+    roundl;
+    scalb;
+    scalbf;
+    scalbln;
+    scalblnf;
+    scalblnl;
+    scalbn;
+    scalbnf;
+    scalbnl;
+    signgam;
+    significand;
+    significandf;
+    significandl;
+    sin;
+    sincos;
+    sincosf;
+    sincosl;
+    sinf;
+    sinh;
+    sinhf;
+    sinhl;
+    sinl;
+    sqrt;
+    sqrtf;
+    sqrtl;
+    tan;
+    tanf;
+    tanh;
+    tanhf;
+    tanhl;
+    tanl;
+    tgamma;
+    tgammaf;
+    tgammal;
+    trunc;
+    truncf;
+    truncl;
+    y0;
+    y0f;
+    y1;
+    y1f;
+    yn;
+    ynf;
+  local:
+    *;
+};
+
diff --git a/libm/libm.map b/libm/libm.map.txt
similarity index 98%
rename from libm/libm.map
rename to libm/libm.map.txt
index 7f02f42..075ebd5 100644
--- a/libm/libm.map
+++ b/libm/libm.map.txt
@@ -271,8 +271,8 @@
     *;
 };
 
-LIBC_PRIVATE {
-  global:
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
     ___Unwind_RaiseException; # arm
@@ -353,7 +353,6 @@
     __lesf2; # arm
     __ltdf2; # arm
     __ltsf2; # arm
-    __muldc3; # arm x86 mips
     __muldf3; # arm
     __nedf2; # arm
     __nesf2; # arm
@@ -375,4 +374,4 @@
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
     restore_core_regs; # arm
-} LIBC;
+} LIBC; # arm mips
diff --git a/libm/libm.mips.map b/libm/libm.mips.map
new file mode 100644
index 0000000..476c6ad
--- /dev/null
+++ b/libm/libm.mips.map
@@ -0,0 +1,281 @@
+# Generated by genversionscripts.py. Do not edit.
+LIBC {
+  global:
+    __fe_dfl_env;
+    __signbit;
+    __signbitf;
+    __signbitl;
+    acos;
+    acosf;
+    acosh;
+    acoshf;
+    acoshl;
+    acosl;
+    asin;
+    asinf;
+    asinh;
+    asinhf;
+    asinhl;
+    asinl;
+    atan;
+    atan2;
+    atan2f;
+    atan2l;
+    atanf;
+    atanh;
+    atanhf;
+    atanhl;
+    atanl;
+    cabs;
+    cabsf;
+    cabsl;
+    cacos;
+    cacosf;
+    cacosh;
+    cacoshf;
+    carg;
+    cargf;
+    cargl;
+    casin;
+    casinf;
+    casinh;
+    casinhf;
+    catan;
+    catanf;
+    catanh;
+    catanhf;
+    cbrt;
+    cbrtf;
+    cbrtl;
+    ccos;
+    ccosf;
+    ccosh;
+    ccoshf;
+    ceil;
+    ceilf;
+    ceill;
+    cexp;
+    cexpf;
+    cimag;
+    cimagf;
+    cimagl;
+    conj;
+    conjf;
+    conjl;
+    copysign;
+    copysignf;
+    copysignl;
+    cos;
+    cosf;
+    cosh;
+    coshf;
+    coshl;
+    cosl;
+    cproj;
+    cprojf;
+    cprojl;
+    creal;
+    crealf;
+    creall;
+    csin;
+    csinf;
+    csinh;
+    csinhf;
+    csqrt;
+    csqrtf;
+    csqrtl;
+    ctan;
+    ctanf;
+    ctanh;
+    ctanhf;
+    drem;
+    dremf;
+    erf;
+    erfc;
+    erfcf;
+    erfcl;
+    erff;
+    erfl;
+    exp;
+    exp2;
+    exp2f;
+    exp2l;
+    expf;
+    expl;
+    expm1;
+    expm1f;
+    expm1l;
+    fabs;
+    fabsf;
+    fabsl;
+    fdim;
+    fdimf;
+    fdiml;
+    feclearexcept;
+    fedisableexcept;
+    feenableexcept;
+    fegetenv;
+    fegetexcept;
+    fegetexceptflag;
+    fegetround;
+    feholdexcept;
+    feraiseexcept;
+    fesetenv;
+    fesetexceptflag;
+    fesetround;
+    fetestexcept;
+    feupdateenv;
+    finite;
+    finitef;
+    floor;
+    floorf;
+    floorl;
+    fma;
+    fmaf;
+    fmal;
+    fmax;
+    fmaxf;
+    fmaxl;
+    fmin;
+    fminf;
+    fminl;
+    fmod;
+    fmodf;
+    fmodl;
+    frexp;
+    frexpf;
+    frexpl;
+    gamma;
+    gamma_r;
+    gammaf;
+    gammaf_r;
+    hypot;
+    hypotf;
+    hypotl;
+    ilogb;
+    ilogbf;
+    ilogbl;
+    j0;
+    j0f;
+    j1;
+    j1f;
+    jn;
+    jnf;
+    ldexpf;
+    ldexpl;
+    lgamma;
+    lgamma_r;
+    lgammaf;
+    lgammaf_r;
+    lgammal;
+    lgammal_r;
+    llrint;
+    llrintf;
+    llrintl;
+    llround;
+    llroundf;
+    llroundl;
+    log;
+    log10;
+    log10f;
+    log10l;
+    log1p;
+    log1pf;
+    log1pl;
+    log2;
+    log2f;
+    log2l;
+    logb;
+    logbf;
+    logbl;
+    logf;
+    logl;
+    lrint;
+    lrintf;
+    lrintl;
+    lround;
+    lroundf;
+    lroundl;
+    modf;
+    modff;
+    modfl;
+    nan;
+    nanf;
+    nanl;
+    nearbyint;
+    nearbyintf;
+    nearbyintl;
+    nextafter;
+    nextafterf;
+    nextafterl;
+    nexttoward;
+    nexttowardf;
+    nexttowardl;
+    pow;
+    powf;
+    powl;
+    remainder;
+    remainderf;
+    remainderl;
+    remquo;
+    remquof;
+    remquol;
+    rint;
+    rintf;
+    rintl;
+    round;
+    roundf;
+    roundl;
+    scalb;
+    scalbf;
+    scalbln;
+    scalblnf;
+    scalblnl;
+    scalbn;
+    scalbnf;
+    scalbnl;
+    signgam;
+    significand;
+    significandf;
+    significandl;
+    sin;
+    sincos;
+    sincosf;
+    sincosl;
+    sinf;
+    sinh;
+    sinhf;
+    sinhl;
+    sinl;
+    sqrt;
+    sqrtf;
+    sqrtl;
+    tan;
+    tanf;
+    tanh;
+    tanhf;
+    tanhl;
+    tanl;
+    tgamma;
+    tgammaf;
+    tgammal;
+    trunc;
+    truncf;
+    truncl;
+    y0;
+    y0f;
+    y1;
+    y1f;
+    yn;
+    ynf;
+  local:
+    *;
+};
+
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
+    __fixdfdi; # arm mips
+    __fixsfdi; # arm mips
+    __fixunsdfdi; # arm mips
+    __fixunssfdi; # arm mips
+} LIBC; # arm mips
diff --git a/libm/libm.mips64.map b/libm/libm.mips64.map
new file mode 100644
index 0000000..1623ea0
--- /dev/null
+++ b/libm/libm.mips64.map
@@ -0,0 +1,274 @@
+# Generated by genversionscripts.py. Do not edit.
+LIBC {
+  global:
+    __fe_dfl_env;
+    __signbit;
+    __signbitf;
+    __signbitl;
+    acos;
+    acosf;
+    acosh;
+    acoshf;
+    acoshl;
+    acosl;
+    asin;
+    asinf;
+    asinh;
+    asinhf;
+    asinhl;
+    asinl;
+    atan;
+    atan2;
+    atan2f;
+    atan2l;
+    atanf;
+    atanh;
+    atanhf;
+    atanhl;
+    atanl;
+    cabs;
+    cabsf;
+    cabsl;
+    cacos;
+    cacosf;
+    cacosh;
+    cacoshf;
+    carg;
+    cargf;
+    cargl;
+    casin;
+    casinf;
+    casinh;
+    casinhf;
+    catan;
+    catanf;
+    catanh;
+    catanhf;
+    cbrt;
+    cbrtf;
+    cbrtl;
+    ccos;
+    ccosf;
+    ccosh;
+    ccoshf;
+    ceil;
+    ceilf;
+    ceill;
+    cexp;
+    cexpf;
+    cimag;
+    cimagf;
+    cimagl;
+    conj;
+    conjf;
+    conjl;
+    copysign;
+    copysignf;
+    copysignl;
+    cos;
+    cosf;
+    cosh;
+    coshf;
+    coshl;
+    cosl;
+    cproj;
+    cprojf;
+    cprojl;
+    creal;
+    crealf;
+    creall;
+    csin;
+    csinf;
+    csinh;
+    csinhf;
+    csqrt;
+    csqrtf;
+    csqrtl;
+    ctan;
+    ctanf;
+    ctanh;
+    ctanhf;
+    drem;
+    dremf;
+    erf;
+    erfc;
+    erfcf;
+    erfcl;
+    erff;
+    erfl;
+    exp;
+    exp2;
+    exp2f;
+    exp2l;
+    expf;
+    expl;
+    expm1;
+    expm1f;
+    expm1l;
+    fabs;
+    fabsf;
+    fabsl;
+    fdim;
+    fdimf;
+    fdiml;
+    feclearexcept;
+    fedisableexcept;
+    feenableexcept;
+    fegetenv;
+    fegetexcept;
+    fegetexceptflag;
+    fegetround;
+    feholdexcept;
+    feraiseexcept;
+    fesetenv;
+    fesetexceptflag;
+    fesetround;
+    fetestexcept;
+    feupdateenv;
+    finite;
+    finitef;
+    floor;
+    floorf;
+    floorl;
+    fma;
+    fmaf;
+    fmal;
+    fmax;
+    fmaxf;
+    fmaxl;
+    fmin;
+    fminf;
+    fminl;
+    fmod;
+    fmodf;
+    fmodl;
+    frexp;
+    frexpf;
+    frexpl;
+    gamma;
+    gamma_r;
+    gammaf;
+    gammaf_r;
+    hypot;
+    hypotf;
+    hypotl;
+    ilogb;
+    ilogbf;
+    ilogbl;
+    j0;
+    j0f;
+    j1;
+    j1f;
+    jn;
+    jnf;
+    ldexpf;
+    ldexpl;
+    lgamma;
+    lgamma_r;
+    lgammaf;
+    lgammaf_r;
+    lgammal;
+    lgammal_r;
+    llrint;
+    llrintf;
+    llrintl;
+    llround;
+    llroundf;
+    llroundl;
+    log;
+    log10;
+    log10f;
+    log10l;
+    log1p;
+    log1pf;
+    log1pl;
+    log2;
+    log2f;
+    log2l;
+    logb;
+    logbf;
+    logbl;
+    logf;
+    logl;
+    lrint;
+    lrintf;
+    lrintl;
+    lround;
+    lroundf;
+    lroundl;
+    modf;
+    modff;
+    modfl;
+    nan;
+    nanf;
+    nanl;
+    nearbyint;
+    nearbyintf;
+    nearbyintl;
+    nextafter;
+    nextafterf;
+    nextafterl;
+    nexttoward;
+    nexttowardf;
+    nexttowardl;
+    pow;
+    powf;
+    powl;
+    remainder;
+    remainderf;
+    remainderl;
+    remquo;
+    remquof;
+    remquol;
+    rint;
+    rintf;
+    rintl;
+    round;
+    roundf;
+    roundl;
+    scalb;
+    scalbf;
+    scalbln;
+    scalblnf;
+    scalblnl;
+    scalbn;
+    scalbnf;
+    scalbnl;
+    signgam;
+    significand;
+    significandf;
+    significandl;
+    sin;
+    sincos;
+    sincosf;
+    sincosl;
+    sinf;
+    sinh;
+    sinhf;
+    sinhl;
+    sinl;
+    sqrt;
+    sqrtf;
+    sqrtl;
+    tan;
+    tanf;
+    tanh;
+    tanhf;
+    tanhl;
+    tanl;
+    tgamma;
+    tgammaf;
+    tgammal;
+    trunc;
+    truncf;
+    truncl;
+    y0;
+    y0f;
+    y1;
+    y1f;
+    yn;
+    ynf;
+  local:
+    *;
+};
+
diff --git a/libm/libm.x86.map b/libm/libm.x86.map
new file mode 100644
index 0000000..1623ea0
--- /dev/null
+++ b/libm/libm.x86.map
@@ -0,0 +1,274 @@
+# Generated by genversionscripts.py. Do not edit.
+LIBC {
+  global:
+    __fe_dfl_env;
+    __signbit;
+    __signbitf;
+    __signbitl;
+    acos;
+    acosf;
+    acosh;
+    acoshf;
+    acoshl;
+    acosl;
+    asin;
+    asinf;
+    asinh;
+    asinhf;
+    asinhl;
+    asinl;
+    atan;
+    atan2;
+    atan2f;
+    atan2l;
+    atanf;
+    atanh;
+    atanhf;
+    atanhl;
+    atanl;
+    cabs;
+    cabsf;
+    cabsl;
+    cacos;
+    cacosf;
+    cacosh;
+    cacoshf;
+    carg;
+    cargf;
+    cargl;
+    casin;
+    casinf;
+    casinh;
+    casinhf;
+    catan;
+    catanf;
+    catanh;
+    catanhf;
+    cbrt;
+    cbrtf;
+    cbrtl;
+    ccos;
+    ccosf;
+    ccosh;
+    ccoshf;
+    ceil;
+    ceilf;
+    ceill;
+    cexp;
+    cexpf;
+    cimag;
+    cimagf;
+    cimagl;
+    conj;
+    conjf;
+    conjl;
+    copysign;
+    copysignf;
+    copysignl;
+    cos;
+    cosf;
+    cosh;
+    coshf;
+    coshl;
+    cosl;
+    cproj;
+    cprojf;
+    cprojl;
+    creal;
+    crealf;
+    creall;
+    csin;
+    csinf;
+    csinh;
+    csinhf;
+    csqrt;
+    csqrtf;
+    csqrtl;
+    ctan;
+    ctanf;
+    ctanh;
+    ctanhf;
+    drem;
+    dremf;
+    erf;
+    erfc;
+    erfcf;
+    erfcl;
+    erff;
+    erfl;
+    exp;
+    exp2;
+    exp2f;
+    exp2l;
+    expf;
+    expl;
+    expm1;
+    expm1f;
+    expm1l;
+    fabs;
+    fabsf;
+    fabsl;
+    fdim;
+    fdimf;
+    fdiml;
+    feclearexcept;
+    fedisableexcept;
+    feenableexcept;
+    fegetenv;
+    fegetexcept;
+    fegetexceptflag;
+    fegetround;
+    feholdexcept;
+    feraiseexcept;
+    fesetenv;
+    fesetexceptflag;
+    fesetround;
+    fetestexcept;
+    feupdateenv;
+    finite;
+    finitef;
+    floor;
+    floorf;
+    floorl;
+    fma;
+    fmaf;
+    fmal;
+    fmax;
+    fmaxf;
+    fmaxl;
+    fmin;
+    fminf;
+    fminl;
+    fmod;
+    fmodf;
+    fmodl;
+    frexp;
+    frexpf;
+    frexpl;
+    gamma;
+    gamma_r;
+    gammaf;
+    gammaf_r;
+    hypot;
+    hypotf;
+    hypotl;
+    ilogb;
+    ilogbf;
+    ilogbl;
+    j0;
+    j0f;
+    j1;
+    j1f;
+    jn;
+    jnf;
+    ldexpf;
+    ldexpl;
+    lgamma;
+    lgamma_r;
+    lgammaf;
+    lgammaf_r;
+    lgammal;
+    lgammal_r;
+    llrint;
+    llrintf;
+    llrintl;
+    llround;
+    llroundf;
+    llroundl;
+    log;
+    log10;
+    log10f;
+    log10l;
+    log1p;
+    log1pf;
+    log1pl;
+    log2;
+    log2f;
+    log2l;
+    logb;
+    logbf;
+    logbl;
+    logf;
+    logl;
+    lrint;
+    lrintf;
+    lrintl;
+    lround;
+    lroundf;
+    lroundl;
+    modf;
+    modff;
+    modfl;
+    nan;
+    nanf;
+    nanl;
+    nearbyint;
+    nearbyintf;
+    nearbyintl;
+    nextafter;
+    nextafterf;
+    nextafterl;
+    nexttoward;
+    nexttowardf;
+    nexttowardl;
+    pow;
+    powf;
+    powl;
+    remainder;
+    remainderf;
+    remainderl;
+    remquo;
+    remquof;
+    remquol;
+    rint;
+    rintf;
+    rintl;
+    round;
+    roundf;
+    roundl;
+    scalb;
+    scalbf;
+    scalbln;
+    scalblnf;
+    scalblnl;
+    scalbn;
+    scalbnf;
+    scalbnl;
+    signgam;
+    significand;
+    significandf;
+    significandl;
+    sin;
+    sincos;
+    sincosf;
+    sincosl;
+    sinf;
+    sinh;
+    sinhf;
+    sinhl;
+    sinl;
+    sqrt;
+    sqrtf;
+    sqrtl;
+    tan;
+    tanf;
+    tanh;
+    tanhf;
+    tanhl;
+    tanl;
+    tgamma;
+    tgammaf;
+    tgammal;
+    trunc;
+    truncf;
+    truncl;
+    y0;
+    y0f;
+    y1;
+    y1f;
+    yn;
+    ynf;
+  local:
+    *;
+};
+
diff --git a/libm/libm.x86_64.map b/libm/libm.x86_64.map
new file mode 100644
index 0000000..1623ea0
--- /dev/null
+++ b/libm/libm.x86_64.map
@@ -0,0 +1,274 @@
+# Generated by genversionscripts.py. Do not edit.
+LIBC {
+  global:
+    __fe_dfl_env;
+    __signbit;
+    __signbitf;
+    __signbitl;
+    acos;
+    acosf;
+    acosh;
+    acoshf;
+    acoshl;
+    acosl;
+    asin;
+    asinf;
+    asinh;
+    asinhf;
+    asinhl;
+    asinl;
+    atan;
+    atan2;
+    atan2f;
+    atan2l;
+    atanf;
+    atanh;
+    atanhf;
+    atanhl;
+    atanl;
+    cabs;
+    cabsf;
+    cabsl;
+    cacos;
+    cacosf;
+    cacosh;
+    cacoshf;
+    carg;
+    cargf;
+    cargl;
+    casin;
+    casinf;
+    casinh;
+    casinhf;
+    catan;
+    catanf;
+    catanh;
+    catanhf;
+    cbrt;
+    cbrtf;
+    cbrtl;
+    ccos;
+    ccosf;
+    ccosh;
+    ccoshf;
+    ceil;
+    ceilf;
+    ceill;
+    cexp;
+    cexpf;
+    cimag;
+    cimagf;
+    cimagl;
+    conj;
+    conjf;
+    conjl;
+    copysign;
+    copysignf;
+    copysignl;
+    cos;
+    cosf;
+    cosh;
+    coshf;
+    coshl;
+    cosl;
+    cproj;
+    cprojf;
+    cprojl;
+    creal;
+    crealf;
+    creall;
+    csin;
+    csinf;
+    csinh;
+    csinhf;
+    csqrt;
+    csqrtf;
+    csqrtl;
+    ctan;
+    ctanf;
+    ctanh;
+    ctanhf;
+    drem;
+    dremf;
+    erf;
+    erfc;
+    erfcf;
+    erfcl;
+    erff;
+    erfl;
+    exp;
+    exp2;
+    exp2f;
+    exp2l;
+    expf;
+    expl;
+    expm1;
+    expm1f;
+    expm1l;
+    fabs;
+    fabsf;
+    fabsl;
+    fdim;
+    fdimf;
+    fdiml;
+    feclearexcept;
+    fedisableexcept;
+    feenableexcept;
+    fegetenv;
+    fegetexcept;
+    fegetexceptflag;
+    fegetround;
+    feholdexcept;
+    feraiseexcept;
+    fesetenv;
+    fesetexceptflag;
+    fesetround;
+    fetestexcept;
+    feupdateenv;
+    finite;
+    finitef;
+    floor;
+    floorf;
+    floorl;
+    fma;
+    fmaf;
+    fmal;
+    fmax;
+    fmaxf;
+    fmaxl;
+    fmin;
+    fminf;
+    fminl;
+    fmod;
+    fmodf;
+    fmodl;
+    frexp;
+    frexpf;
+    frexpl;
+    gamma;
+    gamma_r;
+    gammaf;
+    gammaf_r;
+    hypot;
+    hypotf;
+    hypotl;
+    ilogb;
+    ilogbf;
+    ilogbl;
+    j0;
+    j0f;
+    j1;
+    j1f;
+    jn;
+    jnf;
+    ldexpf;
+    ldexpl;
+    lgamma;
+    lgamma_r;
+    lgammaf;
+    lgammaf_r;
+    lgammal;
+    lgammal_r;
+    llrint;
+    llrintf;
+    llrintl;
+    llround;
+    llroundf;
+    llroundl;
+    log;
+    log10;
+    log10f;
+    log10l;
+    log1p;
+    log1pf;
+    log1pl;
+    log2;
+    log2f;
+    log2l;
+    logb;
+    logbf;
+    logbl;
+    logf;
+    logl;
+    lrint;
+    lrintf;
+    lrintl;
+    lround;
+    lroundf;
+    lroundl;
+    modf;
+    modff;
+    modfl;
+    nan;
+    nanf;
+    nanl;
+    nearbyint;
+    nearbyintf;
+    nearbyintl;
+    nextafter;
+    nextafterf;
+    nextafterl;
+    nexttoward;
+    nexttowardf;
+    nexttowardl;
+    pow;
+    powf;
+    powl;
+    remainder;
+    remainderf;
+    remainderl;
+    remquo;
+    remquof;
+    remquol;
+    rint;
+    rintf;
+    rintl;
+    round;
+    roundf;
+    roundl;
+    scalb;
+    scalbf;
+    scalbln;
+    scalblnf;
+    scalblnl;
+    scalbn;
+    scalbnf;
+    scalbnl;
+    signgam;
+    significand;
+    significandf;
+    significandl;
+    sin;
+    sincos;
+    sincosf;
+    sincosl;
+    sinf;
+    sinh;
+    sinhf;
+    sinhl;
+    sinl;
+    sqrt;
+    sqrtf;
+    sqrtl;
+    tan;
+    tanf;
+    tanh;
+    tanhf;
+    tanhl;
+    tanl;
+    tgamma;
+    tgammaf;
+    tgammal;
+    trunc;
+    truncf;
+    truncl;
+    y0;
+    y0f;
+    y1;
+    y1f;
+    yn;
+    ynf;
+  local:
+    *;
+};
+
diff --git a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
index a5668fd..e843d43 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
+++ b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/ld128/k_expl.h 275819 2014-12-16 09:21:56Z ed $");
 
 /*
  * ld128 version of k_expl.h.  See ../ld80/s_expl.c for most comments.
@@ -322,7 +322,7 @@
 	scale2 = 1;
 	SET_LDBL_EXPSIGN(scale1, BIAS + expt - half_expt);
 
-	return (cpackl(cos(y) * exp_x * scale1 * scale2,
+	return (CMPLXL(cos(y) * exp_x * scale1 * scale2,
 	    sinl(y) * exp_x * scale1 * scale2));
 }
 #endif /* _COMPLEX_H */
diff --git a/libm/upstream-freebsd/lib/msun/src/catrig.c b/libm/upstream-freebsd/lib/msun/src/catrig.c
index 200977c..050a88b 100644
--- a/libm/upstream-freebsd/lib/msun/src/catrig.c
+++ b/libm/upstream-freebsd/lib/msun/src/catrig.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/catrig.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <float.h>
@@ -286,19 +286,19 @@
 	if (isnan(x) || isnan(y)) {
 		/* casinh(+-Inf + I*NaN) = +-Inf + I*NaN */
 		if (isinf(x))
-			return (cpack(x, y + y));
+			return (CMPLX(x, y + y));
 		/* casinh(NaN + I*+-Inf) = opt(+-)Inf + I*NaN */
 		if (isinf(y))
-			return (cpack(y, x + x));
+			return (CMPLX(y, x + x));
 		/* casinh(NaN + I*0) = NaN + I*0 */
 		if (y == 0)
-			return (cpack(x + x, y));
+			return (CMPLX(x + x, y));
 		/*
 		 * All other cases involving NaN return NaN + I*NaN.
 		 * C99 leaves it optional whether to raise invalid if one of
 		 * the arguments is not NaN, so we opt not to raise it.
 		 */
-		return (cpack(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+		return (CMPLX(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
@@ -307,7 +307,7 @@
 			w = clog_for_large_values(z) + m_ln2;
 		else
 			w = clog_for_large_values(-z) + m_ln2;
-		return (cpack(copysign(creal(w), x), copysign(cimag(w), y)));
+		return (CMPLX(copysign(creal(w), x), copysign(cimag(w), y)));
 	}
 
 	/* Avoid spuriously raising inexact for z = 0. */
@@ -325,7 +325,7 @@
 		ry = asin(B);
 	else
 		ry = atan2(new_y, sqrt_A2my2);
-	return (cpack(copysign(rx, x), copysign(ry, y)));
+	return (CMPLX(copysign(rx, x), copysign(ry, y)));
 }
 
 /*
@@ -335,9 +335,9 @@
 double complex
 casin(double complex z)
 {
-	double complex w = casinh(cpack(cimag(z), creal(z)));
+	double complex w = casinh(CMPLX(cimag(z), creal(z)));
 
-	return (cpack(cimag(w), creal(w)));
+	return (CMPLX(cimag(w), creal(w)));
 }
 
 /*
@@ -370,19 +370,19 @@
 	if (isnan(x) || isnan(y)) {
 		/* cacos(+-Inf + I*NaN) = NaN + I*opt(-)Inf */
 		if (isinf(x))
-			return (cpack(y + y, -INFINITY));
+			return (CMPLX(y + y, -INFINITY));
 		/* cacos(NaN + I*+-Inf) = NaN + I*-+Inf */
 		if (isinf(y))
-			return (cpack(x + x, -y));
+			return (CMPLX(x + x, -y));
 		/* cacos(0 + I*NaN) = PI/2 + I*NaN with inexact */
 		if (x == 0)
-			return (cpack(pio2_hi + pio2_lo, y + y));
+			return (CMPLX(pio2_hi + pio2_lo, y + y));
 		/*
 		 * All other cases involving NaN return NaN + I*NaN.
 		 * C99 leaves it optional whether to raise invalid if one of
 		 * the arguments is not NaN, so we opt not to raise it.
 		 */
-		return (cpack(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+		return (CMPLX(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
@@ -392,18 +392,18 @@
 		ry = creal(w) + m_ln2;
 		if (sy == 0)
 			ry = -ry;
-		return (cpack(rx, ry));
+		return (CMPLX(rx, ry));
 	}
 
 	/* Avoid spuriously raising inexact for z = 1. */
 	if (x == 1 && y == 0)
-		return (cpack(0, -y));
+		return (CMPLX(0, -y));
 
 	/* All remaining cases are inexact. */
 	raise_inexact();
 
 	if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4)
-		return (cpack(pio2_hi - (x - pio2_lo), -y));
+		return (CMPLX(pio2_hi - (x - pio2_lo), -y));
 
 	do_hard_work(ay, ax, &ry, &B_is_usable, &B, &sqrt_A2mx2, &new_x);
 	if (B_is_usable) {
@@ -419,7 +419,7 @@
 	}
 	if (sy == 0)
 		ry = -ry;
-	return (cpack(rx, ry));
+	return (CMPLX(rx, ry));
 }
 
 /*
@@ -437,15 +437,15 @@
 	ry = cimag(w);
 	/* cacosh(NaN + I*NaN) = NaN + I*NaN */
 	if (isnan(rx) && isnan(ry))
-		return (cpack(ry, rx));
+		return (CMPLX(ry, rx));
 	/* cacosh(NaN + I*+-Inf) = +Inf + I*NaN */
 	/* cacosh(+-Inf + I*NaN) = +Inf + I*NaN */
 	if (isnan(rx))
-		return (cpack(fabs(ry), rx));
+		return (CMPLX(fabs(ry), rx));
 	/* cacosh(0 + I*NaN) = NaN + I*NaN */
 	if (isnan(ry))
-		return (cpack(ry, ry));
-	return (cpack(fabs(ry), copysign(rx, cimag(z))));
+		return (CMPLX(ry, ry));
+	return (CMPLX(fabs(ry), copysign(rx, cimag(z))));
 }
 
 /*
@@ -475,16 +475,16 @@
 	 * this method is still poor since it is uneccessarily slow.
 	 */
 	if (ax > DBL_MAX / 2)
-		return (cpack(log(hypot(x / m_e, y / m_e)) + 1, atan2(y, x)));
+		return (CMPLX(log(hypot(x / m_e, y / m_e)) + 1, atan2(y, x)));
 
 	/*
 	 * Avoid overflow when x or y is large.  Avoid underflow when x or
 	 * y is small.
 	 */
 	if (ax > QUARTER_SQRT_MAX || ay < SQRT_MIN)
-		return (cpack(log(hypot(x, y)), atan2(y, x)));
+		return (CMPLX(log(hypot(x, y)), atan2(y, x)));
 
-	return (cpack(log(ax * ax + ay * ay) / 2, atan2(y, x)));
+	return (CMPLX(log(ax * ax + ay * ay) / 2, atan2(y, x)));
 }
 
 /*
@@ -575,30 +575,30 @@
 
 	/* This helps handle many cases. */
 	if (y == 0 && ax <= 1)
-		return (cpack(atanh(x), y));
+		return (CMPLX(atanh(x), y));
 
 	/* To ensure the same accuracy as atan(), and to filter out z = 0. */
 	if (x == 0)
-		return (cpack(x, atan(y)));
+		return (CMPLX(x, atan(y)));
 
 	if (isnan(x) || isnan(y)) {
 		/* catanh(+-Inf + I*NaN) = +-0 + I*NaN */
 		if (isinf(x))
-			return (cpack(copysign(0, x), y + y));
+			return (CMPLX(copysign(0, x), y + y));
 		/* catanh(NaN + I*+-Inf) = sign(NaN)0 + I*+-PI/2 */
 		if (isinf(y))
-			return (cpack(copysign(0, x),
+			return (CMPLX(copysign(0, x),
 			    copysign(pio2_hi + pio2_lo, y)));
 		/*
 		 * All other cases involving NaN return NaN + I*NaN.
 		 * C99 leaves it optional whether to raise invalid if one of
 		 * the arguments is not NaN, so we opt not to raise it.
 		 */
-		return (cpack(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+		return (CMPLX(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON)
-		return (cpack(real_part_reciprocal(x, y),
+		return (CMPLX(real_part_reciprocal(x, y),
 		    copysign(pio2_hi + pio2_lo, y)));
 
 	if (ax < SQRT_3_EPSILON / 2 && ay < SQRT_3_EPSILON / 2) {
@@ -623,7 +623,7 @@
 	else
 		ry = atan2(2 * ay, (1 - ax) * (1 + ax) - ay * ay) / 2;
 
-	return (cpack(copysign(rx, x), copysign(ry, y)));
+	return (CMPLX(copysign(rx, x), copysign(ry, y)));
 }
 
 /*
@@ -633,7 +633,7 @@
 double complex
 catan(double complex z)
 {
-	double complex w = catanh(cpack(cimag(z), creal(z)));
+	double complex w = catanh(CMPLX(cimag(z), creal(z)));
 
-	return (cpack(cimag(w), creal(w)));
+	return (CMPLX(cimag(w), creal(w)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/catrigf.c b/libm/upstream-freebsd/lib/msun/src/catrigf.c
index 08ebef7..e057d31 100644
--- a/libm/upstream-freebsd/lib/msun/src/catrigf.c
+++ b/libm/upstream-freebsd/lib/msun/src/catrigf.c
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/catrigf.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <float.h>
@@ -156,12 +156,12 @@
 
 	if (isnan(x) || isnan(y)) {
 		if (isinf(x))
-			return (cpackf(x, y + y));
+			return (CMPLXF(x, y + y));
 		if (isinf(y))
-			return (cpackf(y, x + x));
+			return (CMPLXF(y, x + x));
 		if (y == 0)
-			return (cpackf(x + x, y));
-		return (cpackf(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+			return (CMPLXF(x + x, y));
+		return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
@@ -169,7 +169,7 @@
 			w = clog_for_large_values(z) + m_ln2;
 		else
 			w = clog_for_large_values(-z) + m_ln2;
-		return (cpackf(copysignf(crealf(w), x),
+		return (CMPLXF(copysignf(crealf(w), x),
 		    copysignf(cimagf(w), y)));
 	}
 
@@ -186,15 +186,15 @@
 		ry = asinf(B);
 	else
 		ry = atan2f(new_y, sqrt_A2my2);
-	return (cpackf(copysignf(rx, x), copysignf(ry, y)));
+	return (CMPLXF(copysignf(rx, x), copysignf(ry, y)));
 }
 
 float complex
 casinf(float complex z)
 {
-	float complex w = casinhf(cpackf(cimagf(z), crealf(z)));
+	float complex w = casinhf(CMPLXF(cimagf(z), crealf(z)));
 
-	return (cpackf(cimagf(w), crealf(w)));
+	return (CMPLXF(cimagf(w), crealf(w)));
 }
 
 float complex
@@ -214,12 +214,12 @@
 
 	if (isnan(x) || isnan(y)) {
 		if (isinf(x))
-			return (cpackf(y + y, -INFINITY));
+			return (CMPLXF(y + y, -INFINITY));
 		if (isinf(y))
-			return (cpackf(x + x, -y));
+			return (CMPLXF(x + x, -y));
 		if (x == 0)
-			return (cpackf(pio2_hi + pio2_lo, y + y));
-		return (cpackf(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+			return (CMPLXF(pio2_hi + pio2_lo, y + y));
+		return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
@@ -228,16 +228,16 @@
 		ry = crealf(w) + m_ln2;
 		if (sy == 0)
 			ry = -ry;
-		return (cpackf(rx, ry));
+		return (CMPLXF(rx, ry));
 	}
 
 	if (x == 1 && y == 0)
-		return (cpackf(0, -y));
+		return (CMPLXF(0, -y));
 
 	raise_inexact();
 
 	if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4)
-		return (cpackf(pio2_hi - (x - pio2_lo), -y));
+		return (CMPLXF(pio2_hi - (x - pio2_lo), -y));
 
 	do_hard_work(ay, ax, &ry, &B_is_usable, &B, &sqrt_A2mx2, &new_x);
 	if (B_is_usable) {
@@ -253,7 +253,7 @@
 	}
 	if (sy == 0)
 		ry = -ry;
-	return (cpackf(rx, ry));
+	return (CMPLXF(rx, ry));
 }
 
 float complex
@@ -266,12 +266,12 @@
 	rx = crealf(w);
 	ry = cimagf(w);
 	if (isnan(rx) && isnan(ry))
-		return (cpackf(ry, rx));
+		return (CMPLXF(ry, rx));
 	if (isnan(rx))
-		return (cpackf(fabsf(ry), rx));
+		return (CMPLXF(fabsf(ry), rx));
 	if (isnan(ry))
-		return (cpackf(ry, ry));
-	return (cpackf(fabsf(ry), copysignf(rx, cimagf(z))));
+		return (CMPLXF(ry, ry));
+	return (CMPLXF(fabsf(ry), copysignf(rx, cimagf(z))));
 }
 
 static float complex
@@ -291,13 +291,13 @@
 	}
 
 	if (ax > FLT_MAX / 2)
-		return (cpackf(logf(hypotf(x / m_e, y / m_e)) + 1,
+		return (CMPLXF(logf(hypotf(x / m_e, y / m_e)) + 1,
 		    atan2f(y, x)));
 
 	if (ax > QUARTER_SQRT_MAX || ay < SQRT_MIN)
-		return (cpackf(logf(hypotf(x, y)), atan2f(y, x)));
+		return (CMPLXF(logf(hypotf(x, y)), atan2f(y, x)));
 
-	return (cpackf(logf(ax * ax + ay * ay) / 2, atan2f(y, x)));
+	return (CMPLXF(logf(ax * ax + ay * ay) / 2, atan2f(y, x)));
 }
 
 static inline float
@@ -346,22 +346,22 @@
 	ay = fabsf(y);
 
 	if (y == 0 && ax <= 1)
-		return (cpackf(atanhf(x), y));
+		return (CMPLXF(atanhf(x), y));
 
 	if (x == 0)
-		return (cpackf(x, atanf(y)));
+		return (CMPLXF(x, atanf(y)));
 
 	if (isnan(x) || isnan(y)) {
 		if (isinf(x))
-			return (cpackf(copysignf(0, x), y + y));
+			return (CMPLXF(copysignf(0, x), y + y));
 		if (isinf(y))
-			return (cpackf(copysignf(0, x),
+			return (CMPLXF(copysignf(0, x),
 			    copysignf(pio2_hi + pio2_lo, y)));
-		return (cpackf(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
+		return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0)));
 	}
 
 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON)
-		return (cpackf(real_part_reciprocal(x, y),
+		return (CMPLXF(real_part_reciprocal(x, y),
 		    copysignf(pio2_hi + pio2_lo, y)));
 
 	if (ax < SQRT_3_EPSILON / 2 && ay < SQRT_3_EPSILON / 2) {
@@ -381,13 +381,13 @@
 	else
 		ry = atan2f(2 * ay, (1 - ax) * (1 + ax) - ay * ay) / 2;
 
-	return (cpackf(copysignf(rx, x), copysignf(ry, y)));
+	return (CMPLXF(copysignf(rx, x), copysignf(ry, y)));
 }
 
 float complex
 catanf(float complex z)
 {
-	float complex w = catanhf(cpackf(cimagf(z), crealf(z)));
+	float complex w = catanhf(CMPLXF(cimagf(z), crealf(z)));
 
-	return (cpackf(cimagf(w), crealf(w)));
+	return (CMPLXF(cimagf(w), crealf(w)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0.c b/libm/upstream-freebsd/lib/msun/src/e_j0.c
index 8320f25..36e72c2 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0.c
@@ -12,7 +12,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j0.c 283032 2015-05-17 16:27:06Z kargl $");
 
 /* __ieee754_j0(x), __ieee754_y0(x)
  * Bessel function of the first and second kinds of order zero.
@@ -62,7 +62,9 @@
 #include "math.h"
 #include "math_private.h"
 
-static double pzero(double), qzero(double);
+static __inline double pzero(double), qzero(double);
+
+static const volatile double vone = 1, vzero = 0;
 
 static const double
 huge 	= 1e300,
@@ -115,7 +117,7 @@
 	if(ix<0x3f200000) {	/* |x| < 2**-13 */
 	    if(huge+x>one) {	/* raise inexact if x != 0 */
 	        if(ix<0x3e400000) return one;	/* |x|<2**-27 */
-	        else 	      return one - 0.25*x*x;
+	        else 	      return one - x*x/4;
 	    }
 	}
 	z = x*x;
@@ -150,10 +152,16 @@
 
 	EXTRACT_WORDS(hx,lx,x);
         ix = 0x7fffffff&hx;
-    /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0  */
-	if(ix>=0x7ff00000) return  one/(x+x*x); 
-        if((ix|lx)==0) return -one/zero;
-        if(hx<0) return zero/zero;
+	/*
+	 * y0(NaN) = NaN.
+	 * y0(Inf) = 0.
+	 * y0(-Inf) = NaN and raise invalid exception.
+	 */
+	if(ix>=0x7ff00000) return vone/(x+x*x); 
+	/* y0(+-0) = -inf and raise divide-by-zero exception. */
+	if((ix|lx)==0) return -one/vzero;
+	/* y0(x<0) = NaN and raise invalid exception. */
+	if(hx<0) return vzero/vzero;
         if(ix >= 0x40000000) {  /* |x| >= 2.0 */
         /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
          * where x0 = x-pi/4
@@ -268,7 +276,8 @@
   1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
 };
 
-	static double pzero(double x)
+static __inline double
+pzero(double x)
 {
 	const double *p,*q;
 	double z,r,s;
@@ -278,7 +287,7 @@
 	if(ix>=0x40200000)     {p = pR8; q= pS8;}
 	else if(ix>=0x40122E8B){p = pR5; q= pS5;}
 	else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
-	else if(ix>=0x40000000){p = pR2; q= pS2;}
+	else                   {p = pR2; q= pS2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
@@ -363,7 +372,8 @@
  -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
 };
 
-	static double qzero(double x)
+static __inline double
+qzero(double x)
 {
 	const double *p,*q;
 	double s,r,z;
@@ -373,7 +383,7 @@
 	if(ix>=0x40200000)     {p = qR8; q= qS8;}
 	else if(ix>=0x40122E8B){p = qR5; q= qS5;}
 	else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
-	else if(ix>=0x40000000){p = qR2; q= qS2;}
+	else                   {p = qR2; q= qS2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0f.c b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
index c45faf3..e53b218 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
@@ -14,12 +14,18 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j0f.c 283032 2015-05-17 16:27:06Z kargl $");
+
+/*
+ * See e_j0.c for complete comments.
+ */
 
 #include "math.h"
 #include "math_private.h"
 
-static float pzerof(float), qzerof(float);
+static __inline float pzerof(float), qzerof(float);
+
+static const volatile float vone = 1,  vzero = 0;
 
 static const float
 huge 	= 1e30,
@@ -62,17 +68,17 @@
 	 * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
 	 * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
 	 */
-		if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(x);
+		if(ix>0x58000000) z = (invsqrtpi*cc)/sqrtf(x); /* |x|>2**49 */
 		else {
 		    u = pzerof(x); v = qzerof(x);
 		    z = invsqrtpi*(u*cc-v*ss)/sqrtf(x);
 		}
 		return z;
 	}
-	if(ix<0x39000000) {	/* |x| < 2**-13 */
+	if(ix<0x3b000000) {	/* |x| < 2**-9 */
 	    if(huge+x>one) {	/* raise inexact if x != 0 */
-	        if(ix<0x32000000) return one;	/* |x|<2**-27 */
-	        else 	      return one - (float)0.25*x*x;
+	        if(ix<0x39800000) return one;	/* |x|<2**-12 */
+	        else 	      return one - x*x/4;
 	    }
 	}
 	z = x*x;
@@ -107,10 +113,9 @@
 
 	GET_FLOAT_WORD(hx,x);
         ix = 0x7fffffff&hx;
-    /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0  */
-	if(ix>=0x7f800000) return  one/(x+x*x);
-        if(ix==0) return -one/zero;
-        if(hx<0) return zero/zero;
+	if(ix>=0x7f800000) return  vone/(x+x*x);
+	if(ix==0) return -one/vzero;
+	if(hx<0) return vzero/vzero;
         if(ix >= 0x40000000) {  /* |x| >= 2.0 */
         /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
          * where x0 = x-pi/4
@@ -136,14 +141,14 @@
                     if ((s*c)<zero) cc = z/ss;
                     else            ss = z/cc;
                 }
-                if(ix>0x80000000) z = (invsqrtpi*ss)/sqrtf(x);
+                if(ix>0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */
                 else {
                     u = pzerof(x); v = qzerof(x);
                     z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
                 }
                 return z;
 	}
-	if(ix<=0x32000000) {	/* x < 2**-27 */
+	if(ix<=0x39000000) {	/* x < 2**-13 */
 	    return(u00 + tpi*__ieee754_logf(x));
 	}
 	z = x*x;
@@ -224,7 +229,8 @@
   1.4657617569e+01, /* 0x416a859a */
 };
 
-	static float pzerof(float x)
+static __inline float
+pzerof(float x)
 {
 	const float *p,*q;
 	float z,r,s;
@@ -232,9 +238,9 @@
 	GET_FLOAT_WORD(ix,x);
 	ix &= 0x7fffffff;
 	if(ix>=0x41000000)     {p = pR8; q= pS8;}
-	else if(ix>=0x40f71c58){p = pR5; q= pS5;}
-	else if(ix>=0x4036db68){p = pR3; q= pS3;}
-	else if(ix>=0x40000000){p = pR2; q= pS2;}
+	else if(ix>=0x409173eb){p = pR5; q= pS5;}
+	else if(ix>=0x4036d917){p = pR3; q= pS3;}
+	else                   {p = pR2; q= pS2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
@@ -319,7 +325,8 @@
  -5.3109550476e+00, /* 0xc0a9f358 */
 };
 
-	static float qzerof(float x)
+static __inline float
+qzerof(float x)
 {
 	const float *p,*q;
 	float s,r,z;
@@ -327,9 +334,9 @@
 	GET_FLOAT_WORD(ix,x);
 	ix &= 0x7fffffff;
 	if(ix>=0x41000000)     {p = qR8; q= qS8;}
-	else if(ix>=0x40f71c58){p = qR5; q= qS5;}
-	else if(ix>=0x4036db68){p = qR3; q= qS3;}
-	else if(ix>=0x40000000){p = qR2; q= qS2;}
+	else if(ix>=0x409173eb){p = qR5; q= qS5;}
+	else if(ix>=0x4036d917){p = qR3; q= qS3;}
+	else                   {p = qR2; q= qS2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1.c b/libm/upstream-freebsd/lib/msun/src/e_j1.c
index 63800ad..b11ac2d 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j1.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j1.c
@@ -12,7 +12,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j1.c 283032 2015-05-17 16:27:06Z kargl $");
 
 /* __ieee754_j1(x), __ieee754_y1(x)
  * Bessel function of the first and second kinds of order zero.
@@ -62,7 +62,9 @@
 #include "math.h"
 #include "math_private.h"
 
-static double pone(double), qone(double);
+static __inline double pone(double), qone(double);
+
+static const volatile double vone = 1, vzero = 0;
 
 static const double
 huge    = 1e300,
@@ -147,10 +149,16 @@
 
 	EXTRACT_WORDS(hx,lx,x);
         ix = 0x7fffffff&hx;
-    /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
-	if(ix>=0x7ff00000) return  one/(x+x*x); 
-        if((ix|lx)==0) return -one/zero;
-        if(hx<0) return zero/zero;
+	/*
+	 * y1(NaN) = NaN.
+	 * y1(Inf) = 0.
+	 * y1(-Inf) = NaN and raise invalid exception.
+	 */
+	if(ix>=0x7ff00000) return  vone/(x+x*x); 
+	/* y1(+-0) = -inf and raise divide-by-zero exception. */
+        if((ix|lx)==0) return -one/vzero;
+	/* y1(x<0) = NaN and raise invalid exception. */
+        if(hx<0) return vzero/vzero;
         if(ix >= 0x40000000) {  /* |x| >= 2.0 */
                 s = sin(x);
                 c = cos(x);
@@ -262,7 +270,8 @@
   8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
 };
 
-	static double pone(double x)
+static __inline double
+pone(double x)
 {
 	const double *p,*q;
 	double z,r,s;
@@ -272,7 +281,7 @@
         if(ix>=0x40200000)     {p = pr8; q= ps8;}
         else if(ix>=0x40122E8B){p = pr5; q= ps5;}
         else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
-        else if(ix>=0x40000000){p = pr2; q= ps2;}
+	else                   {p = pr2; q= ps2;}	/* ix>=0x40000000 */
         z = one/(x*x);
         r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
         s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
@@ -358,7 +367,8 @@
  -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
 };
 
-	static double qone(double x)
+static __inline double
+qone(double x)
 {
 	const double *p,*q;
 	double  s,r,z;
@@ -368,7 +378,7 @@
 	if(ix>=0x40200000)     {p = qr8; q= qs8;}
 	else if(ix>=0x40122E8B){p = qr5; q= qs5;}
 	else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
-	else if(ix>=0x40000000){p = qr2; q= qs2;}
+	else                   {p = qr2; q= qs2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1f.c b/libm/upstream-freebsd/lib/msun/src/e_j1f.c
index 88e2d83..0cca823 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j1f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j1f.c
@@ -14,12 +14,18 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_j1f.c 283032 2015-05-17 16:27:06Z kargl $");
+
+/*
+ * See e_j1.c for complete comments.
+ */
 
 #include "math.h"
 #include "math_private.h"
 
-static float ponef(float), qonef(float);
+static __inline float ponef(float), qonef(float);
+
+static const volatile float vone = 1, vzero = 0;
 
 static const float
 huge    = 1e30,
@@ -63,7 +69,7 @@
 	 * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
 	 * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
 	 */
-		if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(y);
+		if(ix>0x58000000) z = (invsqrtpi*cc)/sqrtf(y); /* |x|>2**49 */
 		else {
 		    u = ponef(y); v = qonef(y);
 		    z = invsqrtpi*(u*cc-v*ss)/sqrtf(y);
@@ -71,7 +77,7 @@
 		if(hx<0) return -z;
 		else  	 return  z;
 	}
-	if(ix<0x32000000) {	/* |x|<2**-27 */
+	if(ix<0x39000000) {	/* |x|<2**-13 */
 	    if(huge+x>one) return (float)0.5*x;/* inexact if x!=0 necessary */
 	}
 	z = x*x;
@@ -104,10 +110,9 @@
 
 	GET_FLOAT_WORD(hx,x);
         ix = 0x7fffffff&hx;
-    /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
-	if(ix>=0x7f800000) return  one/(x+x*x);
-        if(ix==0) return -one/zero;
-        if(hx<0) return zero/zero;
+	if(ix>=0x7f800000) return  vone/(x+x*x);
+	if(ix==0) return -one/vzero;
+	if(hx<0) return vzero/vzero;
         if(ix >= 0x40000000) {  /* |x| >= 2.0 */
                 s = sinf(x);
                 c = cosf(x);
@@ -129,14 +134,14 @@
          *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
          * to compute the worse one.
          */
-                if(ix>0x48000000) z = (invsqrtpi*ss)/sqrtf(x);
+                if(ix>0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */
                 else {
                     u = ponef(x); v = qonef(x);
                     z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
                 }
                 return z;
         }
-        if(ix<=0x24800000) {    /* x < 2**-54 */
+        if(ix<=0x33000000) {    /* x < 2**-25 */
             return(-tpi/x);
         }
         z = x*x;
@@ -219,7 +224,8 @@
   8.3646392822e+00, /* 0x4105d590 */
 };
 
-	static float ponef(float x)
+static __inline float
+ponef(float x)
 {
 	const float *p,*q;
 	float z,r,s;
@@ -227,9 +233,9 @@
 	GET_FLOAT_WORD(ix,x);
 	ix &= 0x7fffffff;
         if(ix>=0x41000000)     {p = pr8; q= ps8;}
-        else if(ix>=0x40f71c58){p = pr5; q= ps5;}
-        else if(ix>=0x4036db68){p = pr3; q= ps3;}
-        else if(ix>=0x40000000){p = pr2; q= ps2;}
+        else if(ix>=0x409173eb){p = pr5; q= ps5;}
+        else if(ix>=0x4036d917){p = pr3; q= ps3;}
+	else                   {p = pr2; q= ps2;}	/* ix>=0x40000000 */
         z = one/(x*x);
         r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
         s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
@@ -315,17 +321,18 @@
  -4.9594988823e+00, /* 0xc09eb437 */
 };
 
-	static float qonef(float x)
+static __inline float
+qonef(float x)
 {
 	const float *p,*q;
 	float  s,r,z;
 	int32_t ix;
 	GET_FLOAT_WORD(ix,x);
 	ix &= 0x7fffffff;
-	if(ix>=0x40200000)     {p = qr8; q= qs8;}
-	else if(ix>=0x40f71c58){p = qr5; q= qs5;}
-	else if(ix>=0x4036db68){p = qr3; q= qs3;}
-	else if(ix>=0x40000000){p = qr2; q= qs2;}
+	if(ix>=0x41000000)     {p = qr8; q= qs8;}
+	else if(ix>=0x409173eb){p = qr5; q= qs5;}
+	else if(ix>=0x4036d917){p = qr3; q= qs3;}
+	else                   {p = qr2; q= qs2;}	/* ix>=0x40000000 */
 	z = one/(x*x);
 	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
 	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
diff --git a/libm/upstream-freebsd/lib/msun/src/e_jn.c b/libm/upstream-freebsd/lib/msun/src/e_jn.c
index 8b0bc62..a1130c5 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_jn.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_jn.c
@@ -12,7 +12,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_jn.c 279856 2015-03-10 17:10:54Z kargl $");
 
 /*
  * __ieee754_jn(n, x), __ieee754_yn(n, x)
@@ -43,6 +43,8 @@
 #include "math.h"
 #include "math_private.h"
 
+static const volatile double vone = 1, vzero = 0;
+
 static const double
 invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
 two   =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
@@ -220,10 +222,12 @@
 
 	EXTRACT_WORDS(hx,lx,x);
 	ix = 0x7fffffff&hx;
-    /* if Y(n,NaN) is NaN */
+	/* yn(n,NaN) = NaN */
 	if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
-	if((ix|lx)==0) return -one/zero;
-	if(hx<0) return zero/zero;
+	/* yn(n,+-0) = -inf and raise divide-by-zero exception. */
+	if((ix|lx)==0) return -one/vzero;
+	/* yn(n,x<0) = NaN and raise invalid exception. */
+	if(hx<0) return vzero/vzero;
 	sign = 1;
 	if(n<0){
 		n = -n;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_jnf.c b/libm/upstream-freebsd/lib/msun/src/e_jnf.c
index f564aec..c82d5cf 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_jnf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_jnf.c
@@ -14,11 +14,17 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/e_jnf.c 279856 2015-03-10 17:10:54Z kargl $");
+
+/*
+ * See e_jn.c for complete comments.
+ */
 
 #include "math.h"
 #include "math_private.h"
 
+static const volatile float vone = 1, vzero = 0;
+
 static const float
 two   =  2.0000000000e+00, /* 0x40000000 */
 one   =  1.0000000000e+00; /* 0x3F800000 */
@@ -172,10 +178,9 @@
 
 	GET_FLOAT_WORD(hx,x);
 	ix = 0x7fffffff&hx;
-    /* if Y(n,NaN) is NaN */
 	if(ix>0x7f800000) return x+x;
-	if(ix==0) return -one/zero;
-	if(hx<0) return zero/zero;
+	if(ix==0) return -one/vzero;
+	if(hx<0) return vzero/vzero;
 	sign = 1;
 	if(n<0){
 		n = -n;
diff --git a/libm/upstream-freebsd/lib/msun/src/k_exp.c b/libm/upstream-freebsd/lib/msun/src/k_exp.c
index f592f69..5aa3ef3 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_exp.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_exp.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/k_exp.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 
@@ -103,6 +103,6 @@
 	half_expt = expt - half_expt;
 	INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0);
 
-	return (cpack(cos(y) * exp_x * scale1 * scale2,
+	return (CMPLX(cos(y) * exp_x * scale1 * scale2,
 	    sin(y) * exp_x * scale1 * scale2));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/k_expf.c b/libm/upstream-freebsd/lib/msun/src/k_expf.c
index 548a008..8fe8c46 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_expf.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_expf.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/k_expf.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 
@@ -82,6 +82,6 @@
 	half_expt = expt - half_expt;
 	SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23);
 
-	return (cpackf(cosf(y) * exp_x * scale1 * scale2,
+	return (CMPLXF(cosf(y) * exp_x * scale1 * scale2,
 	    sinf(y) * exp_x * scale1 * scale2));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/math_private.h b/libm/upstream-freebsd/lib/msun/src/math_private.h
index 8af2c65..1f10e8b 100644
--- a/libm/upstream-freebsd/lib/msun/src/math_private.h
+++ b/libm/upstream-freebsd/lib/msun/src/math_private.h
@@ -11,7 +11,7 @@
 
 /*
  * from: @(#)fdlibm.h 5.1 93/09/24
- * $FreeBSD$
+ * $FreeBSD: head/lib/msun/src/math_private.h 276176 2014-12-24 10:13:53Z ed $
  */
 
 #ifndef _MATH_PRIVATE_H_
@@ -454,9 +454,15 @@
  * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product.
  * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted
  * to -0.0+I*0.0.
+ *
+ * The C11 standard introduced the macros CMPLX(), CMPLXF() and CMPLXL()
+ * to construct complex values.  Compilers that conform to the C99
+ * standard require the following functions to avoid the above issues.
  */
+
+#ifndef CMPLXF
 static __inline float complex
-cpackf(float x, float y)
+CMPLXF(float x, float y)
 {
 	float_complex z;
 
@@ -464,9 +470,11 @@
 	IMAGPART(z) = y;
 	return (z.f);
 }
+#endif
 
+#ifndef CMPLX
 static __inline double complex
-cpack(double x, double y)
+CMPLX(double x, double y)
 {
 	double_complex z;
 
@@ -474,9 +482,11 @@
 	IMAGPART(z) = y;
 	return (z.f);
 }
+#endif
 
+#ifndef CMPLXL
 static __inline long double complex
-cpackl(long double x, long double y)
+CMPLXL(long double x, long double y)
 {
 	long_double_complex z;
 
@@ -484,6 +494,8 @@
 	IMAGPART(z) = y;
 	return (z.f);
 }
+#endif
+
 #endif /* _COMPLEX_H */
  
 #ifdef __GNUCLIKE_ASM
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccosh.c b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
index 9ea962b..e544e91 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
@@ -32,10 +32,12 @@
  *
  * Exceptional values are noted in the comments within the source code.
  * These values and the return value were taken from n1124.pdf.
+ * The sign of the result for some exceptional values is unspecified but
+ * must satisfy both cosh(conj(z)) == conj(cosh(z)) and cosh(-z) == cosh(z).
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_ccosh.c 284423 2015-06-15 20:11:06Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -62,49 +64,48 @@
 	/* Handle the nearly-non-exceptional cases where x and y are finite. */
 	if (ix < 0x7ff00000 && iy < 0x7ff00000) {
 		if ((iy | ly) == 0)
-			return (cpack(cosh(x), x * y));
-		if (ix < 0x40360000)	/* small x: normal case */
-			return (cpack(cosh(x) * cos(y), sinh(x) * sin(y)));
+			return (CMPLX(cosh(x), x * y));
+		if (ix < 0x40360000)	/* |x| < 22: normal case */
+			return (CMPLX(cosh(x) * cos(y), sinh(x) * sin(y)));
 
 		/* |x| >= 22, so cosh(x) ~= exp(|x|) */
 		if (ix < 0x40862e42) {
 			/* x < 710: exp(|x|) won't overflow */
 			h = exp(fabs(x)) * 0.5;
-			return (cpack(h * cos(y), copysign(h, x) * sin(y)));
+			return (CMPLX(h * cos(y), copysign(h, x) * sin(y)));
 		} else if (ix < 0x4096bbaa) {
 			/* x < 1455: scale to avoid overflow */
-			z = __ldexp_cexp(cpack(fabs(x), y), -1);
-			return (cpack(creal(z), cimag(z) * copysign(1, x)));
+			z = __ldexp_cexp(CMPLX(fabs(x), y), -1);
+			return (CMPLX(creal(z), cimag(z) * copysign(1, x)));
 		} else {
 			/* x >= 1455: the result always overflows */
 			h = huge * x;
-			return (cpack(h * h * cos(y), h * sin(y)));
+			return (CMPLX(h * h * cos(y), h * sin(y)));
 		}
 	}
 
 	/*
-	 * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0.
-	 * The sign of 0 in the result is unspecified.  Choice = normally
-	 * the same as dNaN.  Raise the invalid floating-point exception.
+	 * cosh(+-0 +- I Inf) = dNaN + I (+-)(+-)0.
+	 * The sign of 0 in the result is unspecified.  Choice = product
+	 * of the signs of the argument.  Raise the invalid floating-point
+	 * exception.
 	 *
-	 * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0.
-	 * The sign of 0 in the result is unspecified.  Choice = normally
-	 * the same as d(NaN).
+	 * cosh(+-0 +- I NaN) = d(NaN) + I (+-)(+-)0.
+	 * The sign of 0 in the result is unspecified.  Choice = product
+	 * of the signs of the argument.
 	 */
-	if ((ix | lx) == 0 && iy >= 0x7ff00000)
-		return (cpack(y - y, copysign(0, x * (y - y))));
+	if ((ix | lx) == 0)		/* && iy >= 0x7ff00000 */
+		return (CMPLX(y - y, x * copysign(0, y)));
 
 	/*
 	 * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0.
 	 *
-	 * cosh(NaN +- I 0)   = d(NaN) + I sign(d(NaN, +-0))0.
-	 * The sign of 0 in the result is unspecified.
+	 * cosh(NaN +- I 0)   = d(NaN) + I (+-)(+-)0.
+	 * The sign of 0 in the result is unspecified.  Choice = product
+	 * of the signs of the argument.
 	 */
-	if ((iy | ly) == 0 && ix >= 0x7ff00000) {
-		if (((hx & 0xfffff) | lx) == 0)
-			return (cpack(x * x, copysign(0, x) * y));
-		return (cpack(x * x, copysign(0, (x + x) * y)));
-	}
+	if ((iy | ly) == 0)		/* && ix >= 0x7ff00000 */
+		return (CMPLX(x * x, copysign(0, x) * y));
 
 	/*
 	 * cosh(x +- I Inf) = dNaN + I dNaN.
@@ -114,8 +115,8 @@
 	 * Optionally raises the invalid floating-point exception for finite
 	 * nonzero x.  Choice = don't raise (except for signaling NaNs).
 	 */
-	if (ix < 0x7ff00000 && iy >= 0x7ff00000)
-		return (cpack(y - y, x * (y - y)));
+	if (ix < 0x7ff00000)		/* && iy >= 0x7ff00000 */
+		return (CMPLX(y - y, x * (y - y)));
 
 	/*
 	 * cosh(+-Inf + I NaN)  = +Inf + I d(NaN).
@@ -126,10 +127,10 @@
 	 *
 	 * cosh(+-Inf + I y)   = +Inf cos(y) +- I Inf sin(y)
 	 */
-	if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+	if (ix == 0x7ff00000 && lx == 0) {
 		if (iy >= 0x7ff00000)
-			return (cpack(x * x, x * (y - y)));
-		return (cpack((x * x) * cos(y), x * sin(y)));
+			return (CMPLX(INFINITY, x * (y - y)));
+		return (CMPLX(INFINITY * cos(y), x * sin(y)));
 	}
 
 	/*
@@ -143,7 +144,7 @@
 	 * Optionally raises the invalid floating-point exception for finite
 	 * nonzero y.  Choice = don't raise (except for signaling NaNs).
 	 */
-	return (cpack((x * x) * (y - y), (x + x) * (y - y)));
+	return (CMPLX((x * x) * (y - y), (x + x) * (y - y)));
 }
 
 double complex
@@ -151,5 +152,5 @@
 {
 
 	/* ccos(z) = ccosh(I * z) */
-	return (ccosh(cpack(-cimag(z), creal(z))));
+	return (ccosh(CMPLX(-cimag(z), creal(z))));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
index 1de9ad4..e33840a 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
@@ -25,11 +25,11 @@
  */
 
 /*
- * Hyperbolic cosine of a complex argument.  See s_ccosh.c for details.
+ * Float version of ccosh().  See s_ccosh.c for details.
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_ccoshf.c 284423 2015-06-15 20:11:06Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -55,50 +55,47 @@
 
 	if (ix < 0x7f800000 && iy < 0x7f800000) {
 		if (iy == 0)
-			return (cpackf(coshf(x), x * y));
-		if (ix < 0x41100000)	/* small x: normal case */
-			return (cpackf(coshf(x) * cosf(y), sinhf(x) * sinf(y)));
+			return (CMPLXF(coshf(x), x * y));
+		if (ix < 0x41100000)	/* |x| < 9: normal case */
+			return (CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y)));
 
 		/* |x| >= 9, so cosh(x) ~= exp(|x|) */
 		if (ix < 0x42b17218) {
 			/* x < 88.7: expf(|x|) won't overflow */
-			h = expf(fabsf(x)) * 0.5f;
-			return (cpackf(h * cosf(y), copysignf(h, x) * sinf(y)));
+			h = expf(fabsf(x)) * 0.5F;
+			return (CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y)));
 		} else if (ix < 0x4340b1e7) {
 			/* x < 192.7: scale to avoid overflow */
-			z = __ldexp_cexpf(cpackf(fabsf(x), y), -1);
-			return (cpackf(crealf(z), cimagf(z) * copysignf(1, x)));
+			z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1);
+			return (CMPLXF(crealf(z), cimagf(z) * copysignf(1, x)));
 		} else {
 			/* x >= 192.7: the result always overflows */
 			h = huge * x;
-			return (cpackf(h * h * cosf(y), h * sinf(y)));
+			return (CMPLXF(h * h * cosf(y), h * sinf(y)));
 		}
 	}
 
-	if (ix == 0 && iy >= 0x7f800000)
-		return (cpackf(y - y, copysignf(0, x * (y - y))));
+	if (ix == 0)			/* && iy >= 0x7f800000 */
+		return (CMPLXF(y - y, x * copysignf(0, y)));
 
-	if (iy == 0 && ix >= 0x7f800000) {
-		if ((hx & 0x7fffff) == 0)
-			return (cpackf(x * x, copysignf(0, x) * y));
-		return (cpackf(x * x, copysignf(0, (x + x) * y)));
-	}
+	if (iy == 0)			/* && ix >= 0x7f800000 */
+		return (CMPLXF(x * x, copysignf(0, x) * y));
 
-	if (ix < 0x7f800000 && iy >= 0x7f800000)
-		return (cpackf(y - y, x * (y - y)));
+	if (ix < 0x7f800000)		/* && iy >= 0x7f800000 */
+		return (CMPLXF(y - y, x * (y - y)));
 
-	if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+	if (ix == 0x7f800000) {
 		if (iy >= 0x7f800000)
-			return (cpackf(x * x, x * (y - y)));
-		return (cpackf((x * x) * cosf(y), x * sinf(y)));
+			return (CMPLXF(INFINITY, x * (y - y)));
+		return (CMPLXF(INFINITY * cosf(y), x * sinf(y)));
 	}
 
-	return (cpackf((x * x) * (y - y), (x + x) * (y - y)));
+	return (CMPLXF((x * x) * (y - y), (x + x) * (y - y)));
 }
 
 float complex
 ccosf(float complex z)
 {
 
-	return (ccoshf(cpackf(-cimagf(z), crealf(z))));
+	return (ccoshf(CMPLXF(-cimagf(z), crealf(z))));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexp.c b/libm/upstream-freebsd/lib/msun/src/s_cexp.c
index abe178f..660a68d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cexp.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cexp.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cexp.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -50,22 +50,22 @@
 
 	/* cexp(x + I 0) = exp(x) + I 0 */
 	if ((hy | ly) == 0)
-		return (cpack(exp(x), y));
+		return (CMPLX(exp(x), y));
 	EXTRACT_WORDS(hx, lx, x);
 	/* cexp(0 + I y) = cos(y) + I sin(y) */
 	if (((hx & 0x7fffffff) | lx) == 0)
-		return (cpack(cos(y), sin(y)));
+		return (CMPLX(cos(y), sin(y)));
 
 	if (hy >= 0x7ff00000) {
 		if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) {
 			/* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
-			return (cpack(y - y, y - y));
+			return (CMPLX(y - y, y - y));
 		} else if (hx & 0x80000000) {
 			/* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
-			return (cpack(0.0, 0.0));
+			return (CMPLX(0.0, 0.0));
 		} else {
 			/* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
-			return (cpack(x, y - y));
+			return (CMPLX(x, y - y));
 		}
 	}
 
@@ -84,6 +84,6 @@
 		 *  -  x = NaN (spurious inexact exception from y)
 		 */
 		exp_x = exp(x);
-		return (cpack(exp_x * cos(y), exp_x * sin(y)));
+		return (CMPLX(exp_x * cos(y), exp_x * sin(y)));
 	}
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexpf.c b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
index 0e30d08..709ad47 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cexpf.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -50,22 +50,22 @@
 
 	/* cexp(x + I 0) = exp(x) + I 0 */
 	if (hy == 0)
-		return (cpackf(expf(x), y));
+		return (CMPLXF(expf(x), y));
 	GET_FLOAT_WORD(hx, x);
 	/* cexp(0 + I y) = cos(y) + I sin(y) */
 	if ((hx & 0x7fffffff) == 0)
-		return (cpackf(cosf(y), sinf(y)));
+		return (CMPLXF(cosf(y), sinf(y)));
 
 	if (hy >= 0x7f800000) {
 		if ((hx & 0x7fffffff) != 0x7f800000) {
 			/* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
-			return (cpackf(y - y, y - y));
+			return (CMPLXF(y - y, y - y));
 		} else if (hx & 0x80000000) {
 			/* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
-			return (cpackf(0.0, 0.0));
+			return (CMPLXF(0.0, 0.0));
 		} else {
 			/* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
-			return (cpackf(x, y - y));
+			return (CMPLXF(x, y - y));
 		}
 	}
 
@@ -84,6 +84,6 @@
 		 *  -  x = NaN (spurious inexact exception from y)
 		 */
 		exp_x = expf(x);
-		return (cpackf(exp_x * cosf(y), exp_x * sinf(y)));
+		return (CMPLXF(exp_x * cosf(y), exp_x * sinf(y)));
 	}
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conj.c b/libm/upstream-freebsd/lib/msun/src/s_conj.c
index 5770c29..61fac63 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conj.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conj.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/lib/msun/src/s_conj.c 275819 2014-12-16 09:21:56Z ed $
  */
 
 #include <complex.h>
@@ -34,5 +34,5 @@
 conj(double complex z)
 {
 
-	return (cpack(creal(z), -cimag(z)));
+	return (CMPLX(creal(z), -cimag(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjf.c b/libm/upstream-freebsd/lib/msun/src/s_conjf.c
index b090760..83c9ef0 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conjf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conjf.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/lib/msun/src/s_conjf.c 275819 2014-12-16 09:21:56Z ed $
  */
 
 #include <complex.h>
@@ -34,5 +34,5 @@
 conjf(float complex z)
 {
 
-	return (cpackf(crealf(z), -cimagf(z)));
+	return (CMPLXF(crealf(z), -cimagf(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjl.c b/libm/upstream-freebsd/lib/msun/src/s_conjl.c
index 0e431ef..d9e6a16 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conjl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conjl.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/lib/msun/src/s_conjl.c 275819 2014-12-16 09:21:56Z ed $
  */
 
 #include <complex.h>
@@ -34,5 +34,5 @@
 conjl(long double complex z)
 {
 
-	return (cpackl(creall(z), -cimagl(z)));
+	return (CMPLXL(creall(z), -cimagl(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cproj.c b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
index 8e9404c..ec2266e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cproj.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cproj.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -39,7 +39,7 @@
 	if (!isinf(creal(z)) && !isinf(cimag(z)))
 		return (z);
 	else
-		return (cpack(INFINITY, copysign(0.0, cimag(z))));
+		return (CMPLX(INFINITY, copysign(0.0, cimag(z))));
 }
 
 #if LDBL_MANT_DIG == 53
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojf.c b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
index 68ea77b..63af75f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cprojf.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -39,5 +39,5 @@
 	if (!isinf(crealf(z)) && !isinf(cimagf(z)))
 		return (z);
 	else
-		return (cpackf(INFINITY, copysignf(0.0, cimagf(z))));
+		return (CMPLXF(INFINITY, copysignf(0.0, cimagf(z))));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojl.c b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
index 07385bc..8386f81 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_cprojl.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -39,5 +39,5 @@
 	if (!isinf(creall(z)) && !isinf(cimagl(z)))
 		return (z);
 	else
-		return (cpackl(INFINITY, copysignl(0.0, cimagl(z))));
+		return (CMPLXL(INFINITY, copysignl(0.0, cimagl(z))));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinh.c b/libm/upstream-freebsd/lib/msun/src/s_csinh.c
index c192f30..cff1402 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csinh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csinh.c
@@ -32,10 +32,12 @@
  *
  * Exceptional values are noted in the comments within the source code.
  * These values and the return value were taken from n1124.pdf.
+ * The sign of the result for some exceptional values is unspecified but
+ * must satisfy both sinh(conj(z)) == conj(sinh(z)) and sinh(-z) == -sinh(z).
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_csinh.c 284426 2015-06-15 20:16:53Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -62,48 +64,45 @@
 	/* Handle the nearly-non-exceptional cases where x and y are finite. */
 	if (ix < 0x7ff00000 && iy < 0x7ff00000) {
 		if ((iy | ly) == 0)
-			return (cpack(sinh(x), y));
-		if (ix < 0x40360000)	/* small x: normal case */
-			return (cpack(sinh(x) * cos(y), cosh(x) * sin(y)));
+			return (CMPLX(sinh(x), y));
+		if (ix < 0x40360000)	/* |x| < 22: normal case */
+			return (CMPLX(sinh(x) * cos(y), cosh(x) * sin(y)));
 
 		/* |x| >= 22, so cosh(x) ~= exp(|x|) */
 		if (ix < 0x40862e42) {
 			/* x < 710: exp(|x|) won't overflow */
 			h = exp(fabs(x)) * 0.5;
-			return (cpack(copysign(h, x) * cos(y), h * sin(y)));
+			return (CMPLX(copysign(h, x) * cos(y), h * sin(y)));
 		} else if (ix < 0x4096bbaa) {
 			/* x < 1455: scale to avoid overflow */
-			z = __ldexp_cexp(cpack(fabs(x), y), -1);
-			return (cpack(creal(z) * copysign(1, x), cimag(z)));
+			z = __ldexp_cexp(CMPLX(fabs(x), y), -1);
+			return (CMPLX(creal(z) * copysign(1, x), cimag(z)));
 		} else {
 			/* x >= 1455: the result always overflows */
 			h = huge * x;
-			return (cpack(h * cos(y), h * h * sin(y)));
+			return (CMPLX(h * cos(y), h * h * sin(y)));
 		}
 	}
 
 	/*
-	 * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
-	 * The sign of 0 in the result is unspecified.  Choice = normally
-	 * the same as dNaN.  Raise the invalid floating-point exception.
+	 * sinh(+-0 +- I Inf) = +-0 + I dNaN.
+	 * The sign of 0 in the result is unspecified.  Choice = same sign
+	 * as the argument.  Raise the invalid floating-point exception.
 	 *
-	 * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
-	 * The sign of 0 in the result is unspecified.  Choice = normally
-	 * the same as d(NaN).
+	 * sinh(+-0 +- I NaN) = +-0 + I d(NaN).
+	 * The sign of 0 in the result is unspecified.  Choice = same sign
+	 * as the argument.
 	 */
-	if ((ix | lx) == 0 && iy >= 0x7ff00000)
-		return (cpack(copysign(0, x * (y - y)), y - y));
+	if ((ix | lx) == 0)		/* && iy >= 0x7ff00000 */
+		return (CMPLX(x, y - y));
 
 	/*
 	 * sinh(+-Inf +- I 0) = +-Inf + I +-0.
 	 *
 	 * sinh(NaN +- I 0)   = d(NaN) + I +-0.
 	 */
-	if ((iy | ly) == 0 && ix >= 0x7ff00000) {
-		if (((hx & 0xfffff) | lx) == 0)
-			return (cpack(x, y));
-		return (cpack(x, copysign(0, y)));
-	}
+	if ((iy | ly) == 0)		/* && ix >= 0x7ff00000 */
+		return (CMPLX(x + x, y));
 
 	/*
 	 * sinh(x +- I Inf) = dNaN + I dNaN.
@@ -113,45 +112,45 @@
 	 * Optionally raises the invalid floating-point exception for finite
 	 * nonzero x.  Choice = don't raise (except for signaling NaNs).
 	 */
-	if (ix < 0x7ff00000 && iy >= 0x7ff00000)
-		return (cpack(y - y, x * (y - y)));
+	if (ix < 0x7ff00000)		/* && iy >= 0x7ff00000 */
+		return (CMPLX(y - y, y - y));
 
 	/*
 	 * sinh(+-Inf + I NaN)  = +-Inf + I d(NaN).
-	 * The sign of Inf in the result is unspecified.  Choice = normally
-	 * the same as d(NaN).
+	 * The sign of Inf in the result is unspecified.  Choice = same sign
+	 * as the argument.
 	 *
-	 * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
-	 * The sign of Inf in the result is unspecified.  Choice = always +.
-	 * Raise the invalid floating-point exception.
+	 * sinh(+-Inf +- I Inf) = +-Inf + I dNaN.
+	 * The sign of Inf in the result is unspecified.  Choice = same sign
+	 * as the argument.  Raise the invalid floating-point exception.
 	 *
 	 * sinh(+-Inf + I y)   = +-Inf cos(y) + I Inf sin(y)
 	 */
-	if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+	if (ix == 0x7ff00000 && lx == 0) {
 		if (iy >= 0x7ff00000)
-			return (cpack(x * x, x * (y - y)));
-		return (cpack(x * cos(y), INFINITY * sin(y)));
+			return (CMPLX(x, y - y));
+		return (CMPLX(x * cos(y), INFINITY * sin(y)));
 	}
 
 	/*
-	 * sinh(NaN + I NaN)  = d(NaN) + I d(NaN).
+	 * sinh(NaN1 + I NaN2) = d(NaN1, NaN2) + I d(NaN1, NaN2).
 	 *
-	 * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
+	 * sinh(NaN +- I Inf)  = d(NaN, dNaN) + I d(NaN, dNaN).
 	 * Optionally raises the invalid floating-point exception.
 	 * Choice = raise.
 	 *
-	 * sinh(NaN + I y)    = d(NaN) + I d(NaN).
+	 * sinh(NaN + I y)     = d(NaN) + I d(NaN).
 	 * Optionally raises the invalid floating-point exception for finite
 	 * nonzero y.  Choice = don't raise (except for signaling NaNs).
 	 */
-	return (cpack((x * x) * (y - y), (x + x) * (y - y)));
+	return (CMPLX((x + x) * (y - y), (x * x) * (y - y)));
 }
 
 double complex
 csin(double complex z)
 {
 
-	/* csin(z) = -I * csinh(I * z) */
-	z = csinh(cpack(-cimag(z), creal(z)));
-	return (cpack(cimag(z), -creal(z)));
+	/* csin(z) = -I * csinh(I * z) = I * conj(csinh(I * conj(z))). */
+	z = csinh(CMPLX(cimag(z), creal(z)));
+	return (CMPLX(cimag(z), creal(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinhf.c b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
index c523125..f050890 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
@@ -25,11 +25,11 @@
  */
 
 /*
- * Hyperbolic sine of a complex argument z.  See s_csinh.c for details.
+ * Float version of csinh().  See s_csinh.c for details.
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_csinhf.c 284426 2015-06-15 20:16:53Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -55,51 +55,48 @@
 
 	if (ix < 0x7f800000 && iy < 0x7f800000) {
 		if (iy == 0)
-			return (cpackf(sinhf(x), y));
-		if (ix < 0x41100000)	/* small x: normal case */
-			return (cpackf(sinhf(x) * cosf(y), coshf(x) * sinf(y)));
+			return (CMPLXF(sinhf(x), y));
+		if (ix < 0x41100000)	/* |x| < 9: normal case */
+			return (CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y)));
 
 		/* |x| >= 9, so cosh(x) ~= exp(|x|) */
 		if (ix < 0x42b17218) {
 			/* x < 88.7: expf(|x|) won't overflow */
-			h = expf(fabsf(x)) * 0.5f;
-			return (cpackf(copysignf(h, x) * cosf(y), h * sinf(y)));
+			h = expf(fabsf(x)) * 0.5F;
+			return (CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y)));
 		} else if (ix < 0x4340b1e7) {
 			/* x < 192.7: scale to avoid overflow */
-			z = __ldexp_cexpf(cpackf(fabsf(x), y), -1);
-			return (cpackf(crealf(z) * copysignf(1, x), cimagf(z)));
+			z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1);
+			return (CMPLXF(crealf(z) * copysignf(1, x), cimagf(z)));
 		} else {
 			/* x >= 192.7: the result always overflows */
 			h = huge * x;
-			return (cpackf(h * cosf(y), h * h * sinf(y)));
+			return (CMPLXF(h * cosf(y), h * h * sinf(y)));
 		}
 	}
 
-	if (ix == 0 && iy >= 0x7f800000)
-		return (cpackf(copysignf(0, x * (y - y)), y - y));
+	if (ix == 0)			/* && iy >= 0x7f800000 */
+		return (CMPLXF(x, y - y));
 
-	if (iy == 0 && ix >= 0x7f800000) {
-		if ((hx & 0x7fffff) == 0)
-			return (cpackf(x, y));
-		return (cpackf(x, copysignf(0, y)));
-	}
+	if (iy == 0)			/* && ix >= 0x7f800000 */
+		return (CMPLXF(x + x, y));
 
-	if (ix < 0x7f800000 && iy >= 0x7f800000)
-		return (cpackf(y - y, x * (y - y)));
+	if (ix < 0x7f800000)		/* && iy >= 0x7f800000 */
+		return (CMPLXF(y - y, y - y));
 
-	if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+	if (ix == 0x7f800000) {
 		if (iy >= 0x7f800000)
-			return (cpackf(x * x, x * (y - y)));
-		return (cpackf(x * cosf(y), INFINITY * sinf(y)));
+			return (CMPLXF(x, y - y));
+		return (CMPLXF(x * cosf(y), INFINITY * sinf(y)));
 	}
 
-	return (cpackf((x * x) * (y - y), (x + x) * (y - y)));
+	return (CMPLXF((x + x) * (y - y), (x * x) * (y - y)));
 }
 
 float complex
 csinf(float complex z)
 {
 
-	z = csinhf(cpackf(-cimagf(z), crealf(z)));
-	return (cpackf(cimagf(z), -crealf(z)));
+	z = csinhf(CMPLXF(cimagf(z), crealf(z)));
+	return (CMPLXF(cimagf(z), crealf(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrt.c b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
index 18a7ae3..c908a2d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_csqrt.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <float.h>
@@ -58,12 +58,12 @@
 
 	/* Handle special cases. */
 	if (z == 0)
-		return (cpack(0, b));
+		return (CMPLX(0, b));
 	if (isinf(b))
-		return (cpack(INFINITY, b));
+		return (CMPLX(INFINITY, b));
 	if (isnan(a)) {
 		t = (b - b) / (b - b);	/* raise invalid if b is not a NaN */
-		return (cpack(a, t));	/* return NaN + NaN i */
+		return (CMPLX(a, t));	/* return NaN + NaN i */
 	}
 	if (isinf(a)) {
 		/*
@@ -73,9 +73,9 @@
 		 * csqrt(-inf + y i)   = 0   +  inf i
 		 */
 		if (signbit(a))
-			return (cpack(fabs(b - b), copysign(a, b)));
+			return (CMPLX(fabs(b - b), copysign(a, b)));
 		else
-			return (cpack(a, copysign(b - b, b)));
+			return (CMPLX(a, copysign(b - b, b)));
 	}
 	/*
 	 * The remaining special case (b is NaN) is handled just fine by
@@ -94,10 +94,10 @@
 	/* Algorithm 312, CACM vol 10, Oct 1967. */
 	if (a >= 0) {
 		t = sqrt((a + hypot(a, b)) * 0.5);
-		result = cpack(t, b / (2 * t));
+		result = CMPLX(t, b / (2 * t));
 	} else {
 		t = sqrt((-a + hypot(a, b)) * 0.5);
-		result = cpack(fabs(b) / (2 * t), copysign(t, b));
+		result = CMPLX(fabs(b) / (2 * t), copysign(t, b));
 	}
 
 	/* Rescale. */
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
index da7fe18..12a894f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_csqrtf.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <math.h>
@@ -49,12 +49,12 @@
 
 	/* Handle special cases. */
 	if (z == 0)
-		return (cpackf(0, b));
+		return (CMPLXF(0, b));
 	if (isinf(b))
-		return (cpackf(INFINITY, b));
+		return (CMPLXF(INFINITY, b));
 	if (isnan(a)) {
 		t = (b - b) / (b - b);	/* raise invalid if b is not a NaN */
-		return (cpackf(a, t));	/* return NaN + NaN i */
+		return (CMPLXF(a, t));	/* return NaN + NaN i */
 	}
 	if (isinf(a)) {
 		/*
@@ -64,9 +64,9 @@
 		 * csqrtf(-inf + y i)   = 0   +  inf i
 		 */
 		if (signbit(a))
-			return (cpackf(fabsf(b - b), copysignf(a, b)));
+			return (CMPLXF(fabsf(b - b), copysignf(a, b)));
 		else
-			return (cpackf(a, copysignf(b - b, b)));
+			return (CMPLXF(a, copysignf(b - b, b)));
 	}
 	/*
 	 * The remaining special case (b is NaN) is handled just fine by
@@ -80,9 +80,9 @@
 	 */
 	if (a >= 0) {
 		t = sqrt((a + hypot(a, b)) * 0.5);
-		return (cpackf(t, b / (2.0 * t)));
+		return (CMPLXF(t, b / (2.0 * t)));
 	} else {
 		t = sqrt((-a + hypot(a, b)) * 0.5);
-		return (cpackf(fabsf(b) / (2.0 * t), copysignf(t, b)));
+		return (CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b)));
 	}
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
index dd18e1e..7bcff59 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_csqrtl.c 275819 2014-12-16 09:21:56Z ed $");
 
 #include <complex.h>
 #include <float.h>
@@ -58,12 +58,12 @@
 
 	/* Handle special cases. */
 	if (z == 0)
-		return (cpackl(0, b));
+		return (CMPLXL(0, b));
 	if (isinf(b))
-		return (cpackl(INFINITY, b));
+		return (CMPLXL(INFINITY, b));
 	if (isnan(a)) {
 		t = (b - b) / (b - b);	/* raise invalid if b is not a NaN */
-		return (cpackl(a, t));	/* return NaN + NaN i */
+		return (CMPLXL(a, t));	/* return NaN + NaN i */
 	}
 	if (isinf(a)) {
 		/*
@@ -73,9 +73,9 @@
 		 * csqrt(-inf + y i)   = 0   +  inf i
 		 */
 		if (signbit(a))
-			return (cpackl(fabsl(b - b), copysignl(a, b)));
+			return (CMPLXL(fabsl(b - b), copysignl(a, b)));
 		else
-			return (cpackl(a, copysignl(b - b, b)));
+			return (CMPLXL(a, copysignl(b - b, b)));
 	}
 	/*
 	 * The remaining special case (b is NaN) is handled just fine by
@@ -94,10 +94,10 @@
 	/* Algorithm 312, CACM vol 10, Oct 1967. */
 	if (a >= 0) {
 		t = sqrtl((a + hypotl(a, b)) * 0.5);
-		result = cpackl(t, b / (2 * t));
+		result = CMPLXL(t, b / (2 * t));
 	} else {
 		t = sqrtl((-a + hypotl(a, b)) * 0.5);
-		result = cpackl(fabsl(b) / (2 * t), copysignl(t, b));
+		result = CMPLXL(fabsl(b) / (2 * t), copysignl(t, b));
 	}
 
 	/* Rescale. */
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanh.c b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
index d427e28..e5973c3 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
@@ -25,7 +25,7 @@
  */
 
 /*
- * Hyperbolic tangent of a complex argument z = x + i y.
+ * Hyperbolic tangent of a complex argument z = x + I y.
  *
  * The algorithm is from:
  *
@@ -44,15 +44,15 @@
  *
  *   tanh(z) = sinh(z) / cosh(z)
  *
- *             sinh(x) cos(y) + i cosh(x) sin(y)
+ *             sinh(x) cos(y) + I cosh(x) sin(y)
  *           = ---------------------------------
- *             cosh(x) cos(y) + i sinh(x) sin(y)
+ *             cosh(x) cos(y) + I sinh(x) sin(y)
  *
- *             cosh(x) sinh(x) / cos^2(y) + i tan(y)
+ *             cosh(x) sinh(x) / cos^2(y) + I tan(y)
  *           = -------------------------------------
  *                    1 + sinh^2(x) / cos^2(y)
  *
- *             beta rho s + i t
+ *             beta rho s + I t
  *           = ----------------
  *               1 + beta s^2
  *
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_ctanh.c 284427 2015-06-15 20:40:44Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -85,16 +85,16 @@
 	ix = hx & 0x7fffffff;
 
 	/*
-	 * ctanh(NaN + i 0) = NaN + i 0
+	 * ctanh(NaN +- I 0) = d(NaN) +- I 0
 	 *
-	 * ctanh(NaN + i y) = NaN + i NaN		for y != 0
+	 * ctanh(NaN + I y) = d(NaN,y) + I d(NaN,y)	for y != 0
 	 *
 	 * The imaginary part has the sign of x*sin(2*y), but there's no
 	 * special effort to get this right.
 	 *
-	 * ctanh(+-Inf +- i Inf) = +-1 +- 0
+	 * ctanh(+-Inf +- I Inf) = +-1 +- I 0
 	 *
-	 * ctanh(+-Inf + i y) = +-1 + 0 sin(2y)		for y finite
+	 * ctanh(+-Inf + I y) = +-1 + I 0 sin(2y)	for y finite
 	 *
 	 * The imaginary part of the sign is unspecified.  This special
 	 * case is only needed to avoid a spurious invalid exception when
@@ -102,26 +102,27 @@
 	 */
 	if (ix >= 0x7ff00000) {
 		if ((ix & 0xfffff) | lx)	/* x is NaN */
-			return (cpack(x, (y == 0 ? y : x * y)));
+			return (CMPLX((x + 0) * (y + 0),
+			    y == 0 ? y : (x + 0) * (y + 0)));
 		SET_HIGH_WORD(x, hx - 0x40000000);	/* x = copysign(1, x) */
-		return (cpack(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))));
+		return (CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))));
 	}
 
 	/*
-	 * ctanh(x + i NAN) = NaN + i NaN
-	 * ctanh(x +- i Inf) = NaN + i NaN
+	 * ctanh(x + I NaN) = d(NaN) + I d(NaN)
+	 * ctanh(x +- I Inf) = dNaN + I dNaN
 	 */
 	if (!isfinite(y))
-		return (cpack(y - y, y - y));
+		return (CMPLX(y - y, y - y));
 
 	/*
-	 * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the
+	 * ctanh(+-huge +- I y) ~= +-1 +- I 2sin(2y)/exp(2x), using the
 	 * approximation sinh^2(huge) ~= exp(2*huge) / 4.
 	 * We use a modified formula to avoid spurious overflow.
 	 */
-	if (ix >= 0x40360000) {	/* x >= 22 */
+	if (ix >= 0x40360000) {	/* |x| >= 22 */
 		double exp_mx = exp(-fabs(x));
-		return (cpack(copysign(1, x),
+		return (CMPLX(copysign(1, x),
 		    4 * sin(y) * cos(y) * exp_mx * exp_mx));
 	}
 
@@ -131,14 +132,14 @@
 	s = sinh(x);
 	rho = sqrt(1 + s * s);	/* = cosh(x) */
 	denom = 1 + beta * s * s;
-	return (cpack((beta * rho * s) / denom, t / denom));
+	return (CMPLX((beta * rho * s) / denom, t / denom));
 }
 
 double complex
 ctan(double complex z)
 {
 
-	/* ctan(z) = -I * ctanh(I * z) */
-	z = ctanh(cpack(-cimag(z), creal(z)));
-	return (cpack(cimag(z), -creal(z)));
+	/* ctan(z) = -I * ctanh(I * z) = I * conj(ctanh(I * conj(z))) */
+	z = ctanh(CMPLX(cimag(z), creal(z)));
+	return (CMPLX(cimag(z), creal(z)));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
index 4be28d8..e9826c0 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_ctanhf.c 284428 2015-06-15 20:47:26Z tijl $");
 
 #include <complex.h>
 #include <math.h>
@@ -51,18 +51,19 @@
 
 	if (ix >= 0x7f800000) {
 		if (ix & 0x7fffff)
-			return (cpackf(x, (y == 0 ? y : x * y)));
+			return (CMPLXF((x + 0) * (y + 0),
+			    y == 0 ? y : (x + 0) * (y + 0)));
 		SET_FLOAT_WORD(x, hx - 0x40000000);
-		return (cpackf(x,
+		return (CMPLXF(x,
 		    copysignf(0, isinf(y) ? y : sinf(y) * cosf(y))));
 	}
 
 	if (!isfinite(y))
-		return (cpackf(y - y, y - y));
+		return (CMPLXF(y - y, y - y));
 
-	if (ix >= 0x41300000) {	/* x >= 11 */
+	if (ix >= 0x41300000) {	/* |x| >= 11 */
 		float exp_mx = expf(-fabsf(x));
-		return (cpackf(copysignf(1, x),
+		return (CMPLXF(copysignf(1, x),
 		    4 * sinf(y) * cosf(y) * exp_mx * exp_mx));
 	}
 
@@ -71,14 +72,14 @@
 	s = sinhf(x);
 	rho = sqrtf(1 + s * s);
 	denom = 1 + beta * s * s;
-	return (cpackf((beta * rho * s) / denom, t / denom));
+	return (CMPLXF((beta * rho * s) / denom, t / denom));
 }
 
 float complex
 ctanf(float complex z)
 {
 
-	z = ctanhf(cpackf(-cimagf(z), crealf(z)));
-	return (cpackf(cimagf(z), -crealf(z)));
+	z = ctanhf(CMPLXF(cimagf(z), crealf(z)));
+	return (CMPLXF(cimagf(z), crealf(z)));
 }
 
diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2.c b/libm/upstream-freebsd/lib/msun/src/s_exp2.c
index fde11c2..dbef729 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_exp2.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_exp2.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_exp2.c 286515 2015-08-09 10:00:13Z dim $");
 
 #include <float.h>
 
@@ -376,14 +376,14 @@
 	/* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
 	t = tbl[i0];		/* exp2t[i0] */
 	z -= tbl[i0 + 1];	/* eps[i0]   */
-	if (k >= -1021 << 20)
+	if (k >= -(1021 << 20))
 		INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
 	else
 		INSERT_WORDS(twopkp1000, 0x3ff00000 + k + (1000 << 20), 0);
 	r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
 
 	/* Scale by 2**(k>>20). */
-	if(k >= -1021 << 20) {
+	if(k >= -(1021 << 20)) {
 		if (k == 1024 << 20)
 			return (r * 2.0 * 0x1p1023);
 		return (r * twopk);
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabs.c b/libm/upstream-freebsd/lib/msun/src/s_fabs.c
deleted file mode 100644
index 15529e5..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_fabs.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* @(#)s_fabs.c 5.1 93/09/24 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#ifndef lint
-static char rcsid[] = "$FreeBSD$";
-#endif
-
-/*
- * fabs(x) returns the absolute value of x.
- */
-
-#include "math.h"
-#include "math_private.h"
-
-double
-fabs(double x)
-{
-	u_int32_t high;
-	GET_HIGH_WORD(high,x);
-	SET_HIGH_WORD(x,high&0x7fffffff);
-        return x;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabsf.c b/libm/upstream-freebsd/lib/msun/src/s_fabsf.c
deleted file mode 100644
index e9383d0..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_fabsf.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* s_fabsf.c -- float version of s_fabs.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * fabsf(x) returns the absolute value of x.
- */
-
-#include "math.h"
-#include "math_private.h"
-
-float
-fabsf(float x)
-{
-	u_int32_t ix;
-	GET_FLOAT_WORD(ix,x);
-	SET_FLOAT_WORD(x,ix&0x7fffffff);
-        return x;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbln.c b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
index d609d4e..8e61377 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
@@ -25,52 +25,30 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/lib/msun/src/s_scalbln.c 278339 2015-02-07 00:38:18Z kargl $");
 
-#include <limits.h>
 #include <math.h>
 
-double
-scalbln (double x, long n)
-{
-	int in;
+#define	NMAX	65536
+#define	NMIN	-65536
 
-	in = (int)n;
-	if (in != n) {
-		if (n > 0)
-			in = INT_MAX;
-		else
-			in = INT_MIN;
-	}
-	return (scalbn(x, in));
+double
+scalbln(double x, long n)
+{
+
+	return (scalbn(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
 }
 
 float
-scalblnf (float x, long n)
+scalblnf(float x, long n)
 {
-	int in;
 
-	in = (int)n;
-	if (in != n) {
-		if (n > 0)
-			in = INT_MAX;
-		else
-			in = INT_MIN;
-	}
-	return (scalbnf(x, in));
+	return (scalbnf(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
 }
 
 long double
-scalblnl (long double x, long n)
+scalblnl(long double x, long n)
 {
-	int in;
 
-	in = (int)n;
-	if (in != n) {
-		if (n > 0)
-			in = INT_MAX;
-		else
-			in = INT_MIN;
-	}
-	return (scalbnl(x, (int)n));
+	return (scalbnl(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
 }
diff --git a/linker/Android.mk b/linker/Android.mk
index 7a9b5d9..85ac0ca 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -2,16 +2,20 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES := \
     debugger.cpp \
     dlfcn.cpp \
     linker.cpp \
     linker_allocator.cpp \
-    linker_sdk_versions.cpp \
     linker_block_allocator.cpp \
     linker_libc_support.c \
+    linker_mapped_file_fragment.cpp \
     linker_memory.cpp \
     linker_phdr.cpp \
+    linker_sdk_versions.cpp \
+    linker_utils.cpp \
     rt.cpp \
 
 LOCAL_SRC_FILES_arm     := arch/arm/begin.S
@@ -35,14 +39,13 @@
     -fvisibility=hidden \
     -Wall -Wextra -Wunused -Werror \
 
-LOCAL_CFLAGS_arm += -D__work_around_b_19059885__
-LOCAL_CFLAGS_x86 += -D__work_around_b_19059885__
+LOCAL_CFLAGS_arm += -D__work_around_b_24465209__
+LOCAL_CFLAGS_x86 += -D__work_around_b_24465209__
 
 LOCAL_CONLYFLAGS += \
     -std=gnu99 \
 
 LOCAL_CPPFLAGS += \
-    -std=gnu++11 \
     -Wold-style-cast \
 
 ifeq ($(TARGET_IS_64_BIT),true)
@@ -60,7 +63,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libz liblog
+LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libbase libz liblog
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
@@ -83,4 +86,20 @@
 
 include $(BUILD_EXECUTABLE)
 
+
+define add-linker-symlink
+$(eval _from := $(TARGET_OUT)/bin/$(1))
+$(eval _to:=$(2))
+$(_from): $(LOCAL_MODULE_MAKEFILE)
+	@echo "Symlink: $$@ -> $(_to)"
+	@mkdir -p $$(dir $$@)
+	@rm -rf $$@
+	$(hide) ln -sf $(_to) $$@
+endef
+
+$(eval $(call add-linker-symlink,linker_asan,linker))
+ifeq ($(TARGET_IS_64_BIT),true)
+$(eval $(call add-linker-symlink,linker_asan64,linker64))
+endif
+
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/linker/NOTICE b/linker/NOTICE
index 139b26e..2c70ab8 100644
--- a/linker/NOTICE
+++ b/linker/NOTICE
@@ -42,34 +42,6 @@
 
 -------------------------------------------------------------------
 
-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.
-
--------------------------------------------------------------------
-
 Copyright (C) 2012 The Android Open Source Project
 All rights reserved.
 
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 46c97af..3731c99 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -135,9 +135,6 @@
       signal_name = "SIGILL";
       has_address = true;
       break;
-    case SIGPIPE:
-      signal_name = "SIGPIPE";
-      break;
     case SIGSEGV:
       signal_name = "SIGSEGV";
       has_address = true;
@@ -273,7 +270,7 @@
   signal(signal_number, SIG_DFL);
 
   // These signals are not re-thrown when we resume.  This means that
-  // crashing due to (say) SIGPIPE doesn't work the way you'd expect it
+  // crashing due to (say) SIGABRT doesn't work the way you'd expect it
   // to.  We work around this by throwing them manually.  We don't want
   // to do this for *all* signals because it'll screw up the si_addr for
   // faults like SIGSEGV. It does screw up the si_code, which is why we
@@ -281,7 +278,6 @@
   switch (signal_number) {
     case SIGABRT:
     case SIGFPE:
-    case SIGPIPE:
 #if defined(SIGSTKFLT)
     case SIGSTKFLT:
 #endif
@@ -307,7 +303,6 @@
   sigaction(SIGBUS, &action, nullptr);
   sigaction(SIGFPE, &action, nullptr);
   sigaction(SIGILL, &action, nullptr);
-  sigaction(SIGPIPE, &action, nullptr);
   sigaction(SIGSEGV, &action, nullptr);
 #if defined(SIGSTKFLT)
   sigaction(SIGSTKFLT, &action, nullptr);
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index ef454ab..a7c3fb0 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -16,12 +16,10 @@
 
 #include "linker.h"
 
-#include <dlfcn.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <android/dlext.h>
 #include <android/api-level.h>
 
 #include <bionic/pthread_internal.h>
@@ -67,9 +65,10 @@
   do_android_update_LD_LIBRARY_PATH(ld_library_path);
 }
 
-static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
+static void* dlopen_ext(const char* filename, int flags,
+                        const android_dlextinfo* extinfo, void* caller_addr) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
-  soinfo* result = do_dlopen(filename, flags, extinfo);
+  soinfo* result = do_dlopen(filename, flags, extinfo, caller_addr);
   if (result == nullptr) {
     __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
     return nullptr;
@@ -78,77 +77,41 @@
 }
 
 void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
-  return dlopen_ext(filename, flags, extinfo);
+  void* caller_addr = __builtin_return_address(0);
+  return dlopen_ext(filename, flags, extinfo, caller_addr);
 }
 
 void* dlopen(const char* filename, int flags) {
-  return dlopen_ext(filename, flags, nullptr);
+  void* caller_addr = __builtin_return_address(0);
+  return dlopen_ext(filename, flags, nullptr, caller_addr);
+}
+
+extern android_namespace_t* g_anonymous_namespace;
+
+void* dlsym_impl(void* handle, const char* symbol, const char* version, void* caller_addr) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  void* result;
+  if (!do_dlsym(handle, symbol, version, caller_addr, &result)) {
+    __bionic_format_dlerror(linker_get_error_buffer(), nullptr);
+    return nullptr;
+  }
+
+  return result;
 }
 
 void* dlsym(void* handle, const char* symbol) {
-  ScopedPthreadMutexLocker locker(&g_dl_mutex);
-
-#if !defined(__LP64__)
-  if (handle == nullptr) {
-    __bionic_format_dlerror("dlsym library handle is null", nullptr);
-    return nullptr;
-  }
-#endif
-
-  if (symbol == nullptr) {
-    __bionic_format_dlerror("dlsym symbol name is null", nullptr);
-    return nullptr;
-  }
-
-  soinfo* found = nullptr;
-  const ElfW(Sym)* sym = nullptr;
   void* caller_addr = __builtin_return_address(0);
-  soinfo* caller = find_containing_library(caller_addr);
+  return dlsym_impl(handle, symbol, nullptr, caller_addr);
+}
 
-  if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
-    sym = dlsym_linear_lookup(symbol, &found, caller, handle);
-  } else {
-    sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
-  }
-
-  if (sym != nullptr) {
-    unsigned bind = ELF_ST_BIND(sym->st_info);
-
-    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
-      return reinterpret_cast<void*>(found->resolve_symbol_address(sym));
-    }
-
-    __bionic_format_dlerror("symbol found but not global", symbol);
-    return nullptr;
-  } else {
-    __bionic_format_dlerror("undefined symbol", symbol);
-    return nullptr;
-  }
+void* dlvsym(void* handle, const char* symbol, const char* version) {
+  void* caller_addr = __builtin_return_address(0);
+  return dlsym_impl(handle, symbol, version, caller_addr);
 }
 
 int dladdr(const void* addr, Dl_info* info) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
-
-  // Determine if this address can be found in any library currently mapped.
-  soinfo* si = find_containing_library(addr);
-  if (si == nullptr) {
-    return 0;
-  }
-
-  memset(info, 0, sizeof(Dl_info));
-
-  info->dli_fname = si->get_realpath();
-  // Address at which the shared object is loaded.
-  info->dli_fbase = reinterpret_cast<void*>(si->base);
-
-  // Determine if any symbol in the library contains the specified address.
-  ElfW(Sym)* sym = si->find_symbol_by_address(addr);
-  if (sym != nullptr) {
-    info->dli_sname = si->get_string(sym->st_name);
-    info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
-  }
-
-  return 1;
+  return do_dladdr(addr, info);
 }
 
 int dlclose(void* handle) {
@@ -173,6 +136,34 @@
   return get_application_target_sdk_version();
 }
 
+bool android_init_namespaces(const char* public_ns_sonames,
+                             const char* anon_ns_library_path) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
+  if (!success) {
+    __bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
+  }
+
+  return success;
+}
+
+android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
+                                              const char* default_library_path, uint64_t type,
+                                              const char* permitted_when_isolated_path) {
+  void* caller_addr = __builtin_return_address(0);
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+  android_namespace_t* result = create_namespace(caller_addr, name, ld_library_path,
+                                                 default_library_path, type,
+                                                 permitted_when_isolated_path);
+
+  if (result == nullptr) {
+    __bionic_format_dlerror("android_create_namespace failed", linker_get_error_buffer());
+  }
+
+  return result;
+}
+
 // name_offset: starting index of the name in libdl_info.strtab
 #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
     { name_offset, \
@@ -199,11 +190,11 @@
   // 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"
+  // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677
+  // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901
+    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0"
 #if defined(__arm__)
-  // 216
+  // 272
     "dl_unwind_find_exidx\0"
 #endif
     ;
@@ -225,8 +216,11 @@
   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),
+  ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
+  ELFW(SYM_INITIALIZER)(265, &dlvsym, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(216, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(272, &dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -243,18 +237,20 @@
 // 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, 11, 12, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
 static soinfo* __libdl_info = nullptr;
 
+extern android_namespace_t g_default_namespace;
+
 // This is used by the dynamic linker. Every process gets these symbols for free.
 soinfo* get_libdl_info() {
   if (__libdl_info == nullptr) {
-    __libdl_info = new (__libdl_info_buf) soinfo("libdl.so", nullptr, 0, RTLD_GLOBAL);
+    __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, "libdl.so", nullptr, 0, RTLD_GLOBAL);
     __libdl_info->flags_ |= FLAG_LINKED;
     __libdl_info->strtab_ = ANDROID_LIBDL_STRTAB;
     __libdl_info->symtab_ = g_libdl_symtab;
@@ -267,7 +263,7 @@
     __libdl_info->local_group_root_ = __libdl_info;
     __libdl_info->soname_ = "libdl.so";
     __libdl_info->target_sdk_version_ = __ANDROID_API__;
-#if defined(__arm__)
+#if defined(__work_around_b_24465209__)
     strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
 #endif
   }
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 8003dbf..88386b0 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -25,12 +25,49 @@
   T* element;
 };
 
+// ForwardInputIterator
+template<typename T>
+class LinkedListIterator {
+ public:
+  LinkedListIterator() : entry_(nullptr) {}
+  LinkedListIterator(const LinkedListIterator<T>& that) : entry_(that.entry_) {}
+  explicit LinkedListIterator(LinkedListEntry<T>* entry) : entry_(entry) {}
+
+  LinkedListIterator<T>& operator=(const LinkedListIterator<T>& that) {
+    entry_ = that.entry_;
+    return *this;
+  }
+
+  LinkedListIterator<T>& operator++() {
+    entry_ = entry_->next;
+    return *this;
+  }
+
+  T* operator*() {
+    return entry_->element;
+  }
+
+  bool operator==(const LinkedListIterator<T>& that) const {
+    return entry_ == that.entry_;
+  }
+
+  bool operator!=(const LinkedListIterator<T>& that) const {
+    return entry_ != that.entry_;
+  }
+
+ private:
+  LinkedListEntry<T> *entry_;
+};
+
 /*
  * Represents linked list of objects of type T
  */
 template<typename T, typename Allocator>
 class LinkedList {
  public:
+  typedef LinkedListIterator<T> iterator;
+  typedef T* value_type;
+
   LinkedList() : head_(nullptr), tail_(nullptr) {}
   ~LinkedList() {
     clear();
@@ -127,7 +164,13 @@
         } else {
           p->next = next;
         }
+
+        if (tail_ == e) {
+          tail_ = p;
+        }
+
         Allocator::free(e);
+
         e = next;
       } else {
         p = e;
@@ -147,6 +190,24 @@
     return nullptr;
   }
 
+  iterator begin() {
+    return iterator(head_);
+  }
+
+  iterator end() {
+    return iterator(nullptr);
+  }
+
+  iterator find(T* value) {
+    for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+      if (e->element == value) {
+        return iterator(e);
+      }
+    }
+
+    return end();
+  }
+
   size_t copy_to_array(T* array[], size_t array_length) const {
     size_t sz = 0;
     for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index d3ac1d0..791f94d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -27,7 +27,6 @@
  */
 
 #include <android/api-level.h>
-#include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -37,11 +36,11 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include <sys/prctl.h>
 #include <unistd.h>
 
 #include <new>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 // Private C library headers.
@@ -49,7 +48,6 @@
 #include "private/KernelArgumentBlock.h"
 #include "private/ScopedPthreadMutexLocker.h"
 #include "private/ScopeGuard.h"
-#include "private/UniquePtr.h"
 
 #include "linker.h"
 #include "linker_block_allocator.h"
@@ -58,19 +56,73 @@
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
+#include "linker_utils.h"
+
+#include "android-base/strings.h"
 #include "ziparchive/zip_archive.h"
 
+extern void __libc_init_globals(KernelArgumentBlock&);
 extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
 
 // Override macros to use C++ style casts.
 #undef ELF_ST_TYPE
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
+struct android_namespace_t {
+ public:
+  android_namespace_t() : name_(nullptr), is_isolated_(false) {}
+
+  const char* get_name() const { return name_; }
+  void set_name(const char* name) { name_ = name; }
+
+  bool is_isolated() const { return is_isolated_; }
+  void set_isolated(bool isolated) { is_isolated_ = isolated; }
+
+  const std::vector<std::string>& get_ld_library_paths() const {
+    return ld_library_paths_;
+  }
+  void set_ld_library_paths(std::vector<std::string>&& library_paths) {
+    ld_library_paths_ = library_paths;
+  }
+
+  const std::vector<std::string>& get_default_library_paths() const {
+    return default_library_paths_;
+  }
+  void set_default_library_paths(std::vector<std::string>&& library_paths) {
+    default_library_paths_ = library_paths;
+  }
+
+  void set_permitted_paths(std::vector<std::string>&& permitted_paths) {
+    permitted_paths_ = permitted_paths;
+  }
+
+  soinfo::soinfo_list_t& soinfo_list() { return soinfo_list_; }
+
+  // For isolated namespaces - checks if the file is on the search path;
+  // always returns true for not isolated namespace.
+  bool is_accessible(const std::string& path);
+
+ private:
+  const char* name_;
+  bool is_isolated_;
+  std::vector<std::string> ld_library_paths_;
+  std::vector<std::string> default_library_paths_;
+  std::vector<std::string> permitted_paths_;
+  soinfo::soinfo_list_t soinfo_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
+};
+
+android_namespace_t g_default_namespace;
+android_namespace_t* g_anonymous_namespace = &g_default_namespace;
+
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
 static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
 static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
 
+static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
+
 static soinfo* solist;
 static soinfo* sonext;
 static soinfo* somain; // main process, always the one after libdl_info
@@ -86,18 +138,90 @@
   nullptr
 };
 
+static const char* const kAsanDefaultLdPaths[] = {
+#if defined(__LP64__)
+  "/data/vendor/lib64",
+  "/vendor/lib64",
+  "/data/lib64",
+  "/system/lib64",
+#else
+  "/data/vendor/lib",
+  "/vendor/lib",
+  "/data/lib",
+  "/system/lib",
+#endif
+  nullptr
+};
+
+static bool is_system_library(const std::string& realpath) {
+  for (const auto& dir : g_default_namespace.get_default_library_paths()) {
+    if (file_is_in_dir(realpath, dir)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// TODO(dimitry): This is workaround for http://b/26394120 - it will be removed before the release
+static bool is_greylisted(const char* name, const soinfo* needed_by) {
+  static const char* const kLibraryGreyList[] = {
+    "libandroid_runtime.so",
+    "libbinder.so",
+    "libcrypto.so",
+    "libcutils.so",
+    "libmedia.so",
+    "libnativehelper.so",
+    "libssl.so",
+    "libstagefright.so",
+    "libutils.so",
+    nullptr
+  };
+
+  // limit greylisting to apps targeting sdk version 23 and below
+  if (get_application_target_sdk_version() > 23) {
+    return false;
+  }
+
+  // if the library needed by a system library - implicitly assume it
+  // is greylisted
+
+  if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
+    return true;
+  }
+
+  for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
+    if (strcmp(name, kLibraryGreyList[i]) == 0) {
+      return true;
+    }
+  }
+
+  return false;
+}
+// END OF WORKAROUND
+
 static const ElfW(Versym) kVersymNotNeeded = 0;
 static const ElfW(Versym) kVersymGlobal = 1;
 
-static std::vector<std::string> g_ld_library_paths;
+static const char* const* g_default_ld_paths;
 static std::vector<std::string> g_ld_preload_names;
 
 static std::vector<soinfo*> g_ld_preloads;
 
+static bool g_public_namespace_initialized;
+static soinfo::soinfo_list_t g_public_namespace;
+
 __LIBC_HIDDEN__ int g_ld_debug_verbosity;
 
 __LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
 
+static std::string dirname(const char *path) {
+  const char* last_slash = strrchr(path, '/');
+  if (last_slash == path) return "/";
+  else if (last_slash == nullptr) return ".";
+  else
+    return std::string(path, last_slash - path);
+}
+
 #if STATS
 struct linker_stats_t {
   int count[kRelocMax];
@@ -218,6 +342,32 @@
   rtld_db_dlactivity();
 }
 
+bool android_namespace_t::is_accessible(const std::string& file) {
+  if (!is_isolated_) {
+    return true;
+  }
+
+  for (const auto& dir : ld_library_paths_) {
+    if (file_is_in_dir(file, dir)) {
+      return true;
+    }
+  }
+
+  for (const auto& dir : default_library_paths_) {
+    if (file_is_in_dir(file, dir)) {
+      return true;
+    }
+  }
+
+  for (const auto& dir : permitted_paths_) {
+    if (file_is_under_dir(file, dir)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
   return g_soinfo_links_allocator.alloc();
 }
@@ -226,18 +376,22 @@
   g_soinfo_links_allocator.free(entry);
 }
 
-static soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
-                            off64_t file_offset, uint32_t rtld_flags) {
+static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
+                            struct stat* file_stat, off64_t file_offset,
+                            uint32_t rtld_flags) {
   if (strlen(name) >= PATH_MAX) {
     DL_ERR("library name \"%s\" too long", name);
     return nullptr;
   }
 
-  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
+  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
+                                                       file_offset, rtld_flags);
 
   sonext->next = si;
   sonext = si;
 
+  ns->soinfo_list().push_back(si);
+
   TRACE("name %s: allocated soinfo @ %p", name, si);
   return si;
 }
@@ -278,59 +432,173 @@
     sonext = prev;
   }
 
+  // remove from the namespace
+  si->get_namespace()->soinfo_list().remove_if([&](soinfo* candidate) {
+    return si == candidate;
+  });
+
   si->~soinfo();
   g_soinfo_allocator.free(si);
 }
 
-static void parse_path(const char* path, const char* delimiters,
+// For every path element this function checks of it exists, and is a directory,
+// and normalizes it:
+// 1. For regular path it converts it to realpath()
+// 2. For path in a zip file it uses realpath on the zipfile
+//    normalizes entry name by calling normalize_path function.
+static void resolve_paths(std::vector<std::string>& paths,
+                          std::vector<std::string>* resolved_paths) {
+  resolved_paths->clear();
+  for (const auto& path : paths) {
+    char resolved_path[PATH_MAX];
+    const char* original_path = path.c_str();
+    if (realpath(original_path, resolved_path) != nullptr) {
+      struct stat s;
+      if (stat(resolved_path, &s) == 0) {
+        if (S_ISDIR(s.st_mode)) {
+          resolved_paths->push_back(resolved_path);
+        } else {
+          DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
+          continue;
+        }
+      } else {
+        DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
+        continue;
+      }
+    } else {
+      std::string zip_path;
+      std::string entry_path;
+
+      std::string normalized_path;
+
+      if (!normalize_path(original_path, &normalized_path)) {
+        DL_WARN("Warning: unable to normalize \"%s\"", original_path);
+        continue;
+      }
+
+      if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
+        if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
+          DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
+          continue;
+        }
+
+        ZipArchiveHandle handle = nullptr;
+        if (OpenArchive(resolved_path, &handle) != 0) {
+          DL_WARN("Warning: unable to open zip archive: %s", resolved_path);
+          continue;
+        }
+
+        // Check if zip-file has a dir with entry_path name
+        void* cookie = nullptr;
+        std::string prefix_str = entry_path + "/";
+        ZipString prefix(prefix_str.c_str());
+
+        ZipEntry out_data;
+        ZipString out_name;
+
+        int32_t error_code;
+
+        if ((error_code = StartIteration(handle, &cookie, &prefix, nullptr)) != 0) {
+          DL_WARN("Unable to iterate over zip-archive entries \"%s\";"
+                  " error code: %d", zip_path.c_str(), error_code);
+          continue;
+        }
+
+        if (Next(cookie, &out_data, &out_name) != 0) {
+          DL_WARN("Unable to find entries starting with \"%s\" in \"%s\"",
+                  prefix_str.c_str(), zip_path.c_str());
+          continue;
+        }
+
+        auto zip_guard = make_scope_guard([&]() {
+          if (cookie != nullptr) {
+            EndIteration(cookie);
+          }
+          CloseArchive(handle);
+        });
+
+        resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
+      }
+    }
+  }
+}
+
+static void split_path(const char* path, const char* delimiters,
                        std::vector<std::string>* paths) {
-  if (path == nullptr) {
-    return;
+  if (path != nullptr && path[0] != 0) {
+    *paths = android::base::Split(path, delimiters);
   }
+}
 
-  paths->clear();
-
-  for (const char *p = path; ; ++p) {
-    size_t len = strcspn(p, delimiters);
-    // skip empty tokens
-    if (len == 0) {
-      continue;
-    }
-
-    paths->push_back(std::string(p, len));
-    p += len;
-
-    if (*p == '\0') {
-      break;
-    }
-  }
+static void parse_path(const char* path, const char* delimiters,
+                       std::vector<std::string>* resolved_paths) {
+  std::vector<std::string> paths;
+  split_path(path, delimiters, &paths);
+  resolve_paths(paths, resolved_paths);
 }
 
 static void parse_LD_LIBRARY_PATH(const char* path) {
-  parse_path(path, ":", &g_ld_library_paths);
+  std::vector<std::string> ld_libary_paths;
+  parse_path(path, ":", &ld_libary_paths);
+  g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
+}
+
+void soinfo::set_dt_runpath(const char* path) {
+  if (!has_min_version(3)) {
+    return;
+  }
+
+  std::vector<std::string> runpaths;
+
+  split_path(path, ":", &runpaths);
+
+  std::string origin = dirname(get_realpath());
+  // FIXME: add $LIB and $PLATFORM.
+  std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
+  for (auto&& s : runpaths) {
+    size_t pos = 0;
+    while (pos < s.size()) {
+      pos = s.find("$", pos);
+      if (pos == std::string::npos) break;
+      for (const auto& subst : substs) {
+        const std::string& token = subst.first;
+        const std::string& replacement = subst.second;
+        if (s.substr(pos + 1, token.size()) == token) {
+          s.replace(pos, token.size() + 1, replacement);
+          // -1 to compensate for the ++pos below.
+          pos += replacement.size() - 1;
+          break;
+        } else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") {
+          s.replace(pos, token.size() + 3, replacement);
+          pos += replacement.size() - 1;
+          break;
+        }
+      }
+      // Skip $ in case it did not match any of the known substitutions.
+      ++pos;
+    }
+  }
+
+  resolve_paths(runpaths, &dt_runpath_);
 }
 
 static void parse_LD_PRELOAD(const char* path) {
-  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
-  parse_path(path, " :", &g_ld_preload_names);
+  g_ld_preload_names.clear();
+  if (path != nullptr) {
+    // We have historically supported ':' as well as ' ' in LD_PRELOAD.
+    g_ld_preload_names = android::base::Split(path, " :");
+  }
 }
 
 static bool realpath_fd(int fd, std::string* realpath) {
   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);
-  // set DUMPABLE to 1 to access /proc/self/fd
-  int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
-  prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-  auto guard = make_scope_guard([&]() {
-    // restore dumpable
-    prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
-  });
+  __libc_format_buffer(&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;
   }
 
-  *realpath = std::string(&buf[0]);
+  *realpath = &buf[0];
   return true;
 }
 
@@ -640,8 +908,9 @@
   return true;
 }
 
-soinfo::soinfo(const char* realpath, const struct stat* file_stat,
-               off64_t file_offset, int rtld_flags) {
+soinfo::soinfo(android_namespace_t* ns, const char* realpath,
+               const struct stat* file_stat, off64_t file_offset,
+               int rtld_flags) {
   memset(this, 0, sizeof(*this));
 
   if (realpath != nullptr) {
@@ -658,22 +927,26 @@
   }
 
   this->rtld_flags_ = rtld_flags;
+  this->namespace_ = ns;
 }
 
+static uint32_t calculate_elf_hash(const char* name) {
+  const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
+  uint32_t h = 0, g;
+
+  while (*name_bytes) {
+    h = (h << 4) + *name_bytes++;
+    g = h & 0xf0000000;
+    h ^= g;
+    h ^= g >> 24;
+  }
+
+  return h;
+}
 
 uint32_t SymbolName::elf_hash() {
   if (!has_elf_hash_) {
-    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
-    uint32_t h = 0, g;
-
-    while (*name) {
-      h = (h << 4) + *name++;
-      g = h & 0xf0000000;
-      h ^= g;
-      h ^= g >> 24;
-    }
-
-    elf_hash_ = h;
+    elf_hash_ = calculate_elf_hash(name_);
     has_elf_hash_ = true;
   }
 
@@ -809,6 +1082,7 @@
   void protect_data(int protection) {
     g_soinfo_allocator.protect_all(protection);
     g_soinfo_links_allocator.protect_all(protection);
+    g_namespace_allocator.protect_all(protection);
   }
 
   static size_t ref_count_;
@@ -851,17 +1125,17 @@
  public:
   struct deleter_t {
     void operator()(LoadTask* t) {
+      t->~LoadTask();
       TypeBasedAllocator<LoadTask>::free(t);
     }
   };
 
-  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
-
   static deleter_t deleter;
 
-  static LoadTask* create(const char* name, soinfo* needed_by) {
+  static LoadTask* create(const char* name, soinfo* needed_by,
+                          std::unordered_map<const soinfo*, ElfReader>* readers_map) {
     LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
-    return new (ptr) LoadTask(name, needed_by);
+    return new (ptr) LoadTask(name, needed_by, readers_map);
   }
 
   const char* get_name() const {
@@ -871,12 +1145,94 @@
   soinfo* get_needed_by() const {
     return needed_by_;
   }
+
+  soinfo* get_soinfo() const {
+    return si_;
+  }
+
+  void set_soinfo(soinfo* si) {
+    si_ = si;
+  }
+
+  off64_t get_file_offset() const {
+    return file_offset_;
+  }
+
+  void set_file_offset(off64_t offset) {
+    file_offset_ = offset;
+  }
+
+  int get_fd() const {
+    return fd_;
+  }
+
+  void set_fd(int fd, bool assume_ownership) {
+    fd_ = fd;
+    close_fd_ = assume_ownership;
+  }
+
+  const android_dlextinfo* get_extinfo() const {
+    return extinfo_;
+  }
+
+  void set_extinfo(const android_dlextinfo* extinfo) {
+    extinfo_ = extinfo;
+  }
+
+  const ElfReader& get_elf_reader() const {
+    CHECK(si_ != nullptr);
+    return (*elf_readers_map_)[si_];
+  }
+
+  ElfReader& get_elf_reader() {
+    CHECK(si_ != nullptr);
+    return (*elf_readers_map_)[si_];
+  }
+
+  std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
+    return elf_readers_map_;
+  }
+
+  bool read(const char* realpath, off64_t file_size) {
+    ElfReader& elf_reader = get_elf_reader();
+    return elf_reader.Read(realpath, fd_, file_offset_, file_size);
+  }
+
+  bool load() {
+    ElfReader& elf_reader = get_elf_reader();
+    if (!elf_reader.Load(extinfo_)) {
+      return false;
+    }
+
+    si_->base = elf_reader.load_start();
+    si_->size = elf_reader.load_size();
+    si_->load_bias = elf_reader.load_bias();
+    si_->phnum = elf_reader.phdr_count();
+    si_->phdr = elf_reader.loaded_phdr();
+
+    return true;
+  }
+
  private:
-  LoadTask(const char* name, soinfo* needed_by)
-    : name_(name), needed_by_(needed_by) {}
+  LoadTask(const char* name, soinfo* needed_by,
+           std::unordered_map<const soinfo*, ElfReader>* readers_map)
+    : name_(name), needed_by_(needed_by), si_(nullptr),
+      fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map) {}
+
+  ~LoadTask() {
+    if (fd_ != -1 && close_fd_) {
+      close(fd_);
+    }
+  }
 
   const char* name_;
   soinfo* needed_by_;
+  soinfo* si_;
+  const android_dlextinfo* extinfo_;
+  int fd_;
+  bool close_fd_;
+  off64_t file_offset_;
+  std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
 };
@@ -888,7 +1244,7 @@
 
 typedef linked_list_t<soinfo> SoinfoLinkedList;
 typedef linked_list_t<const char> StringLinkedList;
-typedef linked_list_t<LoadTask> LoadTaskList;
+typedef std::vector<LoadTask*> LoadTaskList;
 
 
 // This function walks down the tree of soinfo dependencies
@@ -929,7 +1285,8 @@
 
 
 static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
-                                            soinfo** found, SymbolName& symbol_name) {
+                                            soinfo** found, SymbolName& symbol_name,
+                                            const version_info* vi) {
   const ElfW(Sym)* result = nullptr;
   bool skip_lookup = skip_until != nullptr;
 
@@ -939,7 +1296,7 @@
       return true;
     }
 
-    if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
+    if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
       result = nullptr;
       return false;
     }
@@ -955,9 +1312,17 @@
   return result;
 }
 
+static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
+                                            const char* name,
+                                            const version_info* vi,
+                                            soinfo** found,
+                                            soinfo* caller,
+                                            void* handle);
+
 // 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* si, soinfo** found,
+                                            const char* name, const version_info* vi) {
   // 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.
@@ -966,11 +1331,11 @@
   // 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);
+    return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
   }
 
   SymbolName symbol_name(name);
-  return dlsym_handle_lookup(si, nullptr, found, symbol_name);
+  return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
 }
 
 /* This is used by dlsym(3) to performs a global symbol lookup. If the
@@ -978,24 +1343,30 @@
    beginning of the global solist. Otherwise the search starts at the
    specified soinfo (for RTLD_NEXT).
  */
-const ElfW(Sym)* dlsym_linear_lookup(const char* name,
-                                     soinfo** found,
-                                     soinfo* caller,
-                                     void* handle) {
+static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
+                                            const char* name,
+                                            const version_info* vi,
+                                            soinfo** found,
+                                            soinfo* caller,
+                                            void* handle) {
   SymbolName symbol_name(name);
 
-  soinfo* start = solist;
+  soinfo::soinfo_list_t& soinfo_list = ns->soinfo_list();
+  soinfo::soinfo_list_t::iterator start = soinfo_list.begin();
 
   if (handle == RTLD_NEXT) {
     if (caller == nullptr) {
       return nullptr;
     } else {
-      start = caller->next;
+      soinfo::soinfo_list_t::iterator it = soinfo_list.find(caller);
+      CHECK (it != soinfo_list.end());
+      start = ++it;
     }
   }
 
   const ElfW(Sym)* s = nullptr;
-  for (soinfo* si = start; si != nullptr; si = si->next) {
+  for (soinfo::soinfo_list_t::iterator it = start, end = soinfo_list.end(); it != end; ++it) {
+    soinfo* si = *it;
     // 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
@@ -1003,7 +1374,7 @@
       continue;
     }
 
-    if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
+    if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
       return nullptr;
     }
 
@@ -1019,7 +1390,7 @@
   if (s == nullptr && caller != nullptr &&
       (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
     return dlsym_handle_lookup(caller->get_local_group_root(),
-        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
+        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
   }
 
   if (s != nullptr) {
@@ -1086,15 +1457,64 @@
   return nullptr;
 }
 
-static int open_library_in_zipfile(const char* const path,
-                                   off64_t* file_offset) {
-  TRACE("Trying zip file open from path '%s'", path);
+class ZipArchiveCache {
+ public:
+  ZipArchiveCache() {}
+  ~ZipArchiveCache();
+
+  bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
+
+  std::unordered_map<std::string, ZipArchiveHandle> cache_;
+};
+
+bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
+  std::string key(zip_path);
+
+  auto it = cache_.find(key);
+  if (it != cache_.end()) {
+    *handle = it->second;
+    return true;
+  }
+
+  int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    return false;
+  }
+
+  if (OpenArchiveFd(fd, "", handle) != 0) {
+    // invalid zip-file (?)
+    close(fd);
+    return false;
+  }
+
+  cache_[key] = *handle;
+  return true;
+}
+
+ZipArchiveCache::~ZipArchiveCache() {
+  for (const auto& it : cache_) {
+    CloseArchive(it.second);
+  }
+}
+
+static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
+                                   const char* const input_path,
+                                   off64_t* file_offset, std::string* realpath) {
+  std::string normalized_path;
+  if (!normalize_path(input_path, &normalized_path)) {
+    return -1;
+  }
+
+  const char* const path = normalized_path.c_str();
+  TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
 
   // 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
   // "bar/bas/x.so" within "foo.zip".
-  const char* separator = strstr(path, "!/");
+  const char* const separator = strstr(path, kZipFileSeparator);
   if (separator == nullptr) {
     return -1;
   }
@@ -1115,19 +1535,15 @@
   }
 
   ZipArchiveHandle handle;
-  if (OpenArchiveFd(fd, "", &handle, false) != 0) {
+  if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
     // invalid zip-file (?)
     close(fd);
     return -1;
   }
 
-  auto archive_guard = make_scope_guard([&]() {
-    CloseArchive(handle);
-  });
-
   ZipEntry entry;
 
-  if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
+  if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
     // Entry was not found.
     close(fd);
     return -1;
@@ -1140,6 +1556,15 @@
   }
 
   *file_offset = entry.offset;
+
+  if (realpath_fd(fd, realpath)) {
+    *realpath += separator;
+  } else {
+    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+          normalized_path.c_str());
+    *realpath = normalized_path;
+  }
+
   return fd;
 }
 
@@ -1153,40 +1578,29 @@
   return true;
 }
 
-static int open_library_on_default_path(const char* name, off64_t* file_offset) {
-  for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
+static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
+                                 const char* name, off64_t* file_offset,
+                                 const std::vector<std::string>& paths,
+                                 std::string* realpath) {
+  for (const auto& path : paths) {
     char buf[512];
-    if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) {
-      continue;
-    }
-
-    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
-    if (fd != -1) {
-      *file_offset = 0;
-      return fd;
-    }
-  }
-
-  return -1;
-}
-
-static int open_library_on_ld_library_path(const char* name, off64_t* file_offset) {
-  for (const auto& path_str : g_ld_library_paths) {
-    char buf[512];
-    const char* const path = path_str.c_str();
-    if (!format_path(buf, sizeof(buf), path, name)) {
+    if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
       continue;
     }
 
     int fd = -1;
-    if (strchr(buf, '!') != nullptr) {
-      fd = open_library_in_zipfile(buf, file_offset);
+    if (strstr(buf, kZipFileSeparator) != nullptr) {
+      fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
     }
 
     if (fd == -1) {
       fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
       if (fd != -1) {
         *file_offset = 0;
+        if (!realpath_fd(fd, realpath)) {
+          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
+          *realpath = buf;
+        }
       }
     }
 
@@ -1198,30 +1612,56 @@
   return -1;
 }
 
-static int open_library(const char* name, off64_t* file_offset) {
+static int open_library(android_namespace_t* ns,
+                        ZipArchiveCache* zip_archive_cache,
+                        const char* name, soinfo *needed_by,
+                        off64_t* file_offset, std::string* realpath) {
   TRACE("[ opening %s ]", name);
 
   // If the name contains a slash, we should attempt to open it directly and not search the paths.
   if (strchr(name, '/') != nullptr) {
-    if (strchr(name, '!') != nullptr) {
-      int fd = open_library_in_zipfile(name, file_offset);
+    int fd = -1;
+
+    if (strstr(name, kZipFileSeparator) != nullptr) {
+      fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
+    }
+
+    if (fd == -1) {
+      fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
       if (fd != -1) {
-        return fd;
+        *file_offset = 0;
+        if (!realpath_fd(fd, realpath)) {
+          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
+          *realpath = name;
+        }
       }
     }
 
-    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
-    if (fd != -1) {
-      *file_offset = 0;
-    }
     return fd;
   }
 
-  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
-  int fd = open_library_on_ld_library_path(name, file_offset);
-  if (fd == -1) {
-    fd = open_library_on_default_path(name, file_offset);
+  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
+  int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
+  if (fd == -1 && needed_by != nullptr) {
+    fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
+    // Check if the library is accessible
+    if (fd != -1 && !ns->is_accessible(*realpath)) {
+      fd = -1;
+    }
   }
+
+  if (fd == -1) {
+    fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
+  }
+
+  // TODO(dimitry): workaround for http://b/26394120 - will be removed before the release
+  if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
+    // try searching for it on default_namespace default_library_path
+    fd = open_library_on_paths(zip_archive_cache, name, file_offset,
+                               g_default_namespace.get_default_library_paths(), realpath);
+  }
+  // END OF WORKAROUND
+
   return fd;
 }
 
@@ -1242,120 +1682,184 @@
 
 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) {
+  for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
     if (d->d_tag == DT_NEEDED) {
       action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
     }
   }
 }
 
-static soinfo* load_library(int fd, off64_t file_offset,
-                            LoadTaskList& load_tasks,
-                            const char* name, int rtld_flags,
-                            const android_dlextinfo* extinfo) {
+template<typename F>
+static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
+  for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_NEEDED) {
+      action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
+    }
+  }
+}
+
+static bool load_library(android_namespace_t* ns,
+                         LoadTask* task,
+                         LoadTaskList* load_tasks,
+                         int rtld_flags,
+                         const std::string& realpath) {
+  off64_t file_offset = task->get_file_offset();
+  const char* name = task->get_name();
+  const android_dlextinfo* extinfo = task->get_extinfo();
+
   if ((file_offset % PAGE_SIZE) != 0) {
     DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
-    return nullptr;
+    return false;
   }
   if (file_offset < 0) {
     DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
-    return nullptr;
+    return false;
   }
 
   struct stat file_stat;
-  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
+  if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
     DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
-    return nullptr;
+    return false;
   }
   if (file_offset >= file_stat.st_size) {
     DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
         name, file_offset, file_stat.st_size);
-    return nullptr;
+    return false;
   }
 
   // Check for symlink and other situations where
   // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
   if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
-    for (soinfo* si = solist; si != nullptr; si = si->next) {
-      if (si->get_st_dev() != 0 &&
-          si->get_st_ino() != 0 &&
-          si->get_st_dev() == file_stat.st_dev &&
-          si->get_st_ino() == file_stat.st_ino &&
-          si->get_file_offset() == file_offset) {
-        TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
-            "will return existing soinfo", name, si->get_realpath());
-        return si;
+    auto predicate = [&](soinfo* si) {
+      return si->get_st_dev() != 0 &&
+             si->get_st_ino() != 0 &&
+             si->get_st_dev() == file_stat.st_dev &&
+             si->get_st_ino() == file_stat.st_ino &&
+             si->get_file_offset() == file_offset;
+    };
+
+    soinfo* si = ns->soinfo_list().find_if(predicate);
+
+    // check public namespace
+    if (si == nullptr) {
+      si = g_public_namespace.find_if(predicate);
+      if (si != nullptr) {
+        ns->soinfo_list().push_back(si);
       }
     }
+
+    if (si != nullptr) {
+      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
+            "will return existing soinfo", name, si->get_realpath());
+      task->set_soinfo(si);
+      return true;
+    }
   }
 
   if ((rtld_flags & RTLD_NOLOAD) != 0) {
     DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
-    return nullptr;
+    return false;
   }
 
-  std::string realpath = name;
-  if (!realpath_fd(fd, &realpath)) {
-    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
-    realpath = name;
+  if (!ns->is_accessible(realpath)) {
+    // TODO(dimitry): workaround for http://b/26394120 - will be removed before the release
+    const soinfo* needed_by = task->get_needed_by();
+    if (is_greylisted(name, needed_by)) {
+      // print warning only if needed by non-system library
+      if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
+        DL_WARN("library \"%s\" (\"%s\") is not accessible for the namespace \"%s\" - the access is temporarily granted as a workaround for http://b/26394120",
+                name, realpath.c_str(), ns->get_name());
+      }
+    } else {
+      // do not load libraries if they are not accessible for the specified namespace.
+      DL_ERR("library \"%s\" is not accessible for the namespace \"%s\"",
+             name, ns->get_name());
+      return false;
+    }
   }
 
-  // Read the ELF header and load the segments.
-  ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
-  if (!elf_reader.Load(extinfo)) {
-    return nullptr;
-  }
-
-  soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
+  soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
   if (si == nullptr) {
-    return nullptr;
+    return false;
   }
-  si->base = elf_reader.load_start();
-  si->size = elf_reader.load_size();
-  si->load_bias = elf_reader.load_bias();
-  si->phnum = elf_reader.phdr_count();
-  si->phdr = elf_reader.loaded_phdr();
 
-  if (!si->prelink_image()) {
+  task->set_soinfo(si);
+
+  // Read the ELF header and some of the segments.
+  if (!task->read(realpath.c_str(), file_stat.st_size)) {
     soinfo_free(si);
-    return nullptr;
+    task->set_soinfo(nullptr);
+    return false;
   }
 
-  for_each_dt_needed(si, [&] (const char* name) {
-    load_tasks.push_back(LoadTask::create(name, si));
+  // find and set DT_RUNPATH and dt_soname
+  // Note that these field values are temporary and are
+  // going to be overwritten on soinfo::prelink_image
+  // with values from PT_LOAD segments.
+  const ElfReader& elf_reader = task->get_elf_reader();
+  for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_RUNPATH) {
+      si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
+    }
+    if (d->d_tag == DT_SONAME) {
+      si->set_soname(elf_reader.get_string(d->d_un.d_val));
+    }
+  }
+
+  for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
+    load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
   });
 
-  return si;
+  return true;
 }
 
-static soinfo* load_library(LoadTaskList& load_tasks,
-                            const char* name, int rtld_flags,
-                            const android_dlextinfo* extinfo) {
+static bool load_library(android_namespace_t* ns,
+                         LoadTask* task,
+                         ZipArchiveCache* zip_archive_cache,
+                         LoadTaskList* load_tasks,
+                         int rtld_flags) {
+  const char* name = task->get_name();
+  soinfo* needed_by = task->get_needed_by();
+  const android_dlextinfo* extinfo = task->get_extinfo();
+
+  off64_t file_offset;
+  std::string realpath;
   if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
-    off64_t file_offset = 0;
+    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);
+
+    if (!realpath_fd(extinfo->library_fd, &realpath)) {
+      PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
+            "Will use given name.", name);
+      realpath = name;
+    }
+
+    task->set_fd(extinfo->library_fd, false);
+    task->set_file_offset(file_offset);
+    return load_library(ns, task, load_tasks, rtld_flags, realpath);
   }
 
   // Open the file.
-  off64_t file_offset;
-  int fd = open_library(name, &file_offset);
+  int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
   if (fd == -1) {
     DL_ERR("library \"%s\" not found", name);
-    return nullptr;
+    return false;
   }
-  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
-  close(fd);
-  return result;
+
+  task->set_fd(fd, true);
+  task->set_file_offset(file_offset);
+
+  return load_library(ns, task, load_tasks, rtld_flags, realpath);
 }
 
 // Returns true if library was found and false in 2 cases
-// 1. The library was found but loaded under different target_sdk_version
-//    (*candidate != nullptr)
+// 1. (for default namespace only) The library was found but loaded under different
+//    target_sdk_version (*candidate != nullptr)
 // 2. The library was not found by soname (*candidate is nullptr)
-static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
+static bool find_loaded_library_by_soname(android_namespace_t* ns,
+                                          const char* name, soinfo** candidate) {
   *candidate = nullptr;
 
   // Ignore filename with path.
@@ -1365,7 +1869,7 @@
 
   uint32_t target_sdk_version = get_application_target_sdk_version();
 
-  for (soinfo* si = solist; si != nullptr; si = si->next) {
+  return !ns->soinfo_list().visit([&](soinfo* si) {
     const char* soname = si->get_soname();
     if (soname != nullptr && (strcmp(name, soname) == 0)) {
       // If the library was opened under different target sdk version
@@ -1375,42 +1879,64 @@
       // in any case.
       bool is_libdl = si == solist;
       if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
-          !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
+          !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
+          ns != &g_default_namespace) {
         *candidate = si;
-        return true;
+        return false;
       } else if (*candidate == nullptr) {
-        // for the different sdk version - remember the first library.
+        // for the different sdk version in the default namespace
+        // remember the first library.
         *candidate = si;
       }
     }
-  }
 
-  return false;
+    return true;
+  });
 }
 
-static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
-                                     int rtld_flags, const android_dlextinfo* extinfo) {
+static bool find_library_internal(android_namespace_t* ns,
+                                  LoadTask* task,
+                                  ZipArchiveCache* zip_archive_cache,
+                                  LoadTaskList* load_tasks,
+                                  int rtld_flags) {
   soinfo* candidate;
 
-  if (find_loaded_library_by_soname(name, &candidate)) {
-    return candidate;
+  if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
+    task->set_soinfo(candidate);
+    return true;
+  }
+
+  if (ns != &g_default_namespace) {
+    // check public namespace
+    candidate = g_public_namespace.find_if([&](soinfo* si) {
+      return strcmp(task->get_name(), si->get_soname()) == 0;
+    });
+
+    if (candidate != nullptr) {
+      ns->soinfo_list().push_back(candidate);
+      task->set_soinfo(candidate);
+      return true;
+    }
   }
 
   // Library might still be loaded, the accurate detection
   // of this fact is done by load_library.
   TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
-      name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
+      task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
 
-  soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
-
-  // In case we were unable to load the library but there
-  // is a candidate loaded under the same soname but different
-  // sdk level - return it anyways.
-  if (si == nullptr && candidate != nullptr) {
-    si = candidate;
+  if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
+    return true;
+  } else {
+    // In case we were unable to load the library but there
+    // is a candidate loaded under the same soname but different
+    // sdk level - return it anyways.
+    if (candidate != nullptr) {
+      task->set_soinfo(candidate);
+      return true;
+    }
   }
 
-  return si;
+  return false;
 }
 
 static void soinfo_unload(soinfo* si);
@@ -1422,29 +1948,48 @@
 //
 // This group consists of the main executable, LD_PRELOADs
 // and libraries with the DF_1_GLOBAL flag set.
-static soinfo::soinfo_list_t make_global_group() {
+static soinfo::soinfo_list_t make_global_group(android_namespace_t* ns) {
   soinfo::soinfo_list_t global_group;
-  for (soinfo* si = somain; si != nullptr; si = si->next) {
+  ns->soinfo_list().for_each([&](soinfo* si) {
     if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
       global_group.push_back(si);
     }
-  }
+  });
 
   return global_group;
 }
 
-static bool find_libraries(soinfo* start_with, const char* const library_names[],
-      size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
-      size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
+static void shuffle(std::vector<LoadTask*>* v) {
+  for (size_t i = 0, size = v->size(); i < size; ++i) {
+    size_t n = size - i;
+    size_t r = arc4random_uniform(n);
+    std::swap((*v)[n-1], (*v)[r]);
+  }
+}
+
+// add_as_children - add first-level loaded libraries (i.e. library_names[], but
+// not their transitive dependencies) as children of the start_with library.
+// This is false when find_libraries is called for dlopen(), when newly loaded
+// libraries must form a disjoint tree.
+static bool find_libraries(android_namespace_t* ns,
+                           soinfo* start_with,
+                           const char* const library_names[],
+                           size_t library_names_count, soinfo* soinfos[],
+                           std::vector<soinfo*>* ld_preloads,
+                           size_t ld_preloads_count, int rtld_flags,
+                           const android_dlextinfo* extinfo,
+                           bool add_as_children) {
   // Step 0: prepare.
   LoadTaskList load_tasks;
+  std::unordered_map<const soinfo*, ElfReader> readers_map;
+
   for (size_t i = 0; i < library_names_count; ++i) {
     const char* name = library_names[i];
-    load_tasks.push_back(LoadTask::create(name, start_with));
+    load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
   }
 
   // Construct global_group.
-  soinfo::soinfo_list_t global_group = make_global_group();
+  soinfo::soinfo_list_t global_group = make_global_group(ns);
 
   // If soinfos array is null allocate one on stack.
   // The array is needed in case of failure; for example
@@ -1462,29 +2007,37 @@
   // list of libraries to link - see step 2.
   size_t soinfos_count = 0;
 
+  auto scope_guard = make_scope_guard([&]() {
+    for (LoadTask* t : load_tasks) {
+      LoadTask::deleter(t);
+    }
+  });
+
   auto failure_guard = make_scope_guard([&]() {
     // Housekeeping
-    load_tasks.for_each([] (LoadTask* t) {
-      LoadTask::deleter(t);
-    });
-
     for (size_t i = 0; i<soinfos_count; ++i) {
       soinfo_unload(soinfos[i]);
     }
   });
 
-  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
-  for (LoadTask::unique_ptr task(load_tasks.pop_front());
-      task.get() != nullptr; task.reset(load_tasks.pop_front())) {
+  ZipArchiveCache zip_archive_cache;
+
+  // Step 1: expand the list of load_tasks to include
+  // all DT_NEEDED libraries (do not load them just yet)
+  for (size_t i = 0; i<load_tasks.size(); ++i) {
+    LoadTask* task = load_tasks[i];
     soinfo* needed_by = task->get_needed_by();
 
-    soinfo* si = find_library_internal(load_tasks, task->get_name(),
-                                       rtld_flags, needed_by == nullptr ? extinfo : nullptr);
-    if (si == nullptr) {
+    bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
+    task->set_extinfo(is_dt_needed ? nullptr : extinfo);
+
+    if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
       return false;
     }
 
-    if (needed_by != nullptr) {
+    soinfo* si = task->get_soinfo();
+
+    if (is_dt_needed) {
       needed_by->add_child(si);
     }
 
@@ -1495,11 +2048,6 @@
     // When ld_preloads is not null, the first
     // ld_preloads_count libs are in fact ld_preloads.
     if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
-      // Add LD_PRELOADed libraries to the global group for future runs.
-      // There is no need to explicitly add them to the global group
-      // for this run because they are going to appear in the local
-      // group in the correct order.
-      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
       ld_preloads->push_back(si);
     }
 
@@ -1508,11 +2056,51 @@
     }
   }
 
-  // Step 2: link libraries.
+  // Step 2: Load libraries in random order (see b/24047022)
+  LoadTaskList load_list;
+  for (auto&& task : load_tasks) {
+    soinfo* si = task->get_soinfo();
+    auto pred = [&](const LoadTask* t) {
+      return t->get_soinfo() == si;
+    };
+
+    if (!si->is_linked() &&
+        std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
+      load_list.push_back(task);
+    }
+  }
+  shuffle(&load_list);
+
+  for (auto&& task : load_list) {
+    if (!task->load()) {
+      return false;
+    }
+  }
+
+  // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
+  for (auto&& task : load_tasks) {
+    soinfo* si = task->get_soinfo();
+    if (!si->is_linked() && !si->prelink_image()) {
+      return false;
+    }
+  }
+
+  // Step 4: Add LD_PRELOADed libraries to the global group for
+  // future runs. There is no need to explicitly add them to
+  // the global group for this run because they are going to
+  // appear in the local group in the correct order.
+  if (ld_preloads != nullptr) {
+    for (auto&& si : *ld_preloads) {
+      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+    }
+  }
+
+
+  // Step 5: link libraries.
   soinfo::soinfo_list_t local_group;
   walk_dependencies_tree(
-      start_with == nullptr ? soinfos : &start_with,
-      start_with == nullptr ? soinfos_count : 1,
+      (start_with != nullptr && add_as_children) ? &start_with : soinfos,
+      (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
       [&] (soinfo* si) {
     local_group.push_back(si);
     return true;
@@ -1544,12 +2132,16 @@
   return linked;
 }
 
-static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
+static soinfo* find_library(android_namespace_t* ns,
+                            const char* name, int rtld_flags,
+                            const android_dlextinfo* extinfo,
+                            soinfo* needed_by) {
   soinfo* si;
 
   if (name == nullptr) {
     si = somain;
-  } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
+  } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
+                             extinfo, /* add_as_children */ false)) {
     return nullptr;
   }
 
@@ -1603,7 +2195,7 @@
           }
         }
       } else {
-#if !defined(__work_around_b_19059885__)
+#if !defined(__work_around_b_24465209__)
         __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_realpath(), si);
@@ -1611,7 +2203,9 @@
           TRACE("deprecated (old format of soinfo): %s needs to unload %s",
               si->get_realpath(), library_name);
 
-          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
+          soinfo* needed = find_library(si->get_namespace(),
+                                        library_name, RTLD_NOLOAD, nullptr, 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.
@@ -1651,6 +2245,14 @@
   }
 }
 
+static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
+  if (sym_ver == nullptr) {
+    return sym_name;
+  }
+
+  return std::string(sym_name) + ", version " + sym_ver;
+}
+
 void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
   // Use basic string manipulation calls to avoid snprintf.
   // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
@@ -1659,51 +2261,247 @@
   // See b/17302493 for further details.
   // Once the above bug is fixed, this code can be modified to use
   // snprintf again.
-  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
+  size_t required_len = 0;
+  for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
+    required_len += strlen(g_default_ld_paths[i]) + 1;
+  }
   if (buffer_size < required_len) {
     __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
                  "buffer len %zu, required len %zu", buffer_size, required_len);
   }
-  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
-  *end = ':';
-  strcpy(end + 1, kDefaultLdPaths[1]);
+  char* end = buffer;
+  for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
+    if (i > 0) *end++ = ':';
+    end = stpcpy(end, g_default_ld_paths[i]);
+  }
 }
 
 void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
   parse_LD_LIBRARY_PATH(ld_library_path);
 }
 
-soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
+soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
+                  void* caller_addr) {
+  soinfo* const caller = find_containing_library(caller_addr);
+
   if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
     DL_ERR("invalid flags to dlopen: %x", flags);
     return nullptr;
   }
+
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+
   if (extinfo != nullptr) {
     if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
       DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
       return nullptr;
     }
+
     if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
         (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
       DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
           "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
       return nullptr;
     }
+
+    if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
+        (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
+      DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
+             "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
+      return nullptr;
+    }
+
+    if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
+      if (extinfo->library_namespace == nullptr) {
+        DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
+        return nullptr;
+      }
+      ns = extinfo->library_namespace;
+    }
   }
 
   ProtectedDataGuard guard;
-  soinfo* si = find_library(name, flags, extinfo);
+  soinfo* si = find_library(ns, name, flags, extinfo, caller);
   if (si != nullptr) {
     si->call_constructors();
   }
+
   return si;
 }
 
+int do_dladdr(const void* addr, Dl_info* info) {
+  // Determine if this address can be found in any library currently mapped.
+  soinfo* si = find_containing_library(addr);
+  if (si == nullptr) {
+    return 0;
+  }
+
+  memset(info, 0, sizeof(Dl_info));
+
+  info->dli_fname = si->get_realpath();
+  // Address at which the shared object is loaded.
+  info->dli_fbase = reinterpret_cast<void*>(si->base);
+
+  // Determine if any symbol in the library contains the specified address.
+  ElfW(Sym)* sym = si->find_symbol_by_address(addr);
+  if (sym != nullptr) {
+    info->dli_sname = si->get_string(sym->st_name);
+    info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
+  }
+
+  return 1;
+}
+
+bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
+              void* caller_addr, void** symbol) {
+#if !defined(__LP64__)
+  if (handle == nullptr) {
+    DL_ERR("dlsym failed: library handle is null");
+    return false;
+  }
+#endif
+
+  if (sym_name == nullptr) {
+    DL_ERR("dlsym failed: symbol name is null");
+    return false;
+  }
+
+  soinfo* found = nullptr;
+  const ElfW(Sym)* sym = nullptr;
+  soinfo* caller = find_containing_library(caller_addr);
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+
+  version_info vi_instance;
+  version_info* vi = nullptr;
+
+  if (sym_ver != nullptr) {
+    vi_instance.name = sym_ver;
+    vi_instance.elf_hash = calculate_elf_hash(sym_ver);
+    vi = &vi_instance;
+  }
+
+  if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
+    sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
+  } else {
+    sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, sym_name, vi);
+  }
+
+  if (sym != nullptr) {
+    uint32_t bind = ELF_ST_BIND(sym->st_info);
+
+    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
+      *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
+      return true;
+    }
+
+    DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
+    return false;
+  }
+
+  DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
+  return false;
+}
+
 void do_dlclose(soinfo* si) {
   ProtectedDataGuard guard;
   soinfo_unload(si);
 }
 
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
+  CHECK(public_ns_sonames != nullptr);
+  if (g_public_namespace_initialized) {
+    DL_ERR("public namespace has already been initialized.");
+    return false;
+  }
+
+  std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
+
+  ProtectedDataGuard guard;
+
+  auto failure_guard = make_scope_guard([&]() {
+    g_public_namespace.clear();
+  });
+
+  for (const auto& soname : sonames) {
+    soinfo* candidate = nullptr;
+
+    find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
+
+    if (candidate == nullptr) {
+      DL_ERR("error initializing public namespace: \"%s\" was not found"
+             " in the default namespace", soname.c_str());
+      return false;
+    }
+
+    candidate->set_nodelete();
+    g_public_namespace.push_back(candidate);
+  }
+
+  g_public_namespace_initialized = true;
+
+  // create anonymous namespace
+  // When the caller is nullptr - create_namespace will take global group
+  // from the anonymous namespace, which is fine because anonymous namespace
+  // is still pointing to the default one.
+  android_namespace_t* anon_ns =
+      create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
+                       ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
+
+  if (anon_ns == nullptr) {
+    g_public_namespace_initialized = false;
+    return false;
+  }
+  g_anonymous_namespace = anon_ns;
+  failure_guard.disable();
+  return true;
+}
+
+android_namespace_t* create_namespace(const void* caller_addr,
+                                      const char* name,
+                                      const char* ld_library_path,
+                                      const char* default_library_path,
+                                      uint64_t type,
+                                      const char* permitted_when_isolated_path) {
+  if (!g_public_namespace_initialized) {
+    DL_ERR("cannot create namespace: public namespace is not initialized.");
+    return nullptr;
+  }
+
+  soinfo* caller_soinfo = find_containing_library(caller_addr);
+
+  android_namespace_t* caller_ns = caller_soinfo != nullptr ?
+                                   caller_soinfo->get_namespace() :
+                                   g_anonymous_namespace;
+
+  ProtectedDataGuard guard;
+  std::vector<std::string> ld_library_paths;
+  std::vector<std::string> default_library_paths;
+  std::vector<std::string> permitted_paths;
+
+  parse_path(ld_library_path, ":", &ld_library_paths);
+  parse_path(default_library_path, ":", &default_library_paths);
+  parse_path(permitted_when_isolated_path, ":", &permitted_paths);
+
+  android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
+  ns->set_name(name);
+  ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
+  ns->set_ld_library_paths(std::move(ld_library_paths));
+  ns->set_default_library_paths(std::move(default_library_paths));
+  ns->set_permitted_paths(std::move(permitted_paths));
+
+  if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
+    // If shared - clone the caller namespace
+    auto& soinfo_list = caller_ns->soinfo_list();
+    std::copy(soinfo_list.begin(), soinfo_list.end(), std::back_inserter(ns->soinfo_list()));
+  } else {
+    // If not shared - copy only the global group
+    auto global_group = make_global_group(caller_ns);
+    std::copy(global_group.begin(), global_group.end(), std::back_inserter(ns->soinfo_list()));
+  }
+
+  return ns;
+}
+
 static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
   typedef ElfW(Addr) (*ifunc_resolver_t)(void);
   ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
@@ -2025,24 +2823,23 @@
         count_relocation(kRelocAbsolute);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
-                   reloc, (sym_addr + addend), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+                   reloc, sym_addr + addend, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
         break;
       case R_AARCH64_ABS32:
         count_relocation(kRelocAbsolute);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
-                   reloc, (sym_addr + addend), sym_name);
+                   reloc, sym_addr + addend, sym_name);
         {
-          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
           const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
           const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
-          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
-              ((reloc_value + (sym_addr + addend)) <= max_value)) {
-            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          if ((min_value <= (sym_addr + addend)) &&
+              ((sym_addr + addend) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
           } else {
             DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                   (reloc_value + (sym_addr + addend)), min_value, max_value);
+                   sym_addr + addend, min_value, max_value);
             return false;
           }
         }
@@ -2051,17 +2848,16 @@
         count_relocation(kRelocAbsolute);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
-                   reloc, (sym_addr + addend), sym_name);
+                   reloc, sym_addr + addend, sym_name);
         {
-          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
           const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
           const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
-          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
-              ((reloc_value + (sym_addr + addend)) <= max_value)) {
-            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
+          if ((min_value <= (sym_addr + addend)) &&
+              ((sym_addr + addend) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
           } else {
             DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                   reloc_value + (sym_addr + addend), min_value, max_value);
+                   sym_addr + addend, min_value, max_value);
             return false;
           }
         }
@@ -2070,24 +2866,23 @@
         count_relocation(kRelocRelative);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
-                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset;
+                   reloc, sym_addr + addend, rel->r_offset, sym_name);
+        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
         break;
       case R_AARCH64_PREL32:
         count_relocation(kRelocRelative);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
-                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
+                   reloc, sym_addr + addend, rel->r_offset, sym_name);
         {
-          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
           const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
           const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
-          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
-              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
-            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
+              ((sym_addr + addend - rel->r_offset) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
           } else {
             DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+                   sym_addr + addend - rel->r_offset, min_value, max_value);
             return false;
           }
         }
@@ -2096,17 +2891,16 @@
         count_relocation(kRelocRelative);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
-                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
+                   reloc, sym_addr + addend, rel->r_offset, sym_name);
         {
-          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
           const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
           const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
-          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
-              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
-            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
+          if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
+              ((sym_addr + addend - rel->r_offset) <= max_value)) {
+            *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
           } else {
             DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
-                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
+                   sym_addr + addend - rel->r_offset, min_value, max_value);
             return false;
           }
         }
@@ -2138,14 +2932,14 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
                    static_cast<size_t>(sym_addr), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
         break;
       case R_X86_64_64:
         count_relocation(kRelocRelative);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
                    static_cast<size_t>(sym_addr), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
         break;
       case R_X86_64_PC32:
         count_relocation(kRelocRelative);
@@ -2153,7 +2947,7 @@
         TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
                    static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
                    static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
+        *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
         break;
 #elif defined(__arm__)
       case R_ARM_ABS32:
@@ -2376,8 +3170,12 @@
   }
 }
 
+void soinfo::set_nodelete() {
+  rtld_flags_ |= RTLD_NODELETE;
+}
+
 const char* soinfo::get_realpath() const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
     return realpath_.c_str();
   } else {
@@ -2388,8 +3186,19 @@
 #endif
 }
 
+void soinfo::set_soname(const char* soname) {
+#if defined(__work_around_b_24465209__)
+  if (has_min_version(2)) {
+    soname_ = soname;
+  }
+  strlcpy(old_name_, soname_, sizeof(old_name_));
+#else
+  soname_ = soname;
+#endif
+}
+
 const char* soinfo::get_soname() const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
     return soname_;
   } else {
@@ -2428,6 +3237,24 @@
   return g_empty_list;
 }
 
+static std::vector<std::string> g_empty_runpath;
+
+const std::vector<std::string>& soinfo::get_dt_runpath() const {
+  if (has_min_version(3)) {
+    return dt_runpath_;
+  }
+
+  return g_empty_runpath;
+}
+
+android_namespace_t* soinfo::get_namespace() {
+  if (has_min_version(3)) {
+    return namespace_;
+  }
+
+  return &g_default_namespace;
+}
+
 ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
   if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
     return call_ifunc_resolver(s->st_value + load_bias);
@@ -2504,7 +3331,7 @@
   /* We can't log anything until the linker is relocated */
   bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
   if (!relocating_linker) {
-    INFO("[ linking %s ]", get_realpath());
+    INFO("[ Linking '%s' ]", get_realpath());
     DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
   }
 
@@ -2864,6 +3691,10 @@
         verneed_cnt_ = d->d_un.d_val;
         break;
 
+      case DT_RUNPATH:
+        // this is parsed after we have strtab initialized (see below).
+        break;
+
       default:
         if (!relocating_linker) {
           DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
@@ -2873,6 +3704,12 @@
     }
   }
 
+#if defined(__mips__) && !defined(__LP64__)
+  if (!mips_check_and_adjust_fp_modes()) {
+    return false;
+  }
+#endif
+
   DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
         reinterpret_cast<void*>(base), strtab_, symtab_);
 
@@ -2897,12 +3734,13 @@
 
   // 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;
+    switch (d->d_tag) {
+      case DT_SONAME:
+        set_soname(get_string(d->d_un.d_val));
+        break;
+      case DT_RUNPATH:
+        set_dt_runpath(get_string(d->d_un.d_val));
+        break;
     }
   }
 
@@ -2942,15 +3780,13 @@
 #if !defined(__LP64__)
   if (has_text_relocations) {
     // Fail if app is targeting sdk version > 22
-    // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
-    if (get_application_target_sdk_version() != __ANDROID_API__
-        && get_application_target_sdk_version() > 22) {
+    if (get_application_target_sdk_version() > 22) {
       PRINT("%s: has text relocations", get_realpath());
       DL_ERR("%s: has text relocations", get_realpath());
       return false;
     }
     // 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.
+    // phdr_table_protect_segments() after all of them are applied.
     DL_WARN("%s has text relocations. This is wasting memory and prevents "
             "security hardening. Please fix.", get_realpath());
     if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
@@ -3080,7 +3916,7 @@
     return;
   }
 
-  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
+  soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
 
   si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
   si->phnum = ehdr_vdso->e_phnum;
@@ -3116,7 +3952,8 @@
  * be on the soinfo list.
  */
 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 = new (linker_soinfo_for_gdb_buf) soinfo(nullptr, LINKER_PATH,
+                                                                 nullptr, 0, 0);
 
   linker_soinfo_for_gdb->load_bias = linker_base;
 
@@ -3133,6 +3970,27 @@
   insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
 }
 
+static void init_default_namespace() {
+  g_default_namespace.set_name("(default)");
+  g_default_namespace.set_isolated(false);
+
+  const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
+                                                       somain->load_bias);
+  const char* bname = basename(interp);
+  if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
+    g_default_ld_paths = kAsanDefaultLdPaths;
+  } else {
+    g_default_ld_paths = kDefaultLdPaths;
+  }
+
+  std::vector<std::string> ld_default_paths;
+  for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
+    ld_default_paths.push_back(g_default_ld_paths[i]);
+  }
+
+  g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
+};
+
 extern "C" int __system_properties_init(void);
 
 /*
@@ -3160,18 +4018,28 @@
     g_ld_debug_verbosity = atoi(LD_DEBUG);
   }
 
+#if defined(__LP64__)
+  INFO("[ Android dynamic linker (64-bit) ]");
+#else
+  INFO("[ Android dynamic linker (32-bit) ]");
+#endif
+
   // 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 (!getauxval(AT_SECURE)) {
     ldpath_env = getenv("LD_LIBRARY_PATH");
+    if (ldpath_env != nullptr) {
+      INFO("[ LD_LIBRARY_PATH set to '%s' ]", ldpath_env);
+    }
     ldpreload_env = getenv("LD_PRELOAD");
+    if (ldpreload_env != nullptr) {
+      INFO("[ LD_PRELOAD set to '%s' ]", ldpreload_env);
+    }
   }
 
-  INFO("[ android linker & debugger ]");
-
-  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
+  soinfo* si = soinfo_alloc(&g_default_namespace, args.argv[0], nullptr, 0, RTLD_GLOBAL);
   if (si == nullptr) {
     exit(EXIT_FAILURE);
   }
@@ -3223,9 +4091,10 @@
 
   somain = si;
 
+  init_default_namespace();
+
   if (!si->prelink_image()) {
-    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
-    exit(EXIT_FAILURE);
+    __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
   }
 
   // add somain to global group
@@ -3253,14 +4122,13 @@
   needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
 
   if (needed_libraries_count > 0 &&
-      !find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
-          &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
-    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
-    exit(EXIT_FAILURE);
+      !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
+                      nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
+                      /* add_as_children */ true)) {
+    __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
   } else if (needed_libraries_count == 0) {
     if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
-      __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
-      exit(EXIT_FAILURE);
+      __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
     }
     si->increment_ref_count();
   }
@@ -3350,6 +4218,7 @@
   return 0;
 }
 
+extern "C" int __set_tls(void*);
 extern "C" void _start();
 
 /*
@@ -3364,12 +4233,15 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   KernelArgumentBlock args(raw_args);
 
+  void* tls[BIONIC_TLS_SLOTS];
+  __set_tls(tls);
+
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
   ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
   ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
 
-  soinfo linker_so(nullptr, nullptr, 0, 0);
+  soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
 
   // If the linker is not acting as PT_INTERP entry_point is equal to
   // _start. Which means that the linker is running as an executable and
@@ -3378,7 +4250,7 @@
   // This happens when user tries to run 'adb shell /system/bin/linker'
   // see also https://code.google.com/p/android/issues/detail?id=63174
   if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
-    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
+    __libc_fatal("This is %s, the helper program for shared library executables.", args.argv[0]);
   }
 
   linker_so.base = linker_addr;
@@ -3396,18 +4268,13 @@
   // are not yet initialized, and therefore we cannot use linked_list.push_*
   // functions at this point.
   if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
-    // It would be nice to print an error message, but if the linker
-    // can't link itself, there's no guarantee that we'll be able to
-    // call write() (because it involves a GOT reference). We may as
-    // well try though...
-    const char* msg = "CANNOT LINK EXECUTABLE: ";
-    write(2, msg, strlen(msg));
-    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
-    write(2, "\n", 1);
-    _exit(EXIT_FAILURE);
+    __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
   }
 
-  __libc_init_tls(args);
+  __libc_init_main_thread(args);
+
+  // Initialize the linker's static libc's globals
+  __libc_init_globals(args);
 
   // Initialize the linker's own global variables
   linker_so.call_constructors();
@@ -3417,13 +4284,14 @@
   // before get_libdl_info().
   solist = get_libdl_info();
   sonext = get_libdl_info();
+  g_default_namespace.soinfo_list().push_back(get_libdl_info());
 
   // We have successfully fixed our own relocations. It's safe to run
   // the main part of the linker now.
   args.abort_message_ptr = &g_abort_message;
   ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
 
-  INFO("[ jumping to _start ]");
+  INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
 
   // Return the address that the calling assembly stub should jump to.
   return start_address;
diff --git a/linker/linker.h b/linker/linker.h
index 023b672..5a06853 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -29,13 +29,15 @@
 #ifndef _LINKER_H_
 #define _LINKER_H_
 
+#include <dlfcn.h>
+#include <android/dlext.h>
 #include <elf.h>
 #include <inttypes.h>
 #include <link.h>
-#include <unistd.h>
-#include <android/dlext.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
+#include "private/bionic_page.h"
 #include "private/libc_logging.h"
 #include "linked_list.h"
 
@@ -77,16 +79,6 @@
 #define ELF64_R_TYPE(info)  (((info) >> 56) & 0xff)
 #endif
 
-// Returns the address of the page containing address 'x'.
-#define PAGE_START(x)  ((x) & PAGE_MASK)
-
-// Returns the offset of address 'x' in its page.
-#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
-
-// Returns the address of the next page after address 'x', unless 'x' is
-// itself at the start of a page.
-#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
-
 #define FLAG_LINKED     0x00000001
 #define FLAG_EXE        0x00000004 // The main executable
 #define FLAG_LINKER     0x00000010 // The linker itself
@@ -95,9 +87,9 @@
 
 #define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
 
-#define SOINFO_VERSION 2
+#define SOINFO_VERSION 3
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
 #define SOINFO_NAME_LEN 128
 #endif
 
@@ -144,7 +136,7 @@
 };
 
 struct version_info {
-  version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
+  constexpr version_info() : elf_hash(0), name(nullptr), target_si(nullptr) {}
 
   uint32_t elf_hash;
   const char* name;
@@ -172,7 +164,7 @@
 struct soinfo {
  public:
   typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
  private:
   char old_name_[SOINFO_NAME_LEN];
 #endif
@@ -183,13 +175,13 @@
   ElfW(Addr) base;
   size_t size;
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   uint32_t unused1;  // DO NOT USE, maintained for compatibility.
 #endif
 
   ElfW(Dyn)* dynamic;
 
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
   uint32_t unused2; // DO NOT USE, maintained for compatibility
   uint32_t unused3; // DO NOT USE, maintained for compatibility
 #endif
@@ -250,7 +242,9 @@
   bool mips_relocate_got(const VersionTracker& version_tracker,
                          const soinfo_list_t& global_group,
                          const soinfo_list_t& local_group);
-
+#if !defined(__LP64__)
+  bool mips_check_and_adjust_fp_modes();
+#endif
 #endif
   size_t ref_count_;
  public:
@@ -268,7 +262,8 @@
   bool has_DT_SYMBOLIC;
 
  public:
-  soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags);
+  soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
+         off64_t file_offset, int rtld_flags);
 
   void call_constructors();
   void call_destructors();
@@ -305,7 +300,7 @@
   bool is_gnu_hash() const;
 
   bool inline has_min_version(uint32_t min_version __unused) const {
-#if defined(__work_around_b_19059885__)
+#if defined(__work_around_b_24465209__)
     return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
 #else
     return true;
@@ -318,12 +313,14 @@
   void set_linked();
   void set_linker_flag();
   void set_main_executable();
+  void set_nodelete();
 
   void increment_ref_count();
   size_t decrement_ref_count();
 
   soinfo* get_local_group_root() const;
 
+  void set_soname(const char* soname);
   const char* get_soname() const;
   const char* get_realpath() const;
   const ElfW(Versym)* get_versym(size_t n) const;
@@ -336,6 +333,10 @@
 
   uint32_t get_target_sdk_version() const;
 
+  void set_dt_runpath(const char *);
+  const std::vector<std::string>& get_dt_runpath() const;
+  android_namespace_t* get_namespace();
+
  private:
   bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* elf_addr_lookup(const void* addr);
@@ -397,6 +398,10 @@
 
   uint32_t target_sdk_version_;
 
+  // version >= 3
+  std::vector<std::string> dt_runpath_;
+  android_namespace_t* namespace_;
+
   friend soinfo* get_libdl_info();
 };
 
@@ -418,15 +423,15 @@
 
 void do_android_get_LD_LIBRARY_PATH(char*, size_t);
 void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
-soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
+soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, void* caller_addr);
 void do_dlclose(soinfo* si);
 
 int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
 
-const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
-soinfo* find_containing_library(const void* addr);
+bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
+              void* caller_addr, void** symbol);
 
-const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
+int do_dladdr(const void* addr, Dl_info* info);
 
 void debuggerd_init();
 extern "C" abort_msg_t* g_abort_message;
@@ -438,4 +443,9 @@
 void set_application_target_sdk_version(uint32_t target);
 uint32_t get_application_target_sdk_version();
 
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
+android_namespace_t* create_namespace(const void* caller_addr, const char* name,
+                                      const char* ld_library_path, const char* default_library_path,
+                                      uint64_t type, const char* permitted_when_isolated_path);
+
 #endif
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 51f8d4c..5af9929 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -55,9 +55,17 @@
  *********************************************************************/
 
 #include "private/libc_logging.h"
+#include <unistd.h>
 
 __LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
 
+#define CHECK(predicate) { \
+    if (!(predicate)) { \
+      __libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
+          __FILE__, __LINE__, __FUNCTION__); \
+    } \
+  }
+
 #if LINKER_DEBUG_TO_LOG
 #define _PRINTVF(v, x...) \
     do { \
diff --git a/linker/linker_libc_support.c b/linker/linker_libc_support.c
index 4c49384..77a0252 100644
--- a/linker/linker_libc_support.c
+++ b/linker/linker_libc_support.c
@@ -15,7 +15,9 @@
  */
 
 #include "../libc/arch-common/bionic/__dso_handle.h"
+#include "../libc/arch-common/bionic/pthread_atfork.h"
 
 int atexit(void (*function)(void) __attribute__((__unused__))) {
   return -1;
 }
+
diff --git a/linker/linker_mapped_file_fragment.cpp b/linker/linker_mapped_file_fragment.cpp
new file mode 100644
index 0000000..27c1c69
--- /dev/null
+++ b/linker/linker_mapped_file_fragment.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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_mapped_file_fragment.h"
+#include "linker_debug.h"
+#include "linker_utils.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+MappedFileFragment::MappedFileFragment() : map_start_(nullptr), map_size_(0),
+                                           data_(nullptr), size_ (0)
+{ }
+
+MappedFileFragment::~MappedFileFragment() {
+  if (map_start_ != nullptr) {
+    munmap(map_start_, map_size_);
+  }
+}
+
+bool MappedFileFragment::Map(int fd, off64_t base_offset, size_t elf_offset, size_t size) {
+  off64_t offset;
+  CHECK(safe_add(&offset, base_offset, elf_offset));
+
+  off64_t page_min = page_start(offset);
+  off64_t end_offset;
+
+  CHECK(safe_add(&end_offset, offset, size));
+  CHECK(safe_add(&end_offset, end_offset, page_offset(offset)));
+
+  size_t map_size = static_cast<size_t>(end_offset - page_min);
+  CHECK(map_size >= size);
+
+  uint8_t* map_start = static_cast<uint8_t*>(
+                          mmap64(nullptr, map_size, PROT_READ, MAP_PRIVATE, fd, page_min));
+
+  if (map_start == MAP_FAILED) {
+    return false;
+  }
+
+  map_start_ = map_start;
+  map_size_ = map_size;
+
+  data_ = map_start + page_offset(offset);
+  size_ = size;
+
+  return true;
+}
diff --git a/linker/linker_mapped_file_fragment.h b/linker/linker_mapped_file_fragment.h
new file mode 100644
index 0000000..91bd077
--- /dev/null
+++ b/linker/linker_mapped_file_fragment.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+#ifndef LINKER_MAPPED_FILE_FRAGMENT_H
+#define LINKER_MAPPED_FILE_FRAGMENT_H
+
+#include <unistd.h>
+
+#include "private/bionic_macros.h"
+
+class MappedFileFragment {
+ public:
+  MappedFileFragment();
+  ~MappedFileFragment();
+
+  bool Map(int fd, off64_t base_offset, size_t elf_offset, size_t size);
+
+  void* data() const { return data_; }
+  size_t size() const { return size_; }
+ private:
+  void* map_start_;
+  size_t map_size_;
+  void* data_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(MappedFileFragment);
+};
+
+#endif /* LINKER_MAPPED_FILE_FRAGMENT_H */
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index a7a4bc0..27fb68b 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -26,8 +26,21 @@
  * SUCH DAMAGE.
  */
 
+#if !defined(__LP64__) && __mips_isa_rev >= 5
+#include <sys/prctl.h>
+#if defined(PR_SET_FP_MODE)
+#error "remove following defs when avail in Android's kernel headers"
+#else
+#define PR_SET_FP_MODE 45
+#define PR_GET_FP_MODE 46
+#define PR_FP_MODE_FR  (1 << 0)
+#define PR_FP_MODE_FRE (1 << 1)
+#endif
+#endif
+
 #include "linker.h"
 #include "linker_debug.h"
+#include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
 #include "linker_sleb128.h"
@@ -62,7 +75,7 @@
     ElfW(Addr) sym_addr = 0;
     const char* sym_name = nullptr;
 
-    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;
     }
@@ -84,7 +97,8 @@
 
       if (s == nullptr) {
         // mips does not support relocation with weak-undefined symbols
-        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;
       } else {
         // We got a definition.
@@ -171,20 +185,22 @@
       }
     } else if (st_visibility == STV_PROTECTED) {
       if (local_sym->st_value == 0) {
-        DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", get_soname(), sym_name);
+        DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ",
+               get_realpath(), 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);
+      DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x",
+             get_realpath(), sym_name, st_visibility);
       return false;
     }
 
     if (s == nullptr) {
       // We only allow an undefined symbol if this is a weak reference.
       if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) {
-        DL_ERR("%s: cannot locate \"%s\"...", get_soname(), sym_name);
+        DL_ERR("%s: cannot locate \"%s\"...", get_realpath(), sym_name);
         return false;
       }
       *got = 0;
@@ -198,3 +214,134 @@
   return true;
 }
 
+#if !defined(__LP64__)
+
+// Checks for mips32's various floating point abis.
+// (Mips64 Android has a single floating point abi and doesn't need any checks)
+
+// Linux kernel has declarations similar to the following
+//   in <linux>/arch/mips/include/asm/elf.h,
+// but that non-uapi internal header file will never be imported
+// into bionic's kernel headers.
+
+#define PT_MIPS_ABIFLAGS  0x70000003	// is .MIPS.abiflags segment
+
+struct mips_elf_abiflags_v0 {
+  uint16_t version;  // version of this structure
+  uint8_t  isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size;
+  uint8_t  fp_abi;  // mips32 ABI variants for floating point
+  uint32_t isa_ext, ases, flags1, flags2;
+};
+
+// Bits of flags1:
+#define MIPS_AFL_FLAGS1_ODDSPREG 1  // Uses odd-numbered single-prec fp regs
+
+// Some values of fp_abi:        via compiler flag:
+#define MIPS_ABI_FP_DOUBLE 1  // -mdouble-float
+#define MIPS_ABI_FP_XX     5  // -mfpxx
+#define MIPS_ABI_FP_64A    7  // -mips32r* -mfp64 -mno-odd-spreg
+
+#if __mips_isa_rev >= 5
+static bool mips_fre_mode_on = false;  // have set FRE=1 mode for process
+#endif
+
+bool soinfo::mips_check_and_adjust_fp_modes() {
+  mips_elf_abiflags_v0* abiflags = nullptr;
+  int mips_fpabi;
+
+  // Find soinfo's optional .MIPS.abiflags segment
+  for (size_t i = 0; i<phnum; ++i) {
+    const ElfW(Phdr)& ph = phdr[i];
+    if (ph.p_type == PT_MIPS_ABIFLAGS) {
+      if (ph.p_filesz < sizeof (mips_elf_abiflags_v0)) {
+        DL_ERR("Corrupt PT_MIPS_ABIFLAGS header found \"%s\"", get_realpath());
+        return false;
+      }
+      abiflags = reinterpret_cast<mips_elf_abiflags_v0*>(ph.p_vaddr + load_bias);
+      break;
+    }
+  }
+
+  // FP ABI-variant compatibility checks for MIPS o32 ABI
+  if (abiflags == nullptr) {
+    // Old compilers and some translators don't emit the new abiflags section.
+    const char* filename = get_realpath();
+    size_t len = strlen(filename);
+    if (len > 4 && (strcmp(filename+len-4, ".dex") == 0 ||
+                    strcmp(filename+len-4, ".oat") == 0   )) {
+      // Assume dex2oat is compatible with target
+      mips_fpabi = MIPS_ABI_FP_XX;
+    } else {
+      // Old Android compilers used -mfp32 -mdouble-float -modd-spreg defaults,
+      //   ie FP32 aka DOUBLE, using FR=0 mode fpregs & odd single-prec fpregs
+      mips_fpabi = MIPS_ABI_FP_DOUBLE;
+    }
+  } else {
+    mips_fpabi = abiflags->fp_abi;
+    if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG)
+         && (mips_fpabi == MIPS_ABI_FP_XX ||
+             mips_fpabi == MIPS_ABI_FP_64A   ) ) {
+      // Android supports fewer cases than Linux
+      DL_ERR("Unsupported odd-single-prec FloatPt reg uses in \"%s\"",
+             get_realpath());
+      return false;
+    }
+  }
+  if (!(mips_fpabi == MIPS_ABI_FP_DOUBLE ||
+#if __mips_isa_rev >= 5
+        mips_fpabi == MIPS_ABI_FP_64A    ||
+#endif
+        mips_fpabi == MIPS_ABI_FP_XX       )) {
+    DL_ERR("Unsupported MIPS32 FloatPt ABI %d found in \"%s\"",
+           mips_fpabi, get_realpath());
+    return false;
+  }
+
+#if __mips_isa_rev >= 5
+  // Adjust process's FR Emulation mode, if needed
+  //
+  // On Mips R5 & R6, Android runs continuously in FR=1 64bit-fpreg mode.
+  // NDK mips32 apps compiled with old compilers generate FP32 code
+  //   which expects FR=0 32-bit fp registers.
+  // NDK mips32 apps compiled with newer compilers generate modeless
+  //   FPXX code which runs on both FR=0 and FR=1 modes.
+  // Android itself is compiled in FP64A which requires FR=1 mode.
+  // FP32, FPXX, and FP64A all interlink okay, without dynamic FR mode
+  //   changes during calls.  For details, see
+  //   http://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
+  // Processes containing FR32 FR=0 code are run via kernel software assist,
+  //   which maps all odd-numbered single-precision reg refs onto the
+  //   upper half of the paired even-numbered double-precision reg.
+  // FRE=1 triggers traps to the kernel's emulator on every single-precision
+  //   fp op (for both odd and even-numbered registers).
+  // Turning on FRE=1 traps is done at most once per process, simultanously
+  //   for all threads of that process, when dlopen discovers FP32 code.
+  // The kernel repacks threads' registers when FRE mode is turn on or off.
+  //   These asynchronous adjustments are wrong if any thread was executing
+  //   FPXX code using odd-numbered single-precision regs.
+  // Current Android compilers default to the -mno-oddspreg option,
+  //   and this requirement is checked by Android's dlopen.
+  //   So FRE can always be safely turned on for FP32, anytime.
+  // Deferred enhancement: Allow loading of odd-spreg FPXX modules.
+
+  if (mips_fpabi == MIPS_ABI_FP_DOUBLE && !mips_fre_mode_on) {
+    // Turn on FRE mode, which emulates mode-sensitive FR=0 code on FR=1
+    //   register files, by trapping to kernel on refs to single-precision regs
+    if (prctl(PR_SET_FP_MODE, PR_FP_MODE_FR|PR_FP_MODE_FRE)) {
+      DL_ERR("Kernel or cpu failed to set FRE mode required for running \"%s\"",
+             get_realpath());
+      return false;
+    }
+    DL_WARN("Using FRE=1 mode to run \"%s\"", get_realpath());
+    mips_fre_mode_on = true;  // Avoid future redundant mode-switch calls
+    // FRE mode is never turned back off.
+    // Deferred enhancement:
+    //   Reset FRE mode when dlclose() removes all FP32 modules
+  }
+#else
+  // Android runs continuously in FR=0 32bit-fpreg mode.
+#endif  // __mips_isa_rev
+  return true;
+}
+
+#endif  // __LP64___
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 30118e3..4c4ce17 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -37,6 +37,7 @@
 
 #include "linker.h"
 #include "linker_debug.h"
+#include "linker_utils.h"
 
 static int GetTargetElfMachine() {
 #if defined(__arm__)
@@ -133,37 +134,59 @@
                                       MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
                                       MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
 
-ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
-    : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size),
-      phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
-      load_start_(nullptr), load_size_(0), load_bias_(0),
-      loaded_phdr_(nullptr) {
+ElfReader::ElfReader()
+    : did_read_(false), did_load_(false), fd_(-1), file_offset_(0), file_size_(0), phdr_num_(0),
+      phdr_table_(nullptr), shdr_table_(nullptr), shdr_num_(0), dynamic_(nullptr), strtab_(nullptr),
+      strtab_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), loaded_phdr_(nullptr) {
 }
 
-ElfReader::~ElfReader() {
-  if (phdr_mmap_ != nullptr) {
-    munmap(phdr_mmap_, phdr_size_);
+bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
+  CHECK(!did_read_);
+  CHECK(!did_load_);
+  name_ = name;
+  fd_ = fd;
+  file_offset_ = file_offset;
+  file_size_ = file_size;
+
+  if (ReadElfHeader() &&
+      VerifyElfHeader() &&
+      ReadProgramHeaders() &&
+      ReadSectionHeaders() &&
+      ReadDynamicSection()) {
+    did_read_ = true;
   }
+
+  return did_read_;
 }
 
 bool ElfReader::Load(const android_dlextinfo* extinfo) {
-  return ReadElfHeader() &&
-         VerifyElfHeader() &&
-         ReadProgramHeader() &&
-         ReserveAddressSpace(extinfo) &&
-         LoadSegments() &&
-         FindPhdr();
+  CHECK(did_read_);
+  CHECK(!did_load_);
+  if (ReserveAddressSpace(extinfo) &&
+      LoadSegments() &&
+      FindPhdr()) {
+    did_load_ = true;
+  }
+
+  return did_load_;
+}
+
+const char* ElfReader::get_string(ElfW(Word) index) const {
+  CHECK(strtab_ != nullptr);
+  CHECK(index < strtab_size_);
+
+  return strtab_ + index;
 }
 
 bool ElfReader::ReadElfHeader() {
   ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
   if (rc < 0) {
-    DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
+    DL_ERR("can't read file \"%s\": %s", name_.c_str(), strerror(errno));
     return false;
   }
 
   if (rc != sizeof(header_)) {
-    DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
+    DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
            static_cast<size_t>(rc));
     return false;
   }
@@ -172,7 +195,7 @@
 
 bool ElfReader::VerifyElfHeader() {
   if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
-    DL_ERR("\"%s\" has bad ELF magic", name_);
+    DL_ERR("\"%s\" has bad ELF magic", name_.c_str());
     return false;
   }
 
@@ -182,73 +205,161 @@
 #if defined(__LP64__)
   if (elf_class != ELFCLASS64) {
     if (elf_class == ELFCLASS32) {
-      DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
+      DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_.c_str());
     } else {
-      DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
+      DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
     }
     return false;
   }
 #else
   if (elf_class != ELFCLASS32) {
     if (elf_class == ELFCLASS64) {
-      DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
+      DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_.c_str());
     } else {
-      DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
+      DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
     }
     return false;
   }
 #endif
 
   if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
-    DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
+    DL_ERR("\"%s\" not little-endian: %d", name_.c_str(), header_.e_ident[EI_DATA]);
     return false;
   }
 
   if (header_.e_type != ET_DYN) {
-    DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
+    DL_ERR("\"%s\" has unexpected e_type: %d", name_.c_str(), header_.e_type);
     return false;
   }
 
   if (header_.e_version != EV_CURRENT) {
-    DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
+    DL_ERR("\"%s\" has unexpected e_version: %d", name_.c_str(), header_.e_version);
     return false;
   }
 
   if (header_.e_machine != GetTargetElfMachine()) {
-    DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
+    DL_ERR("\"%s\" has unexpected e_machine: %d", name_.c_str(), header_.e_machine);
     return false;
   }
 
   return true;
 }
 
+bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) {
+  off64_t range_start;
+  off64_t range_end;
+
+  return safe_add(&range_start, file_offset_, offset) &&
+         safe_add(&range_end, range_start, size) &&
+         range_start < file_size_ &&
+         range_end <= file_size_;
+}
+
 // Loads the program header table from an ELF file into a read-only private
 // anonymous mmap-ed block.
-bool ElfReader::ReadProgramHeader() {
+bool ElfReader::ReadProgramHeaders() {
   phdr_num_ = header_.e_phnum;
 
   // Like the kernel, we only accept program header tables that
   // are smaller than 64KiB.
   if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
-    DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
+    DL_ERR("\"%s\" has invalid e_phnum: %zd", name_.c_str(), phdr_num_);
     return false;
   }
 
-  ElfW(Addr) page_min = PAGE_START(header_.e_phoff);
-  ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
-  ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
-
-  phdr_size_ = page_max - page_min;
-
-  void* mmap_result =
-      mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
-  if (mmap_result == MAP_FAILED) {
-    DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
+  // Boundary checks
+  size_t size = phdr_num_ * sizeof(ElfW(Phdr));
+  if (!CheckFileRange(header_.e_phoff, size)) {
+    DL_ERR("\"%s\" has invalid phdr offset/size", name_.c_str());
     return false;
   }
 
-  phdr_mmap_ = mmap_result;
-  phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
+  if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
+    DL_ERR("\"%s\" phdr mmap failed: %s", name_.c_str(), strerror(errno));
+    return false;
+  }
+
+  phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_fragment_.data());
+  return true;
+}
+
+bool ElfReader::ReadSectionHeaders() {
+  shdr_num_ = header_.e_shnum;
+
+  if (shdr_num_ == 0) {
+    DL_ERR("\"%s\" has no section headers", name_.c_str());
+    return false;
+  }
+
+  size_t size = shdr_num_ * sizeof(ElfW(Shdr));
+  if (!CheckFileRange(header_.e_shoff, size)) {
+    DL_ERR("\"%s\" has invalid shdr offset/size", name_.c_str());
+    return false;
+  }
+
+  if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
+    DL_ERR("\"%s\" shdr mmap failed: %s", name_.c_str(), strerror(errno));
+    return false;
+  }
+
+  shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_fragment_.data());
+  return true;
+}
+
+bool ElfReader::ReadDynamicSection() {
+  // 1. Find .dynamic section (in section headers)
+  const ElfW(Shdr)* dynamic_shdr = nullptr;
+  for (size_t i = 0; i < shdr_num_; ++i) {
+    if (shdr_table_[i].sh_type == SHT_DYNAMIC) {
+      dynamic_shdr = &shdr_table_ [i];
+      break;
+    }
+  }
+
+  if (dynamic_shdr == nullptr) {
+    DL_ERR("\"%s\" .dynamic section header was not found", name_.c_str());
+    return false;
+  }
+
+  if (dynamic_shdr->sh_link >= shdr_num_) {
+    DL_ERR("\"%s\" .dynamic section has invalid sh_link: %d", name_.c_str(), dynamic_shdr->sh_link);
+    return false;
+  }
+
+  const ElfW(Shdr)* strtab_shdr = &shdr_table_[dynamic_shdr->sh_link];
+
+  if (strtab_shdr->sh_type != SHT_STRTAB) {
+    DL_ERR("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
+           name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
+    return false;
+  }
+
+  if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    PRINT("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    return false;
+  }
+
+  if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
+    DL_ERR("\"%s\" dynamic section mmap failed: %s", name_.c_str(), strerror(errno));
+    return false;
+  }
+
+  dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
+
+  if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
+           name_.c_str());
+    return false;
+  }
+
+  if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
+    DL_ERR("\"%s\" strtab section mmap failed: %s", name_.c_str(), strerror(errno));
+    return false;
+  }
+
+  strtab_ = static_cast<const char*>(strtab_fragment_.data());
+  strtab_size_ = strtab_fragment_.size();
   return true;
 }
 
@@ -308,7 +419,7 @@
   ElfW(Addr) min_vaddr;
   load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
   if (load_size_ == 0) {
-    DL_ERR("\"%s\" has no loadable segments", name_);
+    DL_ERR("\"%s\" has no loadable segments", name_.c_str());
     return false;
   }
 
@@ -316,8 +427,9 @@
   void* start;
   size_t reserved_size = 0;
   bool reserved_hint = true;
+  bool strict_hint = false;
   // Assume position independent executable by default.
-  uint8_t* mmap_hint = nullptr;
+  void* mmap_hint = nullptr;
 
   if (extinfo != nullptr) {
     if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -327,21 +439,30 @@
       reserved_size = extinfo->reserved_size;
     }
 
-    if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
+    if (addr != nullptr && (extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
       mmap_hint = addr;
+    } else if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0) {
+      mmap_hint = extinfo->reserved_addr;
+      strict_hint = true;
     }
   }
 
   if (load_size_ > reserved_size) {
     if (!reserved_hint) {
       DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
-             reserved_size - load_size_, load_size_, name_);
+             reserved_size - load_size_, load_size_, name_.c_str());
       return false;
     }
     int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
     start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
     if (start == MAP_FAILED) {
-      DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
+      DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
+      return false;
+    }
+    if (strict_hint && (start != mmap_hint)) {
+      munmap(start, load_size_);
+      DL_ERR("couldn't reserve %zd bytes of address space at %p for \"%s\"",
+             load_size_, mmap_hint, name_.c_str());
       return false;
     }
   } else {
@@ -378,14 +499,14 @@
     ElfW(Addr) file_length = file_end - file_page_start;
 
     if (file_size_ <= 0) {
-      DL_ERR("\"%s\" invalid file size: %" PRId64, name_, file_size_);
+      DL_ERR("\"%s\" invalid file size: %" PRId64, name_.c_str(), file_size_);
       return false;
     }
 
-    if (file_end >= static_cast<size_t>(file_size_)) {
+    if (file_end > static_cast<size_t>(file_size_)) {
       DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
           " p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
-          name_, i, reinterpret_cast<void*>(phdr->p_offset),
+          name_.c_str(), i, reinterpret_cast<void*>(phdr->p_offset),
           reinterpret_cast<void*>(phdr->p_filesz),
           reinterpret_cast<void*>(file_end), file_size_);
       return false;
@@ -399,7 +520,7 @@
                             fd_,
                             file_offset_ + file_page_start);
       if (seg_addr == MAP_FAILED) {
-        DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
+        DL_ERR("couldn't map \"%s\" segment %zd: %s", name_.c_str(), i, strerror(errno));
         return false;
       }
     }
@@ -424,7 +545,7 @@
                            -1,
                            0);
       if (zeromap == MAP_FAILED) {
-        DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
+        DL_ERR("couldn't zero fill \"%s\" gap: %s", name_.c_str(), strerror(errno));
         return false;
       }
     }
@@ -771,6 +892,26 @@
   }
 }
 
+/* Return the program interpreter string, or nullptr if missing.
+ *
+ * Input:
+ *   phdr_table  -> program header table
+ *   phdr_count  -> number of entries in tables
+ *   load_bias   -> load bias
+ * Return:
+ *   pointer to the program interpreter string.
+ */
+const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
+                                            ElfW(Addr) load_bias) {
+  for (size_t i = 0; i<phdr_count; ++i) {
+    const ElfW(Phdr)& phdr = phdr_table[i];
+    if (phdr.p_type == PT_INTERP) {
+      return reinterpret_cast<const char*>(load_bias + phdr.p_vaddr);
+    }
+  }
+  return nullptr;
+}
+
 // Sets loaded_phdr_ to the address of the program header table as it appears
 // in the loaded segments in memory. This is in contrast with phdr_table_,
 // which is temporary and will be released before the library is relocated.
@@ -799,7 +940,7 @@
     }
   }
 
-  DL_ERR("can't find loaded phdr for \"%s\"", name_);
+  DL_ERR("can't find loaded phdr for \"%s\"", name_.c_str());
   return false;
 }
 
@@ -809,7 +950,7 @@
 bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
   const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
   ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
-  for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
+  for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
     if (phdr->p_type != PT_LOAD) {
       continue;
     }
@@ -820,6 +961,7 @@
       return true;
     }
   }
-  DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
+  DL_ERR("\"%s\" loaded phdr %p not in loadable segment",
+         name_.c_str(), reinterpret_cast<void*>(loaded));
   return false;
 }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 3affa66..c359cca 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -36,30 +36,39 @@
  */
 
 #include "linker.h"
+#include "linker_mapped_file_fragment.h"
 
 class ElfReader {
  public:
-  ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
-  ~ElfReader();
+  ElfReader();
 
+  bool Read(const char* name, int fd, off64_t file_offset, off64_t file_size);
   bool Load(const android_dlextinfo* extinfo);
 
-  size_t phdr_count() { return phdr_num_; }
-  ElfW(Addr) load_start() { return reinterpret_cast<ElfW(Addr)>(load_start_); }
-  size_t load_size() { return load_size_; }
-  ElfW(Addr) load_bias() { return load_bias_; }
-  const ElfW(Phdr)* loaded_phdr() { return loaded_phdr_; }
+  const char* name() const { return name_.c_str(); }
+  size_t phdr_count() const { return phdr_num_; }
+  ElfW(Addr) load_start() const { return reinterpret_cast<ElfW(Addr)>(load_start_); }
+  size_t load_size() const { return load_size_; }
+  ElfW(Addr) load_bias() const { return load_bias_; }
+  const ElfW(Phdr)* loaded_phdr() const { return loaded_phdr_; }
+  const ElfW(Dyn)* dynamic() const { return dynamic_; }
+  const char* get_string(ElfW(Word) index) const;
 
  private:
   bool ReadElfHeader();
   bool VerifyElfHeader();
-  bool ReadProgramHeader();
+  bool ReadProgramHeaders();
+  bool ReadSectionHeaders();
+  bool ReadDynamicSection();
   bool ReserveAddressSpace(const android_dlextinfo* extinfo);
   bool LoadSegments();
   bool FindPhdr();
   bool CheckPhdr(ElfW(Addr));
+  bool CheckFileRange(ElfW(Addr) offset, size_t size);
 
-  const char* name_;
+  bool did_read_;
+  bool did_load_;
+  std::string name_;
   int fd_;
   off64_t file_offset_;
   off64_t file_size_;
@@ -67,9 +76,19 @@
   ElfW(Ehdr) header_;
   size_t phdr_num_;
 
-  void* phdr_mmap_;
-  ElfW(Phdr)* phdr_table_;
-  ElfW(Addr) phdr_size_;
+  MappedFileFragment phdr_fragment_;
+  const ElfW(Phdr)* phdr_table_;
+
+  MappedFileFragment shdr_fragment_;
+  const ElfW(Shdr)* shdr_table_;
+  size_t shdr_num_;
+
+  MappedFileFragment dynamic_fragment_;
+  const ElfW(Dyn)* dynamic_;
+
+  MappedFileFragment strtab_fragment_;
+  const char* strtab_;
+  size_t strtab_size_;
 
   // First page of reserved address space.
   void* load_start_;
@@ -109,4 +128,7 @@
                                     ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
                                     ElfW(Word)* dynamic_flags);
 
+const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
+                                            ElfW(Addr) load_bias);
+
 #endif /* LINKER_PHDR_H */
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
new file mode 100644
index 0000000..1b0c4e4
--- /dev/null
+++ b/linker/linker_utils.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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_utils.h"
+#include "linker_debug.h"
+
+bool normalize_path(const char* path, std::string* normalized_path) {
+  // Input should be an absolute path
+  if (path[0] != '/') {
+    PRINT("normalize_path - invalid input: '%s', the input path should be absolute", path);
+    return false;
+  }
+
+  const size_t len = strlen(path) + 1;
+  char buf[len];
+
+  const char* in_ptr = path;
+  char* out_ptr = buf;
+
+  while (*in_ptr != 0) {
+    if (*in_ptr == '/') {
+      char c1 = in_ptr[1];
+      if (c1 == '.') {
+        char c2 = in_ptr[2];
+        if (c2 == '/') {
+          in_ptr += 2;
+          continue;
+        } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
+          in_ptr += 3;
+          while (out_ptr > buf && *--out_ptr != '/') {
+          }
+          if (in_ptr[0] == 0) {
+            // retain '/'
+            out_ptr++;
+          }
+          continue;
+        }
+      } else if (c1 == '/') {
+        ++in_ptr;
+        continue;
+      }
+    }
+    *out_ptr++ = *in_ptr++;
+  }
+
+  *out_ptr = 0;
+  *normalized_path = buf;
+  return true;
+}
+
+bool file_is_in_dir(const std::string& file, const std::string& dir) {
+  const char* needle = dir.c_str();
+  const char* haystack = file.c_str();
+  size_t needle_len = strlen(needle);
+
+  return strncmp(haystack, needle, needle_len) == 0 &&
+         haystack[needle_len] == '/' &&
+         strchr(haystack + needle_len + 1, '/') == nullptr;
+}
+
+bool file_is_under_dir(const std::string& file, const std::string& dir) {
+  const char* needle = dir.c_str();
+  const char* haystack = file.c_str();
+  size_t needle_len = strlen(needle);
+
+  return strncmp(haystack, needle, needle_len) == 0 &&
+         haystack[needle_len] == '/';
+}
+
+const char* const kZipFileSeparator = "!/";
+
+bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) {
+  std::string normalized_path;
+  if (!normalize_path(input_path, &normalized_path)) {
+    return false;
+  }
+
+  const char* const path = normalized_path.c_str();
+  TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
+
+  // 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
+  // "bar/bas/x.so" within "foo.zip".
+  const char* const separator = strstr(path, kZipFileSeparator);
+  if (separator == nullptr) {
+    return false;
+  }
+
+  char buf[512];
+  if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
+    PRINT("Warning: ignoring very long library path: %s", path);
+    return false;
+  }
+
+  buf[separator - path] = '\0';
+
+  *zip_path = buf;
+  *entry_path = &buf[separator - path + 2];
+
+  return true;
+}
+
+constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
+
+off64_t page_start(off64_t offset) {
+  return offset & kPageMask;
+}
+
+bool safe_add(off64_t* out, off64_t a, size_t b) {
+  CHECK(a >= 0);
+  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
+    return false;
+  }
+
+  *out = a + b;
+  return true;
+}
+
+size_t page_offset(off64_t offset) {
+  return static_cast<size_t>(offset & (PAGE_SIZE-1));
+}
+
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
new file mode 100644
index 0000000..987eabd
--- /dev/null
+++ b/linker/linker_utils.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef __LINKER_UTILS_H
+#define __LINKER_UTILS_H
+
+#include <string>
+
+extern const char* const kZipFileSeparator;
+
+bool normalize_path(const char* path, std::string* normalized_path);
+bool file_is_in_dir(const std::string& file, const std::string& dir);
+bool file_is_under_dir(const std::string& file, const std::string& dir);
+bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path);
+
+off64_t page_start(off64_t offset);
+size_t page_offset(off64_t offset);
+bool safe_add(off64_t* out, off64_t a, size_t b);
+
+#endif
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 35992c5..a061877 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -23,15 +23,18 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_CFLAGS += -g -Wall -Wextra -Wunused -Werror -std=gnu++11
+LOCAL_CFLAGS += -g -Wall -Wextra -Wunused -Werror
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
 
 LOCAL_SRC_FILES := \
+  linker_globals.cpp \
   linked_list_test.cpp \
   linker_block_allocator_test.cpp \
   ../linker_block_allocator.cpp \
   linker_memory_allocator_test.cpp \
-  ../linker_allocator.cpp
+  ../linker_allocator.cpp \
+  linker_utils_test.cpp \
+  ../linker_utils.cpp
 
 # for __libc_fatal
 LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp
index 09ad687..12348d9 100644
--- a/linker/tests/linked_list_test.cpp
+++ b/linker/tests/linked_list_test.cpp
@@ -133,6 +133,23 @@
   ASSERT_TRUE(list.pop_front() == nullptr);
 }
 
+TEST(linked_list, remove_if_last_then_push_back) {
+  test_list_t list;
+
+  list.push_back("a");
+  list.push_back("b");
+  list.push_back("c");
+  list.push_back("d");
+
+  list.remove_if([](const char* c) {
+    return *c == 'c' || *c == 'd';
+  });
+
+  ASSERT_EQ("ab", test_list_to_string(list));
+  list.push_back("d");
+  ASSERT_EQ("abd", test_list_to_string(list));
+}
+
 TEST(linked_list, copy_to_array) {
   test_list_t list;
   const size_t max_size = 128;
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/linker/tests/linker_globals.cpp
similarity index 78%
rename from libc/upstream-freebsd/android/include/spinlock.h
rename to linker/tests/linker_globals.cpp
index f5c3785..7762a87 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/linker/tests/linker_globals.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+// To enable logging
+int g_ld_debug_verbosity = 0;
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
diff --git a/linker/tests/linker_memory_allocator_test.cpp b/linker/tests/linker_memory_allocator_test.cpp
index f002a0d..defd4f3 100644
--- a/linker/tests/linker_memory_allocator_test.cpp
+++ b/linker/tests/linker_memory_allocator_test.cpp
@@ -53,7 +53,7 @@
   LinkerMemoryAllocator allocator;
   void* ptr = allocator.alloc(0);
   ASSERT_TRUE(ptr != nullptr);
-  free(ptr);
+  allocator.free(ptr);
 }
 
 TEST(linker_memory, test_free_nullptr) {
@@ -110,7 +110,7 @@
 
   ASSERT_TRUE(memcmp(reallocated_ptr, model, 4000) == 0);
 
-  ASSERT_EQ(nullptr, realloc(reallocated_ptr, 0));
+  ASSERT_EQ(nullptr, allocator.realloc(reallocated_ptr, 0));
 }
 
 TEST(linker_memory, test_small_smoke) {
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
new file mode 100644
index 0000000..fd749fa
--- /dev/null
+++ b/linker/tests/linker_utils_test.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include "../linker_utils.h"
+
+TEST(linker_utils, normalize_path_smoke) {
+  std::string output;
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/zipfile!/dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/.../zipfile!/.dir/dir9//..///afile", &output));
+  ASSERT_EQ("/root/dir/dir2/somedir/.../zipfile!/.dir/afile", output);
+
+  ASSERT_TRUE(normalize_path("/root/..", &output));
+  ASSERT_EQ("/", output);
+
+  ASSERT_TRUE(normalize_path("/root/notroot/..", &output));
+  ASSERT_EQ("/root/", output);
+
+  ASSERT_TRUE(normalize_path("/a/../../b", &output));
+  ASSERT_EQ("/b", output);
+
+  output = "unchanged";
+  ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
+  ASSERT_EQ("unchanged", output);
+}
+
+TEST(linker_utils, file_is_in_dir_smoke) {
+  ASSERT_TRUE(file_is_in_dir("/foo/bar/file", "/foo/bar"));
+  ASSERT_FALSE(file_is_in_dir("/foo/bar/file", "/foo"));
+
+  ASSERT_FALSE(file_is_in_dir("/foo/bar/file", "/bar/foo"));
+
+  ASSERT_TRUE(file_is_in_dir("/file", ""));
+  ASSERT_FALSE(file_is_in_dir("/file", "/"));
+}
+
+TEST(linker_utils, file_is_under_dir_smoke) {
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo/bar"));
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo"));
+
+  ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/bar/foo"));
+
+  ASSERT_TRUE(file_is_under_dir("/file", ""));
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", ""));
+  ASSERT_FALSE(file_is_under_dir("/file", "/"));
+  ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/"));
+}
+
+TEST(linker_utils, parse_zip_path_smoke) {
+  std::string zip_path;
+  std::string entry_path;
+
+  ASSERT_FALSE(parse_zip_path("/not/a/zip/path/file.zip", &zip_path, &entry_path));
+  ASSERT_FALSE(parse_zip_path("/not/a/zip/path/file.zip!path/in/zip", &zip_path, &entry_path));
+  ASSERT_TRUE(parse_zip_path("/zip/path/file.zip!/path/in/zip", &zip_path, &entry_path));
+  ASSERT_EQ("/zip/path/file.zip", zip_path);
+  ASSERT_EQ("path/in/zip", entry_path);
+
+  ASSERT_TRUE(parse_zip_path("/zip/path/file2.zip!/", &zip_path, &entry_path));
+  ASSERT_EQ("/zip/path/file2.zip", zip_path);
+  ASSERT_EQ("", entry_path);
+}
+
+TEST(linker_utils, page_start) {
+  ASSERT_EQ(0x0001000, page_start(0x0001000));
+  ASSERT_EQ(0x3002000, page_start(0x300222f));
+  ASSERT_EQ(0x6001000, page_start(0x6001fff));
+}
+
+TEST(linker_utils, page_offset) {
+  ASSERT_EQ(0x0U, page_offset(0x0001000));
+  ASSERT_EQ(0x22fU, page_offset(0x300222f));
+  ASSERT_EQ(0xfffU, page_offset(0x6001fff));
+}
+
+TEST(linker_utils, safe_add) {
+  int64_t val = 42;
+  ASSERT_FALSE(safe_add(&val, INT64_MAX-20, 21U));
+  ASSERT_EQ(42, val);
+  ASSERT_TRUE(safe_add(&val, INT64_MAX-42, 42U));
+  ASSERT_EQ(INT64_MAX, val);
+  ASSERT_TRUE(safe_add(&val, 2000, 42U));
+  ASSERT_EQ(2042, val);
+}
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 5b2b417..740c2f4 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -28,16 +28,24 @@
     LOCAL_MODULE_STEM_32 := $(module)32
     LOCAL_MODULE_STEM_64 := $(module)64
 else
+
+ifneq ($($(module)_install_to_out_data_dir),)
+  $(module)_install_to_out_data := true
+endif
+
 ifeq ($($(module)_install_to_out_data),true)
-    LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$(module)
-    LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(module)
+    ifeq ($($(module)_install_to_out_data_dir),)
+      $(module)_install_to_out_data_dir := $(module)
+    endif
+    LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$($(module)_install_to_out_data_dir)
+    LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$($(module)_install_to_out_data_dir)
 endif
 endif
 
 LOCAL_CLANG := $($(module)_clang_$(build_type))
 
 ifneq ($($(module)_allow_asan),true)
-LOCAL_ADDRESS_SANITIZER := false
+LOCAL_SANITIZE := never
 endif
 
 LOCAL_FORCE_STATIC_EXECUTABLE := $($(module)_force_static_executable)
@@ -48,6 +56,10 @@
     LOCAL_MULTILIB := $($(module)_multilib)
 endif
 
+ifneq ($($(module)_relative_path),)
+    LOCAL_MODULE_RELATIVE_PATH := $($(module)_relative_path)
+endif
+
 LOCAL_CFLAGS := \
     $(common_cflags) \
     $($(module)_cflags) \
diff --git a/tests/Android.mk b/tests/Android.mk
index dc2e410..0e84331 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -40,18 +40,18 @@
 
 test_cflags += -D__STDC_LIMIT_MACROS  # For glibc.
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
 test_cflags += -DUSE_DLMALLOC
 else
 test_cflags += -DUSE_JEMALLOC
 endif
 
-test_cppflags = \
-    -std=gnu++11 \
+test_cppflags := \
 
 libBionicStandardTests_src_files := \
     arpa_inet_test.cpp \
     buffer_tests.cpp \
+    bug_26110743_test.cpp \
     complex_test.cpp \
     ctype_test.cpp \
     dirent_test.cpp \
@@ -62,14 +62,17 @@
     ftw_test.cpp \
     getauxval_test.cpp \
     getcwd_test.cpp \
+    ifaddrs_test.cpp \
     inttypes_test.cpp \
     libc_logging_test.cpp \
+    libgen_basename_test.cpp \
     libgen_test.cpp \
     locale_test.cpp \
     malloc_test.cpp \
     math_test.cpp \
     mntent_test.cpp \
     netdb_test.cpp \
+    netinet_udp_test.cpp \
     pthread_test.cpp \
     pty_test.cpp \
     regex_test.cpp \
@@ -93,6 +96,7 @@
     sys_epoll_test.cpp \
     sys_mman_test.cpp \
     sys_personality_test.cpp \
+    sys_prctl_test.cpp \
     sys_procfs_test.cpp \
     sys_resource_test.cpp \
     sys_select_test.cpp \
@@ -118,7 +122,7 @@
 libBionicStandardTests_cflags := \
     $(test_cflags) \
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
   libBionicStandardTests_cflags += -DUSE_DLMALLOC
 else
   libBionicStandardTests_cflags += -DUSE_JEMALLOC
@@ -137,6 +141,13 @@
 libBionicStandardTests_ldlibs_host := \
     -lrt \
 
+# Clang/llvm has incompatible long double (fp128) for x86_64.
+# https://llvm.org/bugs/show_bug.cgi?id=23897
+# This affects most of math_test.cpp.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64))
+libBionicStandardTests_clang_target := false
+endif
+
 module := libBionicStandardTests
 module_tag := optional
 build_type := target
@@ -162,6 +173,7 @@
   ) \
 )
 
+fortify1-tests-gcc_clang_target := false
 module := fortify1-tests-gcc
 module_tag := optional
 build_type := target
@@ -170,6 +182,7 @@
 build_type := host
 include $(LOCAL_PATH)/Android.build.mk
 
+fortify2-tests-gcc_clang_target := false
 module := fortify2-tests-gcc
 module_tag := optional
 build_type := target
@@ -231,7 +244,13 @@
 build_target := STATIC_TEST_LIBRARY
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
+
+ifeq ($(HOST_OS),$(filter $(HOST_OS),linux darwin))
+saved_build_host := $(build_host)
+build_host := true
 include $(LOCAL_PATH)/Android.build.mk
+build_host := $(saved_build_host)
+endif
 
 # -----------------------------------------------------------------------------
 # Library of bionic customized gtest main function, with normal gtest output format,
@@ -243,11 +262,6 @@
 
 libBionicCtsGtestMain_cppflags := $(test_cppflags) -DUSING_GTEST_OUTPUT_FORMAT \
 
-# Temporarily fix the job count to 1 for CTS since on some devices the
-# number of online cores is incorrectly read as the total number of cores
-# in the system. When b/24376925 is fixed, this should be removed.
-libBionicCtsGtestMain_cppflags += -DJOB_COUNT_FIXED=1
-
 module := libBionicCtsGtestMain
 module_tag := optional
 build_type := target
@@ -260,18 +274,20 @@
 # Tests for the device using bionic's .so. Run with:
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
+#   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests-gcc32
+#   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests-gcc64
 # -----------------------------------------------------------------------------
-bionic-unit-tests_whole_static_libraries := \
+common_bionic-unit-tests_whole_static_libraries := \
     libBionicTests \
     libBionicGtestMain \
 
-bionic-unit-tests_static_libraries := \
+common_bionic-unit-tests_static_libraries := \
     libtinyxml2 \
     liblog \
     libbase \
 
 # TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
-bionic-unit-tests_src_files := \
+common_bionic-unit-tests_src_files := \
     atexit_test.cpp \
     dl_test.cpp \
     dlext_test.cpp \
@@ -279,38 +295,58 @@
     dlfcn_test.cpp \
     libdl_test.cpp \
     pthread_dlfcn_test.cpp \
+    thread_local_test.cpp \
 
-bionic-unit-tests_cflags := $(test_cflags)
+common_bionic-unit-tests_cflags := $(test_cflags)
 
-bionic-unit-tests_conlyflags := \
+common_bionic-unit-tests_conlyflags := \
     -fexceptions \
     -fnon-call-exceptions \
 
-bionic-unit-tests_cppflags := $(test_cppflags)
+common_bionic-unit-tests_cppflags := $(test_cppflags)
 
-bionic-unit-tests_ldflags := \
+common_bionic-unit-tests_ldflags := \
     -Wl,--export-dynamic
 
-bionic-unit-tests_c_includes := \
+common_bionic-unit-tests_c_includes := \
     bionic/libc \
-    $(call include-path-for, libpagemap) \
 
-bionic-unit-tests_shared_libraries_target := \
+common_bionic-unit-tests_shared_libraries_target := \
     libdl \
     libpagemap \
     libdl_preempt_test_1 \
     libdl_preempt_test_2
 
-# TODO: clang support for thread_local on arm is done via __aeabi_read_tp()
-# which bionic does not support. Reenable this once this question is resolved.
-bionic-unit-tests_clang_target := false
+common_bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global
 
-bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global
-
-module := bionic-unit-tests
 module_tag := optional
 build_type := target
 build_target := NATIVE_TEST
+
+module := bionic-unit-tests
+bionic-unit-tests_clang_target := true
+bionic-unit-tests_whole_static_libraries := $(common_bionic-unit-tests_whole_static_libraries)
+bionic-unit-tests_static_libraries := $(common_bionic-unit-tests_static_libraries)
+bionic-unit-tests_src_files := $(common_bionic-unit-tests_src_files)
+bionic-unit-tests_cflags := $(common_bionic-unit-tests_cflags)
+bionic-unit-tests_conlyflags := $(common_bionic-unit-tests_conlyflags)
+bionic-unit-tests_cppflags := $(common_bionic-unit-tests_cppflags)
+bionic-unit-tests_ldflags := $(common_bionic-unit-tests_ldflags)
+bionic-unit-tests_c_includes := $(common_bionic-unit-tests_c_includes)
+bionic-unit-tests_shared_libraries_target := $(common_bionic-unit-tests_shared_libraries_target)
+include $(LOCAL_PATH)/Android.build.mk
+
+module := bionic-unit-tests-gcc
+bionic-unit-tests-gcc_clang_target := false
+bionic-unit-tests-gcc_whole_static_libraries := $(common_bionic-unit-tests_whole_static_libraries)
+bionic-unit-tests-gcc_static_libraries := $(common_bionic-unit-tests_static_libraries)
+bionic-unit-tests-gcc_src_files := $(common_bionic-unit-tests_src_files)
+bionic-unit-tests-gcc_cflags := $(common_bionic-unit-tests_cflags)
+bionic-unit-tests-gcc_conlyflags := $(common_bionic-unit-tests_conlyflags)
+bionic-unit-tests-gcc_cppflags := $(common_bionic-unit-tests_cppflags)
+bionic-unit-tests-gcc_ldflags := $(common_bionic-unit-tests_ldflags)
+bionic-unit-tests-gcc_c_includes := $(common_bionic-unit-tests_c_includes)
+bionic-unit-tests-gcc_shared_libraries_target := $(common_bionic-unit-tests_shared_libraries_target)
 include $(LOCAL_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
@@ -413,6 +449,8 @@
 LOCAL_CLANG := false
 LOCAL_MODULE := bionic-compile-time-tests-g++
 LOCAL_CPPFLAGS := -Wall
+# Disable color diagnostics so the warnings output matches the source
+LOCAL_CPPFLAGS +=  -fdiagnostics-color=never
 LOCAL_SRC_FILES := fortify_compilation_test.cpp
 include $(BUILD_STATIC_LIBRARY)
 
@@ -430,6 +468,8 @@
 LOCAL_CLANG := true
 LOCAL_MODULE := bionic-compile-time-tests-clang++
 LOCAL_CPPFLAGS := -Wall
+# Disable color diagnostics so the warnings output matches the source
+LOCAL_CPPFLAGS += -fno-color-diagnostics
 # FileCheck will error if there aren't any CLANG: lines in the file, but there
 # don't appear to be any cases where clang _does_ emit warnings for sn?printf :(
 LOCAL_SRC_FILES :=
@@ -443,6 +483,7 @@
 # Make sure to create ANDROID_DATA/local/tmp if doesn't exist.
 # Use the current target out directory as ANDROID_DATA.
 # BIONIC_TEST_FLAGS is either empty or it comes from the user.
+.PHONY: bionic-unit-tests-glibc-run
 bionic-unit-tests-glibc-run: bionic-unit-tests-glibc
 	mkdir -p $(TARGET_OUT_DATA)/local/tmp
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
@@ -460,6 +501,7 @@
 TEST_TIMEOUT := 0
 
 # BIONIC_TEST_FLAGS is either empty or it comes from the user.
+.PHONY: bionic-unit-tests-run-on-host32
 bionic-unit-tests-run-on-host32: bionic-unit-tests bionic-prepare-run-on-host
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_DNS_MODE=local \
@@ -469,6 +511,7 @@
 
 ifeq ($(TARGET_IS_64_BIT),true)
 # add target to run lp64 tests
+.PHONY: bionic-unit-tests-run-on-host64
 bionic-unit-tests-run-on-host64: bionic-unit-tests bionic-prepare-run-on-host
 	ANDROID_DATA=$(TARGET_OUT_DATA) \
 	ANDROID_DNS_MODE=local \
diff --git a/tests/__cxa_thread_atexit_test.cpp b/tests/__cxa_thread_atexit_test.cpp
index e388f3b..1432968 100644
--- a/tests/__cxa_thread_atexit_test.cpp
+++ b/tests/__cxa_thread_atexit_test.cpp
@@ -35,7 +35,12 @@
   std::string message;
 };
 
+#if defined(__clang__) && defined(__aarch64__)
+// b/25642296, aarch64 clang compiled "thread_local" does not link.
+static ClassWithDtor class_with_dtor;
+#else
 static thread_local ClassWithDtor class_with_dtor;
+#endif
 
 static void* thread_nop(void* arg) {
   class_with_dtor.set_message(*static_cast<std::string*>(arg));
@@ -47,7 +52,12 @@
   pthread_t t;
   ASSERT_EQ(0, pthread_create(&t, nullptr, thread_nop, &msg));
   ASSERT_EQ(0, pthread_join(t, nullptr));
+#if defined(__clang__) && defined(__aarch64__)
+  GTEST_LOG_(INFO) << "Skipping test, b/25642296, "
+                   << "thread_local does not work with aarch64 clang/llvm.\n";
+#else
   ASSERT_EQ("dtor called.", class_with_dtor_output);
+#endif
 }
 
 class ClassWithDtorForMainThread {
@@ -64,7 +74,13 @@
 };
 
 static void thread_atexit_main() {
+#if defined(__clang__) && defined(__aarch64__)
+  static ClassWithDtorForMainThread class_with_dtor_for_main_thread;
+  GTEST_LOG_(INFO) << "Skipping test, b/25642296, "
+                   << "thread_local does not work with aarch64 clang/llvm.\n";
+#else
   static thread_local ClassWithDtorForMainThread class_with_dtor_for_main_thread;
+#endif
   class_with_dtor_for_main_thread.set_message("d-tor for main thread called.");
   exit(0);
 }
diff --git a/tests/arpa_inet_test.cpp b/tests/arpa_inet_test.cpp
index 5e53337..a368b8f 100644
--- a/tests/arpa_inet_test.cpp
+++ b/tests/arpa_inet_test.cpp
@@ -24,8 +24,85 @@
 
 TEST(arpa_inet, inet_aton) {
   in_addr a;
-  ASSERT_EQ(1, inet_aton("127.0.0.1", &a));
+
+  // a.b.c.d
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.2.3", &a));
+  ASSERT_EQ((htonl)(0x7f010203), a.s_addr);
+
+  // a.b.c
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.2", &a));
+  ASSERT_EQ((htonl)(0x7f010002), a.s_addr);
+
+  // a.b
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1", &a));
   ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  // a
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0x7f000001", &a));
+  ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  // Hex (0x) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0xFf.0.0.1", &a));
+  ASSERT_EQ((htonl)(0xff000001), a.s_addr);
+
+  // Hex (0X) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0XfF.0.0.1", &a));
+  ASSERT_EQ((htonl)(0xff000001), a.s_addr);
+
+  // Octal.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0177.0.0.1", &a));
+  ASSERT_EQ((htonl)(0x7f000001), a.s_addr);
+
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("036", &a));
+  ASSERT_EQ((htonl)(036U), a.s_addr);
+}
+
+TEST(arpa_inet, inet_aton_nullptr) {
+  ASSERT_EQ(0, inet_aton("", nullptr));
+  ASSERT_EQ(1, inet_aton("127.0.0.1", nullptr));
+}
+
+TEST(arpa_inet, inet_aton_invalid) {
+  ASSERT_EQ(0, inet_aton("", nullptr)); // Empty.
+  ASSERT_EQ(0, inet_aton("x", nullptr)); // Leading junk.
+  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk.
+  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr)); // Invalid octal.
+  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr)); // Invalid hex.
+
+  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr)); // Too many dots.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr)); // Trailing dot.
+
+  // Out of range a.b.c.d form.
+  ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.999.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.999.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0.999", nullptr));
+
+  // Out of range a.b.c form.
+  ASSERT_EQ(0, inet_aton("256.0.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0x10000", nullptr));
+
+  // Out of range a.b form.
+  ASSERT_EQ(0, inet_aton("256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0x1000000", nullptr));
+
+  // Out of range a form.
+  ASSERT_EQ(0, inet_aton("0x100000000", nullptr));
+
+  // 64-bit overflow.
+  ASSERT_EQ(0, inet_aton("0x10000000000000000", nullptr));
+
+  // Out of range octal.
+  ASSERT_EQ(0, inet_aton("0400.0.0.1", nullptr));
 }
 
 TEST(arpa_inet, inet_lnaof) {
@@ -45,6 +122,8 @@
 
 TEST(arpa_inet, inet_network) {
   ASSERT_EQ(0x7f000001U, inet_network("127.0.0.1"));
+  ASSERT_EQ(0x7fU, inet_network("0x7f"));
+  ASSERT_EQ(~0U, inet_network(""));
 }
 
 TEST(arpa_inet, inet_ntoa) {
diff --git a/tests/atexit_test.cpp b/tests/atexit_test.cpp
index e92889d..67fbfd2 100644
--- a/tests/atexit_test.cpp
+++ b/tests/atexit_test.cpp
@@ -14,7 +14,17 @@
  * limitations under the License.
  */
 
+// To work around b/25643775, we disable clang optimization so that
+//   VTT for std::__1::basic_stringstream<char, std::__1::char_traits<char>,
+//   std::__1::allocator<char> >
+// will be correctly kept for other module's references.
+#if defined(__clang__) && (defined(__arm__) || defined(__aarch64__))
+#pragma clang optimize off
+#endif
 #include <gtest/gtest.h>
+#if defined(__clang__) && (defined(__arm__) || defined(__aarch64__))
+#pragma clang optimize on
+#endif
 
 #include <dlfcn.h>
 #include <libgen.h>
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index 4967382..a5a0c2a 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -256,7 +256,7 @@
       VerifyFencepost(&buf_align[len]);
     }
   }
-  delete buf;
+  delete[] buf;
 }
 
 void RunSrcDstBufferAlignTest(
@@ -292,8 +292,8 @@
       VerifyFencepost(&dst_align[len]);
     }
   }
-  delete src;
-  delete dst;
+  delete[] src;
+  delete[] dst;
 }
 
 void RunCmpBufferAlignTest(
@@ -344,8 +344,8 @@
       }
     }
   }
-  delete buf1;
-  delete buf2;
+  delete[] buf1;
+  delete[] buf2;
 }
 
 void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) {
@@ -381,15 +381,19 @@
   // Make the second page unreadable and unwritable.
   ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
 
-  uint8_t* dst = new uint8_t[pagesize];
-  for (size_t i = 0; i < pagesize; i++) {
-    uint8_t* src = &memory[pagesize-i];
+  uint8_t* dst_buffer = new uint8_t[2*pagesize];
+  // Change the dst alignment as we change the source.
+  for (size_t i = 0; i < 16; i++) {
+    uint8_t* dst = &dst_buffer[i];
+    for (size_t j = 0; j < pagesize; j++) {
+      uint8_t* src = &memory[pagesize-j];
 
-    test_func(src, dst, i);
+      test_func(src, dst, j);
+    }
   }
   ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
   free(memory);
-  delete dst;
+  delete[] dst_buffer;
 }
 
 void RunCmpBufferOverreadTest(
diff --git a/tests/bug_26110743_test.cpp b/tests/bug_26110743_test.cpp
new file mode 100644
index 0000000..c49a9dc
--- /dev/null
+++ b/tests/bug_26110743_test.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+
+#include "private/ScopeGuard.h"
+
+extern "C" pid_t gettid();
+
+static void ProcSelfReadlinkBody() {
+  char buf[100];
+  char buf2[1024];
+  int fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+  ASSERT_NE(-1, fd);
+  snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+  const char* ERRORMSG = "Please apply the following two kernel patches:\n"
+    "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=73af963f9f3036dffed55c3a2898598186db1045\n"
+    "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=96d0df79f2644fc823f26c06491e182d87a90c2a\n";
+  ASSERT_NE(-1, readlink(buf, buf2, sizeof(buf2))) << ERRORMSG;
+  ASSERT_STREQ("/dev/null", buf2);
+  close(fd);
+}
+
+static void* ProcSelfReadlink(void*) {
+  ProcSelfReadlinkBody();
+  return NULL;
+}
+
+TEST(bug_26110743, ProcSelfReadlink) {
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ProcSelfReadlink, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_EQ(NULL, result);
+}
+
+TEST(bug_26110743, ProcSelfReadlink_NotDumpable) {
+  int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+  prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+  auto guard = make_scope_guard([&]() {
+    // restore dumpable
+    prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
+  });
+
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ProcSelfReadlink, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_EQ(NULL, result);
+}
+
+static void ProcTaskFdReadlinkBody() {
+  char buf[200];
+  char buf2[1024];
+  int fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+  ASSERT_NE(-1, fd);
+  pid_t mypid = getpid();
+  pid_t mytid = gettid();
+  ASSERT_NE(mypid, mytid);
+  snprintf(buf, sizeof(buf), "/proc/%d/task/%d/fd/%d", mypid, mytid, fd);
+  const char* ERRORMSG = "Please apply the following kernel patch:\n"
+    "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=54708d2858e79a2bdda10bf8a20c80eb96c20613\n";
+  ASSERT_NE(-1, readlink(buf, buf2, sizeof(buf2))) << ERRORMSG;
+  ASSERT_STREQ("/dev/null", buf2);
+  close(fd);
+}
+
+static void* ProcTaskFdReadlink(void*) {
+  ProcTaskFdReadlinkBody();
+  return NULL;
+}
+
+TEST(bug_26110743, ProcTaskFdReadlink) {
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ProcTaskFdReadlink, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_EQ(NULL, result);
+}
+
+TEST(bug_26110743, ProcTaskFdReadlink_NotDumpable) {
+  int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+  prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+  auto guard = make_scope_guard([&]() {
+    // restore dumpable
+    prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
+  });
+
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, ProcTaskFdReadlink, NULL));
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_EQ(NULL, result);
+}
diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp
index 214dd78..fa05ca1 100644
--- a/tests/dirent_test.cpp
+++ b/tests/dirent_test.cpp
@@ -81,6 +81,72 @@
   CheckProcSelf(name_set);
 }
 
+TEST(dirent, scandirat_scandirat64) {
+  // Get everything from /proc/self...
+  dirent** entries;
+  int entry_count = scandir("/proc/self", &entries, NULL, alphasort);
+  ASSERT_GE(entry_count, 0);
+
+  int proc_fd = open("/proc", O_DIRECTORY);
+  ASSERT_NE(-1, proc_fd);
+
+  dirent** entries_at;
+  int entry_count_at = scandirat(proc_fd, "self", &entries_at, NULL, alphasort);
+  ASSERT_EQ(entry_count, entry_count_at);
+
+  dirent64** entries_at64;
+  int entry_count_at64 = scandirat64(proc_fd, "self", &entries_at64, NULL, alphasort64);
+  ASSERT_EQ(entry_count, entry_count_at64);
+
+  close(proc_fd);
+
+  // scandirat and scandirat64 should return the same results as scandir.
+  std::set<std::string> name_set, name_set_at, name_set_at64;
+  std::vector<std::string> unsorted_name_list, unsorted_name_list_at, unsorted_name_list_at64;
+  ScanEntries(entries, entry_count, name_set, unsorted_name_list);
+  ScanEntries(entries_at, entry_count_at, name_set_at, unsorted_name_list_at);
+  ScanEntries(entries_at64, entry_count_at64, name_set_at64, unsorted_name_list_at64);
+
+  ASSERT_EQ(name_set, name_set_at);
+  ASSERT_EQ(name_set, name_set_at64);
+  ASSERT_EQ(unsorted_name_list, unsorted_name_list_at);
+  ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64);
+}
+
+TEST(dirent, scandir_ENOENT) {
+  dirent** entries;
+  errno = 0;
+  ASSERT_EQ(-1, scandir("/does-not-exist", &entries, nullptr, nullptr));
+  ASSERT_EQ(ENOENT, errno);
+}
+
+TEST(dirent, scandir64_ENOENT) {
+  dirent64** entries;
+  errno = 0;
+  ASSERT_EQ(-1, scandir64("/does-not-exist", &entries, nullptr, nullptr));
+  ASSERT_EQ(ENOENT, errno);
+}
+
+TEST(dirent, scandirat_ENOENT) {
+  int root_fd = open("/", O_DIRECTORY | O_RDONLY);
+  ASSERT_NE(-1, root_fd);
+  dirent** entries;
+  errno = 0;
+  ASSERT_EQ(-1, scandirat(root_fd, "does-not-exist", &entries, nullptr, nullptr));
+  ASSERT_EQ(ENOENT, errno);
+  close(root_fd);
+}
+
+TEST(dirent, scandirat64_ENOENT) {
+  int root_fd = open("/", O_DIRECTORY | O_RDONLY);
+  ASSERT_NE(-1, root_fd);
+  dirent64** entries;
+  errno = 0;
+  ASSERT_EQ(-1, scandirat64(root_fd, "does-not-exist", &entries, nullptr, nullptr));
+  ASSERT_EQ(ENOENT, errno);
+  close(root_fd);
+}
+
 TEST(dirent, fdopendir_invalid) {
   ASSERT_TRUE(fdopendir(-1) == NULL);
   ASSERT_EQ(EBADF, errno);
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index f901708..261aa55 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -32,6 +32,7 @@
 #include <pagemap/pagemap.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 #define ASSERT_DL_NOTNULL(ptr) \
     ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
@@ -52,15 +53,16 @@
 #define LIBSIZE 1024*1024 // how much address space to reserve for it
 
 #if defined(__LP64__)
-#define LIBPATH_PREFIX "/nativetest64/libdlext_test_fd/"
+#define NATIVE_TESTS_PATH "/nativetest64"
 #else
-#define LIBPATH_PREFIX "/nativetest/libdlext_test_fd/"
+#define NATIVE_TESTS_PATH "/nativetest"
 #endif
 
-#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so"
-#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
+#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so"
+#define LIBZIPPATH NATIVE_TESTS_PATH "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
+#define LIBZIPPATH_WITH_RUNPATH NATIVE_TESTS_PATH "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
 
-#define LIBZIP_OFFSET 2*PAGE_SIZE
+#define LIBZIP_OFFSET PAGE_SIZE
 
 class DlExtTest : public ::testing::Test {
 protected:
@@ -114,6 +116,10 @@
   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
   ASSERT_DL_NOTNULL(f);
   EXPECT_EQ(4, f());
+
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
@@ -127,9 +133,9 @@
   handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_DL_NOTNULL(handle_);
 
-  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
-  ASSERT_DL_NOTNULL(f);
-  EXPECT_EQ(4, f());
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
@@ -159,11 +165,16 @@
   ASSERT_TRUE(handle_ == nullptr);
   ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
 
-  extinfo.library_fd_offset = PAGE_SIZE;
+  extinfo.library_fd_offset = 0;
   handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle_ == nullptr);
   ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
 
+  // Check if dlsym works after unsuccessful dlopen().
+  // Supply non-exiting one to make linker visit every soinfo.
+  void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___");
+  ASSERT_TRUE(sym == nullptr);
+
   close(extinfo.library_fd);
 }
 
@@ -214,17 +225,34 @@
 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/libatest_simple_zip.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
-  int (*fn)(void);
-  fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
-  ASSERT_TRUE(fn != nullptr);
-  EXPECT_EQ(4, fn());
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
 
   dlclose(handle);
 }
 
+TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
+
+  void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
+
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr) << dlerror();
+
+  dlclose(p);
+  dlclose(handle);
+}
+
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
 
@@ -234,12 +262,12 @@
 
   ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
 
-  void* handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+  void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
   ASSERT_TRUE(handle == nullptr);
 
   android_update_LD_LIBRARY_PATH(lib_path.c_str());
 
-  handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
+  handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
   int (*fn)(void);
@@ -247,6 +275,10 @@
   ASSERT_TRUE(fn != nullptr);
   EXPECT_EQ(4, fn());
 
+  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+  ASSERT_DL_NOTNULL(taxicab_number);
+  EXPECT_EQ(1729U, *taxicab_number);
+
   dlclose(handle);
 }
 
@@ -317,6 +349,43 @@
   EXPECT_EQ(4, f());
 }
 
+TEST_F(DlExtTest, LoadAtFixedAddress) {
+  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
+                     -1, 0);
+  ASSERT_TRUE(start != MAP_FAILED);
+  munmap(start, LIBSIZE);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
+  extinfo.reserved_addr = start;
+
+  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
+  ASSERT_DL_NOTNULL(handle_);
+  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
+  ASSERT_DL_NOTNULL(f);
+  EXPECT_GE(reinterpret_cast<void*>(f), start);
+  EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE);
+
+  EXPECT_EQ(4, f());
+}
+
+TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
+  void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE,
+                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_TRUE(start != MAP_FAILED);
+  munmap(start, LIBSIZE + PAGE_SIZE);
+  void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_TRUE(new_addr != MAP_FAILED);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
+  extinfo.reserved_addr = start;
+
+  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle_ == nullptr);
+}
+
 class DlExtRelroSharingTest : public DlExtTest {
 protected:
   virtual void SetUp() {
@@ -372,6 +441,10 @@
     fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
     ASSERT_DL_NOTNULL(f);
     EXPECT_EQ(4, f());
+
+    uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
+    ASSERT_DL_NOTNULL(taxicab_number);
+    EXPECT_EQ(1729U, *taxicab_number);
   }
 
   void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
@@ -530,3 +603,432 @@
     ASSERT_EQ(0, WEXITSTATUS(status));
   }
 }
+
+// Testing namespaces
+static const char* g_public_lib = "libnstest_public.so";
+
+TEST(dlext, ns_smoke) {
+  static const char* root_lib = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
+  ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
+               "\"libnstest_public.so\" was not found in the default namespace", dlerror());
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+
+  // Check that libraries added to public namespace are NODELETE
+  dlclose(handle_public);
+  handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
+                         RTLD_NOW | RTLD_NOLOAD);
+
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  android_namespace_t* ns1 =
+          android_create_namespace("private", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
+  ASSERT_TRUE(ns1 != nullptr) << dlerror();
+
+  android_namespace_t* ns2 =
+          android_create_namespace("private_isolated", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
+  ASSERT_TRUE(ns2 != nullptr) << dlerror();
+
+  // This should not have affect search path for default namespace:
+  ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
+  void* handle = dlopen(g_public_lib, RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  dlclose(handle);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns1;
+
+  void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle1 != nullptr) << dlerror();
+
+  extinfo.library_namespace = ns2;
+  void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+
+  ASSERT_TRUE(handle1 != handle2);
+
+  // dlopen for a public library using an absolute path should work for isolated namespaces
+  extinfo.library_namespace = ns2;
+  handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  ASSERT_TRUE(handle == handle_public);
+
+  dlclose(handle);
+
+  typedef const char* (*fn_t)();
+
+  fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
+  ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
+  fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
+  ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
+
+  EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
+  EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
+
+  ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
+
+  fn_t ns_get_private_extern_string1 =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
+  ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
+  fn_t ns_get_private_extern_string2 =
+          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
+  ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
+
+  EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
+  EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
+
+  ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
+
+  fn_t ns_get_public_extern_string1 =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
+  ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
+  fn_t ns_get_public_extern_string2 =
+          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
+  ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
+
+  EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
+  ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
+
+  // and now check that dlopen() does the right thing in terms of preserving namespace
+  fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
+  fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
+
+  EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
+  EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
+
+  ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
+
+  dlclose(handle1);
+
+  // Check if handle2 is still alive (and well)
+  ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
+  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
+  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
+  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
+
+  dlclose(handle2);
+}
+
+extern "C" void android_set_application_target_sdk_version(uint32_t target);
+
+TEST(dlext, ns_isolated) {
+  static const char* root_lib = "libnstest_root_not_isolated.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  android_set_application_target_sdk_version(42U); // something > 23
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+
+  android_namespace_t* ns_not_isolated =
+          android_create_namespace("private", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
+  ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
+
+  android_namespace_t* ns_isolated =
+          android_create_namespace("private_isolated1", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
+  ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
+
+  android_namespace_t* ns_isolated2 =
+          android_create_namespace("private_isolated2",
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   nullptr, ANDROID_NAMESPACE_TYPE_ISOLATED, lib_path.c_str());
+  ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
+
+  ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
+  ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
+
+  std::string lib_private_external_path =
+      lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
+
+  // Load lib_private_external_path to default namespace
+  // (it should remain invisible for the isolated namespaces after this)
+  void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns_not_isolated;
+
+  void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle1 != nullptr) << dlerror();
+
+  extinfo.library_namespace = ns_isolated;
+
+  void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 == nullptr);
+  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
+
+  // Check dlopen by absolute path
+  handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 == nullptr);
+  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated1\"", dlerror());
+
+  extinfo.library_namespace = ns_isolated2;
+
+  // this should work because isolation_path for private_isolated2 includes lib_path
+  handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+  dlclose(handle2);
+
+  // Check dlopen by absolute path
+  handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+  dlclose(handle2);
+
+  typedef const char* (*fn_t)();
+  fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
+  ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is local to root library", ns_get_local_string());
+
+  fn_t ns_get_private_extern_string =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
+  ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
+
+  fn_t ns_get_public_extern_string =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
+  ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
+
+  fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
+
+  dlclose(handle1);
+}
+
+TEST(dlext, ns_shared) {
+  static const char* root_lib = "libnstest_root_not_isolated.so";
+  static const char* root_lib_isolated = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  android_set_application_target_sdk_version(42U); // something > 23
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+
+  // preload this library to the default namespace to check if it
+  // is shared later on.
+  void* handle_dlopened =
+          dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
+
+  android_namespace_t* ns_not_isolated =
+          android_create_namespace("private", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
+  ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
+
+  android_namespace_t* ns_isolated_shared =
+          android_create_namespace("private_isolated_shared", nullptr,
+                                   (lib_path + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
+                                   nullptr);
+  ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
+
+  ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
+  ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
+
+  std::string lib_private_external_path =
+      lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
+
+  // Load lib_private_external_path to default namespace
+  // (it should remain invisible for the isolated namespaces after this)
+  void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns_not_isolated;
+
+  void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle1 != nullptr) << dlerror();
+
+  extinfo.library_namespace = ns_isolated_shared;
+
+  void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 == nullptr);
+  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
+
+  // Check dlopen by absolute path
+  handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle2 == nullptr);
+  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated_shared\"", dlerror());
+
+  // load libnstest_root.so to shared namespace in order to check that everything is different
+  // except shared libnstest_dlopened.so
+
+  handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo);
+
+  typedef const char* (*fn_t)();
+  fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
+  ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
+  fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
+  ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is local to root library", ns_get_local_string());
+  ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared());
+  ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared());
+
+  fn_t ns_get_private_extern_string =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
+  ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
+  fn_t ns_get_private_extern_string_shared =
+          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
+  ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
+  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared());
+  ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared());
+
+  fn_t ns_get_public_extern_string =
+          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
+  ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
+  fn_t ns_get_public_extern_string_shared =
+          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
+  ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
+  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared());
+  ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared());
+
+  fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
+  fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror();
+  const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string"));
+  ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror();
+
+  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
+  ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string);
+  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared());
+  ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared());
+  ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared());
+
+  dlclose(handle1);
+  dlclose(handle2);
+}
+
+TEST(dlext, ns_anonymous) {
+  static const char* root_lib = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
+      << dlerror();
+
+  android_namespace_t* ns = android_create_namespace(
+                                "private", nullptr,
+                                (lib_path + "/private_namespace_libs").c_str(),
+                                ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
+
+  ASSERT_TRUE(ns != nullptr) << dlerror();
+
+  std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns;
+
+  // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
+  void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  uintptr_t ns_get_dlopened_string_addr =
+      reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
+  typedef const char* (*fn_t)();
+  fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
+
+  std::vector<map_record> maps;
+  Maps::parse_maps(&maps);
+
+  uintptr_t addr_start = 0;
+  uintptr_t addr_end = 0;
+  std::vector<map_record> maps_to_copy;
+
+  for (const auto& rec : maps) {
+    if (rec.pathname == private_library_absolute_path) {
+      if (addr_start == 0) {
+        addr_start = rec.addr_start;
+      }
+      addr_end = rec.addr_end;
+
+      maps_to_copy.push_back(rec);
+    }
+  }
+
+  // some sanity checks..
+  ASSERT_TRUE(addr_start > 0);
+  ASSERT_TRUE(addr_end > 0);
+  ASSERT_EQ(3U, maps_to_copy.size());
+  ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
+  ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
+
+  // copy
+  uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
+                                                             PROT_NONE, MAP_ANON | MAP_PRIVATE,
+                                                             -1, 0));
+  ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
+
+  for (const auto& rec : maps_to_copy) {
+    uintptr_t offset = rec.addr_start - addr_start;
+    size_t size = rec.addr_end - rec.addr_start;
+    void* addr = reinterpret_cast<void*>(reserved_addr + offset);
+    void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
+                     MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
+    ASSERT_TRUE(map != MAP_FAILED);
+    memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
+    mprotect(map, size, rec.perms);
+  }
+
+  // call the function copy
+  uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start;
+  fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_anon());
+
+  // They should belong to different namespaces (private and anonymous)
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_private());
+
+  ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
+}
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 3c9b8e3..81479d5 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -51,12 +51,12 @@
 
 TEST(dlfcn, dlsym_in_executable) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym = dlsym(self, "DlSymTestFunction");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr);
 
   void (*function)() = reinterpret_cast<void(*)()>(sym);
 
@@ -175,11 +175,11 @@
 
 TEST(dlfcn, dlopen_noload) {
   void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
-  ASSERT_TRUE(handle == NULL);
+  ASSERT_TRUE(handle == nullptr);
   handle = dlopen("libtest_simple.so", RTLD_NOW);
   void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
-  ASSERT_TRUE(handle != NULL);
-  ASSERT_TRUE(handle2 != NULL);
+  ASSERT_TRUE(handle != nullptr);
+  ASSERT_TRUE(handle2 != nullptr);
   ASSERT_TRUE(handle == handle2);
   ASSERT_EQ(0, dlclose(handle));
   ASSERT_EQ(0, dlclose(handle2));
@@ -220,11 +220,11 @@
   // first check the set case
   setenv("IFUNC_CHOICE", "set", 1);
   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != NULL);
-  ASSERT_TRUE(foo_library_ptr != NULL);
+  ASSERT_TRUE(foo_ptr != nullptr);
+  ASSERT_TRUE(foo_library_ptr != nullptr);
   ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
   ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
   dlclose(handle);
@@ -232,11 +232,11 @@
   // then check the unset case
   unsetenv("IFUNC_CHOICE");
   handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != NULL);
-  ASSERT_TRUE(foo_library_ptr != NULL);
+  ASSERT_TRUE(foo_ptr != nullptr);
+  ASSERT_TRUE(foo_library_ptr != nullptr);
   ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
   ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
   dlclose(handle);
@@ -315,9 +315,9 @@
   typedef int (*fn_t) (void);
   fn_t fn, fn2;
   fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
-  ASSERT_TRUE(fn != NULL) << dlerror();
+  ASSERT_TRUE(fn != nullptr) << dlerror();
   fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
-  ASSERT_TRUE(fn2 != NULL) << dlerror();
+  ASSERT_TRUE(fn2 != nullptr) << dlerror();
 
   ASSERT_EQ(42, fn());
   ASSERT_EQ(43, fn2());
@@ -624,8 +624,10 @@
   handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
   ASSERT_TRUE(handle == nullptr);
 #ifdef __BIONIC__
-  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
   ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
+#else
+  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
+  ASSERT_TRUE(dlerror() == nullptr);
 #endif
 
   handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
@@ -718,7 +720,7 @@
 
 TEST(dlfcn, dlopen_failure) {
   void* self = dlopen("/does/not/exist", RTLD_NOW);
-  ASSERT_TRUE(self == NULL);
+  ASSERT_TRUE(self == nullptr);
 #if defined(__BIONIC__)
   ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
 #else
@@ -737,7 +739,7 @@
   ASSERT_SUBSTR("/main/thread", main_thread_error);
 
   pthread_t t;
-  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
+  ASSERT_EQ(0, pthread_create(&t, nullptr, ConcurrentDlErrorFn, nullptr));
   void* result;
   ASSERT_EQ(0, pthread_join(t, &result));
   char* child_thread_error = static_cast<char*>(result);
@@ -749,31 +751,23 @@
 
 TEST(dlfcn, dlsym_failures) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym;
 
 #if defined(__BIONIC__) && !defined(__LP64__)
   // RTLD_DEFAULT in lp32 bionic is not (void*)0
   // so it can be distinguished from the NULL handle.
-  sym = dlsym(NULL, "test");
-  ASSERT_TRUE(sym == NULL);
-  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
-#endif
-
-  // NULL symbol name.
-#if defined(__BIONIC__)
-  // glibc marks this parameter non-null and SEGVs if you cheat.
-  sym = dlsym(self, NULL);
-  ASSERT_TRUE(sym == NULL);
-  ASSERT_SUBSTR("", dlerror());
+  sym = dlsym(nullptr, "test");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
 #endif
 
   // Symbol that doesn't exist.
   sym = dlsym(self, "ThisSymbolDoesNotExist");
-  ASSERT_TRUE(sym == NULL);
+  ASSERT_TRUE(sym == nullptr);
   ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
 
   ASSERT_EQ(0, dlclose(self));
@@ -781,12 +775,12 @@
 
 TEST(dlfcn, dladdr_executable) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym = dlsym(self, "DlSymTestFunction");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr);
 
   // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
   void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
@@ -830,10 +824,11 @@
 }
 
 #if defined(__LP64__)
-#define BIONIC_PATH_TO_LIBC "/system/lib64/libc.so"
+#define PATH_TO_SYSTEM_LIB "/system/lib64/"
 #else
-#define BIONIC_PATH_TO_LIBC "/system/lib/libc.so"
+#define PATH_TO_SYSTEM_LIB "/system/lib/"
 #endif
+#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
 
 TEST(dlfcn, dladdr_libc) {
 #if defined(__BIONIC__)
@@ -843,7 +838,7 @@
 
   // /system/lib is symlink when this test is executed on host.
   char libc_realpath[PATH_MAX];
-  ASSERT_TRUE(realpath(BIONIC_PATH_TO_LIBC, libc_realpath) == libc_realpath);
+  ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
 
   ASSERT_STREQ(libc_realpath, info.dli_fname);
   // TODO: add check for dfi_fbase
@@ -861,12 +856,12 @@
   dlerror(); // Clear any pending errors.
 
   // No symbol corresponding to NULL.
-  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
-  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
+  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
+  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
 
   // No symbol corresponding to a stack address.
   ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
-  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
+  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
 }
 
 // GNU-style ELF hash tables are incompatible with the MIPS ABI.
@@ -922,49 +917,49 @@
 
 #if defined(__GLIBC__)
   // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
-  handle = dlopen(NULL, 0);
-  ASSERT_TRUE(handle == NULL);
+  handle = dlopen(nullptr, 0);
+  ASSERT_TRUE(handle == nullptr);
   ASSERT_SUBSTR("invalid", dlerror());
 #endif
 
-  handle = dlopen(NULL, 0xffffffff);
-  ASSERT_TRUE(handle == NULL);
+  handle = dlopen(nullptr, 0xffffffff);
+  ASSERT_TRUE(handle == nullptr);
   ASSERT_SUBSTR("invalid", dlerror());
 
   // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
-  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
-  ASSERT_TRUE(handle != NULL);
-  ASSERT_SUBSTR(NULL, dlerror());
+  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
+  ASSERT_TRUE(handle != nullptr);
+  ASSERT_SUBSTR(nullptr, dlerror());
 }
 
 TEST(dlfcn, rtld_default_unknown_symbol) {
   void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
-  ASSERT_TRUE(addr == NULL);
+  ASSERT_TRUE(addr == nullptr);
 }
 
 TEST(dlfcn, rtld_default_known_symbol) {
   void* addr = dlsym(RTLD_DEFAULT, "fopen");
-  ASSERT_TRUE(addr != NULL);
+  ASSERT_TRUE(addr != nullptr);
 }
 
 TEST(dlfcn, rtld_next_unknown_symbol) {
   void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
-  ASSERT_TRUE(addr == NULL);
+  ASSERT_TRUE(addr == nullptr);
 }
 
 TEST(dlfcn, rtld_next_known_symbol) {
   void* addr = dlsym(RTLD_NEXT, "fopen");
-  ASSERT_TRUE(addr != NULL);
+  ASSERT_TRUE(addr != nullptr);
 }
 
 TEST(dlfcn, dlsym_weak_func) {
   dlerror();
   void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
 
   int (*weak_func)();
   weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
-  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
+  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
   EXPECT_EQ(42, weak_func());
   dlclose(handle);
 }
@@ -982,8 +977,8 @@
 TEST(dlfcn, dlopen_symlink) {
   void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
   void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
-  ASSERT_TRUE(handle1 != NULL);
-  ASSERT_TRUE(handle2 != NULL);
+  ASSERT_TRUE(handle1 != nullptr);
+  ASSERT_TRUE(handle2 != nullptr);
   ASSERT_EQ(handle1, handle2);
   dlclose(handle1);
   dlclose(handle2);
@@ -1053,6 +1048,26 @@
   dlclose(handle);
 }
 
+TEST(dlfcn, dlvsym_smoke) {
+  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+
+  {
+    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
+    ASSERT_TRUE(fn == nullptr);
+    ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
+  }
+
+  {
+    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
+    ASSERT_TRUE(fn != nullptr) << dlerror();
+    ASSERT_EQ(2, fn());
+  }
+
+  dlclose(handle);
+}
+
 // This preempts the implementation from libtest_versioned_lib.so
 extern "C" int version_zero_function() {
   return 0;
@@ -1062,3 +1077,31 @@
 extern "C" int version_zero_function2() {
   return 0;
 }
+
+TEST(dlfcn, dt_runpath_smoke) {
+  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr);
+
+  dlclose(handle);
+}
+
+TEST(dlfcn, dt_runpath_absolute_path) {
+  void* handle = dlopen(PATH_TO_SYSTEM_LIB "libtest_dt_runpath_d.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p != nullptr);
+
+  dlclose(handle);
+}
diff --git a/tests/file-check-cxx b/tests/file-check-cxx
index 8ece835..4018265 100755
--- a/tests/file-check-cxx
+++ b/tests/file-check-cxx
@@ -2,10 +2,10 @@
 FILECHECK=$1
 CXX=$2
 PREFIX=$3
-ARGS=${*:4}
-SOURCE=$(echo $ARGS | grep -oP '\S+\.cpp\b')
-OBJ=$(echo $ARGS | grep -oP '\S+\.o\b')
-$CXX $ARGS 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
+shift 3
+SOURCE=$(echo "$@" | grep -oP '\S+\.cpp\b')
+OBJ=$(echo "$@" | grep -oP '\S+\.o\b')
+$CXX "$@" 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
 if [ "$?" -eq 0 ]; then
   touch $OBJ
 else
diff --git a/tests/fortify_compilation_test.cpp b/tests/fortify_compilation_test.cpp
index 537b341..1326597 100644
--- a/tests/fortify_compilation_test.cpp
+++ b/tests/fortify_compilation_test.cpp
@@ -21,6 +21,7 @@
 #include <poll.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -230,3 +231,67 @@
   // clang should emit a warning, but doesn't
   ppoll(fds, 2, &timeout, NULL);
 }
+
+void test_fread_overflow() {
+  char buf[4];
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__fread_overflow' declared with attribute error: fread called with overflowing size * count
+  // clang should emit a warning, but doesn't
+  fread(buf, 2, (size_t)-1, stdin);
+}
+
+void test_fread_too_big() {
+  char buf[4];
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__fread_too_big_error' declared with attribute error: fread called with size * count bigger than buffer
+  // clang should emit a warning, but doesn't
+  fread(buf, 1, 5, stdin);
+}
+
+void test_fwrite_overflow() {
+  char buf[4] = {0};
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__fwrite_overflow' declared with attribute error: fwrite called with overflowing size * count
+  // clang should emit a warning, but doesn't
+  fwrite(buf, 2, (size_t)-1, stdout);
+}
+
+void test_fwrite_too_big() {
+  char buf[4] = {0};
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__fwrite_too_big_error' declared with attribute error: fwrite called with size * count bigger than buffer
+  // clang should emit a warning, but doesn't
+  fwrite(buf, 1, 5, stdout);
+}
+
+void test_getcwd() {
+  char buf[4];
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__getcwd_dest_size_error' declared with attribute error: getcwd called with size bigger than destination
+  // clang should emit a warning, but doesn't
+  getcwd(buf, 5);
+}
+
+void test_pwrite64_size() {
+  char buf[4] = {0};
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__pwrite64_dest_size_error' declared with attribute error: pwrite64 called with size bigger than destination
+  // clang should emit a warning, but doesn't
+  pwrite64(STDOUT_FILENO, buf, 5, 0);
+}
+
+void test_pwrite64_too_big() {
+  void *buf = calloc(atoi("5"), 1);
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__pwrite64_count_toobig_error' declared with attribute error: pwrite64 called with count > SSIZE_MAX
+  // clang should emit a warning, but doesn't
+  pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
+}
+
+void test_write_size() {
+  char buf[4] = {0};
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__write_dest_size_error' declared with attribute error: write called with size bigger than destination
+  // clang should emit a warning, but doesn't
+  write(STDOUT_FILENO, buf, 5);
+}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 4faccb4..a349da9 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -623,6 +623,12 @@
   ASSERT_FORTIFY(FD_ISSET(0, set));
 }
 
+TEST_F(DEATHTEST, getcwd_fortified) {
+  char buf[1];
+  size_t ct = atoi("2"); // prevent optimizations
+  ASSERT_FORTIFY(getcwd(buf, ct));
+}
+
 TEST_F(DEATHTEST, pread_fortified) {
   char buf[1];
   size_t ct = atoi("2"); // prevent optimizations
@@ -639,6 +645,22 @@
   close(fd);
 }
 
+TEST_F(DEATHTEST, pwrite_fortified) {
+  char buf[1] = {0};
+  size_t ct = atoi("2"); // prevent optimizations
+  int fd = open("/dev/null", O_WRONLY);
+  ASSERT_FORTIFY(pwrite(fd, buf, ct, 0));
+  close(fd);
+}
+
+TEST_F(DEATHTEST, pwrite64_fortified) {
+  char buf[1] = {0};
+  size_t ct = atoi("2"); // prevent optimizations
+  int fd = open("/dev/null", O_WRONLY);
+  ASSERT_FORTIFY(pwrite64(fd, buf, ct, 0));
+  close(fd);
+}
+
 TEST_F(DEATHTEST, read_fortified) {
   char buf[1];
   size_t ct = atoi("2"); // prevent optimizations
@@ -647,6 +669,30 @@
   close(fd);
 }
 
+TEST_F(DEATHTEST, write_fortified) {
+  char buf[1] = {0};
+  size_t ct = atoi("2"); // prevent optimizations
+  int fd = open("/dev/null", O_WRONLY);
+  ASSERT_EXIT(write(fd, buf, ct), testing::KilledBySignal(SIGABRT), "");
+  close(fd);
+}
+
+TEST_F(DEATHTEST, fread_fortified) {
+  char buf[1];
+  size_t ct = atoi("2"); // prevent optimizations
+  FILE* fp = fopen("/dev/null", "r");
+  ASSERT_FORTIFY(fread(buf, 1, ct, fp));
+  fclose(fp);
+}
+
+TEST_F(DEATHTEST, fwrite_fortified) {
+  char buf[1] = {0};
+  size_t ct = atoi("2"); // prevent optimizations
+  FILE* fp = fopen("/dev/null", "w");
+  ASSERT_FORTIFY(fwrite(buf, 1, ct, fp));
+  fclose(fp);
+}
+
 TEST_F(DEATHTEST, readlink_fortified) {
   char buf[1];
   size_t ct = atoi("2"); // prevent optimizations
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 5d25a4c..a662c73 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -26,15 +26,25 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/wait.h>
-#include <time.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <string>
 #include <tuple>
 #include <utility>
 #include <vector>
 
-#include "BionicDeathTest.h" // For selftest.
+#ifndef TEMP_FAILURE_RETRY
+
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    __typeof__(exp) _rc;                   \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+
+#endif
 
 namespace testing {
 namespace internal {
@@ -90,7 +100,7 @@
          "      Don't use isolation mode, run all tests in a single process.\n"
          "  --deadline=[TIME_IN_MS]\n"
          "      Run each test in no longer than [TIME_IN_MS] time.\n"
-         "      It takes effect only in isolation mode. Deafult deadline is 60000 ms.\n"
+         "      It takes effect only in isolation mode. Deafult deadline is 90000 ms.\n"
          "  --warnline=[TIME_IN_MS]\n"
          "      Test running longer than [TIME_IN_MS] will be warned.\n"
          "      It takes effect only in isolation mode. Default warnline is 2000 ms.\n"
@@ -221,10 +231,8 @@
 }
 
 static int64_t NanoTime() {
-  struct timespec t;
-  t.tv_sec = t.tv_nsec = 0;
-  clock_gettime(CLOCK_MONOTONIC, &t);
-  return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
+  std::chrono::nanoseconds duration(std::chrono::steady_clock::now().time_since_epoch());
+  return static_cast<int64_t>(duration.count());
 }
 
 static bool EnumerateTests(int argc, char** argv, std::vector<TestCase>& testcase_list) {
@@ -256,7 +264,7 @@
     while (*p != '\0' && isspace(*p)) {
       ++p;
     }
-    if (*p != '\0') {
+    if (*p != '\0' && *p != '#') {
       // This is not we want, gtest must meet with some error when parsing the arguments.
       fprintf(stderr, "argument error, check with --help\n");
       return false;
@@ -501,6 +509,43 @@
   fclose(fp);
 }
 
+static bool sigint_flag;
+static bool sigquit_flag;
+
+static void signal_handler(int sig) {
+  if (sig == SIGINT) {
+    sigint_flag = true;
+  } else if (sig == SIGQUIT) {
+    sigquit_flag = true;
+  }
+}
+
+static bool RegisterSignalHandler() {
+  sigint_flag = false;
+  sigquit_flag = false;
+  sig_t ret = signal(SIGINT, signal_handler);
+  if (ret != SIG_ERR) {
+    ret = signal(SIGQUIT, signal_handler);
+  }
+  if (ret == SIG_ERR) {
+    perror("RegisterSignalHandler");
+    return false;
+  }
+  return true;
+}
+
+static bool UnregisterSignalHandler() {
+  sig_t ret = signal(SIGINT, SIG_DFL);
+  if (ret != SIG_ERR) {
+    ret = signal(SIGQUIT, SIG_DFL);
+  }
+  if (ret == SIG_ERR) {
+    perror("UnregisterSignalHandler");
+    return false;
+  }
+  return true;
+}
+
 struct ChildProcInfo {
   pid_t pid;
   int64_t start_time_ns;
@@ -531,11 +576,14 @@
 }
 
 static ChildProcInfo RunChildProcess(const std::string& test_name, int testcase_id, int test_id,
-                                     sigset_t sigmask, int argc, char** argv) {
+                                     int argc, char** argv) {
   int pipefd[2];
-  int ret = pipe2(pipefd, O_NONBLOCK);
-  if (ret == -1) {
-    perror("pipe2 in RunTestInSeparateProc");
+  if (pipe(pipefd) == -1) {
+    perror("pipe in RunTestInSeparateProc");
+    exit(1);
+  }
+  if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) == -1) {
+    perror("fcntl in RunTestInSeparateProc");
     exit(1);
   }
   pid_t pid = fork();
@@ -550,8 +598,7 @@
     dup2(pipefd[1], STDOUT_FILENO);
     dup2(pipefd[1], STDERR_FILENO);
 
-    if (sigprocmask(SIG_SETMASK, &sigmask, NULL) == -1) {
-      perror("sigprocmask SIG_SETMASK");
+    if (!UnregisterSignalHandler()) {
       exit(1);
     }
     ChildProcessFn(argc, argv, test_name);
@@ -572,42 +619,29 @@
 
 static void HandleSignals(std::vector<TestCase>& testcase_list,
                             std::vector<ChildProcInfo>& child_proc_list) {
-  sigset_t waiting_mask;
-  sigemptyset(&waiting_mask);
-  sigaddset(&waiting_mask, SIGINT);
-  sigaddset(&waiting_mask, SIGQUIT);
-  timespec timeout;
-  timeout.tv_sec = timeout.tv_nsec = 0;
-  while (true) {
-    int signo = TEMP_FAILURE_RETRY(sigtimedwait(&waiting_mask, NULL, &timeout));
-    if (signo == -1) {
-      if (errno == EAGAIN) {
-        return; // Timeout, no pending signals.
+  if (sigquit_flag) {
+    sigquit_flag = false;
+    // Print current running tests.
+    printf("List of current running tests:\n");
+    for (const auto& child_proc : child_proc_list) {
+      if (child_proc.pid != 0) {
+        std::string test_name = testcase_list[child_proc.testcase_id].GetTestName(child_proc.test_id);
+        int64_t current_time_ns = NanoTime();
+        int64_t run_time_ms = (current_time_ns - child_proc.start_time_ns) / 1000000;
+        printf("  %s (%" PRId64 " ms)\n", test_name.c_str(), run_time_ms);
       }
-      perror("sigtimedwait");
-      exit(1);
-    } else if (signo == SIGQUIT) {
-      // Print current running tests.
-      printf("List of current running tests:\n");
-      for (auto& child_proc : child_proc_list) {
-        if (child_proc.pid != 0) {
-          std::string test_name = testcase_list[child_proc.testcase_id].GetTestName(child_proc.test_id);
-          int64_t current_time_ns = NanoTime();
-          int64_t run_time_ms = (current_time_ns - child_proc.start_time_ns) / 1000000;
-          printf("  %s (%" PRId64 " ms)\n", test_name.c_str(), run_time_ms);
-        }
-      }
-    } else if (signo == SIGINT) {
-      // Kill current running tests.
-      for (auto& child_proc : child_proc_list) {
-        if (child_proc.pid != 0) {
-          // Send SIGKILL to ensure the child process can be killed unconditionally.
-          kill(child_proc.pid, SIGKILL);
-        }
-      }
-      // SIGINT kills the parent process as well.
-      exit(1);
     }
+  } else if (sigint_flag) {
+    sigint_flag = false;
+    // Kill current running tests.
+    for (const auto& child_proc : child_proc_list) {
+      if (child_proc.pid != 0) {
+        // Send SIGKILL to ensure the child process can be killed unconditionally.
+        kill(child_proc.pid, SIGKILL);
+      }
+    }
+    // SIGINT kills the parent process as well.
+    exit(1);
   }
 }
 
@@ -639,6 +673,30 @@
   return timeout_child_count;
 }
 
+static void ReadChildProcOutput(std::vector<TestCase>& testcase_list,
+                                std::vector<ChildProcInfo>& child_proc_list) {
+  for (const auto& child_proc : child_proc_list) {
+    TestCase& testcase = testcase_list[child_proc.testcase_id];
+    int test_id = child_proc.test_id;
+    while (true) {
+      char buf[1024];
+      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(child_proc.child_read_fd, buf, sizeof(buf) - 1));
+      if (bytes_read > 0) {
+        buf[bytes_read] = '\0';
+        testcase.GetTest(test_id).AppendTestOutput(buf);
+      } else if (bytes_read == 0) {
+        break; // Read end.
+      } else {
+        if (errno == EAGAIN) {
+          break;
+        }
+        perror("failed to read child_read_fd");
+        exit(1);
+      }
+    }
+  }
+}
+
 static void WaitChildProcs(std::vector<TestCase>& testcase_list,
                            std::vector<ChildProcInfo>& child_proc_list) {
   size_t finished_child_count = 0;
@@ -663,6 +721,7 @@
       finished_child_count += CheckChildProcTimeout(child_proc_list);
     }
 
+    ReadChildProcOutput(testcase_list, child_proc_list);
     if (finished_child_count > 0) {
       return;
     }
@@ -696,26 +755,6 @@
     kill(child_proc.pid, SIGKILL);
     WaitForOneChild(child_proc.pid);
   }
-
-  while (true) {
-    char buf[1024];
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(child_proc.child_read_fd, buf, sizeof(buf) - 1));
-    if (bytes_read > 0) {
-      buf[bytes_read] = '\0';
-      testcase.GetTest(test_id).AppendTestOutput(buf);
-    } else if (bytes_read == 0) {
-      break; // Read end.
-    } else {
-      if (errno == EAGAIN) {
-        // No data is available. This rarely happens, only when the child process created other
-        // processes which have not exited so far. But the child process has already exited or
-        // been killed, so the test has finished, and we shouldn't wait further.
-        break;
-      }
-      perror("read child_read_fd in RunTestInSeparateProc");
-      exit(1);
-    }
-  }
   close(child_proc.child_read_fd);
 
   if (child_proc.timed_out) {
@@ -734,8 +773,14 @@
     testcase.GetTest(test_id).AppendTestOutput(buf);
 
   } else {
-    testcase.SetTestResult(test_id, WEXITSTATUS(child_proc.exit_status) == 0 ?
-                           TEST_SUCCESS : TEST_FAILED);
+    int exitcode = WEXITSTATUS(child_proc.exit_status);
+    testcase.SetTestResult(test_id, exitcode == 0 ? TEST_SUCCESS : TEST_FAILED);
+    if (exitcode != 0) {
+      char buf[1024];
+      snprintf(buf, sizeof(buf), "%s exited with exitcode %d.\n",
+               testcase.GetTestName(test_id).c_str(), exitcode);
+      testcase.GetTest(test_id).AppendTestOutput(buf);
+    }
   }
 }
 
@@ -750,13 +795,7 @@
                         testing::UnitTest::GetInstance()->listeners().default_result_printer());
   testing::UnitTest::GetInstance()->listeners().Append(new TestResultPrinter);
 
-  // Signals are blocked here as we want to handle them in HandleSignals() later.
-  sigset_t block_mask, orig_mask;
-  sigemptyset(&block_mask);
-  sigaddset(&block_mask, SIGINT);
-  sigaddset(&block_mask, SIGQUIT);
-  if (sigprocmask(SIG_BLOCK, &block_mask, &orig_mask) == -1) {
-    perror("sigprocmask SIG_BLOCK");
+  if (!RegisterSignalHandler()) {
     exit(1);
   }
 
@@ -785,7 +824,7 @@
       while (child_proc_list.size() < job_count && next_testcase_id < testcase_list.size()) {
         std::string test_name = testcase_list[next_testcase_id].GetTestName(next_test_id);
         ChildProcInfo child_proc = RunChildProcess(test_name, next_testcase_id, next_test_id,
-                                                   orig_mask, argc, argv);
+                                                   argc, argv);
         child_proc_list.push_back(child_proc);
         if (++next_test_id == testcase_list[next_testcase_id].TestCount()) {
           next_test_id = 0;
@@ -830,9 +869,7 @@
     }
   }
 
-  // Restore signal mask.
-  if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) == -1) {
-    perror("sigprocmask SIG_SETMASK");
+  if (!UnregisterSignalHandler()) {
     exit(1);
   }
 
@@ -840,11 +877,7 @@
 }
 
 static size_t GetDefaultJobCount() {
-#if defined(JOB_COUNT_FIXED)
-  return JOB_COUNT_FIXED;
-#else
   return static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
-#endif
 }
 
 static void AddPathSeparatorInTestProgramPath(std::vector<char*>& args) {
@@ -1107,7 +1140,12 @@
   *p = 3;
 }
 
-class bionic_selftest_DeathTest : public BionicDeathTest {};
+class bionic_selftest_DeathTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  }
+};
 
 static void deathtest_helper_success() {
   ASSERT_EQ(1, 1);
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
new file mode 100644
index 0000000..67857cb
--- /dev/null
+++ b/tests/ifaddrs_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 <ifaddrs.h>
+
+TEST(ifaddrs, freeifaddrs_null) {
+  freeifaddrs(nullptr);
+}
+
+TEST(ifaddrs, getifaddrs_smoke) {
+  ifaddrs* addrs = nullptr;
+
+  ASSERT_EQ(0, getifaddrs(&addrs));
+  ASSERT_TRUE(addrs != nullptr);
+
+  bool saw_loopback = false;
+  for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
+    if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) saw_loopback = true;
+  }
+  ASSERT_TRUE(saw_loopback);
+
+  freeifaddrs(addrs);
+}
diff --git a/tests/libgen_basename_test.cpp b/tests/libgen_basename_test.cpp
new file mode 100644
index 0000000..d97e0da
--- /dev/null
+++ b/tests/libgen_basename_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _GNU_SOURCE
+  #define _GNU_SOURCE 1
+#endif
+
+#include <string.h>
+
+#if defined(basename)
+  #error basename should not be defined at this point
+#endif
+
+static const char* gnu_basename(const char* in) {
+  return basename(in);
+}
+
+#include <libgen.h>
+
+#if !defined(basename)
+  #error basename should be defined at this point
+#endif
+
+static char* posix_basename(char* in) {
+  return basename(in);
+}
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+static void __TestGnuBasename(const char* in, const char* expected_out, int line) {
+  errno = 0;
+  const char* out = gnu_basename(in);
+  ASSERT_STREQ(expected_out, out) << "(" << line << "): " << in << std::endl;
+  ASSERT_EQ(0, errno) << "(" << line << "): " << in << std::endl;
+}
+
+static void __TestPosixBasename(const char* in, const char* expected_out, int line) {
+  char* writable_in = (in != NULL) ? strdup(in) : NULL;
+  errno = 0;
+  const char* out = posix_basename(&writable_in[0]);
+  ASSERT_STREQ(expected_out, out) << "(" << line << "): " << in << std::endl;
+  ASSERT_EQ(0, errno) << "(" << line << "): " << in << std::endl;
+  free(writable_in);
+}
+
+#define TestGnuBasename(in, expected) __TestGnuBasename(in, expected, __LINE__)
+#define TestPosixBasename(in, expected) __TestPosixBasename(in, expected, __LINE__)
+
+TEST(libgen_basename, gnu_basename) {
+  // GNU's basename doesn't accept NULL
+  // TestGnuBasename(NULL, ".");
+  TestGnuBasename("", "");
+  TestGnuBasename("/usr/lib", "lib");
+  TestGnuBasename("/system/bin/sh/", "");
+  TestGnuBasename("/usr/", "");
+  TestGnuBasename("usr", "usr");
+  TestGnuBasename("/", "");
+  TestGnuBasename(".", ".");
+  TestGnuBasename("..", "..");
+  TestGnuBasename("///", "");
+  TestGnuBasename("//usr//lib//", "");
+}
+
+TEST(libgen_basename, posix_basename) {
+  TestPosixBasename(NULL, ".");
+  TestPosixBasename("", ".");
+  TestPosixBasename("/usr/lib", "lib");
+  TestPosixBasename("/system/bin/sh/", "sh");
+  TestPosixBasename("/usr/", "usr");
+  TestPosixBasename("usr", "usr");
+  TestPosixBasename("/", "/");
+  TestPosixBasename(".", ".");
+  TestPosixBasename("..", "..");
+  TestPosixBasename("///", "/");
+  TestPosixBasename("//usr//lib//", "lib");
+}
diff --git a/tests/libgen_test.cpp b/tests/libgen_test.cpp
index e9a5d5c..8a37a3f 100644
--- a/tests/libgen_test.cpp
+++ b/tests/libgen_test.cpp
@@ -19,15 +19,6 @@
 #include <errno.h>
 #include <gtest/gtest.h>
 
-static void TestBasename(const char* in, const char* expected_out) {
-  char* writable_in = (in != NULL) ? strdup(in) : NULL;
-  errno = 0;
-  const char* out = basename(&writable_in[0]);
-  ASSERT_STREQ(expected_out, out) << in;
-  ASSERT_EQ(0, errno) << in;
-  free(writable_in);
-}
-
 static void TestDirname(const char* in, const char* expected_out) {
   char* writable_in = (in != NULL) ? strdup(in) : NULL;
   errno = 0;
@@ -37,21 +28,6 @@
   free(writable_in);
 }
 
-// Do not use basename as the test name, it's defined to another value in glibc
-// so leads to a differently named test on host versus target architectures.
-TEST(libgen, posix_basename) {
-  TestBasename(NULL, ".");
-  TestBasename("", ".");
-  TestBasename("/usr/lib", "lib");
-  TestBasename("/usr/", "usr");
-  TestBasename("usr", "usr");
-  TestBasename("/", "/");
-  TestBasename(".", ".");
-  TestBasename("..", "..");
-  TestBasename("///", "/");
-  TestBasename("//usr//lib//", "lib");
-}
-
 TEST(libgen, dirname) {
   TestDirname(NULL, ".");
   TestDirname("", ".");
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 7cc0dae..c06f4a9 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -21,21 +21,62 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MODULE := libdlext_test_fd_zipaligned
+LOCAL_MODULE := libdlext_test_zip_zipaligned
 LOCAL_MODULE_SUFFIX := .zip
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_zip
 LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
 my_shared_libs := \
-  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_zip.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libatest_simple_zip.so
 
-$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE
 $(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
-	@echo "Zipalign $(PRIVATE_ALIGNMENT): $@"
+	@echo "Zipalign: $@"
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir
 	$(hide) cp $^ $(dir $@)/libdir
-	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
-	$(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
+	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned
+LOCAL_MODULE_SUFFIX := .zip
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_runpath_zip
+LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+my_shared_libs := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := \
+  $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
+$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
+	@echo "Zipalign: $@"
+	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir && \
+    mkdir -p $(dir $@)/libdir/dt_runpath_a && mkdir -p $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_D) $(dir $@)/libdir
+	$(hide) cp $(PRIVATE_LIB_A) $(dir $@)/libdir/dt_runpath_a
+	$(hide) cp $(PRIVATE_LIB_B) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_C) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) cp $(PRIVATE_LIB_X) $(dir $@)/libdir/dt_runpath_b_c_x
+	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir)
+	$(hide) $(ZIPALIGN) -p 4 $@.unaligned $@
+
diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk
new file mode 100644
index 0000000..4544bb1
--- /dev/null
+++ b/tests/libs/Android.build.dt_runpath.mk
@@ -0,0 +1,94 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# -----------------------------------------------------------------------------
+# Libraries used by dt_runpath tests.
+# -----------------------------------------------------------------------------
+
+#
+# Dependencies
+#
+# libtest_dt_runpath_d.so                       runpath: ${ORIGIN}/dt_runpath_b_c_x
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_b.so  runpath: ${ORIGIN}/../dt_runpath_a
+# |   |-> dt_runpath_a/libtest_dt_runpath_a.so
+# |-> dt_runpath_b_c_x/libtest_dt_runpath_c.so  runpath: ${ORIGIN}/invalid_dt_runpath
+# |   |-> libtest_dt_runpath_a.so (soname)
+#
+# This one is used to test dlopen
+# dt_runpath_b_c_x/libtest_dt_runpath_x.so
+#
+
+# A leaf library in a non-standard directory.
+libtest_dt_runpath_a_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_a_relative_path := dt_runpath_a
+module := libtest_dt_runpath_a
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# Depends on library A with a DT_RUNPATH
+libtest_dt_runpath_b_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_b_shared_libraries := libtest_dt_runpath_a
+libtest_dt_runpath_b_ldflags := -Wl,--rpath,\$${ORIGIN}/../dt_runpath_a -Wl,--enable-new-dtags
+libtest_dt_runpath_b_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_b
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# Depends on library A with an incorrect DT_RUNPATH. This does not matter
+# because B is the first in the D (below) dependency order, and library A
+# is already loaded using the correct DT_RUNPATH from library B.
+libtest_dt_runpath_c_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_c_shared_libraries := libtest_dt_runpath_a
+libtest_dt_runpath_c_ldflags := -Wl,--rpath,\$${ORIGIN}/invalid_dt_runpath -Wl,--enable-new-dtags
+libtest_dt_runpath_c_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_c
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# D depends on B and C with DT_RUNPATH.
+libtest_dt_runpath_d_src_files := \
+    dlopen_b.cpp
+
+libtest_dt_runpath_d_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
+libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+module := libtest_dt_runpath_d
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# D version for open-from-zip test with runpath
+libtest_dt_runpath_d_zip_src_files := \
+    dlopen_b.cpp
+
+libtest_dt_runpath_d_zip_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
+libtest_dt_runpath_d_zip_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags
+libtest_dt_runpath_d_zip_install_to_out_data := true
+module := libtest_dt_runpath_d_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+
+# A leaf library in a directory library D has DT_RUNPATH for.
+libtest_dt_runpath_x_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_x_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_x
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
diff --git a/tests/libs/Android.build.linker_namespaces.mk b/tests/libs/Android.build.linker_namespaces.mk
new file mode 100644
index 0000000..f913780
--- /dev/null
+++ b/tests/libs/Android.build.linker_namespaces.mk
@@ -0,0 +1,84 @@
+#
+# 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.
+#
+
+# -----------------------------------------------------------------------------
+# This set of libraries are used to verify linker namespaces.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Test cases
+# 1. Check that private libraries loaded in different namespaces are
+#    different. Check that dlsym does not confuse them.
+# 2. Check that public libraries loaded in different namespaces are shared
+#    between them.
+# 3. Check that namespace sticks on dlopen
+#
+# Dependency tree (visibility)
+# libnstest_root.so (this should be local to the namespace)
+# +-> libnstest_public.so
+# +-> libnstest_private.so
+#
+# libnstest_dlopened.so (library in private namespace dlopened from libnstest_root.so)
+# -----------------------------------------------------------------------------
+libnstest_root_src_files := namespaces_root.cpp
+libnstest_root_shared_libraries := libnstest_public libnstest_private
+libnstest_root_install_to_out_data_dir := private_namespace_libs
+module := libnstest_root
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
+
+libnstest_public_src_files := namespaces_public.cpp
+module := libnstest_public
+libnstest_public_install_to_out_data_dir := public_namespace_libs
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
+
+libnstest_private_src_files := namespaces_private.cpp
+libnstest_private_install_to_out_data_dir := private_namespace_libs
+module := libnstest_private
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
+
+libnstest_dlopened_src_files := namespaces_dlopened.cpp
+libnstest_dlopened_install_to_out_data_dir := private_namespace_libs
+module := libnstest_dlopened
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
+
+# -----------------------------------------------------------------------------
+# This set of libraries is to test isolated namespaces
+#
+# Isolated namespaces do not allow loading of the library outside of
+# the search paths.
+#
+# This library cannot be loaded in isolated namespace because one of DT_NEEDED
+# libraries is outside of the search paths.
+#
+# libnstest_root_not_isolated.so (DT_RUNPATH = $ORIGIN/../private_namespace_libs_external/)
+# +-> libnstest_public.so
+# +-> libnstest_private_external.so (located in $ORIGIN/../private_namespace_libs_external/)
+#
+# Search path: $NATIVE_TESTS/private_namespace_libs/
+# -----------------------------------------------------------------------------
+libnstest_root_not_isolated_src_files := namespaces_root.cpp
+libnstest_root_not_isolated_shared_libraries := libnstest_public libnstest_private_external
+libnstest_root_not_isolated_install_to_out_data_dir := private_namespace_libs
+libnstest_root_not_isolated_ldflags := -Wl,--rpath,\$$ORIGIN/../private_namespace_libs_external \
+                                       -Wl,--enable-new-dtags
+
+module := libnstest_root_not_isolated
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
+
+libnstest_private_external_src_files := namespaces_private.cpp
+libnstest_private_external_install_to_out_data_dir := private_namespace_libs_external
+module := libnstest_private_external
+include $(LOCAL_PATH)/Android.build.target.testlib.mk
diff --git a/tests/libs/Android.build.target.testlib.mk b/tests/libs/Android.build.target.testlib.mk
new file mode 100644
index 0000000..1e767c2
--- /dev/null
+++ b/tests/libs/Android.build.target.testlib.mk
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+build_target := SHARED_LIBRARY
+build_type := target
+include $(TEST_PATH)/Android.build.mk
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 5b96306..93d95ee 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -17,14 +17,16 @@
 LOCAL_PATH := $(call my-dir)
 TEST_PATH := $(LOCAL_PATH)/..
 
-common_cppflags += -std=gnu++11
+common_cppflags :=
 common_additional_dependencies := \
     $(LOCAL_PATH)/Android.mk \
+    $(LOCAL_PATH)/Android.build.dt_runpath.mk \
     $(LOCAL_PATH)/Android.build.dlext_testzip.mk \
     $(LOCAL_PATH)/Android.build.dlopen_2_parents_reloc.mk \
     $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \
     $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \
     $(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \
+    $(LOCAL_PATH)/Android.build.linker_namespaces.mk \
     $(LOCAL_PATH)/Android.build.pthread_atfork.mk \
     $(LOCAL_PATH)/Android.build.testlib.mk \
     $(LOCAL_PATH)/Android.build.versioned_lib.mk \
@@ -102,6 +104,8 @@
 libdlext_test_norelro_ldflags := \
     -Wl,-z,norelro \
 
+libdlext_test_norelro_shared_libraries := libtest_simple
+
 module := libdlext_test_norelro
 module_tag := optional
 build_type := target
@@ -114,6 +118,8 @@
 libdlext_test_fd_src_files := \
     dlext_test_library.cpp \
 
+libdlext_test_fd_shared_libraries := libtest_simple
+
 libdlext_test_fd_install_to_out_data := true
 module := libdlext_test_fd
 module_tag := optional
@@ -121,6 +127,32 @@
 build_target := SHARED_LIBRARY
 include $(TEST_PATH)/Android.build.mk
 
+
+# -----------------------------------------------------------------------------
+# Libraries used by dlext tests for open from a zip-file
+# -----------------------------------------------------------------------------
+libdlext_test_zip_src_files := \
+    dlext_test_library.cpp \
+
+libdlext_test_zip_shared_libraries := libatest_simple_zip
+
+libdlext_test_zip_install_to_out_data := true
+module := libdlext_test_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+libatest_simple_zip_src_files := \
+    dlopen_testlib_simple.cpp
+
+libatest_simple_zip_install_to_out_data := true
+module := libatest_simple_zip
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
 # ----------------------------------------------------------------------------
 # Library with soname which does not match filename
 # ----------------------------------------------------------------------------
@@ -182,6 +214,16 @@
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
 # -----------------------------------------------------------------------------
+# Build test helper libraries for linker namespaces
+# -----------------------------------------------------------------------------
+include $(LOCAL_PATH)/Android.build.linker_namespaces.mk
+
+# -----------------------------------------------------------------------------
+# Build DT_RUNPATH test helper libraries
+# -----------------------------------------------------------------------------
+include $(LOCAL_PATH)/Android.build.dt_runpath.mk
+
+# -----------------------------------------------------------------------------
 # Build library with two parents
 # -----------------------------------------------------------------------------
 include $(LOCAL_PATH)/Android.build.dlopen_2_parents_reloc.mk
diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp
new file mode 100644
index 0000000..cd81e16
--- /dev/null
+++ b/tests/libs/dlopen_b.cpp
@@ -0,0 +1,16 @@
+#include <dlfcn.h>
+extern "C" void *dlopen_b() {
+  // TODO (dimitry): this is to work around http://b/20049306
+  // remove once it is fixed
+  static int dummy = 0;
+
+  // This is supposed to succeed because this library has DT_RUNPATH
+  // for libtest_dt_runpath_x.so which should be taken into account
+  // by dlopen.
+  void *handle = dlopen("libtest_dt_runpath_x.so", RTLD_NOW);
+  if (handle != nullptr) {
+    dummy++;
+    return handle;
+  }
+  return nullptr;
+}
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/tests/libs/namespaces_dlopened.cpp
similarity index 71%
copy from libc/upstream-freebsd/android/include/spinlock.h
copy to tests/libs/namespaces_dlopened.cpp
index f5c3785..9d11689 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/tests/libs/namespaces_dlopened.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 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.
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+const char* g_private_dlopened_string = "This string is from private namespace "
+                                        "(dlopened library)";
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/tests/libs/namespaces_private.cpp
similarity index 71%
copy from libc/upstream-freebsd/android/include/spinlock.h
copy to tests/libs/namespaces_private.cpp
index f5c3785..07cab70 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/tests/libs/namespaces_private.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 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.
@@ -14,9 +14,5 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+const char* g_private_extern_string = "This string is from private namespace";
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
diff --git a/libc/upstream-freebsd/android/include/spinlock.h b/tests/libs/namespaces_public.cpp
similarity index 71%
copy from libc/upstream-freebsd/android/include/spinlock.h
copy to tests/libs/namespaces_public.cpp
index f5c3785..bb2a8de 100644
--- a/libc/upstream-freebsd/android/include/spinlock.h
+++ b/tests/libs/namespaces_public.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 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.
@@ -14,9 +14,5 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_FREEBSD_SPINLOCK_H_included
-#define _BIONIC_FREEBSD_SPINLOCK_H_included
+const char* g_public_extern_string = "This string is from public namespace";
 
-/* TODO: until we have the FreeBSD findfp.c, this is useless. */
-
-#endif
diff --git a/tests/libs/namespaces_root.cpp b/tests/libs/namespaces_root.cpp
new file mode 100644
index 0000000..b0006c7
--- /dev/null
+++ b/tests/libs/namespaces_root.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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>
+
+static const char* g_local_string = "This string is local to root library";
+extern "C" const char* g_private_extern_string;
+extern "C" const char* g_public_extern_string;
+
+bool g_dlopened = false;
+
+extern "C" const char* ns_get_local_string() {
+  return g_local_string;
+}
+
+extern "C" const char* ns_get_private_extern_string() {
+  return g_private_extern_string;
+}
+
+extern "C" const char* ns_get_public_extern_string() {
+  return g_public_extern_string;
+}
+
+extern "C" const char* ns_get_dlopened_string() {
+  void* handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_GLOBAL);
+  if (handle == nullptr) {
+    return nullptr;
+  }
+
+  const char** result = static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
+  if (result == nullptr) {
+    return nullptr;
+  } else {
+    g_dlopened = true;
+  }
+
+  return *result;
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index b76625a..5af5a6f 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -372,3 +372,22 @@
   }
 #endif
 }
+
+TEST(malloc, calloc_usable_size) {
+  for (size_t size = 1; size <= 2048; size++) {
+    void* pointer = malloc(size);
+    ASSERT_TRUE(pointer != nullptr);
+    memset(pointer, 0xeb, malloc_usable_size(pointer));
+    free(pointer);
+
+    // We should get a previous pointer that has been set to non-zero.
+    // If calloc does not zero out all of the data, this will fail.
+    uint8_t* zero_mem = reinterpret_cast<uint8_t*>(calloc(1, size));
+    ASSERT_TRUE(pointer != nullptr);
+    size_t usable_size = malloc_usable_size(zero_mem);
+    for (size_t i = 0; i < usable_size; i++) {
+      ASSERT_EQ(0, zero_mem[i]) << "Failed at allocation size " << size << " at byte " << i;
+    }
+    free(zero_mem);
+  }
+}
diff --git a/tests/netinet_udp_test.cpp b/tests/netinet_udp_test.cpp
new file mode 100644
index 0000000..661458e
--- /dev/null
+++ b/tests/netinet_udp_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <netinet/udp.h>
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+  #define UDPHDR_USES_ANON_UNION
+#elif defined(__GLIBC_PREREQ)
+  #if __GLIBC_PREREQ(2, 18)
+    #define UDPHDR_USES_ANON_UNION
+  #endif
+#endif
+
+TEST(netinet_udp, compat) {
+#if defined(UDPHDR_USES_ANON_UNION)
+    static_assert(offsetof(udphdr, uh_sport) == offsetof(udphdr, source), "udphdr::source");
+    static_assert(offsetof(udphdr, uh_dport) == offsetof(udphdr, dest), "udphdr::dest");
+    static_assert(offsetof(udphdr, uh_ulen) == offsetof(udphdr, len), "udphdr::len");
+    static_assert(offsetof(udphdr, uh_sum) == offsetof(udphdr, check), "udphdr::check");
+
+    udphdr u;
+    u.uh_sport = 0x1111;
+    u.uh_dport = 0x2222;
+    u.uh_ulen = 0x3333;
+    u.uh_sum = 0x4444;
+    ASSERT_EQ(0x1111, u.source);
+    ASSERT_EQ(0x2222, u.dest);
+    ASSERT_EQ(0x3333, u.len);
+    ASSERT_EQ(0x4444, u.check);
+#endif
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index e210255..78dbd39 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -30,18 +30,15 @@
 #include <unwind.h>
 
 #include <atomic>
-#include <regex>
 #include <vector>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-
+#include "private/bionic_constants.h"
 #include "private/bionic_macros.h"
 #include "private/ScopeGuard.h"
 #include "BionicDeathTest.h"
 #include "ScopedSignalHandler.h"
 
-extern "C" pid_t gettid();
+#include "utils.h"
 
 TEST(pthread, pthread_key_create) {
   pthread_key_t key;
@@ -68,7 +65,7 @@
   std::vector<pthread_key_t> keys;
 
   auto scope_guard = make_scope_guard([&keys]{
-    for (auto key : keys) {
+    for (const auto& key : keys) {
       EXPECT_EQ(0, pthread_key_delete(key));
     }
   });
@@ -106,7 +103,7 @@
   }
 
   // Don't leak keys.
-  for (auto key : keys) {
+  for (const auto& key : keys) {
     EXPECT_EQ(0, pthread_key_delete(key));
   }
   keys.clear();
@@ -162,7 +159,7 @@
   pthread_key_t key;
   ASSERT_EQ(0, pthread_key_create(&key, NULL));
 
-  size_t stack_size = 128 * 1024;
+  size_t stack_size = 640 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, stack);
   memset(stack, 0xff, stack_size);
@@ -220,13 +217,13 @@
     while (spin_flag_) {}
     return NULL;
   }
-  static volatile bool spin_flag_;
+  static std::atomic<bool> spin_flag_;
 };
 
 // It doesn't matter if spin_flag_ is used in several tests,
 // because it is always set to false after each test. Each thread
 // loops on spin_flag_ can find it becomes false at some time.
-volatile bool SpinFunctionHelper::spin_flag_ = false;
+std::atomic<bool> SpinFunctionHelper::spin_flag_;
 
 static void* JoinFn(void* arg) {
   return reinterpret_cast<void*>(pthread_join(reinterpret_cast<pthread_t>(arg), NULL));
@@ -419,6 +416,8 @@
   pthread_t t1;
   ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
   ASSERT_EQ(0, pthread_setname_np(t1, "short 2"));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t1, nullptr));
 }
 
 TEST(pthread, pthread_setname_np__no_such_thread) {
@@ -469,6 +468,8 @@
   ASSERT_EQ(0, pthread_getcpuclockid(t, &c));
   timespec ts;
   ASSERT_EQ(0, clock_gettime(c, &ts));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t, nullptr));
 }
 
 TEST(pthread, pthread_getcpuclockid__no_such_thread) {
@@ -537,7 +538,7 @@
   // http://b/11693195 --- pthread_join could return before the thread had actually exited.
   // If the joiner unmapped the thread's stack, that could lead to SIGSEGV in the thread.
   for (size_t i = 0; i < 1024; ++i) {
-    size_t stack_size = 64*1024;
+    size_t stack_size = 640*1024;
     void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 
     pthread_attr_t a;
@@ -719,58 +720,47 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&l));
 }
 
-static void WaitUntilThreadSleep(std::atomic<pid_t>& pid) {
-  while (pid == 0) {
-    usleep(1000);
-  }
-  std::string filename = android::base::StringPrintf("/proc/%d/stat", pid.load());
-  std::regex regex {R"(\s+S\s+)"};
-
-  while (true) {
-    std::string content;
-    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
-    if (std::regex_search(content, regex)) {
-      break;
-    }
-    usleep(1000);
-  }
-}
-
 struct RwlockWakeupHelperArg {
   pthread_rwlock_t lock;
   enum Progress {
     LOCK_INITIALIZED,
     LOCK_WAITING,
     LOCK_RELEASED,
-    LOCK_ACCESSED
+    LOCK_ACCESSED,
+    LOCK_TIMEDOUT,
   };
   std::atomic<Progress> progress;
   std::atomic<pid_t> tid;
+  std::function<int (pthread_rwlock_t*)> trylock_function;
+  std::function<int (pthread_rwlock_t*)> lock_function;
+  std::function<int (pthread_rwlock_t*, const timespec*)> timed_lock_function;
 };
 
-static void pthread_rwlock_reader_wakeup_writer_helper(RwlockWakeupHelperArg* arg) {
+static void pthread_rwlock_wakeup_helper(RwlockWakeupHelperArg* arg) {
   arg->tid = gettid();
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
   arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
 
-  ASSERT_EQ(EBUSY, pthread_rwlock_trywrlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_wrlock(&arg->lock));
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+  ASSERT_EQ(0, arg->lock_function(&arg->lock));
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
   ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
 
   arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
 }
 
-TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+static void test_pthread_rwlock_reader_wakeup_writer(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
   ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
   wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
   wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_trywrlock;
+  wakeup_arg.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_reader_wakeup_writer_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -782,29 +772,31 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
-static void pthread_rwlock_writer_wakeup_reader_helper(RwlockWakeupHelperArg* arg) {
-  arg->tid = gettid();
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
-  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
-
-  ASSERT_EQ(EBUSY, pthread_rwlock_tryrdlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_rdlock(&arg->lock));
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
-  ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
-
-  arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
+TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+  test_pthread_rwlock_reader_wakeup_writer(pthread_rwlock_wrlock);
 }
 
-TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_reader_wakeup_writer([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedwrlock(lock, &ts);
+  });
+}
+
+static void test_pthread_rwlock_writer_wakeup_reader(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
   ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
   wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
   wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_tryrdlock;
+  wakeup_arg.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_writer_wakeup_reader_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -816,6 +808,85 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
+TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+  test_pthread_rwlock_writer_wakeup_reader(pthread_rwlock_rdlock);
+}
+
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_writer_wakeup_reader([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedrdlock(lock, &ts);
+  });
+}
+
+static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
+  arg->tid = gettid();
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
+  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
+
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, arg->progress);
+  arg->progress = RwlockWakeupHelperArg::LOCK_TIMEDOUT;
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+  RwlockWakeupHelperArg wakeup_arg;
+  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+  ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
+  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+  wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_tryrdlock;
+  wakeup_arg.timed_lock_function = pthread_rwlock_timedrdlock;
+
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+  WaitUntilThreadSleep(wakeup_arg.tid);
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
+TEST(pthread, pthread_rwlock_timedwrlock_timeout) {
+  RwlockWakeupHelperArg wakeup_arg;
+  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+  ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
+  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+  wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_trywrlock;
+  wakeup_arg.timed_lock_function = pthread_rwlock_timedwrlock;
+
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+  WaitUntilThreadSleep(wakeup_arg.tid);
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
 class RwlockKindTestHelper {
  private:
   struct ThreadArg {
@@ -1060,36 +1131,44 @@
   };
   std::atomic<Progress> progress;
   pthread_t thread;
+  std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function;
 
  protected:
-  virtual void SetUp() {
-    ASSERT_EQ(0, pthread_mutex_init(&mutex, NULL));
-    ASSERT_EQ(0, pthread_cond_init(&cond, NULL));
+  void SetUp() override {
+    ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+  }
+
+  void InitCond(clockid_t clock=CLOCK_REALTIME) {
+    pthread_condattr_t attr;
+    ASSERT_EQ(0, pthread_condattr_init(&attr));
+    ASSERT_EQ(0, pthread_condattr_setclock(&attr, clock));
+    ASSERT_EQ(0, pthread_cond_init(&cond, &attr));
+    ASSERT_EQ(0, pthread_condattr_destroy(&attr));
+  }
+
+  void StartWaitingThread(std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function) {
     progress = INITIALIZED;
-    ASSERT_EQ(0,
-      pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
-  }
-
-  virtual void TearDown() {
-    ASSERT_EQ(0, pthread_join(thread, NULL));
-    ASSERT_EQ(FINISHED, progress);
-    ASSERT_EQ(0, pthread_cond_destroy(&cond));
-    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
-  }
-
-  void SleepUntilProgress(Progress expected_progress) {
-    while (progress != expected_progress) {
+    this->wait_function = wait_function;
+    ASSERT_EQ(0, pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
+    while (progress != WAITING) {
       usleep(5000);
     }
     usleep(5000);
   }
 
+  void TearDown() override {
+    ASSERT_EQ(0, pthread_join(thread, nullptr));
+    ASSERT_EQ(FINISHED, progress);
+    ASSERT_EQ(0, pthread_cond_destroy(&cond));
+    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
+  }
+
  private:
   static void WaitThreadFn(pthread_CondWakeupTest* test) {
     ASSERT_EQ(0, pthread_mutex_lock(&test->mutex));
     test->progress = WAITING;
     while (test->progress == WAITING) {
-      ASSERT_EQ(0, pthread_cond_wait(&test->cond, &test->mutex));
+      ASSERT_EQ(0, test->wait_function(&test->cond, &test->mutex));
     }
     ASSERT_EQ(SIGNALED, test->progress);
     test->progress = FINISHED;
@@ -1097,39 +1176,65 @@
   }
 };
 
-TEST_F(pthread_CondWakeupTest, signal) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, signal_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_signal(&cond);
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
 }
 
-TEST_F(pthread_CondWakeupTest, broadcast) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, broadcast_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_broadcast(&cond);
+  ASSERT_EQ(0, pthread_cond_broadcast(&cond));
 }
 
-TEST(pthread, pthread_mutex_timedlock) {
-  pthread_mutex_t m;
-  ASSERT_EQ(0, pthread_mutex_init(&m, NULL));
-
-  // If the mutex is already locked, pthread_mutex_timedlock should time out.
-  ASSERT_EQ(0, pthread_mutex_lock(&m));
-
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_REALTIME) {
+  InitCond(CLOCK_REALTIME);
   timespec ts;
   ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
-  // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC) {
+  InitCond(CLOCK_MONOTONIC);
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
+TEST(pthread, pthread_cond_timedwait_timeout) {
+  pthread_mutex_t mutex;
+  ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+  pthread_cond_t cond;
+  ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
+  ASSERT_EQ(0, pthread_mutex_lock(&mutex));
+  timespec ts;
   ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
-
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
-  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(0, pthread_mutex_unlock(&mutex));
 }
 
 TEST(pthread, pthread_attr_getstack__main_thread) {
@@ -1155,31 +1260,30 @@
   // The two methods of asking for the stack size should agree.
   EXPECT_EQ(stack_size, stack_size2);
 
+#if defined(__BIONIC__)
   // What does /proc/self/maps' [stack] line say?
   void* maps_stack_hi = NULL;
-  FILE* fp = fopen("/proc/self/maps", "r");
-  ASSERT_TRUE(fp != NULL);
-  char line[BUFSIZ];
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    uintptr_t lo, hi;
-    char name[10];
-    sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d %10s", &lo, &hi, name);
-    if (strcmp(name, "[stack]") == 0) {
-      maps_stack_hi = reinterpret_cast<void*>(hi);
+  std::vector<map_record> maps;
+  ASSERT_TRUE(Maps::parse_maps(&maps));
+  for (const auto& map : maps) {
+    if (map.pathname == "[stack]") {
+      maps_stack_hi = reinterpret_cast<void*>(map.addr_end);
       break;
     }
   }
-  fclose(fp);
+
+  // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size.
+  // Remember that the stack grows down (and is mapped in on demand), so the low address of the
+  // region isn't very interesting.
+  EXPECT_EQ(maps_stack_hi, reinterpret_cast<uint8_t*>(stack_base) + stack_size);
 
   // The stack size should correspond to RLIMIT_STACK.
   rlimit rl;
   ASSERT_EQ(0, getrlimit(RLIMIT_STACK, &rl));
   uint64_t original_rlim_cur = rl.rlim_cur;
-#if defined(__BIONIC__)
   if (rl.rlim_cur == RLIM_INFINITY) {
     rl.rlim_cur = 8 * 1024 * 1024; // Bionic reports unlimited stacks as 8MiB.
   }
-#endif
   EXPECT_EQ(rl.rlim_cur, stack_size);
 
   auto guard = make_scope_guard([&rl, original_rlim_cur]() {
@@ -1187,11 +1291,6 @@
     ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
   });
 
-  // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size.
-  // Remember that the stack grows down (and is mapped in on demand), so the low address of the
-  // region isn't very interesting.
-  EXPECT_EQ(maps_stack_hi, reinterpret_cast<uint8_t*>(stack_base) + stack_size);
-
   //
   // What if RLIMIT_STACK is smaller than the stack's current extent?
   //
@@ -1219,6 +1318,68 @@
 
   EXPECT_EQ(stack_size, stack_size2);
   ASSERT_EQ(6666U, stack_size);
+#endif
+}
+
+struct GetStackSignalHandlerArg {
+  volatile bool done;
+  void* signal_handler_sp;
+  void* main_stack_base;
+  size_t main_stack_size;
+};
+
+static GetStackSignalHandlerArg getstack_signal_handler_arg;
+
+static void getstack_signal_handler(int sig) {
+  ASSERT_EQ(SIGUSR1, sig);
+  // Use sleep() to make current thread be switched out by the kernel to provoke the error.
+  sleep(1);
+  pthread_attr_t attr;
+  ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attr));
+  void* stack_base;
+  size_t stack_size;
+  ASSERT_EQ(0, pthread_attr_getstack(&attr, &stack_base, &stack_size));
+  getstack_signal_handler_arg.signal_handler_sp = &attr;
+  getstack_signal_handler_arg.main_stack_base = stack_base;
+  getstack_signal_handler_arg.main_stack_size = stack_size;
+  getstack_signal_handler_arg.done = true;
+}
+
+// The previous code obtained the main thread's stack by reading the entry in
+// /proc/self/task/<pid>/maps that was labeled [stack]. Unfortunately, on x86/x86_64, the kernel
+// relies on sp0 in task state segment(tss) to label the stack map with [stack]. If the kernel
+// switches a process while the main thread is in an alternate stack, then the kernel will label
+// the wrong map with [stack]. This test verifies that when the above situation happens, the main
+// thread's stack is found correctly.
+TEST(pthread, pthread_attr_getstack_in_signal_handler) {
+  const size_t sig_stack_size = 16 * 1024;
+  void* sig_stack = mmap(NULL, sig_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+                         -1, 0);
+  ASSERT_NE(MAP_FAILED, sig_stack);
+  stack_t ss;
+  ss.ss_sp = sig_stack;
+  ss.ss_size = sig_stack_size;
+  ss.ss_flags = 0;
+  stack_t oss;
+  ASSERT_EQ(0, sigaltstack(&ss, &oss));
+
+  ScopedSignalHandler handler(SIGUSR1, getstack_signal_handler, SA_ONSTACK);
+  getstack_signal_handler_arg.done = false;
+  kill(getpid(), SIGUSR1);
+  ASSERT_EQ(true, getstack_signal_handler_arg.done);
+
+  // Verify if the stack used by the signal handler is the alternate stack just registered.
+  ASSERT_LE(sig_stack, getstack_signal_handler_arg.signal_handler_sp);
+  ASSERT_GE(reinterpret_cast<char*>(sig_stack) + sig_stack_size,
+            getstack_signal_handler_arg.signal_handler_sp);
+
+  // Verify if the main thread's stack got in the signal handler is correct.
+  ASSERT_LE(getstack_signal_handler_arg.main_stack_base, &ss);
+  ASSERT_GE(reinterpret_cast<char*>(getstack_signal_handler_arg.main_stack_base) +
+            getstack_signal_handler_arg.main_stack_size, reinterpret_cast<void*>(&ss));
+
+  ASSERT_EQ(0, sigaltstack(&oss, nullptr));
+  ASSERT_EQ(0, munmap(sig_stack, sig_stack_size));
 }
 
 static void pthread_attr_getstack_18908062_helper(void*) {
@@ -1245,11 +1406,14 @@
 }
 
 #if defined(__BIONIC__)
-static pthread_mutex_t gettid_mutex;
+static pthread_mutex_t pthread_gettid_np_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 static void* pthread_gettid_np_helper(void* arg) {
-  pthread_mutex_lock(&gettid_mutex);
   *reinterpret_cast<pid_t*>(arg) = gettid();
-  pthread_mutex_unlock(&gettid_mutex);
+
+  // Wait for our parent to call pthread_gettid_np on us before exiting.
+  pthread_mutex_lock(&pthread_gettid_np_mutex);
+  pthread_mutex_unlock(&pthread_gettid_np_mutex);
   return NULL;
 }
 #endif
@@ -1258,17 +1422,19 @@
 #if defined(__BIONIC__)
   ASSERT_EQ(gettid(), pthread_gettid_np(pthread_self()));
 
+  // Ensure the other thread doesn't exit until after we've called
+  // pthread_gettid_np on it.
+  pthread_mutex_lock(&pthread_gettid_np_mutex);
+
   pid_t t_gettid_result;
   pthread_t t;
-  pthread_mutex_init(&gettid_mutex, NULL);
-  pthread_mutex_lock(&gettid_mutex);
   pthread_create(&t, NULL, pthread_gettid_np_helper, &t_gettid_result);
 
   pid_t t_pthread_gettid_np_result = pthread_gettid_np(t);
-  pthread_mutex_unlock(&gettid_mutex);
 
+  // Release the other thread and wait for it to exit.
+  pthread_mutex_unlock(&pthread_gettid_np_mutex);
   pthread_join(t, NULL);
-  pthread_mutex_destroy(&gettid_mutex);
 
   ASSERT_EQ(t_gettid_result, t_pthread_gettid_np_result);
 #else
@@ -1370,6 +1536,9 @@
 
   ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
+  ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
+  ASSERT_EQ(EBUSY, pthread_mutex_trylock(&m.lock));
+  ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
 }
 
 TEST(pthread, pthread_mutex_lock_ERRORCHECK) {
@@ -1392,6 +1561,8 @@
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
+  ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
+  ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(EPERM, pthread_mutex_unlock(&m.lock));
 }
@@ -1489,6 +1660,35 @@
 #endif
 }
 
+TEST(pthread, pthread_mutex_timedlock) {
+  pthread_mutex_t m;
+  ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
+
+  // If the mutex is already locked, pthread_mutex_timedlock should time out.
+  ASSERT_EQ(0, pthread_mutex_lock(&m));
+
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+
+  // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
+  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
+
+  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+}
+
 class StrictAlignmentAllocator {
  public:
   void* allocate(size_t size, size_t alignment) {
@@ -1501,8 +1701,8 @@
   }
 
   ~StrictAlignmentAllocator() {
-    for (auto& p : allocated_array) {
-      delete [] p;
+    for (const auto& p : allocated_array) {
+      delete[] p;
     }
   }
 
@@ -1602,3 +1802,128 @@
   kill(getpid(), SIGUSR1);
   ASSERT_TRUE(signal_handler_on_altstack_done);
 }
+
+TEST(pthread, pthread_barrierattr_smoke) {
+  pthread_barrierattr_t attr;
+  ASSERT_EQ(0, pthread_barrierattr_init(&attr));
+  int pshared;
+  ASSERT_EQ(0, pthread_barrierattr_getpshared(&attr, &pshared));
+  ASSERT_EQ(PTHREAD_PROCESS_PRIVATE, pshared);
+  ASSERT_EQ(0, pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
+  ASSERT_EQ(0, pthread_barrierattr_getpshared(&attr, &pshared));
+  ASSERT_EQ(PTHREAD_PROCESS_SHARED, pshared);
+  ASSERT_EQ(0, pthread_barrierattr_destroy(&attr));
+}
+
+struct BarrierTestHelperArg {
+  std::atomic<pid_t> tid;
+  pthread_barrier_t* barrier;
+  size_t iteration_count;
+};
+
+static void BarrierTestHelper(BarrierTestHelperArg* arg) {
+  arg->tid = gettid();
+  for (size_t i = 0; i < arg->iteration_count; ++i) {
+    ASSERT_EQ(0, pthread_barrier_wait(arg->barrier));
+  }
+}
+
+TEST(pthread, pthread_barrier_smoke) {
+  const size_t BARRIER_ITERATION_COUNT = 10;
+  const size_t BARRIER_THREAD_COUNT = 10;
+  pthread_barrier_t barrier;
+  ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, BARRIER_THREAD_COUNT + 1));
+  std::vector<pthread_t> threads(BARRIER_THREAD_COUNT);
+  std::vector<BarrierTestHelperArg> args(threads.size());
+  for (size_t i = 0; i < threads.size(); ++i) {
+    args[i].tid = 0;
+    args[i].barrier = &barrier;
+    args[i].iteration_count = BARRIER_ITERATION_COUNT;
+    ASSERT_EQ(0, pthread_create(&threads[i], nullptr,
+                                reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &args[i]));
+  }
+  for (size_t iteration = 0; iteration < BARRIER_ITERATION_COUNT; ++iteration) {
+    for (size_t i = 0; i < threads.size(); ++i) {
+      WaitUntilThreadSleep(args[i].tid);
+    }
+    ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));
+  }
+  for (size_t i = 0; i < threads.size(); ++i) {
+    ASSERT_EQ(0, pthread_join(threads[i], nullptr));
+  }
+  ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
+}
+
+TEST(pthread, pthread_barrier_destroy) {
+  pthread_barrier_t barrier;
+  ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, 2));
+  pthread_t thread;
+  BarrierTestHelperArg arg;
+  arg.tid = 0;
+  arg.barrier = &barrier;
+  arg.iteration_count = 1;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                              reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &arg));
+  WaitUntilThreadSleep(arg.tid);
+  ASSERT_EQ(EBUSY, pthread_barrier_destroy(&barrier));
+  ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));
+  // Verify if the barrier can be destroyed directly after pthread_barrier_wait().
+  ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+#if defined(__BIONIC__)
+  ASSERT_EQ(EINVAL, pthread_barrier_destroy(&barrier));
+#endif
+}
+
+struct BarrierOrderingTestHelperArg {
+  pthread_barrier_t* barrier;
+  size_t* array;
+  size_t array_length;
+  size_t id;
+};
+
+void BarrierOrderingTestHelper(BarrierOrderingTestHelperArg* arg) {
+  const size_t ITERATION_COUNT = 10000;
+  for (size_t i = 1; i <= ITERATION_COUNT; ++i) {
+    arg->array[arg->id] = i;
+    int result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
+    for (size_t j = 0; j < arg->array_length; ++j) {
+      ASSERT_EQ(i, arg->array[j]);
+    }
+    result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
+  }
+}
+
+TEST(pthread, pthread_barrier_check_ordering) {
+  const size_t THREAD_COUNT = 4;
+  pthread_barrier_t barrier;
+  ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, THREAD_COUNT));
+  size_t array[THREAD_COUNT];
+  std::vector<pthread_t> threads(THREAD_COUNT);
+  std::vector<BarrierOrderingTestHelperArg> args(THREAD_COUNT);
+  for (size_t i = 0; i < THREAD_COUNT; ++i) {
+    args[i].barrier = &barrier;
+    args[i].array = array;
+    args[i].array_length = THREAD_COUNT;
+    args[i].id = i;
+    ASSERT_EQ(0, pthread_create(&threads[i], nullptr,
+                                reinterpret_cast<void* (*)(void*)>(BarrierOrderingTestHelper),
+                                &args[i]));
+  }
+  for (size_t i = 0; i < THREAD_COUNT; ++i) {
+    ASSERT_EQ(0, pthread_join(threads[i], nullptr));
+  }
+}
+
+TEST(pthread, pthread_spinlock_smoke) {
+  pthread_spinlock_t lock;
+  ASSERT_EQ(0, pthread_spin_init(&lock, 0));
+  ASSERT_EQ(0, pthread_spin_trylock(&lock));
+  ASSERT_EQ(0, pthread_spin_unlock(&lock));
+  ASSERT_EQ(0, pthread_spin_lock(&lock));
+  ASSERT_EQ(EBUSY, pthread_spin_trylock(&lock));
+  ASSERT_EQ(0, pthread_spin_unlock(&lock));
+  ASSERT_EQ(0, pthread_spin_destroy(&lock));
+}
diff --git a/tests/regex_test.cpp b/tests/regex_test.cpp
index d026221..4a4409e 100644
--- a/tests/regex_test.cpp
+++ b/tests/regex_test.cpp
@@ -36,3 +36,13 @@
 
   regfree(&re);
 }
+
+TEST(regex, match_offsets) {
+  regex_t re;
+  regmatch_t matches[1];
+  ASSERT_EQ(0, regcomp(&re, "b", 0));
+  ASSERT_EQ(0, regexec(&re, "abc", 1, matches, 0));
+  ASSERT_EQ(1, matches[0].rm_so);
+  ASSERT_EQ(2, matches[0].rm_eo);
+  regfree(&re);
+}
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index e517f81..84343da 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -117,10 +117,27 @@
   ts.tv_nsec = -1;
   ASSERT_EQ(-1, sem_timedwait(&s, &ts));
   ASSERT_EQ(EINVAL, errno);
+  errno = 0;
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(EINVAL, errno);
+
+  errno = 0;
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(ETIMEDOUT, errno);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
 
+TEST(semaphore_DeathTest, sem_timedwait_null_timeout) {
+  sem_t s;
+  ASSERT_EQ(0, sem_init(&s, 0, 0));
+
+  ASSERT_EXIT(sem_timedwait(&s, nullptr), testing::KilledBySignal(SIGSEGV), "");
+}
+
 TEST(semaphore, sem_getvalue) {
   sem_t s;
   ASSERT_EQ(0, sem_init(&s, 0, 0));
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index a3b5885..c75ab51 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -212,3 +212,38 @@
     CHECK_FREGS;
   }
 }
+
+#if defined(__arm__)
+#define __JB_SIGFLAG 0
+#elif defined(__aarch64__)
+#define __JB_SIGFLAG 0
+#elif defined(__i386__)
+#define __JB_SIGFLAG 7
+#elif defined(__x86_64)
+#define __JB_SIGFLAG 8
+#elif defined(__mips__) && defined(__LP64__)
+#define __JB_SIGFLAG 1
+#elif defined(__mips__)
+#define __JB_SIGFLAG 2
+#endif
+
+TEST(setjmp, setjmp_cookie) {
+  jmp_buf jb;
+  int value = setjmp(jb);
+  ASSERT_EQ(0, value);
+
+#if defined(__mips__) && !defined(__LP64__)
+  // round address to 8-byte boundry
+  uintptr_t jb_aligned = reinterpret_cast<uintptr_t>(jb) & ~7L;
+  long* sigflag = reinterpret_cast<long*>(jb_aligned) + __JB_SIGFLAG;
+#else
+  long* sigflag = reinterpret_cast<long*>(jb) + __JB_SIGFLAG;
+#endif
+
+  // Make sure there's actually a cookie.
+  EXPECT_NE(0, *sigflag & ~1);
+
+  // Wipe it out
+  *sigflag &= 1;
+  EXPECT_DEATH(longjmp(jb, 0), "");
+}
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index c95cbbd..7872567 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -30,6 +30,7 @@
 #include <locale.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 TEST(stdio_ext, __fbufsize) {
   FILE* fp = fopen("/proc/version", "r");
@@ -140,3 +141,24 @@
   ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY));
   fclose(fp);
 }
+
+static void LockingByCallerHelper(std::atomic<pid_t>* pid) {
+  *pid = gettid();
+  flockfile(stdout);
+  funlockfile(stdout);
+}
+
+TEST(stdio_ext, __fsetlocking_BYCALLER) {
+  // Check if users can use flockfile/funlockfile to protect stdio operations.
+  int old_state = __fsetlocking(stdout, FSETLOCKING_BYCALLER);
+  flockfile(stdout);
+  pthread_t thread;
+  std::atomic<pid_t> pid(0);
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                              reinterpret_cast<void* (*)(void*)>(LockingByCallerHelper), &pid));
+  WaitUntilThreadSleep(pid);
+  funlockfile(stdout);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  __fsetlocking(stdout, old_state);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 62677cd..afb1511 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1012,3 +1012,39 @@
 
   fclose(fp);
 }
+
+// https://code.google.com/p/android/issues/detail?id=184847
+TEST(stdio, fread_EOF_184847) {
+  TemporaryFile tf;
+  char buf[6] = {0};
+
+  FILE* fw = fopen(tf.filename, "w");
+  ASSERT_TRUE(fw != nullptr);
+
+  FILE* fr = fopen(tf.filename, "r");
+  ASSERT_TRUE(fr != nullptr);
+
+  fwrite("a", 1, 1, fw);
+  fflush(fw);
+  ASSERT_EQ(1U, fread(buf, 1, 1, fr));
+  ASSERT_STREQ("a", buf);
+
+  // 'fr' is now at EOF.
+  ASSERT_EQ(0U, fread(buf, 1, 1, fr));
+  ASSERT_TRUE(feof(fr));
+
+  // Write some more...
+  fwrite("z", 1, 1, fw);
+  fflush(fw);
+
+  // ...and check that we can read it back.
+  // (BSD thinks that once a stream has hit EOF, it must always return EOF. SysV disagrees.)
+  ASSERT_EQ(1U, fread(buf, 1, 1, fr));
+  ASSERT_STREQ("z", buf);
+
+  // But now we're done.
+  ASSERT_EQ(0U, fread(buf, 1, 1, fr));
+
+  fclose(fr);
+  fclose(fw);
+}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 1d63c76..842e1c7 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 #include <malloc.h>
 #include <math.h>
+#include <stdint.h>
 
 #include "buffer_tests.h"
 
@@ -453,6 +454,13 @@
   }
 }
 
+TEST(string, strchrnul) {
+  const char* s = "01234222";
+  EXPECT_TRUE(strchrnul(s, '2') == &s[2]);
+  EXPECT_TRUE(strchrnul(s, '8') == (s + strlen(s)));
+  EXPECT_TRUE(strchrnul(s, '\0') == (s + strlen(s)));
+}
+
 TEST(string, strcmp) {
   StringTestState<char> state(SMALL);
   for (size_t i = 1; i < state.n; i++) {
@@ -1166,7 +1174,7 @@
   return 1;
 }
 
-#define STRCAT_DST_LEN  128
+#define STRCAT_DST_LEN  64
 
 static void DoStrcatTest(uint8_t* src, uint8_t* dst, size_t len) {
   if (len >= 1) {
@@ -1181,7 +1189,7 @@
       int value2 = 32 + (value + 2) % 96;
       memset(cmp_buf, value2, sizeof(cmp_buf));
 
-      for (size_t i = 1; i <= STRCAT_DST_LEN; i++) {
+      for (size_t i = 1; i <= STRCAT_DST_LEN;) {
         memset(dst, value2, i-1);
         memset(dst+i-1, 0, len-i);
         src[len-i] = '\0';
@@ -1189,6 +1197,13 @@
                                                          reinterpret_cast<char*>(src))));
         ASSERT_TRUE(memcmp(dst, cmp_buf, i-1) == 0);
         ASSERT_TRUE(memcmp(src, dst+i-1, len-i+1) == 0);
+        // This is an expensive loop, so don't loop through every value,
+        // get to a certain size and then start doubling.
+        if (i < 16) {
+          i++;
+        } else {
+          i <<= 1;
+        }
       }
     } else {
       dst[0] = '\0';
@@ -1221,7 +1236,7 @@
       int value2 = 32 + (value + 2) % 96;
       memset(cmp_buf, value2, sizeof(cmp_buf));
 
-      for (size_t i = 1; i <= STRCAT_DST_LEN; i++) {
+      for (size_t i = 1; i <= STRCAT_DST_LEN;) {
         memset(dst, value2, i-1);
         memset(dst+i-1, 0, len-i);
         src[len-i] = '\0';
@@ -1229,6 +1244,13 @@
                                  reinterpret_cast<char*>(src), len));
         ASSERT_TRUE(memcmp(dst, cmp_buf, i-1) == 0);
         ASSERT_TRUE(memcmp(src, dst+i-1, len-i+1) == 0);
+        // This is an expensive loop, so don't loop through every value,
+        // get to a certain size and then start doubling.
+        if (i < 16) {
+          i++;
+        } else {
+          i <<= 1;
+        }
       }
     } else {
       dst[0] = '\0';
@@ -1396,6 +1418,10 @@
   delete[] heap_src;
 }
 
+TEST(string, strnlen_74741) {
+  ASSERT_EQ(4U, strnlen("test", SIZE_MAX));
+}
+
 TEST(string, mempcpy) {
   char dst[6];
   ASSERT_EQ(&dst[4], reinterpret_cast<char*>(mempcpy(dst, "hello", 4)));
diff --git a/tests/stubs_test.cpp b/tests/stubs_test.cpp
index 2d1bdee..c81ca58 100644
--- a/tests/stubs_test.cpp
+++ b/tests/stubs_test.cpp
@@ -122,6 +122,14 @@
   check_get_passwd("radio", 1001, TYPE_SYSTEM);
 }
 
+TEST(getpwnam, oem_id_0) {
+  check_get_passwd("oem_0", 5000, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, oem_id_999) {
+  check_get_passwd("oem_999", 5999, TYPE_SYSTEM);
+}
+
 TEST(getpwnam, app_id_nobody) {
   check_get_passwd("nobody", 9999, TYPE_SYSTEM);
 }
@@ -247,6 +255,14 @@
   check_get_group("radio", 1001);
 }
 
+TEST(getgrnam, oem_id_0) {
+  check_get_group("oem_0", 5000);
+}
+
+TEST(getgrnam, oem_id_999) {
+  check_get_group("oem_999", 5999);
+}
+
 TEST(getgrnam, app_id_nobody) {
   check_get_group("nobody", 9999);
 }
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index b0e40fd..ddb6c77 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <sys/mman.h>
+#include <sys/user.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -215,3 +216,19 @@
 
   ASSERT_EQ(0, munmap(map, pagesize));
 }
+
+TEST(sys_mman, mremap) {
+  ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
+}
+
+const size_t huge = size_t(PTRDIFF_MAX) + 1;
+
+TEST(sys_mman, mmap_PTRDIFF_MAX) {
+  ASSERT_EQ(MAP_FAILED, mmap(nullptr, huge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+}
+
+TEST(sys_mman, mremap_PTRDIFF_MAX) {
+  void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, huge, MREMAP_MAYMOVE));
+}
diff --git a/tests/sys_personality_test.cpp b/tests/sys_personality_test.cpp
index 2dfaa65..6bd00ef 100644
--- a/tests/sys_personality_test.cpp
+++ b/tests/sys_personality_test.cpp
@@ -21,7 +21,9 @@
 TEST(sys_personality, current_persona) {
   int persona = personality(0xffffffff) & PER_MASK;
 #if defined(__BIONIC__)
-#if defined(__LP64__)
+// When personality syscall is executed on mips64, for a 32bit process
+// sys_32_personality() is called, which converts PER_LINUX32 -> PER_LINUX
+#if defined(__LP64__) || (__mips==32 && __mips_isa_rev>2)
   ASSERT_EQ(PER_LINUX, persona);
 #else
   ASSERT_EQ(PER_LINUX32, persona);
diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
new file mode 100644
index 0000000..5a563c1
--- /dev/null
+++ b/tests/sys_prctl_test.cpp
@@ -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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include "private/bionic_prctl.h"
+
+// http://b/20017123.
+TEST(sys_prctl, bug_20017123) {
+#if defined(__ANDROID__)
+  size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
+  void* p = mmap(NULL, page_size * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(MAP_FAILED, p);
+  ASSERT_EQ(0, mprotect(p, page_size, PROT_NONE));
+  ASSERT_NE(-1, prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, page_size * 3, "anonymous map space"));
+  volatile char* vp = reinterpret_cast<volatile char*>(p);
+  // Below memory access causes SEGV if the memory map is screwed up.
+  *(vp + page_size) = 0;
+  ASSERT_EQ(0, munmap(p, page_size * 3));
+#else
+  GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
+#endif
+}
diff --git a/tests/sys_resource_test.cpp b/tests/sys_resource_test.cpp
index 8cefc65..0b6b6ef 100644
--- a/tests/sys_resource_test.cpp
+++ b/tests/sys_resource_test.cpp
@@ -33,7 +33,8 @@
   virtual void SetUp() {
     ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
     ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
-    ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
+    ASSERT_EQ(0, prlimit(0, RLIMIT_CORE, nullptr, &pr_l32_));
+    ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, nullptr, &pr_l64_));
   }
 
   void CheckResourceLimits();
@@ -41,21 +42,28 @@
  protected:
   rlimit l32_;
   rlimit64 l64_;
+  rlimit pr_l32_;
   rlimit64 pr_l64_;
 };
 
 void SysResourceTest::CheckResourceLimits() {
   ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
   ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
+  ASSERT_EQ(0, prlimit(0, RLIMIT_CORE, nullptr, &pr_l32_));
+  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, nullptr, &pr_l64_));
+
+  ASSERT_EQ(l32_.rlim_cur, pr_l32_.rlim_cur);
   ASSERT_EQ(l64_.rlim_cur, pr_l64_.rlim_cur);
+
   if (l64_.rlim_cur == RLIM64_INFINITY) {
     ASSERT_EQ(RLIM_INFINITY, l32_.rlim_cur);
   } else {
     ASSERT_EQ(l64_.rlim_cur, l32_.rlim_cur);
   }
 
+  ASSERT_EQ(l32_.rlim_max, pr_l32_.rlim_max);
   ASSERT_EQ(l64_.rlim_max, pr_l64_.rlim_max);
+
   if (l64_.rlim_max == RLIM64_INFINITY) {
     ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max);
   } else {
@@ -88,13 +96,16 @@
   ASSERT_EQ(456U, l64_.rlim_cur);
 }
 
-TEST_F(SysResourceTest, prlimit64) {
-  pr_l64_.rlim_cur = pr_l64_.rlim_max;
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, NULL));
+TEST_F(SysResourceTest, prlimit) {
+  pr_l32_.rlim_cur = pr_l32_.rlim_max;
+  ASSERT_EQ(0, prlimit(0, RLIMIT_CORE, &pr_l32_, nullptr));
   CheckResourceLimits();
-  ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
+  ASSERT_EQ(pr_l32_.rlim_max, pr_l32_.rlim_cur);
 }
 
-TEST_F(SysResourceTest, prlimit) {
-  // prlimit is prlimit64 on LP64 and unimplemented on 32-bit. So we only test prlimit64.
+TEST_F(SysResourceTest, prlimit64) {
+  pr_l64_.rlim_cur = pr_l64_.rlim_max;
+  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, nullptr));
+  CheckResourceLimits();
+  ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
 }
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index c7af8a7..569d4fb 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -18,10 +18,60 @@
 
 #include <sys/uio.h>
 
-TEST(sys_uio, process_vm_readv_ESRCH) {
+#include "TemporaryFile.h"
+
+TEST(sys_uio, readv_writev) {
+  TemporaryFile tf;
+
+  char buf1[] = "hello";
+  char buf2[] = "world";
+  iovec ios[] = { { buf1, 5 }, { buf2, 5 } };
+
+  ASSERT_EQ(10, writev(tf.fd, ios, 2));
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+
+  memset(buf1, '1', sizeof(buf1));
+  memset(buf2, '2', sizeof(buf2));
+
+  ASSERT_EQ(10, readv(tf.fd, ios, 2));
+  buf1[5] = buf2[5] = '\0';
+  ASSERT_STREQ("hello", buf1);
+  ASSERT_STREQ("world", buf2);
+}
+
+template <typename ReadFn, typename WriteFn>
+void TestPreadVPwriteV(ReadFn read_fn, WriteFn write_fn) {
+  TemporaryFile tf;
+
+  char buf[] = "world";
+  iovec ios[] = { { buf, 5 } };
+
+  ASSERT_EQ(5, write_fn(tf.fd, ios, 1, 5));
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_CUR));
+
+  strcpy(buf, "hello");
+  ASSERT_EQ(5, write_fn(tf.fd, ios, 1, 0));
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_CUR));
+
+  ASSERT_EQ(5, read_fn(tf.fd, ios, 1, 5));
+  ASSERT_STREQ("world", buf);
+  ASSERT_EQ(5, read_fn(tf.fd, ios, 1, 0));
+  ASSERT_STREQ("hello", buf);
+}
+
+TEST(sys_uio, preadv_pwritev) {
+  TestPreadVPwriteV(preadv, pwritev);
+}
+
+TEST(sys_uio, preadv64_pwritev64) {
+  TestPreadVPwriteV(preadv64, pwritev64);
+}
+
+TEST(sys_uio, process_vm_readv) {
   ASSERT_EQ(0, process_vm_readv(0, nullptr, 0, nullptr, 0, 0));
 }
 
-TEST(sys_uio, process_vm_writev_ESRCH) {
+TEST(sys_uio, process_vm_writev) {
   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
index 1842682..113ec26 100644
--- a/tests/sys_xattr_test.cpp
+++ b/tests/sys_xattr_test.cpp
@@ -80,6 +80,7 @@
   ASSERT_EQ(-1, res);
   ASSERT_EQ(EBADF, errno);
 #endif
+  close(fd);
 }
 
 TEST(sys_xattr, fsetxattr_with_opath_toosmall) {
@@ -97,4 +98,32 @@
   ASSERT_EQ(-1, res);
   ASSERT_EQ(EBADF, errno);
 #endif
+  close(fd);
+}
+
+TEST(sys_xattr, flistattr) {
+  TemporaryFile tf;
+  char buf[65536];  // 64kB is max possible xattr list size. See "man 7 xattr".
+  ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "bar", 4, 0));
+  ssize_t result = flistxattr(tf.fd, buf, sizeof(buf));
+  ASSERT_TRUE(result >= 9);
+  ASSERT_TRUE(memmem(buf, sizeof(buf), "user.foo", 9) != NULL);
+}
+
+TEST(sys_xattr, flistattr_opath) {
+  TemporaryFile tf;
+  char buf[65536];  // 64kB is max possible xattr list size. See "man 7 xattr".
+  ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "bar", 4, 0));
+  int fd = open(tf.filename, O_PATH);
+  ASSERT_NE(-1, fd);
+  ssize_t res = flistxattr(fd, buf, sizeof(buf));
+#if defined(__BIONIC__)
+  ASSERT_TRUE(res >= 9);
+  ASSERT_TRUE(static_cast<size_t>(res) <= sizeof(buf));
+  ASSERT_TRUE(memmem(buf, res, "user.foo", 9) != NULL);
+#else
+  ASSERT_EQ(-1, res);
+  ASSERT_EQ(EBADF, errno);
+#endif
+  close(fd);
 }
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index c7bfee6..09eac3f 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -41,9 +41,6 @@
             return;
         }
 
-        old_pa = __system_property_area__;
-        __system_property_area__ = NULL;
-
         pa_dirname = dirname;
         pa_filename = pa_dirname + "/__properties__";
 
@@ -57,9 +54,8 @@
             return;
         }
 
-        __system_property_area__ = old_pa;
-
         __system_property_set_filename(PROP_FILENAME);
+        __system_properties_init();
         unlink(pa_filename.c_str());
         rmdir(pa_dirname.c_str());
     }
@@ -68,7 +64,6 @@
 private:
     std::string pa_dirname;
     std::string pa_filename;
-    void *old_pa;
 };
 
 static void foreach_test_callback(const prop_info *pi, void* cookie) {
diff --git a/tests/thread_local_test.cpp b/tests/thread_local_test.cpp
new file mode 100644
index 0000000..1422ed2
--- /dev/null
+++ b/tests/thread_local_test.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+
+#if defined(__GNUC__) && !defined(__clang__) && \
+    (defined(__arm__) || defined(__aarch64__))
+// Gcc has a bug with -O -fdata-section for the arm target: http://b/22772147.
+// Until that bug is fixed, disable optimization since
+// it is not essential for this test.
+#pragma GCC optimize("-O0")
+#endif
+
+__thread int local_var = 100;
+int shared_var = 200;
+
+static void reset_vars() {
+  local_var = 1000;
+  shared_var = 2000;
+  // local_var should be reset by threads
+}
+
+typedef void* (*MyThread)(void*);
+
+static void* inc_shared_var(void* p) {
+  int *data = reinterpret_cast<int*>(p);
+  shared_var++;
+  *data = shared_var;
+  return nullptr;
+}
+
+static void* inc_local_var(void* p) {
+  int *data = reinterpret_cast<int*>(p);
+  local_var++;
+  *data = local_var;
+  return nullptr;
+}
+
+static int run_one_thread(MyThread foo) {
+  pthread_t t;
+  int data;
+  int error = pthread_create(&t, nullptr, foo, &data);
+  if (!error)
+      error = pthread_join(t, nullptr);
+  return error ? error : data;
+}
+
+TEST(thread_local_storage, shared) {
+  reset_vars();
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2000);
+
+  // Update shared_var, local_var remains 1000.
+  ASSERT_EQ(run_one_thread(inc_shared_var), 2001);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2001);
+
+  ASSERT_EQ(run_one_thread(inc_shared_var), 2002);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2002);
+
+  ASSERT_EQ(run_one_thread(inc_shared_var), 2003);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2003);
+}
+
+TEST(thread_local_storage, local) {
+  reset_vars();
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2000);
+
+  // When a child thread updates its own TLS variable,
+  // this thread's local_var and shared_var are not changed.
+  // TLS local_var is initialized to 100 in a thread.
+  ASSERT_EQ(run_one_thread(inc_local_var), 101);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2000);
+
+  ASSERT_EQ(run_one_thread(inc_local_var), 101);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2000);
+
+  ASSERT_EQ(run_one_thread(inc_local_var), 101);
+  ASSERT_EQ(local_var, 1000);
+  ASSERT_EQ(shared_var, 2000);
+}
+
+// Test TLS initialization of more complicated type, array of struct.
+struct Point {
+  int x, y;
+};
+
+typedef Point Triangle[3];
+
+__thread Triangle local_triangle = {{10,10}, {20,20}, {30,30}};
+Triangle shared_triangle = {{1,1}, {2,2}, {3,3}};
+
+static void reset_triangle() {
+  static const Triangle t1 = {{3,3}, {4,4}, {5,5}};
+  static const Triangle t2 = {{2,2}, {3,3}, {4,4}};
+  memcpy(local_triangle, t1, sizeof(local_triangle));
+  memcpy(shared_triangle, t2, sizeof(shared_triangle));
+}
+
+static void* move_shared_triangle(void* p) {
+  int *data = reinterpret_cast<int*>(p);
+  shared_triangle[1].y++;
+  *data = shared_triangle[1].y;
+  return nullptr;
+}
+
+static void* move_local_triangle(void* p) {
+  int *data = reinterpret_cast<int*>(p);
+  local_triangle[1].y++;
+  *data = local_triangle[1].y;
+  return nullptr;
+}
+
+TEST(thread_local_storage, shared_triangle) {
+  reset_triangle();
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 3);
+
+  // Update shared_triangle, local_triangle remains 1000.
+  ASSERT_EQ(run_one_thread(move_shared_triangle), 4);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 4);
+
+  ASSERT_EQ(run_one_thread(move_shared_triangle), 5);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 5);
+
+  ASSERT_EQ(run_one_thread(move_shared_triangle), 6);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 6);
+}
+
+TEST(thread_local_storage, local_triangle) {
+  reset_triangle();
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 3);
+
+  // Update local_triangle, parent thread's
+  // shared_triangle and local_triangle are unchanged.
+  ASSERT_EQ(run_one_thread(move_local_triangle), 21);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 3);
+
+  ASSERT_EQ(run_one_thread(move_local_triangle), 21);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 3);
+
+  ASSERT_EQ(run_one_thread(move_local_triangle), 21);
+  ASSERT_EQ(local_triangle[1].y, 4);
+  ASSERT_EQ(shared_triangle[1].y, 3);
+}
+
+// Test emutls runtime data structures and __emutls_get_address function.
+typedef unsigned int gcc_word __attribute__((mode(word)));
+typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
+struct gcc_emutls_object {  // for libgcc
+  gcc_word size;
+  gcc_word align;
+  union {
+    gcc_pointer offset;
+    void* ptr;
+  } loc;
+  void* templ;
+};
+
+typedef struct __emutls_control {  // for clang/llvm
+  size_t size;
+  size_t align;
+  union {
+    uintptr_t index;
+    void* address;
+  } object;
+  void* value;
+} __emutls_control;
+
+TEST(thread_local_storage, type_size) {
+  static_assert(sizeof(size_t) == sizeof(gcc_word),
+                "size_t != gcc_word");
+  static_assert(sizeof(uintptr_t) == sizeof(gcc_pointer),
+                "uintptr_t != gcc_pointer");
+  static_assert(sizeof(uintptr_t) == sizeof(void*),
+                "sizoeof(uintptr_t) != sizeof(void*)");
+  static_assert(sizeof(__emutls_control) == sizeof(struct gcc_emutls_object),
+                "sizeof(__emutls_control) != sizeof(struct gcc_emutls_object)");
+}
+
+extern "C" void* __emutls_get_address(__emutls_control*);
+
+TEST(thread_local_storage, init_value) {
+  char tls_value1[] = "123456789";
+  char tls_value2[] = "abcdefghi";
+  constexpr size_t num_saved_values = 10;
+  __emutls_control tls_var[num_saved_values];
+  size_t prev_index = 0;
+  void* saved_gap[num_saved_values];
+  void* saved_p[num_saved_values];
+  ASSERT_TRUE(strlen(tls_value2) <= strlen(tls_value1));
+  __emutls_control c =
+      {strlen(tls_value1) + 1, 1, {0}, tls_value1};
+  for (size_t n = 0; n < num_saved_values; n++) {
+    memcpy(&tls_var[n], &c, sizeof(c));
+    tls_var[n].align = (1 << n);
+  }
+  for (size_t n = 0; n < num_saved_values; n++) {
+    // Try to mess up malloc space so that the next malloc will not have the
+    // required alignment, but __emutls_get_address should still return an
+    // aligned address.
+    saved_gap[n] = malloc(1);
+    void* p = __emutls_get_address(&tls_var[n]);
+    saved_p[n] = p;
+    ASSERT_TRUE(p != nullptr);
+    ASSERT_TRUE(tls_var[n].object.index != 0);
+    // check if p is a new object.
+    if (n > 0) {
+      // In single-thread environment, object.address == p.
+      // In multi-threads environment, object.index is increased.
+      ASSERT_TRUE(prev_index + 1 == tls_var[n].object.index ||
+                  p == tls_var[n].object.address);
+      ASSERT_TRUE(p != saved_p[n - 1]);
+    }
+    prev_index = tls_var[n].object.index;
+    // check if p is aligned
+    uintptr_t align = (1 << n);
+    uintptr_t address= reinterpret_cast<uintptr_t>(p);
+    ASSERT_EQ((address & ~(align - 1)), address);
+    // check if *p is initialized
+    ASSERT_STREQ(tls_value1, static_cast<char*>(p));
+    // change value in *p
+    memcpy(p, tls_value2, strlen(tls_value2) + 1);
+  }
+  for (size_t n = 0; n < num_saved_values; n++) {
+    free(saved_gap[n]);
+  }
+  for (size_t n = 0; n < num_saved_values; n++) {
+    void* p = __emutls_get_address(&tls_var[n]);
+    ASSERT_EQ(p, saved_p[n]);
+    // check if *p has the new value
+    ASSERT_STREQ(tls_value2, static_cast<char*>(p));
+  }
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 0ea90a8..a04c449 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -143,6 +143,44 @@
   EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
 }
 
+TEST(time, strftime_null_tm_zone) {
+  // Netflix on Nexus Player wouldn't start (http://b/25170306).
+  struct tm t;
+  memset(&t, 0, sizeof(tm));
+
+  char buf[64];
+
+  setenv("TZ", "America/Los_Angeles", 1);
+  tzset();
+
+  t.tm_isdst = 0; // "0 if Daylight Savings Time is not in effect".
+  EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+  EXPECT_STREQ("<PST>", buf);
+
+#if defined(__BIONIC__) // glibc 2.19 only copes with tm_isdst being 0 and 1.
+  t.tm_isdst = 2; // "positive if Daylight Savings Time is in effect"
+  EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+  EXPECT_STREQ("<PDT>", buf);
+
+  t.tm_isdst = -123; // "and negative if the information is not available".
+  EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+  EXPECT_STREQ("<>", buf);
+#endif
+
+  setenv("TZ", "UTC", 1);
+  tzset();
+
+  t.tm_isdst = 0;
+  EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+  EXPECT_STREQ("<UTC>", buf);
+
+#if defined(__BIONIC__) // glibc 2.19 thinks UTC DST is "UTC".
+  t.tm_isdst = 1; // UTC has no DST.
+  EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+  EXPECT_STREQ("<>", buf);
+#endif
+}
+
 TEST(time, strptime) {
   setenv("TZ", "UTC", 1);
 
@@ -223,7 +261,7 @@
   ts.it_value.tv_nsec = 1;
   ts.it_interval.tv_sec = 0;
   ts.it_interval.tv_nsec = 0;
-  ASSERT_EQ(0, timer_settime(timer_id, TIMER_ABSTIME, &ts, NULL));
+  ASSERT_EQ(0, timer_settime(timer_id, 0, &ts, NULL));
 
   usleep(500000);
   ASSERT_EQ(1, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 79c16d7..5e06b1f 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -30,6 +30,11 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
+#include <android-base/strings.h>
+
+#include "private/get_cpu_count_from_string.h"
+
 static void* get_brk() {
   return sbrk(0);
 }
@@ -402,11 +407,11 @@
   }
 }
 
-TEST(unistd, getpid_caching_and_fork) {
+static void TestGetPidCachingWithFork(int (*fork_fn)()) {
   pid_t parent_pid = getpid();
   ASSERT_EQ(syscall(__NR_getpid), parent_pid);
 
-  pid_t fork_result = fork();
+  pid_t fork_result = fork_fn();
   ASSERT_NE(fork_result, -1);
   if (fork_result == 0) {
     // We're the child.
@@ -424,6 +429,14 @@
   }
 }
 
+TEST(unistd, getpid_caching_and_fork) {
+  TestGetPidCachingWithFork(fork);
+}
+
+TEST(unistd, getpid_caching_and_vfork) {
+  TestGetPidCachingWithFork(vfork);
+}
+
 static int GetPidCachingCloneStartRoutine(void*) {
   AssertGetPidCorrect();
   return 123;
@@ -694,6 +707,8 @@
   VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
+  VerifySysconf(_SC_PAGE_SIZE, "_SC_PAGE_SIZE",
+                [](long v){return v == sysconf(_SC_PAGESIZE) && v == getpagesize();});
   VERIFY_SYSCONF_POSITIVE(_SC_XOPEN_UNIX);
   VERIFY_SYSCONF_POSITIVE(_SC_AIO_LISTIO_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_AIO_MAX);
@@ -809,6 +824,28 @@
 #endif // defined(__BIONIC__)
 }
 
+TEST(unistd, get_cpu_count_from_string) {
+  ASSERT_EQ(0, GetCpuCountFromString(" "));
+  ASSERT_EQ(1, GetCpuCountFromString("0"));
+  ASSERT_EQ(40, GetCpuCountFromString("0-39"));
+  ASSERT_EQ(4, GetCpuCountFromString("0, 1-2, 4\n"));
+}
+
+TEST(unistd, sysconf_SC_NPROCESSORS_ONLN) {
+  std::string line;
+  ASSERT_TRUE(android::base::ReadFileToString("/sys/devices/system/cpu/online", &line));
+  long online_cpus = 0;
+  for (const std::string& s : android::base::Split(line, ",")) {
+    std::vector<std::string> numbers = android::base::Split(s, "-");
+    if (numbers.size() == 1u) {
+      online_cpus++;
+    } else {
+      online_cpus += atoi(numbers[1].c_str()) - atoi(numbers[0].c_str()) + 1;
+    }
+  }
+  ASSERT_EQ(online_cpus, sysconf(_SC_NPROCESSORS_ONLN));
+}
+
 TEST(unistd, dup2_same) {
   // POSIX says of dup2:
   // If fildes2 is already a valid open file descriptor ...
diff --git a/tests/utils.h b/tests/utils.h
index fd012a3..a8f3441 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -18,6 +18,14 @@
 #define __TEST_UTILS_H
 #include <inttypes.h>
 #include <sys/mman.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <string>
+#include <regex>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 
 #include "private/ScopeGuard.h"
 
@@ -38,9 +46,7 @@
 class Maps {
  public:
   static bool parse_maps(std::vector<map_record>* maps) {
-    char path[64];
-    snprintf(path, sizeof(path), "/proc/self/task/%d/maps", getpid());
-    FILE* fp = fopen(path, "re");
+    FILE* fp = fopen("/proc/self/maps", "re");
     if (fp == nullptr) {
       return false;
     }
@@ -53,11 +59,11 @@
     while (fgets(line, sizeof(line), fp) != nullptr) {
       map_record record;
       uint32_t dev_major, dev_minor;
-      char pathstr[BUFSIZ];
+      int path_offset;
       char prot[5]; // sizeof("rwxp")
-      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %s",
+      if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %x:%x %lu %n",
             &record.addr_start, &record.addr_end, prot, &record.offset,
-            &dev_major, &dev_minor, &record.inode, pathstr) == 8) {
+            &dev_major, &dev_minor, &record.inode, &path_offset) == 7) {
         record.perms = 0;
         if (prot[0] == 'r') {
           record.perms |= PROT_READ;
@@ -72,7 +78,10 @@
         // TODO: parse shared/private?
 
         record.device = makedev(dev_major, dev_minor);
-        record.pathname = pathstr;
+        record.pathname = line + path_offset;
+        if (!record.pathname.empty() && record.pathname.back() == '\n') {
+          record.pathname.pop_back();
+        }
         maps->push_back(record);
       }
     }
@@ -81,4 +90,23 @@
   }
 };
 
+extern "C" pid_t gettid();
+
+static inline void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
+  while (tid == 0) {
+    usleep(1000);
+  }
+  std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
+  std::regex regex {R"(\s+S\s+)"};
+
+  while (true) {
+    std::string content;
+    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
+    if (std::regex_search(content, regex)) {
+      break;
+    }
+    usleep(1000);
+  }
+}
+
 #endif
diff --git a/tests/utmp_test.cpp b/tests/utmp_test.cpp
index b61110d..0fa55c7 100644
--- a/tests/utmp_test.cpp
+++ b/tests/utmp_test.cpp
@@ -23,3 +23,9 @@
   // This test just checks that we're exporting the symbol independently.
   ASSERT_EQ(-1, login_tty(-1));
 }
+
+TEST(utmp, setutent_getutent_endutent) {
+  setutent();
+  getutent();
+  endutent();
+}
diff --git a/tools/bionicbb/presubmit.py b/tools/bionicbb/presubmit.py
index cc6f3cc..3e6ebfa 100644
--- a/tools/bionicbb/presubmit.py
+++ b/tools/bionicbb/presubmit.py
@@ -73,8 +73,10 @@
     build = 'clean-bionic-presubmit'
     if build in jenkins:
         if not dry_run:
-            job = jenkins[build].invoke()
-            url = job.get_build().baseurl
+            _ = jenkins[build].invoke()
+            # https://issues.jenkins-ci.org/browse/JENKINS-27256
+            # url = job.get_build().baseurl
+            url = 'URL UNAVAILABLE'
         else:
             url = 'DRY_RUN_URL'
         logging.info('Cleaning: %s %s', build, url)
diff --git a/tools/relocation_packer/Android.mk b/tools/relocation_packer/Android.mk
index 4e2fd97..35c97a8 100644
--- a/tools/relocation_packer/Android.mk
+++ b/tools/relocation_packer/Android.mk
@@ -96,5 +96,11 @@
 $(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))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32.so))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32_packed.so))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_x64.so))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_x64_packed.so))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32.so))
+$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32_packed.so))
 
 endif
diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc
index 102d614..014883d 100644
--- a/tools/relocation_packer/src/elf_file.cc
+++ b/tools/relocation_packer/src/elf_file.cc
@@ -302,13 +302,75 @@
   }
 }
 
-// Helper for ResizeSection().  Adjust the offsets of any program headers
-// that have offsets currently beyond the hole start.
+// Helpers for ResizeSection().  On packing, reduce p_align for LOAD segments
+// to 4kb if larger.  On unpacking, restore p_align for LOAD segments if
+// packing reduced it to 4kb.  Return true if p_align was changed.
 template <typename ELF>
-static void AdjustProgramHeaderOffsets(typename ELF::Phdr* program_headers,
+static bool ClampLoadSegmentAlignment(typename ELF::Phdr* program_header) {
+  CHECK(program_header->p_type == PT_LOAD);
+
+  // If large, reduce p_align for a LOAD segment to page size on packing.
+  if (program_header->p_align > kPageSize) {
+    program_header->p_align = kPageSize;
+    return true;
+  }
+  return false;
+}
+
+template <typename ELF>
+static bool RestoreLoadSegmentAlignment(typename ELF::Phdr* program_headers,
+                                        size_t count,
+                                        typename ELF::Phdr* program_header) {
+  CHECK(program_header->p_type == PT_LOAD);
+
+  // If p_align was reduced on packing, restore it to its previous value
+  // on unpacking.  We do this by searching for a different LOAD segment
+  // and setting p_align to that of the other LOAD segment found.
+  //
+  // Relies on the following observations:
+  //   - a packable ELF executable has more than one LOAD segment;
+  //   - before packing all LOAD segments have the same p_align;
+  //   - on packing we reduce only one LOAD segment's p_align.
+  if (program_header->p_align == kPageSize) {
+    for (size_t i = 0; i < count; ++i) {
+      typename ELF::Phdr* other_header = &program_headers[i];
+      if (other_header->p_type == PT_LOAD && other_header != program_header) {
+        program_header->p_align = other_header->p_align;
+        return true;
+      }
+    }
+    LOG(WARNING) << "Cannot find a LOAD segment from which to restore p_align";
+  }
+  return false;
+}
+
+template <typename ELF>
+static bool AdjustLoadSegmentAlignment(typename ELF::Phdr* program_headers,
                                        size_t count,
-                                       typename ELF::Off hole_start,
+                                       typename ELF::Phdr* program_header,
                                        ssize_t hole_size) {
+  CHECK(program_header->p_type == PT_LOAD);
+
+  bool status = false;
+  if (hole_size < 0) {
+    status = ClampLoadSegmentAlignment<ELF>(program_header);
+  } else if (hole_size > 0) {
+    status = RestoreLoadSegmentAlignment<ELF>(program_headers,
+                                              count,
+                                              program_header);
+  }
+  return status;
+}
+
+// Helper for ResizeSection().  Adjust the offsets of any program headers
+// that have offsets currently beyond the hole start, and adjust the
+// virtual and physical addrs (and perhaps alignment) of the others.
+template <typename ELF>
+static void AdjustProgramHeaderFields(typename ELF::Phdr* program_headers,
+                                      size_t count,
+                                      typename ELF::Off hole_start,
+                                      ssize_t hole_size) {
+  int alignment_changes = 0;
   for (size_t i = 0; i < count; ++i) {
     typename ELF::Phdr* program_header = &program_headers[i];
 
@@ -327,9 +389,20 @@
     } else {
       program_header->p_vaddr -= hole_size;
       program_header->p_paddr -= hole_size;
-      if (program_header->p_align > kPageSize) {
-        program_header->p_align = kPageSize;
+
+      // If packing, clamp LOAD segment alignment to 4kb to prevent strip
+      // from adjusting it unnecessarily if run on a packed file.  If
+      // unpacking, attempt to restore a reduced alignment to its previous
+      // value.  Ensure that we do this on at most one LOAD segment.
+      if (program_header->p_type == PT_LOAD) {
+        alignment_changes += AdjustLoadSegmentAlignment<ELF>(program_headers,
+                                                             count,
+                                                             program_header,
+                                                             hole_size);
+        LOG_IF(FATAL, alignment_changes > 1)
+            << "Changed p_align on more than one LOAD segment";
       }
+
       VLOG(1) << "phdr[" << i
               << "] p_vaddr adjusted to "<< program_header->p_vaddr
               << "; p_paddr adjusted to "<< program_header->p_paddr
@@ -383,10 +456,10 @@
   target_load_header->p_memsz += hole_size;
 
   // Adjust the offsets and p_vaddrs
-  AdjustProgramHeaderOffsets<ELF>(elf_program_header,
-                                  program_header_count,
-                                  hole_start,
-                                  hole_size);
+  AdjustProgramHeaderFields<ELF>(elf_program_header,
+                                 program_header_count,
+                                 hole_start,
+                                 hole_size);
 }
 
 // Helper for ResizeSection().  Locate and return the dynamic section.
@@ -666,7 +739,7 @@
   VLOG(1) << "Packed         (no padding): " << packed_bytes_estimate << " bytes";
 
   if (packed.empty()) {
-    LOG(INFO) << "Too few relocations to pack";
+    VLOG(1) << "Too few relocations to pack";
     return true;
   }
 
@@ -679,16 +752,16 @@
   // hole_size needs to be page_aligned.
   hole_size -= hole_size % kPreserveAlignment;
 
-  LOG(INFO) << "Compaction                 : " << hole_size << " bytes";
+  VLOG(1) << "Compaction                 : " << hole_size << " bytes";
 
   // Adjusting for alignment may have removed any packing benefit.
   if (hole_size == 0) {
-    LOG(INFO) << "Too few relocations to pack after alignment";
+    VLOG(1) << "Too few relocations to pack after alignment";
     return true;
   }
 
   if (hole_size <= 0) {
-    LOG(INFO) << "Packing relocations saves no space";
+    VLOG(1) << "Packing relocations saves no space";
     return true;
   }
 
diff --git a/tools/relocation_packer/src/elf_file_unittest.cc b/tools/relocation_packer/src/elf_file_unittest.cc
index 32f7968..d5c8918 100644
--- a/tools/relocation_packer/src/elf_file_unittest.cc
+++ b/tools/relocation_packer/src/elf_file_unittest.cc
@@ -183,6 +183,18 @@
   RunPackRelocationsTestFor("arm64");
 }
 
+TEST(ElfFile, PackRelocationsMips32) {
+  RunPackRelocationsTestFor("mips32");
+}
+
+TEST(ElfFile, PackRelocationsIa32) {
+  RunPackRelocationsTestFor("ia32");
+}
+
+TEST(ElfFile, PackRelocationsX64) {
+  RunPackRelocationsTestFor("x64");
+}
+
 TEST(ElfFile, UnpackRelocationsArm32) {
   RunUnpackRelocationsTestFor("arm32");
 }
@@ -191,4 +203,16 @@
   RunUnpackRelocationsTestFor("arm64");
 }
 
+TEST(ElfFile, UnpackRelocationsMips32) {
+  RunUnpackRelocationsTestFor("mips32");
+}
+
+TEST(ElfFile, UnpackRelocationsIa32) {
+  RunUnpackRelocationsTestFor("ia32");
+}
+
+TEST(ElfFile, UnpackRelocationsX64) {
+  RunUnpackRelocationsTestFor("x64");
+}
+
 }  // namespace relocation_packer
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32.so
index 6ce6d0c..5e339ae 100755
--- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32.so
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so
index 6ac2eef..253dd97 100755
--- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64.so
index 945b450..d3d0194 100755
--- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64.so
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64.so
Binary files differ
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 ed85ce1..269b975 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
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32.so
new file mode 100755
index 0000000..42db62c
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32_packed.so
new file mode 100755
index 0000000..27817cc
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32_packed.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32.so
new file mode 100755
index 0000000..6da324b
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32_packed.so
new file mode 100755
index 0000000..b11ca48
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32_packed.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64.so
new file mode 100755
index 0000000..6cb689e
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64.so
Binary files differ
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64_packed.so
new file mode 100755
index 0000000..60b9ad1
--- /dev/null
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64_packed.so
Binary files differ