Merge "linker: changes to init work arounds"
diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp
index 9251a05..77814bf 100644
--- a/benchmarks/property_benchmark.cpp
+++ b/benchmarks/property_benchmark.cpp
@@ -21,7 +21,7 @@
 
 #include <string>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 
 using namespace std::literals;
 
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 21d9dc0..037bbd9 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -20,7 +20,7 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 #include <benchmark/benchmark.h>
 #include "util.h"
 
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index ff4b255..301c294 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -63,7 +63,7 @@
 
 void SystemTests::SanitizeOutput() {
   // Cut off anything after the arguments, since that varies with time.
-  sanitized_output_ = std::regex_replace(raw_output_, std::regex(".+(BM_\\S+) +.+"), "$1");
+  sanitized_output_ = std::regex_replace(raw_output_, std::regex(".*(BM_\\S+)\\s+.+"), "$1");
 
   // Remove everything before the header.
   sanitized_output_.erase(0, sanitized_output_.find("------------------------------------------------"));
@@ -165,7 +165,8 @@
     "          [--benchmark_filter=<regex>]\n"
     "          [--benchmark_min_time=<min_time>]\n"
     "          [--benchmark_repetitions=<num_repetitions>]\n"
-    "          [--benchmark_report_aggregates_only={true|false}\n"
+    "          [--benchmark_report_aggregates_only={true|false}]\n"
+    "          [--benchmark_display_aggregates_only={true|false}]\n"
     "          [--benchmark_format=<console|json|csv>]\n"
     "          [--benchmark_out=<filename>]\n"
     "          [--benchmark_out_format=<json|console|csv>]\n"
diff --git a/docs/elf-tls.md b/docs/elf-tls.md
new file mode 100644
index 0000000..4a62793
--- /dev/null
+++ b/docs/elf-tls.md
@@ -0,0 +1,882 @@
+# Android ELF TLS (Draft)
+
+Internal links:
+ * [go/android-elf-tls](http://go/android-elf-tls)
+ * [One-pager](https://docs.google.com/document/d/1leyPTnwSs24P2LGiqnU6HetnN5YnDlZkihigi6qdf_M)
+ * Tracking bugs: http://b/110100012, http://b/78026329
+
+[TOC]
+
+# Overview
+
+ELF TLS is a system for automatically allocating thread-local variables with cooperation among the
+compiler, linker, dynamic loader, and libc.
+
+Thread-local variables are declared in C and C++ with a specifier, e.g.:
+
+```cpp
+thread_local int tls_var;
+```
+
+At run-time, TLS variables are allocated on a module-by-module basis, where a module is a shared
+object or executable. At program startup, TLS for all initially-loaded modules comprises the "Static
+TLS Block". TLS variables within the Static TLS Block exist at fixed offsets from an
+architecture-specific thread pointer (TP) and can be accessed very efficiently -- typically just a
+few instructions. TLS variables belonging to dlopen'ed shared objects, on the other hand, may be
+allocated lazily, and accessing them typically requires a function call.
+
+# Thread-Specific Memory Layout
+
+Ulrich Drepper's ELF TLS document specifies two ways of organizing memory pointed at by the
+architecture-specific thread-pointer ([`__get_tls()`] in Bionic):
+
+![TLS Variant 1 Layout](img/tls-variant1.png)
+
+![TLS Variant 2 Layout](img/tls-variant2.png)
+
+Variant 1 places the static TLS block after the TP, whereas variant 2 places it before the TP.
+According to Drepper, variant 2 was motivated by backwards compatibility, and variant 1 was designed
+for Itanium. The choice has effects on the toolchain, loader, and libc. In particular, when linking
+an executable, the linker needs to know where an executable's TLS segment is relative to the TP so
+it can correctly relocate TLS accesses. Both variants are incompatible with Bionic's current
+thread-specific data layout, but variant 1 is more problematic than variant 2.
+
+Each thread has a "Dynamic Thread Vector" (DTV) with a pointer to each module's TLS block (or NULL
+if it hasn't been allocated yet). If the executable has a TLS segment, then it will always be module
+1, and its storage will always be immediately after (or before) the TP. In variant 1, the TP is
+expected to point immediately at the DTV pointer, whereas in variant 2, the DTV pointer's offset
+from TP is implementation-defined.
+
+The DTV's "generation" field is used to lazily update/reallocate the DTV when new modules are loaded
+or unloaded.
+
+[`__get_tls()`]: https://android.googlesource.com/platform/bionic/+/7245c082658182c15d2a423fe770388fec707cbc/libc/private/__get_tls.h
+
+# Access Models
+
+When a C/C++ file references a TLS variable, the toolchain generates instructions to find its
+address using a TLS "access model". The access models trade generality against efficiency. The four
+models are:
+
+ * GD: General Dynamic (aka Global Dynamic)
+ * LD: Local Dynamic
+ * IE: Initial Exec
+ * LE: Local Exec
+
+A TLS variable may be in a different module than the reference.
+
+## General Dynamic (or Global Dynamic) (GD)
+
+A GD access can refer to a TLS variable anywhere. To access a variable `tls_var` using the
+"traditional" non-TLSDESC design described in Drepper's TLS document, the toolchain compiler emits a
+call to a `__tls_get_addr` function provided by libc.
+
+For example, if we have this C code in a shared object:
+
+```cpp
+extern thread_local char tls_var;
+char* get_tls_var() {
+  return &tls_var;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+struct TlsIndex {
+  long module; // starts counting at 1
+  long offset;
+};
+
+char* get_tls_var() {
+  static TlsIndex tls_var_idx = { // allocated in the .got
+    R_TLS_DTPMOD(tls_var), // dynamic TP module ID
+    R_TLS_DTPOFF(tls_var), // dynamic TP offset
+  };
+  return __tls_get_addr(&tls_var_idx);
+}
+```
+
+`R_TLS_DTPMOD` is a dynamic relocation to the index of the module containing `tls_var`, and
+`R_TLS_DTPOFF` is a dynamic relocation to the offset of `tls_var` within its module's `PT_TLS`
+segment.
+
+`__tls_get_addr` looks up `TlsIndex::module`'s entry in the DTV and adds `TlsIndex::offset` to the
+module's TLS block. Before it can do this, it ensures that the module's TLS block is allocated. A
+simple approach is to allocate memory lazily:
+
+1. If the current thread's DTV generation count is less than the current global TLS generation, then
+   `__tls_get_addr` may reallocate the DTV or free blocks for unloaded modules.
+
+2. If the DTV's entry for the given module is `NULL`, then `__tls_get_addr` allocates the module's
+   memory.
+
+If an allocation fails, `__tls_get_addr` calls `abort` (like emutls).
+
+musl, on the other, preallocates TLS memory in `pthread_create` and in `dlopen`, and each can report
+out-of-memory.
+
+## Local Dynamic (LD)
+
+LD is a specialization of GD that's useful when a function has references to two or more TLS
+variables that are both part of the same module as the reference. Instead of a call to
+`__tls_get_addr` for each variable, the compiler calls `__tls_get_addr` once to get the current
+module's TLS block, then adds each variable's DTPOFF to the result.
+
+For example, suppose we have this C code:
+
+```cpp
+static thread_local int x;
+static thread_local int y;
+int sum() {
+  return x + y;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+int sum() {
+  static TlsIndex tls_module_idx = { // allocated in the .got
+    // a dynamic relocation against symbol 0 => current module ID
+    R_TLS_DTPMOD(NULL),
+    0,
+  };
+  char* base = __tls_get_addr(&tls_module_idx);
+  // These R_TLS_DTPOFF() relocations are resolved at link-time.
+  int* px = base + R_TLS_DTPOFF(x);
+  int* py = base + R_TLS_DTPOFF(y);
+  return *px + *py;
+}
+```
+
+(XXX: LD might be important for C++ `thread_local` variables -- even a single `thread_local`
+variable with a dynamic initializer has an associated TLS guard variable.)
+
+## Initial Exec (IE)
+
+If the variable is part of the Static TLS Block (i.e. the executable or an initially-loaded shared
+object), then its offset from the TP is known at load-time. The variable can be accessed with a few
+loads.
+
+Example: a C file for an executable:
+
+```cpp
+// tls_var could be defined in the executable, or it could be defined
+// in a shared object the executable links against.
+extern thread_local char tls_var;
+char* get_addr() { return &tls_var; }
+```
+
+Compiles to:
+
+```cpp
+// allocated in the .got, resolved at load-time with a dynamic reloc.
+// Unlike DTPOFF, which is relative to the start of the module’s block,
+// TPOFF is directly relative to the thread pointer.
+static long tls_var_gotoff = R_TLS_TPOFF(tls_var);
+
+char* get_addr() {
+  return (char*)__get_tls() + tls_var_gotoff;
+}
+```
+
+## Local Exec (LE)
+
+LE is a specialization of IE. If the variable is not just part of the Static TLS Block, but is also
+part of the executable (and referenced from the executable), then a GOT access can be avoided. The
+IE example compiles to:
+
+```cpp
+char* get_addr() {
+  // R_TLS_TPOFF() is resolved at (static) link-time
+  return (char*)__get_tls() + R_TLS_TPOFF(tls_var);
+}
+```
+
+## Selecting an Access Model
+
+The compiler selects an access model for each variable reference using these factors:
+ * The absence of `-fpic` implies an executable, so use IE/LE.
+ * Code compiled with `-fpic` could be in a shared object, so use GD/LD.
+ * The per-file default can be overridden with `-ftls-model=<model>`.
+ * Specifiers on the variable (`static`, `extern`, ELF visibility attributes).
+ * A variable can be annotated with `__attribute__((tls_model(...)))`. Clang may still use a more
+   efficient model than the one specified.
+
+# Shared Objects with Static TLS
+
+Shared objects are sometimes compiled with `-ftls-model=initial-exec` (i.e. "static TLS") for better
+performance. On Ubuntu, for example, `libc.so.6` and `libOpenGL.so.0` are compiled this way. Shared
+objects using static TLS can't be loaded with `dlopen` unless libc has reserved enough surplus
+memory in the static TLS block. glibc reserves a kilobyte or two (`TLS_STATIC_SURPLUS`) with the
+intent that only a few core system libraries would use static TLS. Non-core libraries also sometimes
+use it, which can break `dlopen` if the surplus area is exhausted. See:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1124987
+ * web search: [`"dlopen: cannot load any more object with static TLS"`][glibc-static-tls-error]
+
+Neither musl nor the Bionic TLS prototype currently allocate any surplus TLS memory.
+
+In general, supporting surplus TLS memory probably requires maintaining a thread list so that
+`dlopen` can initialize the new static TLS memory in all existing threads. A thread list could be
+omitted if the loader only allowed zero-initialized TLS segments and didn't reclaim memory on
+`dlclose`.
+
+As long as a shared object is one of the initially-loaded modules, a better option is to use
+TLSDESC.
+
+[glibc-static-tls-error]: https://www.google.com/search?q=%22dlopen:+cannot+load+any+more+object+with+static+TLS%22
+
+# TLS Descriptors (TLSDESC)
+
+The code fragments above match the "traditional" TLS design from Drepper's document. For the GD and
+LD models, there is a newer, more efficient design that uses "TLS descriptors". Each TLS variable
+reference has a corresponding descriptor, which contains a resolver function address and an argument
+to pass to the resolver.
+
+For example, if we have this C code in a shared object:
+
+```cpp
+extern thread_local char tls_var;
+char* get_tls_var() {
+  return &tls_var;
+}
+```
+
+The toolchain generates code like this:
+
+```cpp
+struct TlsDescriptor { // NB: arm32 reverses these fields
+  long (*resolver)(long);
+  long arg;
+};
+
+char* get_tls_var() {
+  // allocated in the .got, uses a dynamic relocation
+  static TlsDescriptor desc = R_TLS_DESC(tls_var);
+  return (char*)__get_tls() + desc.resolver(desc.arg);
+}
+```
+
+The dynamic loader fills in the TLS descriptors. For a reference to a variable allocated in the
+Static TLS Block, it can use a simple resolver function:
+
+```cpp
+long static_tls_resolver(long arg) {
+  return arg;
+}
+```
+
+The loader writes `tls_var@TPOFF` into the descriptor's argument.
+
+To support modules loaded with `dlopen`, the loader must use a resolver function that calls
+`__tls_get_addr`. In principle, this simple implementation would work:
+
+```cpp
+long dynamic_tls_resolver(TlsIndex* arg) {
+  return (long)__tls_get_addr(arg) - (long)__get_tls();
+}
+```
+
+There are optimizations that complicate the design a little:
+ * Unlike `__tls_get_addr`, the resolver function has a special calling convention that preserves
+   almost all registers, reducing register pressure in the caller
+   ([example](https://godbolt.org/g/gywcxk)).
+ * In general, the resolver function must call `__tls_get_addr`, so it must save and restore all
+   registers.
+ * To keep the fast path fast, the resolver inlines the fast path of `__tls_get_addr`.
+ * By storing the module's initial generation alongside the TlsIndex, the resolver function doesn't
+   need to use an atomic or synchronized access of the global TLS generation counter.
+
+The resolver must be written in assembly, but in C, the function looks like so:
+
+```cpp
+struct TlsDescDynamicArg {
+  unsigned long first_generation;
+  TlsIndex idx;
+};
+
+struct TlsDtv { // DTV == dynamic thread vector
+  unsigned long generation;
+  char* modules[];
+};
+
+long dynamic_tls_resolver(TlsDescDynamicArg* arg) {
+  TlsDtv* dtv = __get_dtv();
+  char* addr;
+  if (dtv->generation >= arg->first_generation &&
+      dtv->modules[arg->idx.module] != nullptr) {
+    addr = dtv->modules[arg->idx.module] + arg->idx.offset;
+  } else {
+    addr = __tls_get_addr(&arg->idx);
+  }
+  return (long)addr - (long)__get_tls();
+}
+```
+
+The loader needs to allocate a table of `TlsDescDynamicArg` objects for each TLS module with dynamic
+TLSDESC relocations.
+
+The static linker can still relax a TLSDESC-based access to an IE/LE access.
+
+The traditional TLS design is implemented everywhere, but the TLSDESC design has less toolchain
+support:
+ * GCC and the BFD linker support both designs on all supported Android architectures (arm32, arm64,
+   x86, x86-64).
+ * GCC can select the design at run-time using `-mtls-dialect=<dialect>` (`trad`-vs-`desc` on arm64,
+   otherwise `gnu`-vs-`gnu2`). Clang always uses the default mode.
+ * GCC and Clang default to TLSDESC on arm64 and the traditional design on other architectures.
+ * Gold and LLD support for TLSDESC is spotty (except when targeting arm64).
+
+# Linker Relaxations
+
+The (static) linker frequently has more information about the location of a referenced TLS variable
+than the compiler, so it can "relax" TLS accesses to more efficient models. For example, if an
+object file compiled with `-fpic` is linked into an executable, the linker could relax GD accesses
+to IE or LE. To relax a TLS access, the linker looks for an expected sequences of instructions and
+static relocations, then replaces the sequence with a different one of equal size. It may need to
+add or remove no-op instructions.
+
+## Current Support for GD->LE Relaxations Across Linkers
+
+Versions tested:
+ * BFD and Gold linkers: version 2.30
+ * LLD version 6.0.0 (upstream)
+
+Linker support for GD->LE relaxation with `-mtls-dialect=gnu/trad` (traditional):
+
+Architecture    | BFD | Gold | LLD
+--------------- | --- | ---- | ---
+arm32           | no  | no   | no
+arm64 (unusual) | yes | yes  | no
+x86             | yes | yes  | yes
+x86_64          | yes | yes  | yes
+
+Linker support for GD->LE relaxation with `-mtls-dialect=gnu2/desc` (TLSDESC):
+
+Architecture          | BFD | Gold               | LLD
+--------------------- | --- | ------------------ | ------------------
+arm32 (experimental)  | yes | unsupported relocs | unsupported relocs
+arm64                 | yes | yes                | yes
+x86 (experimental)    | yes | yes                | unsupported relocs
+X86_64 (experimental) | yes | yes                | unsupported relocs
+
+arm32 linkers can't relax traditional TLS accesses. BFD can relax an arm32 TLSDESC access, but LLD
+can't link code using TLSDESC at all, except on arm64, where it's used by default.
+
+# dlsym
+
+Calling `dlsym` on a TLS variable returns the address of the current thread's variable.
+
+# Debugger Support
+
+## gdb
+
+gdb uses a libthread_db plugin library to retrieve thread-related information from a target. This
+library is typically a shared object, but for Android, we link our own `libthread_db.a` into
+gdbserver. We will need to implement at least 2 APIs in `libthread_db.a` to find TLS variables, and
+gdb provides APIs for looking up symbols, reading or writing memory, and retrieving the current
+thread pointer (e.g. `ps_get_thread_area`).
+ * Reference: [gdb_proc_service.h]: APIs gdb provides to libthread_db
+ * Reference: [Currently unimplemented TLS functions in Android's libthread_tb][libthread_db.c]
+
+[gdb_proc_service.h]: https://android.googlesource.com/toolchain/gdb/+/a7e49fd02c21a496095c828841f209eef8ae2985/gdb-8.0.1/gdb/gdb_proc_service.h#41
+[libthread_db.c]: https://android.googlesource.com/platform/ndk/+/e1f0ad12fc317c0ca3183529cc9625d3f084d981/sources/android/libthread_db/libthread_db.c#115
+
+## LLDB
+
+LLDB more-or-less implemented Linux TLS debugging in [r192922][rL192922] ([D1944]) for x86 and
+x86-64. [arm64 support came later][D5073]. However, the Linux TLS functionality no longer does
+anything: the `GetThreadPointer` function is no longer implemented. Code for reading the thread
+pointer was removed in [D10661] ([this function][r240543]). (arm32 was apparently never supported.)
+
+[rL192922]: https://reviews.llvm.org/rL192922
+[D1944]: https://reviews.llvm.org/D1944
+[D5073]: https://reviews.llvm.org/D5073
+[D10661]: https://reviews.llvm.org/D10661
+[r240543]: https://github.com/llvm-mirror/lldb/commit/79246050b0f8d6b54acb5366f153d07f235d2780#diff-52dee3d148892cccfcdab28bc2165548L962
+
+## Threading Library Metadata
+
+Both debuggers need metadata from the threading library (`libc.so` / `libpthread.so`) to find TLS
+variables. From [LLDB r192922][rL192922]'s commit message:
+
+> ... All OSes use basically the same algorithm (a per-module lookup table) as detailed in Ulrich
+> Drepper's TLS ELF ABI document, so we can easily write code to decode it ourselves. The only
+> question therefore is the exact field layouts required. Happily, the implementors of libpthread
+> expose the structure of the DTV via metadata exported as symbols from the .so itself, designed
+> exactly for this kind of thing. So this patch simply reads that metadata in, and re-implements
+> libthread_db's algorithm itself. We thereby get cross-platform TLS lookup without either requiring
+> third-party libraries, while still being independent of the version of libpthread being used.
+
+ LLDB uses these variables:
+
+Name                              | Notes
+--------------------------------- | ---------------------------------------------------------------------------------------
+`_thread_db_pthread_dtvp`         | Offset from TP to DTV pointer (0 for variant 1, implementation-defined for variant 2)
+`_thread_db_dtv_dtv`              | Size of a DTV slot (typically/always sizeof(void*))
+`_thread_db_dtv_t_pointer_val`    | Offset within a DTV slot to the pointer to the allocated TLS block (typically/always 0)
+`_thread_db_link_map_l_tls_modid` | Offset of a `link_map` field containing the module's 1-based TLS module ID
+
+The metadata variables are local symbols in glibc's `libpthread.so` symbol table (but not its
+dynamic symbol table). Debuggers can access them, but applications can't.
+
+The debugger lookup process is straightforward:
+ * Find the `link_map` object and module-relative offset for a TLS variable.
+ * Use `_thread_db_link_map_l_tls_modid` to find the TLS variable's module ID.
+ * Read the target thread pointer.
+ * Use `_thread_db_pthread_dtvp` to find the thread's DTV.
+ * Use `_thread_db_dtv_dtv` and `_thread_db_dtv_t_pointer_val` to find the desired module's block
+   within the DTV.
+ * Add the module-relative offset to the module pointer.
+
+This process doesn't appear robust in the face of lazy DTV initialization -- presumably it could
+read past the end of an out-of-date DTV or access an unloaded module. To be robust, it needs to
+compare a module's initial generation count against the DTV's generation count. (XXX: Does gdb have
+these sorts of problems with glibc's libpthread?)
+
+## Reading the Thread Pointer with Ptrace
+
+There are ptrace interfaces for reading the thread pointer for each of arm32, arm64, x86, and x86-64
+(XXX: check 32-vs-64-bit for inferiors, debuggers, and kernels):
+ * arm32: `PTRACE_GET_THREAD_AREA`
+ * arm64: `PTRACE_GETREGSET`, `NT_ARM_TLS`
+ * x86_32: `PTRACE_GET_THREAD_AREA`
+ * x86_64: use `PTRACE_PEEKUSER` to read the `{fs,gs}_base` fields of `user_regs_struct`
+
+# C/C++ Specifiers
+
+C/C++ TLS variables are declared with a specifier:
+
+Specifier       | Notes
+--------------- | -----------------------------------------------------------------------------------------------------------------------------
+`__thread`      |  - non-standard, but ubiquitous in GCC and Clang<br/> - cannot have dynamic initialization or destruction
+`_Thread_local` |  - a keyword standardized in C11<br/> - cannot have dynamic initialization or destruction
+`thread_local`  |  - C11: a macro for `_Thread_local` via `threads.h`<br/> - C++11: a keyword, allows dynamic initialization and/or destruction
+
+The dynamic initialization and destruction of C++ `thread_local` variables is layered on top of ELF
+TLS (or emutls), so this design document mostly ignores it. Like emutls, ELF TLS variables either
+have a static initializer or are zero-initialized.
+
+Aside: Because a `__thread` variable cannot have dynamic initialization, `__thread` is more
+efficient in C++ than `thread_local` when the compiler cannot see the definition of a declared TLS
+variable. The compiler assumes the variable could have a dynamic initializer and generates code, at
+each access, to call a function to initialize the variable.
+
+# Graceful Failure on Old Platforms
+
+ELF TLS isn't implemented on older Android platforms, so dynamic executables and shared objects
+using it generally won't work on them. Ideally, the older platforms would reject these binaries
+rather than experience memory corruption at run-time.
+
+Static executables aren't a problem--the necessary runtime support is part of the executable, so TLS
+just works.
+
+XXX: Shared objects are less of a problem.
+ * On arm32, x86, and x86_64, the loader [should reject a TLS relocation]. (XXX: I haven't verified
+   this.)
+ * On arm64, the primary TLS relocation (R_AARCH64_TLSDESC) is [confused with an obsolete
+   R_AARCH64_TLS_DTPREL32 relocation][R_AARCH64_TLS_DTPREL32] and is [quietly ignored].
+ * Android P [added compatibility checks] for TLS symbols and `DT_TLSDESC_{GOT|PLT}` entries.
+
+XXX: A dynamic executable using ELF TLS would have a PT_TLS segment and no other distinguishing
+marks, so running it on an older platform would result in memory corruption. Should we add something
+to these executables that only newer platforms recognize? (e.g. maybe an entry in .dynamic, a
+reference to a symbol only a new libc.so has...)
+
+[should reject a TLS relocation]: https://android.googlesource.com/platform/bionic/+/android-8.1.0_r48/linker/linker.cpp#2852
+[R_AARCH64_TLS_DTPREL32]: https://android-review.googlesource.com/c/platform/bionic/+/723696
+[quietly ignored]: https://android.googlesource.com/platform/bionic/+/android-8.1.0_r48/linker/linker.cpp#2784
+[added compatibility checks]: https://android-review.googlesource.com/c/platform/bionic/+/648760
+
+# Bionic Prototype Notes
+
+There is an [ELF TLS prototype] uploaded on Gerrit. It implements:
+ * Static TLS Block allocation for static and dynamic executables
+ * TLS for dynamically loaded and unloaded modules (`__tls_get_addr`)
+ * TLSDESC for arm64 only
+
+Missing:
+ * `dlsym` of a TLS variable
+ * debugger support
+
+[ELF TLS prototype]: https://android-review.googlesource.com/q/topic:%22elf-tls-prototype%22+(status:open%20OR%20status:merged)
+
+## Loader/libc Communication
+
+The loader exposes a list of TLS modules ([`struct TlsModules`][TlsModules]) to `libc.so` using the
+`__libc_shared_globals` variable (see `tls_modules()` in [linker_tls.cpp][tls_modules-linker] and
+[elf_tls.cpp][tls_modules-libc]). `__tls_get_addr` in libc.so acquires the `TlsModules::mutex` and
+iterates its module list to lazily allocate and free TLS blocks.
+
+[TlsModules]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/bionic/elf_tls.h#53
+[tls_modules-linker]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/linker/linker_tls.cpp#45
+[tls_modules-libc]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/bionic/elf_tls.cpp#49
+
+## TLS Allocator
+
+The prototype currently allocates a `pthread_internal_t` object and static TLS in a single mmap'ed
+region, along with a thread's stack if it needs one allocated. It doesn't place TLS memory on a
+preallocated stack (either the main thread's stack or one provided with `pthread_attr_setstack`).
+
+The DTV and blocks for dlopen'ed modules are instead allocated using the Bionic loader's
+`LinkerMemoryAllocator`, adapted to avoid the STL and to provide `memalign`. The prototype tries to
+achieve async-signal safety by blocking signals and acquiring a lock.
+
+There are three "entry points" to dynamically locate a TLS variable's address:
+ * libc.so: `__tls_get_addr`
+ * loader: TLSDESC dynamic resolver
+ * loader: dlsym
+
+The loader's entry points need to call `__tls_get_addr`, which needs to allocate memory. Currently,
+the prototype uses a [special function pointer] to call libc.so's `__tls_get_addr` from the loader.
+(This should probably be removed.)
+
+The prototype currently allows for arbitrarily-large TLS variable alignment. IIRC, different
+implementations (glibc, musl, FreeBSD) vary in their level of respect for TLS alignment. It looks
+like the Bionic loader ignores segments' alignment and aligns loaded libraries to 256 KiB. See
+`ReserveAligned`.
+
+[special function pointer]: https://android-review.googlesource.com/c/platform/bionic/+/723698/1/libc/private/bionic_globals.h#52
+
+## Async-Signal Safety
+
+The prototype's `__tls_get_addr` might be async-signal safe. Making it AS-safe is a good idea if
+it's feasible. musl's function is AS-safe, but glibc's isn't (or wasn't). Google had a patch to make
+glibc AS-safe back in 2012-2013. See:
+ * https://sourceware.org/glibc/wiki/TLSandSignals
+ * https://sourceware.org/ml/libc-alpha/2012-06/msg00335.html
+ * https://sourceware.org/ml/libc-alpha/2013-09/msg00563.html
+
+## Out-of-Memory Handling (abort)
+
+The prototype lazily allocates TLS memory for dlopen'ed modules (see `__tls_get_addr`), and an
+out-of-memory error on a TLS access aborts the process. musl, on the other hand, preallocates TLS
+memory on `pthread_create` and `dlopen`, so either function can return out-of-memory. Both functions
+probably need to acquire the same lock.
+
+Maybe Bionic should do the same as musl? Perhaps musl's robustness argument holds for Bionic,
+though, because Bionic (at least the linker) probably already aborts on OOM. musl doesn't support
+`dlclose`/unloading, so it might have an easier time.
+
+On the other hand, maybe lazy allocation is a feature, because not all threads will use a dlopen'ed
+solib's TLS variables. Drepper makes this argument in his TLS document:
+
+> In addition the run-time support should avoid creating the thread-local storage if it is not
+> necessary. For instance, a loaded module might only be used by one thread of the many which make
+> up the process. It would be a waste of memory and time to allocate the storage for all threads. A
+> lazy method is wanted. This is not much extra burden since the requirement to handle dynamically
+> loaded objects already requires recognizing storage which is not yet allocated. This is the only
+> alternative to stopping all threads and allocating storage for all threads before letting them run
+> again.
+
+FWIW: emutls also aborts on out-of-memory.
+
+## ELF TLS Not Usable in libc
+
+The dynamic loader currently can't use ELF TLS, so any part of libc linked into the loader (i.e.
+most of it) also can't use ELF TLS. It might be possible to lift this restriction, perhaps with
+specialized `__tls_get_addr` and TLSDESC resolver functions.
+
+# Open Issues
+
+## Bionic Memory Layout Conflicts with Common TLS Layout
+
+Bionic already allocates thread-specific data in a way that conflicts with TLS variants 1 and 2:
+![Bionic TLS Layout in Android P](img/bionic-tls-layout-in-p.png)
+
+TLS variant 1 allocates everything after the TP to ELF TLS (except the first two words), and variant
+2 allocates everything before the TP. Bionic currently allocates memory before and after the TP to
+the `pthread_internal_t` struct.
+
+The `bionic_tls.h` header is marked with a warning:
+
+```cpp
+/** WARNING WARNING WARNING
+ **
+ ** This header file is *NOT* part of the public Bionic ABI/API
+ ** and should not be used/included by user-serviceable parts of
+ ** the system (e.g. applications).
+ **
+ ** It is only provided here for the benefit of the system dynamic
+ ** linker and the OpenGL sub-system (which needs to access the
+ ** pre-allocated slot directly for performance reason).
+ **/
+```
+
+There are issues with rearranging this memory:
+
+ * `TLS_SLOT_STACK_GUARD` is used for `-fstack-protector`. The location (word #5) was initially used
+   by GCC on x86 (and x86-64), where it is compatible with x86's TLS variant 2. We [modified Clang
+   to use this slot for arm64 in 2016][D18632], though, and the slot isn't compatible with ARM's
+   variant 1 layout. This change shipped in NDK r14, and the NDK's build systems (ndk-build and the
+   CMake toolchain file) enable `-fstack-protector-strong` by default.
+
+ * `TLS_SLOT_TSAN` is used for more than just TSAN -- it's also used by [HWASAN and
+   Scudo](https://reviews.llvm.org/D53906#1285002).
+
+ * The Go runtime allocates a thread-local "g" variable on Android by creating a pthread key and
+   searching for its TP-relative offset, which it assumes is nonnegative:
+    * On arm32/arm64, it creates a pthread key, sets it to a magic value, then scans forward from
+      the thread pointer looking for it. [The scan count was bumped to 384 to fix a reported
+      breakage happening with Android N.](https://go-review.googlesource.com/c/go/+/38636) (XXX: I
+      suspect the actual platform breakage happened with Android M's [lock-free pthread key
+      work][bionic-lockfree-keys].)
+    * On x86/x86-64, it uses a fixed offset from the thread pointer (TP+0xf8 or TP+0x1d0) and
+      creates pthread keys until one of them hits the fixed offset.
+    * CLs:
+       * arm32: https://codereview.appspot.com/106380043
+       * arm64: https://go-review.googlesource.com/c/go/+/17245
+       * x86: https://go-review.googlesource.com/c/go/+/16678
+       * x86-64: https://go-review.googlesource.com/c/go/+/15991
+    * Moving the pthread keys before the thread pointer breaks Go-based apps.
+    * It's unclear how many Android apps use Go. There are at least two with 1,000,000+ installs.
+    * [Some motivation for Go's design][golang-post], [runtime/HACKING.md][go-hacking]
+    * [On x86/x86-64 Darwin, Go uses a TLS slot reserved for both Go and Wine][go-darwin-x86] (On
+      [arm32][go-darwin-arm32]/[arm64][go-darwin-arm64] Darwin, Go scans for pthread keys like it
+      does on Android.)
+
+ * Android's "native bridge" system allows the Zygote to load an app solib of a non-native ABI. (For
+   example, it could be used to load an arm32 solib into an x86 Zygote.) The solib is translated
+   into the host architecture. TLS accesses in the app solib (whether ELF TLS, Bionic slots, or
+   `pthread_internal_t` fields) become host accesses. Laying out TLS memory differently across
+   architectures could complicate this translation.
+
+ * A `pthread_t` is practically just a `pthread_internal_t*`, and some apps directly access the
+   `pthread_internal_t::tid` field. Past examples: http://b/17389248, [aosp/107467]. Reorganizing
+   the initial `pthread_internal_t` fields could break those apps.
+
+It seems easy to fix the incompatibility for variant 2 (x86 and x86_64) by splitting out the Bionic
+slots into a new data structure. Variant 1 is a harder problem.
+
+The TLS prototype currently uses a patched LLD that uses a variant 1 TLS layout with a 16-word TCB
+on all architectures.
+
+Aside: gcc's arm64ilp32 target uses a 32-bit unsigned offset for a TLS IE access
+(https://godbolt.org/z/_NIXjF). If Android ever supports this target, and in a configuration with
+variant 2 TLS, we might need to change the compiler to emit a sign-extending load.
+
+[D18632]: https://reviews.llvm.org/D18632
+[bionic-lockfree-keys]: https://android-review.googlesource.com/c/platform/bionic/+/134202
+[golang-post]: https://groups.google.com/forum/#!msg/golang-nuts/EhndTzcPJxQ/i-w7kAMfBQAJ
+[go-hacking]: https://github.com/golang/go/blob/master/src/runtime/HACKING.md
+[go-darwin-x86]: https://github.com/golang/go/issues/23617
+[go-darwin-arm32]: https://github.com/golang/go/blob/15c106d99305411b587ec0d9e80c882e538c9d47/src/runtime/cgo/gcc_darwin_arm.c
+[go-darwin-arm64]: https://github.com/golang/go/blob/15c106d99305411b587ec0d9e80c882e538c9d47/src/runtime/cgo/gcc_darwin_arm64.c
+[aosp/107467]: https://android-review.googlesource.com/c/platform/bionic/+/107467
+
+### Workaround: Use Variant 2 on arm32/arm64
+
+Pros: simplifies Bionic
+
+Cons:
+ * arm64: requires either subtle reinterpretation of a TLS relocation or addition of a new
+   relocation
+ * arm64: a new TLS relocation reduces compiler/assembler compatibility with non-Android
+
+The point of variant 2 was backwards-compatibility, and ARM Android needs to remain
+backwards-compatible, so we could use variant 2 for ARM. Problems:
+
+ * When linking an executable, the static linker needs to know how TLS is allocated because it
+   writes TP-relative offsets for IE/LE-model accesses. Clang doesn't tell the linker to target
+   Android, so it could pass an `--tls-variant2` flag to configure lld.
+
+ * On arm64, there are different sets of static LE relocations accommodating different ranges of
+   offsets from TP:
+
+   Size | TP offset range   | Static LE relocation types
+   ---- | ----------------- | ---------------------------------------
+   12   | 0 <= x < 2^12     | `R_AARCH64_TLSLE_ADD_TPREL_LO12`
+   "    | "                 | `R_AARCH64_TLSLE_LDST8_TPREL_LO12`
+   "    | "                 | `R_AARCH64_TLSLE_LDST16_TPREL_LO12`
+   "    | "                 | `R_AARCH64_TLSLE_LDST32_TPREL_LO12`
+   "    | "                 | `R_AARCH64_TLSLE_LDST64_TPREL_LO12`
+   "    | "                 | `R_AARCH64_TLSLE_LDST128_TPREL_LO12`
+   16   | -2^16 <= x < 2^16 | `R_AARCH64_TLSLE_MOVW_TPREL_G0`
+   24   | 0 <= x < 2^24     | `R_AARCH64_TLSLE_ADD_TPREL_HI12`
+   "    | "                 | `R_AARCH64_TLSLE_ADD_TPREL_LO12_NC`
+   "    | "                 | `R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC`
+   "    | "                 | `R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC`
+   "    | "                 | `R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC`
+   "    | "                 | `R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC`
+   "    | "                 | `R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC`
+   32   | -2^32 <= x < 2^32 | `R_AARCH64_TLSLE_MOVW_TPREL_G1`
+   "    | "                 | `R_AARCH64_TLSLE_MOVW_TPREL_G0_NC`
+   48   | -2^48 <= x < 2^48 | `R_AARCH64_TLSLE_MOVW_TPREL_G2`
+   "    | "                 | `R_AARCH64_TLSLE_MOVW_TPREL_G1_NC`
+   "    | "                 | `R_AARCH64_TLSLE_MOVW_TPREL_G0_NC`
+
+   GCC for arm64 defaults to the 24-bit model and has an `-mtls-size=SIZE` option for setting other
+   supported sizes. (It supports 12, 24, 32, and 48.) Clang has only implemented the 24-bit model,
+   but that could change. (Clang [briefly used][D44355] load/store relocations, but it was reverted
+   because no linker supported them: [BFD], [Gold], [LLD]).
+
+   The 16-, 32-, and 48-bit models use a `movn/movz` instruction to set the highest 16 bits to a
+   positive or negative value, then `movk` to set the remaining 16 bit chunks. In principle, these
+   relocations should be able to accommodate a negative TP offset.
+
+   The 24-bit model uses `add` to set the high 12 bits, then places the low 12 bits into another
+   `add` or a load/store instruction.
+
+Maybe we could modify the `R_AARCH64_TLSLE_ADD_TPREL_HI12` relocation to allow a negative TP offset
+by converting the relocated `add` instruction to a `sub`. Alternately, we could add a new
+`R_AARCH64_TLSLE_SUB_TPREL_HI12` relocation, and Clang would use a different TLS LE instruction
+sequence when targeting Android/arm64.
+
+ * LLD's arm64 relaxations from GD and IE to LE would need to use `movn` instead of `movk` for
+   Android.
+
+ * Binaries linked with the flag crash on non-Bionic, and binaries without the flag crash on Bionic.
+   We might want to mark the binaries somehow to indicate the non-standard TLS ABI. Suggestion:
+    * Use an `--android-tls-variant2` flag (or `--bionic-tls-variant2`, we're trying to make [Bionic
+      run on the host](http://b/31559095))
+    * Add a `PT_ANDROID_TLS_TPOFF` segment?
+    * Add a [`.note.gnu.property`](https://reviews.llvm.org/D53906#1283425) with a
+      "`GNU_PROPERTY_TLS_TPOFF`" property value?
+
+[D44355]: https://reviews.llvm.org/D44355
+[BFD]: https://sourceware.org/bugzilla/show_bug.cgi?id=22970
+[Gold]: https://sourceware.org/bugzilla/show_bug.cgi?id=22969
+[LLD]: https://bugs.llvm.org/show_bug.cgi?id=36727
+
+### Workaround: Reserve an Extra-Large TCB on ARM
+
+Pros: Minimal linker change, no change to TLS relocations.
+Cons: The reserved amount becomes an arbitrary but immutable part of the Android ABI.
+
+Add an lld option: `--android-tls[-tcb=SIZE]`
+
+As with the first workaround, we'd probably want to mark the binary to indicate the non-standard
+TP-to-TLS-segment offset.
+
+Reservation amount:
+ * We would reserve at least 6 words to cover the stack guard
+ * Reserving 16 covers all the existing Bionic slots and gives a little room for expansion. (If we
+   ever needed more than 16 slots, we could allocate the space before TP.)
+ * 16 isn't enough for the pthread keys, so the Go runtime is still a problem.
+ * Reserving 138 words is enough for existing slots and pthread keys.
+
+### Workaround: Use Variant 1 Everywhere with an Extra-Large TCB
+
+Pros:
+ * memory layout is the same on all architectures, avoids native bridge complications
+ * x86/x86-64 relocations probably handle positive offsets without issue
+
+Cons:
+ * The reserved amount is still arbitrary.
+
+### Workaround: No LE Model in Android Executables
+
+Pros:
+ * Keeps options open. We can allow LE later if we want.
+ * Bionic's existing memory layout doesn't change, and arm32 and 32-bit x86 have the same layout
+ * Fixes everything but static executables
+
+Cons:
+ * more intrusive toolchain changes (affects both Clang and LLD)
+ * statically-linked executables still need another workaround
+ * somewhat larger/slower executables (they must use IE, not LE)
+
+The layout conflict is apparently only a problem because an executable assumes that its TLS segment
+is located at a statically-known offset from the TP (i.e. it uses the LE model). An initially-loaded
+shared object can still use the efficient IE access model, but its TLS segment offset is known at
+load-time, not link-time. If we can guarantee that Android's executables also use the IE model, not
+LE, then the Bionic loader can place the executable's TLS segment at any offset from the TP, leaving
+the existing thread-specific memory layout untouched.
+
+This workaround doesn't help with statically-linked executables, but they're probably less of a
+problem, because the linker and `libc.a` are usually packaged together.
+
+A likely problem: LD is normally relaxed to LE, not to IE. We'd either have to disable LD usage in
+the compiler (bad for performance) or add LD->IE relaxation. This relaxation requires that IE code
+sequences be no larger than LD code sequences, which may not be the case on some architectures.
+(XXX: In some past testing, it looked feasible for TLSDESC but not the traditional design.)
+
+To implement:
+ * Clang would need to stop generating LE accesses.
+ * LLD would need to relax GD and LD to IE instead of LE.
+ * LLD should abort if it sees a TLS LE relocation.
+ * LLD must not statically resolve an executable's IE relocation in the GOT. (It might assume that
+   it knows its value.)
+ * Perhaps LLD should mark executables specially, because a normal ELF linker's output would quietly
+   trample on `pthread_internal_t`. We need something like `DF_STATIC_TLS`, but instead of
+   indicating IE in an solib, we want to indicate the lack of LE in an executable.
+
+### (Non-)workaround for Go: Allocate a Slot with Go's Magic Values
+
+The Go runtime allocates its thread-local "g" variable by searching for a hard-coded magic constant
+(`0x23581321` for arm32 and `0x23581321345589` for arm64). As long as it finds its constant at a
+small positive offset from TP (within the first 384 words), it will think it has found the pthread
+key it allocated.
+
+As a temporary compatibility hack, we might try to keep these programs running by reserving a TLS
+slot with this magic value. This hack doesn't appear to work, however. The runtime finds its pthread
+key, but apps segfault. Perhaps the Go runtime expects its "g" variable to be zero-initialized ([one
+example][go-tlsg-zero]). With this hack, it's never zero, but with its current allocation strategy,
+it is typically zero. After [Bionic's pthread key system was rewritten to be
+lock-free][bionic-lockfree-keys] for Android M, though, it's not guaranteed, because a key could be
+recycled.
+
+[go-tlsg-zero]: https://go.googlesource.com/go/+/5bc1fd42f6d185b8ff0201db09fb82886978908b/src/runtime/asm_arm64.s#980
+
+### Workaround for Go: place pthread keys after the executable's TLS
+
+Most Android executables do not use any `thread_local` variables. In the current prototype, with the
+AOSP hikey960 build, only `/system/bin/netd` has a TLS segment, and it's only 32 bytes. As long as
+`/system/bin/app_process{32,64}` limits its use of TLS memory, then the pthread keys could be
+allocated after `app_process`' TLS segment, and Go will still find them.
+
+Go scans 384 words from the thread pointer. If there are at most 16 Bionic slots and 130 pthread
+keys (2 words per key), then `app_process` can use at most 108 words of TLS memory.
+
+Drawback: In principle, this might make pthread key accesses slower, because Bionic can't assume
+that pthread keys are at a fixed offset from the thread pointer anymore. It must load an offset from
+somewhere (a global variable, another TLS slot, ...). `__get_thread()` already uses a TLS slot to
+find `pthread_internal_t`, though, rather than assume a fixed offset. (XXX: I think it could be
+optimized.)
+
+## TODO: Memory Layout Querying APIs (Proposed)
+
+ * https://sourceware.org/glibc/wiki/ThreadPropertiesAPI
+ * http://b/30609580
+
+## TODO: Sanitizers
+
+XXX: Maybe a sanitizer would want to intercept allocations of TLS memory, and that could be hard if
+the loader is allocating it.
+ * It looks like glibc's ld.so re-relocates itself after loading a program, so a program's symbols
+   can interpose call in the loader: https://sourceware.org/ml/libc-alpha/2014-01/msg00501.html
+
+# References
+
+General (and x86/x86-64)
+ * Ulrich Drepper's TLS document, ["ELF Handling For Thread-Local Storage."][drepper] Describes the
+   overall ELF TLS design and ABI details for x86 and x86-64 (as well as several other architectures
+   that Android doesn't target).
+ * Alexandre Oliva's TLSDESC proposal with details for x86 and x86-64: ["Thread-Local Storage
+   Descriptors for IA32 and AMD64/EM64T."][tlsdesc-x86]
+ * [x86 and x86-64 SystemV psABIs][psabi-x86].
+
+arm32:
+ * Alexandre Oliva's TLSDESC proposal for arm32: ["Thread-Local Storage Descriptors for the ARM
+   platform."][tlsdesc-arm]
+ * ["Addenda to, and Errata in, the ABI for the ARM® Architecture."][arm-addenda] Section 3,
+   "Addendum: Thread Local Storage" has details for arm32 non-TLSDESC ELF TLS.
+ * ["Run-time ABI for the ARM® Architecture."][arm-rtabi] Documents `__aeabi_read_tp`.
+ * ["ELF for the ARM® Architecture."][arm-elf] List TLS relocations (traditional and TLSDESC).
+
+arm64:
+ * [2015 LLVM bugtracker comment][llvm22408] with an excerpt from an unnamed ARM draft specification
+   describing arm64 code sequences necessary for linker relaxation
+ * ["ELF for the ARM® 64-bit Architecture (AArch64)."][arm64-elf] Lists TLS relocations (traditional
+   and TLSDESC).
+
+[drepper]: https://www.akkadia.org/drepper/tls.pdf
+[tlsdesc-x86]: https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
+[psabi-x86]: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
+[tlsdesc-arm]: https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-ARM.txt
+[arm-addenda]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf
+[arm-rtabi]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0043d/IHI0043D_rtabi.pdf
+[arm-elf]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
+[llvm22408]: https://bugs.llvm.org/show_bug.cgi?id=22408#c10
+[arm64-elf]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
diff --git a/docs/img/bionic-tls-layout-in-p.png b/docs/img/bionic-tls-layout-in-p.png
new file mode 100644
index 0000000..4c810d6
--- /dev/null
+++ b/docs/img/bionic-tls-layout-in-p.png
Binary files differ
diff --git a/docs/img/tls-variant1.png b/docs/img/tls-variant1.png
new file mode 100644
index 0000000..bd92f16
--- /dev/null
+++ b/docs/img/tls-variant1.png
Binary files differ
diff --git a/docs/img/tls-variant2.png b/docs/img/tls-variant2.png
new file mode 100644
index 0000000..f941af7
--- /dev/null
+++ b/docs/img/tls-variant2.png
Binary files differ
diff --git a/libc/Android.bp b/libc/Android.bp
index 681394f..bc4dd9e 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -65,7 +65,7 @@
     cppflags: [],
     include_dirs: [
         "bionic/libc/async_safe/include",
-        "external/jemalloc/include",
+        "external/jemalloc_new/include",
     ],
 
     stl: "none",
@@ -76,6 +76,9 @@
     },
     native_coverage: false,
     recovery_available: true,
+
+    // TODO(ivanlozano): Remove after b/118321713
+    xom: false,
 }
 
 // ANDROIDMK TRANSLATION ERROR: unsupported directive
@@ -268,23 +271,11 @@
                 "upstream-freebsd/lib/libc/string/wcscmp.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/wcscat.c",
+                "upstream-freebsd/lib/libc/string/wcscpy.c",
+                "upstream-freebsd/lib/libc/string/wmemcmp.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",
-                ],
-            },
         },
     },
 
@@ -563,13 +554,9 @@
         arm: {
             exclude_srcs: [
                 "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
             ],
-            neon: {
-                exclude_srcs: [
-                    "upstream-openbsd/lib/libc/string/stpcpy.c",
-                    "upstream-openbsd/lib/libc/string/strcat.c",
-                ],
-            },
         },
         arm64: {
             exclude_srcs: [
@@ -603,14 +590,10 @@
                 "upstream-openbsd/lib/libc/string/strcpy.c",
                 "upstream-openbsd/lib/libc/string/strncmp.c",
                 "upstream-openbsd/lib/libc/string/strncpy.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
+                "upstream-openbsd/lib/libc/string/strncat.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: {
@@ -708,120 +691,32 @@
 
     arch: {
         arm: {
-            cflags: ["-DNO___MEMCPY_CHK"],
+            cflags: [
+                "-DNO___MEMCPY_CHK",
+                "-DRENAME___STRCAT_CHK",
+                "-DRENAME___STRCPY_CHK",
+            ],
             srcs: [
                 "arch-arm/generic/bionic/__memcpy_chk.S",
+
+                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+
+                "arch-arm/cortex-a7/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
+
+                "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+
+                "arch-arm/krait/bionic/__strcat_chk.S",
+                "arch-arm/krait/bionic/__strcpy_chk.S",
+
+                "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+                "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+
+                "arch-arm/denver/bionic/__strcat_chk.S",
+                "arch-arm/denver/bionic/__strcpy_chk.S",
             ],
-            neon: {
-                cflags: [
-                    "-DNO___STRCAT_CHK",
-                    "-DNO___STRCPY_CHK",
-                ],
-                srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a7: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a9: {
-                srcs: [
-                    "arch-arm/cortex-a9/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            krait: {
-                srcs: [
-                    "arch-arm/krait/bionic/__strcat_chk.S",
-                    "arch-arm/krait/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a53: {
-                srcs: [
-                    "arch-arm/cortex-a53/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a55: {
-                srcs: [
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a73: {
-                srcs: [
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a75: {
-                srcs: [
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            cortex_a76: {
-                srcs: [
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            denver: {
-                srcs: [
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
-            kryo: {
-                srcs: [
-                    "arch-arm/krait/bionic/__strcat_chk.S",
-                    "arch-arm/krait/bionic/__strcpy_chk.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                ],
-            },
         },
         arm64: {
             cflags: ["-DNO___MEMCPY_CHK"],
@@ -865,6 +760,8 @@
                 "arch-arm/generic/bionic/memcmp.S",
                 "arch-arm/generic/bionic/memmove.S",
                 "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/stpcpy.c",
+                "arch-arm/generic/bionic/strcat.c",
                 "arch-arm/generic/bionic/strcmp.S",
                 "arch-arm/generic/bionic/strcpy.S",
                 "arch-arm/generic/bionic/strlen.c",
@@ -878,162 +775,44 @@
                 "arch-arm/bionic/setjmp.S",
                 "arch-arm/bionic/syscall.S",
                 "arch-arm/bionic/vfork.S",
+
+                "arch-arm/cortex-a15/bionic/memcpy.S",
+                "arch-arm/cortex-a15/bionic/memmove.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/strcmp.S",
+                "arch-arm/cortex-a15/bionic/strcpy.S",
+                "arch-arm/cortex-a15/bionic/strlen.S",
+
+                "arch-arm/cortex-a7/bionic/memcpy.S",
+                "arch-arm/cortex-a7/bionic/memmove.S",
+                "arch-arm/cortex-a7/bionic/memset.S",
+
+                "arch-arm/cortex-a9/bionic/memcpy.S",
+                "arch-arm/cortex-a9/bionic/memmove.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/strcmp.S",
+                "arch-arm/cortex-a9/bionic/strcpy.S",
+                "arch-arm/cortex-a9/bionic/strlen.S",
+
+                "arch-arm/krait/bionic/memcpy.S",
+                "arch-arm/krait/bionic/memmove.S",
+                "arch-arm/krait/bionic/memset.S",
+                "arch-arm/krait/bionic/strcmp.S",
+
+                "arch-arm/cortex-a53/bionic/memcpy.S",
+                "arch-arm/cortex-a53/bionic/memmove.S",
+
+                "arch-arm/denver/bionic/memcpy.S",
+                "arch-arm/denver/bionic/memmove.S",
+                "arch-arm/denver/bionic/memset.S",
+
+                "arch-arm/kryo/bionic/memcpy.S",
+                "arch-arm/kryo/bionic/memmove.S",
             ],
-            cortex_a7: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/memcpy.S",
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                ],
-            },
-            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/strcmp.S",
-                    "arch-arm/cortex-a9/bionic/strcpy.S",
-                    "arch-arm/cortex-a9/bionic/strlen.S",
-                ],
-                exclude_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/strcmp.S",
-                    "arch-arm/cortex-a15/bionic/strcpy.S",
-                    "arch-arm/cortex-a15/bionic/strlen.S",
-                ],
-            },
-            krait: {
-                srcs: [
-                    "arch-arm/krait/bionic/memcpy.S",
-                    "arch-arm/krait/bionic/memset.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            cortex_a53: {
-                srcs: [
-                    "arch-arm/cortex-a53/bionic/memcpy.S",
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                ],
-            },
-            cortex_a55: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                    "arch-arm/denver/bionic/memcpy.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            cortex_a73: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                    "arch-arm/denver/bionic/memcpy.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            cortex_a75: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                    "arch-arm/denver/bionic/memcpy.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            cortex_a76: {
-                srcs: [
-                    "arch-arm/cortex-a7/bionic/memset.S",
-                    "arch-arm/denver/bionic/memcpy.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            denver: {
-                srcs: [
-                    "arch-arm/denver/bionic/memcpy.S",
-                    "arch-arm/denver/bionic/memset.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                ],
-            },
-            kryo: {
-                srcs: [
-                    "arch-arm/kryo/bionic/memcpy.S",
-                    "arch-arm/cortex-a7/bionic/memset.S",
-
-                    "arch-arm/krait/bionic/strcmp.S",
-                ],
-                exclude_srcs: [
-                    "arch-arm/cortex-a15/bionic/memset.S",
-                    "arch-arm/cortex-a15/bionic/memcpy.S",
-                    "arch-arm/cortex-a15/bionic/strcmp.S",
-                ],
-            },
-            // Cores not listed above (like cortex-a8, cortex-a15) or
-            // "generic" core will use the following implementation.
-            neon: {
-                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/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/memmove.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",
-                ],
-            },
         },
         arm64: {
             srcs: [
@@ -1136,6 +915,14 @@
                 "arch-x86/generic/string/strcmp.S",
                 "arch-x86/generic/string/strncmp.S",
                 "arch-x86/generic/string/strcat.S",
+
+                "arch-x86/generic/string/strlcat.c",
+                "arch-x86/generic/string/strlcpy.c",
+                "arch-x86/generic/string/strncat.c",
+                "arch-x86/generic/string/wcscat.c",
+                "arch-x86/generic/string/wcscpy.c",
+                "arch-x86/generic/string/wmemcmp.c",
+
                 "arch-x86/atom/string/sse2-memchr-atom.S",
                 "arch-x86/atom/string/sse2-memrchr-atom.S",
                 "arch-x86/atom/string/sse2-strchr-atom.S",
@@ -1160,6 +947,29 @@
                 "arch-x86/bionic/setjmp.S",
                 "arch-x86/bionic/syscall.S",
                 "arch-x86/bionic/vfork.S",
+
+                // ssse3 functions
+                "arch-x86/atom/string/ssse3-strcat-atom.S",
+                "arch-x86/atom/string/ssse3-strcmp-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-wcscat-atom.S",
+                "arch-x86/atom/string/ssse3-wcscpy-atom.S",
+
+                // sse4 functions
+                "arch-x86/silvermont/string/sse4-memcmp-slm.S",
+                "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
+
+                // atom functions
+                "arch-x86/atom/string/sse2-memset-atom.S",
+                "arch-x86/atom/string/sse2-strlen-atom.S",
+                "arch-x86/atom/string/ssse3-memcmp-atom.S",
+                "arch-x86/atom/string/ssse3-memmove-atom.S",
+                "arch-x86/atom/string/ssse3-strcpy-atom.S",
+                "arch-x86/atom/string/ssse3-strncpy-atom.S",
+                "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
             ],
 
             exclude_srcs: [
@@ -1167,51 +977,6 @@
                 "bionic/strnlen.c",
                 "bionic/strrchr.cpp",
             ],
-            atom: {
-                srcs: [
-                    "arch-x86/atom/string/sse2-memset-atom.S",
-                    "arch-x86/atom/string/sse2-strlen-atom.S",
-                    "arch-x86/atom/string/ssse3-memcmp-atom.S",
-                    "arch-x86/atom/string/ssse3-memcpy-atom.S",
-                    "arch-x86/atom/string/ssse3-strcpy-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-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: [
@@ -1402,9 +1167,7 @@
         "bionic/sys_msg.cpp",
         "bionic/sys_sem.cpp",
         "bionic/sys_shm.cpp",
-        "bionic/sys_siglist.c",
         "bionic/sys_signalfd.cpp",
-        "bionic/sys_signame.c",
         "bionic/sys_time.cpp",
         "bionic/sysinfo.cpp",
         "bionic/syslog.cpp",
@@ -1597,7 +1360,7 @@
         "libc_syscalls",
         "libc_tzcode",
         "libm",
-        "libjemalloc",
+        "libjemalloc5",
         "libstdc++",
     ],
 }
@@ -1656,6 +1419,52 @@
 }
 
 // ========================================================
+// libc_common_static.a For static binaries.
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    name: "libc_common_static",
+
+    arch: {
+        x86: {
+            srcs: ["arch-x86/static_function_dispatch.S"],
+        },
+        arm: {
+            srcs: ["arch-arm/static_function_dispatch.S"],
+        },
+    },
+
+    whole_static_libs: [
+        "libc_common",
+    ],
+}
+
+// ========================================================
+// libc_common_shared.a For shared libraries.
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    name: "libc_common_shared",
+
+    cflags: [
+        "-fno-stack-protector",
+        "-fno-jump-tables",
+    ],
+    arch: {
+        x86: {
+            srcs: ["arch-x86/dynamic_function_dispatch.cpp"],
+        },
+        arm: {
+            srcs: ["arch-arm/dynamic_function_dispatch.cpp"],
+        },
+    },
+
+    whole_static_libs: [
+        "libc_common",
+    ],
+}
+
+// ========================================================
 // libc_nomalloc.a
 // ========================================================
 //
@@ -1679,7 +1488,7 @@
     cflags: ["-DLIBC_STATIC"],
 
     whole_static_libs: [
-        "libc_common",
+        "libc_common_static",
         "libc_init_static",
     ],
 }
@@ -1702,6 +1511,7 @@
     defaults: ["libc_defaults"],
     name: "libc",
     static_ndk_lib: true,
+    export_include_dirs: ["include"],
     product_variables: {
         platform_sdk_version: {
             asflags: ["-DPLATFORM_SDK_VERSION=%d"],
@@ -1713,7 +1523,10 @@
             "bionic/malloc_common.cpp",
         ],
         cflags: ["-DLIBC_STATIC"],
-        whole_static_libs: ["libc_init_static"],
+        whole_static_libs: [
+            "libc_init_static",
+            "libc_common_static",
+        ],
     },
     shared: {
         srcs: [
@@ -1724,7 +1537,10 @@
             "bionic/NetdClient.cpp",
             "arch-common/bionic/crtend_so.S",
         ],
-        whole_static_libs: ["libc_init_dynamic"],
+        whole_static_libs: [
+            "libc_init_dynamic",
+            "libc_common_shared",
+        ],
     },
 
     required: ["tzdata"],
@@ -1751,8 +1567,7 @@
         "libdl",
     ],
     whole_static_libs: [
-        "libc_common",
-        "libjemalloc",
+        "libjemalloc5",
     ],
 
     nocrt: true,
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 5c63c0f..772f0e7 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -5,7 +5,7 @@
 # return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list
 #
 # where:
-#       arch_list ::= "all" | arch+
+#       arch_list ::= "all" | "lp32" | "lp64" | arch+
 #       arch      ::= "arm" | "arm64" | "mips" | "mips64" | "x86" | "x86_64"
 #
 # Note:
@@ -68,11 +68,11 @@
 # On 32-bit systems we use prlimit64 to implement the rlimit64 functions.
 int getrlimit:ugetrlimit(int, struct rlimit*)  arm,x86
 int getrlimit(int, struct rlimit*)  mips
-int getrlimit|getrlimit64(int, struct rlimit*)  arm64,mips64,x86_64
-int setrlimit(int, const struct rlimit*)  arm,mips,x86
-int setrlimit|setrlimit64(int, const struct rlimit*)  arm64,mips64,x86_64
-int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*)  arm64,mips64,x86_64
-int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*)  arm,mips,x86
+int getrlimit|getrlimit64(int, struct rlimit*)  lp64
+int setrlimit(int, const struct rlimit*)  lp32
+int setrlimit|setrlimit64(int, const struct rlimit*)  lp64
+int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*)  lp64
+int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*)  lp32
 
 int     setgroups:setgroups32(int, const gid_t*)   arm,x86
 int     setgroups:setgroups(int, const gid_t*)     arm64,mips,mips64,x86_64
@@ -90,19 +90,19 @@
 # file descriptors
 ssize_t     read(int, void*, size_t)        all
 ssize_t     write(int, const void*, size_t)       all
-ssize_t     pread64(int, void*, size_t, off64_t) arm,mips,x86
-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
+ssize_t     pread64(int, void*, size_t, off64_t) lp32
+ssize_t     pread64|pread(int, void*, size_t, off_t) lp64
+ssize_t     pwrite64(int, void*, size_t, off64_t) lp32
+ssize_t     pwrite64|pwrite(int, void*, size_t, off_t) lp64
 
 # 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
+ssize_t     __preadv64:preadv(int, const struct iovec*, int, long, long) lp32
+ssize_t     preadv|preadv64(int, const struct iovec*, int, off_t) lp64
+ssize_t     __pwritev64:pwritev(int, const struct iovec*, int, long, long) lp32
+ssize_t     pwritev|pwritev64(int, const struct iovec*, int, off_t) lp64
 
 int         ___close:close(int)  all
 pid_t       __getpid:getpid()  all
@@ -119,8 +119,8 @@
 int         __ioctl:ioctl(int, int, void*)  all
 ssize_t     readv(int, const struct iovec*, int)   all
 ssize_t     writev(int, const struct iovec*, int)  all
-int         __fcntl64:fcntl64(int, int, void*)  arm,mips,x86
-int         fcntl(int, int, void*)  arm64,mips64,x86_64
+int         __fcntl64:fcntl64(int, int, void*)  lp32
+int         fcntl(int, int, void*)  lp64
 int         flock(int, int)   all
 int         ___fchmod:fchmod(int, mode_t)  all
 int         dup(int)  all
@@ -143,7 +143,7 @@
 int ___faccessat:faccessat(int, const char*, int)  all
 int ___fchmodat:fchmodat(int, const char*, mode_t)  all
 int fchownat(int, const char*, uid_t, gid_t, int)  all
-int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int)   arm,mips,x86
+int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int)   lp32
 int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int)  arm64,x86_64
 int linkat(int, const char*, int, const char*, int)  all
 int mkdirat(int, const char*, mode_t)  all
@@ -158,23 +158,23 @@
 # sizeof(off_t) == sizeof(off64_t), so there we emit two symbols that are
 # aliases. On 32-bit systems, we have two different system calls.
 # That means that every system call in this section should take three lines.
-off_t lseek(int, off_t, int) arm,mips,x86
-int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
-off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64
-int ftruncate64(int, off64_t) arm,mips,x86
-int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64
-ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86
-ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) arm,mips,x86
-ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) arm64,mips64,x86_64
-int truncate(const char*, off_t) arm,mips,x86
-int truncate64(const char*, off64_t) arm,mips,x86
-int truncate|truncate64(const char*, off_t) arm64,mips64,x86_64
+off_t lseek(int, off_t, int) lp32
+int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) lp32
+off_t lseek|lseek64(int, off_t, int) lp64
+int ftruncate64(int, off64_t) lp32
+int ftruncate|ftruncate64(int, off_t) lp64
+ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) lp32
+ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) lp32
+ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) lp64
+int truncate(const char*, off_t) lp32
+int truncate64(const char*, off64_t) lp32
+int truncate|truncate64(const char*, off_t) lp64
 # (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.)
-void* __mmap2:mmap2(void*, size_t, int, int, int, long)   arm,mips,x86
-void* mmap|mmap64(void*, size_t, int, int, int, off_t)  arm64,mips64,x86_64
+void* __mmap2:mmap2(void*, size_t, int, int, int, long)   lp32
+void* mmap|mmap64(void*, size_t, int, int, int, off_t)  lp64
 # (fallocate only gets two lines because there is no 32-bit variant.)
-int fallocate64:fallocate(int, int, off64_t, off64_t) arm,mips,x86
-int fallocate|fallocate64(int, int, off_t, off_t) arm64,mips64,x86_64
+int fallocate64:fallocate(int, int, off64_t, off64_t) lp32
+int fallocate|fallocate64(int, int, off_t, off_t) lp64
 
 # posix_fadvise64 is awkward: arm has shuffled arguments,
 # the POSIX functions don't set errno, and no architecture has posix_fadvise.
@@ -182,12 +182,12 @@
 int __fadvise64:fadvise64_64(int, off64_t, off64_t, int) x86
 int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64
 
-int __fstatfs64:fstatfs64(int, size_t, struct statfs*)  arm,mips,x86
-int __fstatfs:fstatfs(int, struct statfs*)  arm64,mips64,x86_64
-int __statfs64:statfs64(const char*, size_t, struct statfs*)  arm,mips,x86
-int __statfs:statfs(const char*, struct statfs*)  arm64,mips64,x86_64
+int __fstatfs64:fstatfs64(int, size_t, struct statfs*)  lp32
+int __fstatfs:fstatfs(int, struct statfs*)  lp64
+int __statfs64:statfs64(const char*, size_t, struct statfs*)  lp32
+int __statfs:statfs(const char*, struct statfs*)  lp64
 
-int     fstat64|fstat:fstat64(int, struct stat*)    arm,mips,x86
+int     fstat64|fstat:fstat64(int, struct stat*)    lp32
 int     fstat64|fstat:fstat(int, struct stat*)    arm64,x86_64
 
 # file system
@@ -227,7 +227,7 @@
 int           clock_adjtime(clockid_t, struct timex*)   all
 
 # signals
-int     __sigaction:sigaction(int, const struct sigaction*, struct sigaction*)  arm,mips,x86
+int     __sigaction:sigaction(int, const struct sigaction*, struct sigaction*)  lp32
 int     __rt_sigaction:rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t)  all
 int     __rt_sigpending:rt_sigpending(sigset64_t*, size_t)  all
 int     __rt_sigprocmask:rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t)  all
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
index ca29715..69e405f 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 // 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)
+ENTRY(__strcat_chk_a15)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
index 2679c02..ddde30e 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a15)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
 
 #include "memcpy_base.S"
 
-END(__strcpy_chk)
+END(__strcpy_chk_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 0bab6ee..a9dfaff 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -64,7 +64,7 @@
         .arch armv7-a
 
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a15)
         pld     [r1, #64]
         push    {r0, lr}
         .cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
         .cfi_rel_offset lr, 4
 
 #include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a15)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a15/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a15/bionic/memmove.S
index b60123c..2b12de0 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a15/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_a15
+#define MEMCPY __memcpy_a15
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a15/bionic/memset.S b/libc/arch-arm/cortex-a15/bionic/memset.S
index 4b4388e..ead881e 100644
--- a/libc/arch-arm/cortex-a15/bionic/memset.S
+++ b/libc/arch-arm/cortex-a15/bionic/memset.S
@@ -41,7 +41,7 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a15)
         cmp         r2, r3
         bls         memset
 
@@ -51,9 +51,9 @@
         .cfi_rel_offset lr, 0
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a15)
 
-ENTRY(memset)
+ENTRY(memset_a15)
         stmfd       sp!, {r0}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset r0, 0
@@ -171,4 +171,4 @@
         strbcs      r1, [r0], #1
         ldmfd       sp!, {r0}
         bx          lr
-END(memset)
+END(memset_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/strcat.S b/libc/arch-arm/cortex-a15/bionic/strcat.S
index 157cc9f..260926a 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcat.S
@@ -80,7 +80,7 @@
     \cmd    \reg, \label
     .endm // m_copy_byte
 
-ENTRY(strcat)
+ENTRY(strcat_a15)
     // Quick check to see if src is empty.
     ldrb    r2, [r1]
     pld     [r1, #0]
@@ -572,4 +572,4 @@
 .L_strcat_sub2:
     sub     r0, r0, #2
     b       .L_strcat_r0_scan_done
-END(strcat)
+END(strcat_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/strcmp.S b/libc/arch-arm/cortex-a15/bionic/strcmp.S
index d8993d5..58dbf17 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcmp.S
@@ -61,7 +61,7 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(strcmp)
+ENTRY(strcmp_a15)
       /* Use LDRD whenever possible.  */
 
 /* The main thing to look out for when comparing large blocks is that
@@ -376,4 +376,4 @@
         it      ls
         sbcls   r0, r0, r0
         bx      lr
-END(strcmp)
+END(strcmp_a15)
diff --git a/libc/arch-arm/cortex-a15/bionic/string_copy.S b/libc/arch-arm/cortex-a15/bionic/string_copy.S
index 92d1c98..affbc3b 100644
--- a/libc/arch-arm/cortex-a15/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a15/bionic/string_copy.S
@@ -100,9 +100,9 @@
     .endm // m_copy_byte
 
 #if defined(STPCPY)
-ENTRY(stpcpy)
+ENTRY(stpcpy_a15)
 #else
-ENTRY(strcpy)
+ENTRY(strcpy_a15)
 #endif
     // For short copies, hard-code checking the first 8 bytes since this
     // new code doesn't win until after about 8 bytes.
@@ -514,7 +514,7 @@
     strb    r4, [r0]
     m_pop
 #if defined(STPCPY)
-END(stpcpy)
+END(stpcpy_a15)
 #else
-END(strcpy)
+END(strcpy_a15)
 #endif
diff --git a/libc/arch-arm/cortex-a15/bionic/strlen.S b/libc/arch-arm/cortex-a15/bionic/strlen.S
index 4fd6284..9c5ed29 100644
--- a/libc/arch-arm/cortex-a15/bionic/strlen.S
+++ b/libc/arch-arm/cortex-a15/bionic/strlen.S
@@ -60,7 +60,7 @@
     .thumb
     .thumb_func
 
-ENTRY(strlen)
+ENTRY(strlen_a15)
     pld     [r0, #0]
     mov     r1, r0
 
@@ -162,4 +162,4 @@
 .L_sub2_and_return:
     sub     r0, r0, #2
     bx      lr
-END(strlen)
+END(strlen_a15)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
index ca29715..72be243 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 // 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)
+ENTRY(__strcat_chk_a53)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a53)
diff --git a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
index 2679c02..4922884 100644
--- a/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a53)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
 
 #include "memcpy_base.S"
 
-END(__strcpy_chk)
+END(__strcpy_chk_a53)
diff --git a/libc/arch-arm/cortex-a53/bionic/memcpy.S b/libc/arch-arm/cortex-a53/bionic/memcpy.S
index 0bab6ee..ea748bd 100644
--- a/libc/arch-arm/cortex-a53/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy.S
@@ -64,7 +64,7 @@
         .arch armv7-a
 
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a53)
         pld     [r1, #64]
         push    {r0, lr}
         .cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
         .cfi_rel_offset lr, 4
 
 #include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a53)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a53/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a53/bionic/memmove.S
index b60123c..741acb3 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a53/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_a53
+#define MEMCPY __memcpy_a53
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
index ca29715..36bda6b 100644
--- a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 // 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)
+ENTRY(__strcat_chk_a7)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -200,4 +200,4 @@
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_a7)
diff --git a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
index 2679c02..edbabc7 100644
--- a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a7)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -162,4 +162,4 @@
 
 #include "memcpy_base.S"
 
-END(__strcpy_chk)
+END(__strcpy_chk_a7)
diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy.S b/libc/arch-arm/cortex-a7/bionic/memcpy.S
index 0bab6ee..2f32d2e 100644
--- a/libc/arch-arm/cortex-a7/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a7/bionic/memcpy.S
@@ -64,7 +64,7 @@
         .arch armv7-a
 
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
-ENTRY(__memcpy)
+ENTRY(__memcpy_a7)
         pld     [r1, #64]
         push    {r0, lr}
         .cfi_def_cfa_offset 8
@@ -72,4 +72,4 @@
         .cfi_rel_offset lr, 4
 
 #include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_a7)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a7/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a7/bionic/memmove.S
index b60123c..17ead5a 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a7/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_a7
+#define MEMCPY __memcpy_a7
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <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
index 72ee613..d7d3b34 100644
--- a/libc/arch-arm/cortex-a7/bionic/memset.S
+++ b/libc/arch-arm/cortex-a7/bionic/memset.S
@@ -41,7 +41,7 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a7)
         cmp         r2, r3
         bls         memset
 
@@ -51,9 +51,9 @@
         .cfi_rel_offset lr, 0
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a7)
 
-ENTRY(memset)
+ENTRY(memset_a7)
         mov         r3, r0
         // At this point only d0, d1 are going to be used below.
         vdup.8      q0, r1
@@ -160,4 +160,4 @@
         strbcs      r1, [r3], #1
         strbcs      r1, [r3], #1
         bx          lr
-END(memset)
+END(memset_a7)
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
index 776c782..d20283e 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
@@ -33,10 +33,14 @@
     .thumb
     .thumb_func
 
+    // To avoid warning about deprecated instructions, add an explicit
+    // arch. The code generated is exactly the same.
+    .arch armv7-a
+
 // 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)
+ENTRY(__strcat_chk_a9)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -191,8 +195,8 @@
     pop     {r4, r5}
 
     // Fall through into the memcpy_base function.
-END(__strcat_chk)
+END(__strcat_chk_a9)
 
-#define MEMCPY_BASE         __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#define MEMCPY_BASE         __strcat_chk_a9_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_a9_memcpy_base_aligned
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
index 1d5e70b..1f0a774 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
@@ -33,9 +33,13 @@
     .thumb
     .thumb_func
 
+    // To avoid warning about deprecated instructions, add an explicit
+    // arch. The code generated is exactly the same.
+    .arch armv7-a
+
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_a9)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -159,8 +163,8 @@
     bhi     __strcpy_chk_fail
 
     // Fall through into the memcpy_base function.
-END(__strcpy_chk)
+END(__strcpy_chk_a9)
 
-#define MEMCPY_BASE         __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#define MEMCPY_BASE         __strcpy_chk_a9_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_a9_memcpy_base_aligned
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy.S b/libc/arch-arm/cortex-a9/bionic/memcpy.S
index a71c9d2..e78a7da 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy.S
@@ -39,15 +39,15 @@
         .thumb
         .thumb_func
 
-ENTRY(__memcpy)
+ENTRY(__memcpy_a9)
         pld     [r1, #0]
         stmfd   sp!, {r0, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
         pld     [r1, #64]
-END(__memcpy)
+END(__memcpy_a9)
 
-#define MEMCPY_BASE         __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#define MEMCPY_BASE         __memcpy_base_a9
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_a9
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
index 966b9b3..39da7ff 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
@@ -32,6 +32,12 @@
  * cache line.
  */
 
+        .syntax unified
+
+        // To avoid warning about deprecated instructions, add an explicit
+        // arch. The code generated is exactly the same.
+        .arch armv7-a
+
 ENTRY_PRIVATE(MEMCPY_BASE)
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/cortex-a9/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/cortex-a9/bionic/memmove.S
index b60123c..a457633 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/cortex-a9/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_a9
+#define MEMCPY __memcpy_a9
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index d00231b..cf66e86 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -36,7 +36,7 @@
     .fpu    neon
     .syntax unified
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_a9)
         cmp         r2, r3
         bls         memset
 
@@ -46,10 +46,10 @@
         .cfi_rel_offset lr, 0
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_a9)
 
 /* memset() returns its first argument.  */
-ENTRY(memset)
+ENTRY(memset_a9)
         // The neon memset only wins for less than 132.
         cmp         r2, #132
         bhi         .L_memset_large_copy
@@ -158,4 +158,4 @@
         movs        r2, r2, lsl #2
         strbcs      r1, [r0]
         ldmfd       sp!, {r0, r4-r7, pc}
-END(memset)
+END(memset_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/strcat.S b/libc/arch-arm/cortex-a9/bionic/strcat.S
index 9077a74..430748f 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcat.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcat.S
@@ -57,6 +57,10 @@
 
     .syntax unified
 
+    // To avoid warning about deprecated instructions, add an explicit
+    // arch. The code generated is exactly the same.
+    .arch armv7-a
+
     .thumb
     .thumb_func
 
@@ -80,7 +84,7 @@
     \cmd    \reg, \label
     .endm // m_copy_byte
 
-ENTRY(strcat)
+ENTRY(strcat_a9)
     // Quick check to see if src is empty.
     ldrb        r2, [r1]
     pld         [r1, #0]
@@ -552,4 +556,4 @@
 .Lstrcat_r0_update:
     sub     r0, r0, #1
     b .Lstrcat_r0_scan_done
-END(strcat)
+END(strcat_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/strcmp.S b/libc/arch-arm/cortex-a9/bionic/strcmp.S
index ba191d6..ba7ea13 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcmp.S
@@ -52,12 +52,16 @@
 
 .syntax         unified
 
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
 #if defined (__thumb__)
         .thumb
         .thumb_func
 #endif
 
-ENTRY(strcmp)
+ENTRY(strcmp_a9)
       /* Use LDRD whenever possible.  */
 
 /* The main thing to look out for when comparing large blocks is that
@@ -544,4 +548,4 @@
     adds    sp, sp, #16
 
 	bx	lr
-END(strcmp)
+END(strcmp_a9)
diff --git a/libc/arch-arm/cortex-a9/bionic/string_copy.S b/libc/arch-arm/cortex-a9/bionic/string_copy.S
index 642db0f..3605b7a 100644
--- a/libc/arch-arm/cortex-a9/bionic/string_copy.S
+++ b/libc/arch-arm/cortex-a9/bionic/string_copy.S
@@ -64,6 +64,10 @@
     .thumb
     .thumb_func
 
+    // To avoid warning about deprecated instructions, add an explicit
+    // arch. The code generated is exactly the same.
+    .arch armv7-a
+
 #if defined(STPCPY)
     .macro m_push
     push    {r4, r5, lr}
@@ -100,9 +104,9 @@
     .endm // m_copy_byte
 
 #if defined(STPCPY)
-ENTRY(stpcpy)
+ENTRY(stpcpy_a9)
 #else
-ENTRY(strcpy)
+ENTRY(strcpy_a9)
 #endif
     // Unroll the first 8 bytes that will be copied.
     m_push
@@ -536,7 +540,7 @@
 #endif
     m_ret   inst=pop
 #if defined(STPCPY)
-END(stpcpy)
+END(stpcpy_a9)
 #else
-END(strcpy)
+END(strcpy_a9)
 #endif
diff --git a/libc/arch-arm/cortex-a9/bionic/strlen.S b/libc/arch-arm/cortex-a9/bionic/strlen.S
index b92b043..ffebc9d 100644
--- a/libc/arch-arm/cortex-a9/bionic/strlen.S
+++ b/libc/arch-arm/cortex-a9/bionic/strlen.S
@@ -57,10 +57,14 @@
 
     .syntax unified
 
+    // To avoid warning about deprecated instructions, add an explicit
+    // arch. The code generated is exactly the same.
+    .arch armv7-a
+
     .thumb
     .thumb_func
 
-ENTRY(strlen)
+ENTRY(strlen_a9)
     pld     [r0, #0]
     mov     r1, r0
 
@@ -164,4 +168,4 @@
     sub     r0, r1, r0
     sub     r0, r0, #1
     bx      lr
-END(strlen)
+END(strlen_a9)
diff --git a/libc/arch-arm/denver/bionic/__strcat_chk.S b/libc/arch-arm/denver/bionic/__strcat_chk.S
index d4f651c..1899908 100644
--- a/libc/arch-arm/denver/bionic/__strcat_chk.S
+++ b/libc/arch-arm/denver/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 // 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)
+ENTRY(__strcat_chk_denver)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -190,9 +190,9 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-END(__strcat_chk)
+END(__strcat_chk_denver)
 
-#define MEMCPY_BASE         __strcat_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#define MEMCPY_BASE         __strcat_chk_denver_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_denver_memcpy_base_aligned
 
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/__strcpy_chk.S b/libc/arch-arm/denver/bionic/__strcpy_chk.S
index 9295a00..9910c76 100644
--- a/libc/arch-arm/denver/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/denver/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_denver)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_def_cfa_offset 8
@@ -161,8 +161,8 @@
     bhi     __strcpy_chk_fail
 
     // Fall through into the memcpy_base function.
-END(__strcpy_chk)
+END(__strcpy_chk_denver)
 
-#define MEMCPY_BASE         __strcpy_chk_memcpy_base
-#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#define MEMCPY_BASE         __strcpy_chk_denver_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_denver_memcpy_base_aligned
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/memcpy.S b/libc/arch-arm/denver/bionic/memcpy.S
index f082542..5edee1e 100644
--- a/libc/arch-arm/denver/bionic/memcpy.S
+++ b/libc/arch-arm/denver/bionic/memcpy.S
@@ -65,14 +65,14 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memcpy)
+ENTRY(__memcpy_denver)
         pld     [r1, #64]
         push    {r0, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
-END(__memcpy)
+END(__memcpy_denver)
 
-#define MEMCPY_BASE         __memcpy_base
-#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#define MEMCPY_BASE         __memcpy_base_denver
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_denver
 #include "memcpy_base.S"
diff --git a/libc/arch-arm/denver/bionic/memmove.S b/libc/arch-arm/denver/bionic/memmove.S
index 74d2b31..13c90ef 100644
--- a/libc/arch-arm/denver/bionic/memmove.S
+++ b/libc/arch-arm/denver/bionic/memmove.S
@@ -29,6 +29,14 @@
 
 #include <private/bionic_asm.h>
 
+#ifndef MEMMOVE
+# define MEMMOVE memmove_denver
+#endif
+
+#ifndef MEMCPY
+# define MEMCPY __memcpy_denver
+#endif
+
         .text
         .syntax unified
         .fpu    neon
@@ -40,7 +48,7 @@
 #define PREFETCH_DISTANCE_MID   (CACHE_LINE_SIZE*4)
 #define PREFETCH_DISTANCE_FAR   (CACHE_LINE_SIZE*16)
 
-ENTRY(memmove)
+ENTRY(MEMMOVE)
         cmp         r2, #0
         cmpne       r0, r1
         bxeq        lr
@@ -50,7 +58,7 @@
         bhi         .L_reversed_memcpy
 
 .L_jump_to_memcpy:
-        b           __memcpy
+        b           MEMCPY
 
 .L_reversed_memcpy:
         push        {r0, lr}
@@ -277,6 +285,4 @@
 
         pop         {r0, pc}
 
-END(memmove)
-
-ALIAS_SYMBOL(memcpy, memmove)
+END(MEMMOVE)
diff --git a/libc/arch-arm/denver/bionic/memset.S b/libc/arch-arm/denver/bionic/memset.S
index 88ffe5c..198ecf3 100644
--- a/libc/arch-arm/denver/bionic/memset.S
+++ b/libc/arch-arm/denver/bionic/memset.S
@@ -39,7 +39,7 @@
         .fpu        neon
         .syntax     unified
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_denver)
         cmp         r2, r3
         bls         memset
 
@@ -49,9 +49,9 @@
         .cfi_rel_offset lr, 0
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_denver)
 
-ENTRY(memset)
+ENTRY(memset_denver)
         pldw        [r0]
         mov         r3, r0
 
@@ -183,4 +183,4 @@
         strbcs      r1, [r3]
 2:
         bx          lr
-END(memset)
+END(memset_denver)
diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp
new file mode 100644
index 0000000..90eff56
--- /dev/null
+++ b/libc/arch-arm/dynamic_function_dispatch.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2018 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 <fcntl.h>
+#include <sys/syscall.h>
+
+extern "C" {
+
+enum CpuVariant {
+    kUnknown = 0,
+    kGeneric,
+    kCortexA7,
+    kCortexA9,
+    kCortexA53,
+    kCortexA55,
+    kDenver,
+    kKrait,
+    kKryo,
+};
+
+static constexpr int MAX_CPU_NAME_LEN = 12;
+struct CpuVariantNames {
+    char name[MAX_CPU_NAME_LEN];
+    CpuVariant variant;
+};
+
+static constexpr CpuVariantNames cpu_variant_names[] = {
+    {"cortex-a76", kCortexA55},
+    {"cortex-a75", kCortexA55},
+    {"kryo", kKryo},
+    {"cortex-a73", kCortexA55},
+    {"cortex-a55", kCortexA55},
+    {"cortex-a53", kCortexA53},
+    {"krait", kKrait},
+    {"cortex-a9", kCortexA9},
+    {"cortex-a7", kCortexA7},
+    {"denver", kDenver},
+    // kUnknown indicates the end of this array.
+    {"", kUnknown},
+};
+
+static long ifunc_open(const char* pathname) {
+    register long r0 __asm__("r0") = AT_FDCWD;
+    register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
+    register long r2 __asm__("r2") = O_RDONLY;
+    register long r3 __asm__("r3") = 0;
+    register long r7 __asm__("r7") = __NR_openat;
+    __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
+    return r0;
+}
+
+static ssize_t ifunc_read(int fd, void* buf, size_t count) {
+    register long r0 __asm__("r0") = fd;
+    register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
+    register long r2 __asm__("r2") = count;
+    register long r7 __asm__("r7") = __NR_read;
+    __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
+    return r0;
+}
+
+static int ifunc_close(int fd) {
+    register long r0 __asm__("r0") = fd;
+    register long r7 __asm__("r7") = __NR_close;
+    __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
+    return r0;
+}
+
+#define DEFINE_IFUNC(name) \
+    name##_func name __attribute__((ifunc(#name "_resolver"))); \
+    __attribute__((visibility("hidden"))) \
+    name##_func* name##_resolver()
+
+#define DECLARE_FUNC(type, name) \
+    __attribute__((visibility("hidden"))) \
+    type name
+
+#define RETURN_FUNC(type, name) { \
+        DECLARE_FUNC(type, name); \
+        return name; \
+    }
+
+static CpuVariant init_cpu_variant() {
+    int fd = ifunc_open("/dev/cpu_variant:arm");
+    if (fd < 0) return kGeneric;
+
+    char name[MAX_CPU_NAME_LEN];
+
+    int bytes_read, total_read = 0;
+    while (total_read < MAX_CPU_NAME_LEN - 1 &&
+           (bytes_read = ifunc_read(fd, name + total_read,
+                                    MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
+        total_read += bytes_read;
+    }
+    ifunc_close(fd);
+
+    if (bytes_read != 0) {
+        // The file is too big. We haven't reach the end. Or maybe there is an
+        // error when reading.
+        return kGeneric;
+    }
+    name[total_read] = 0;
+
+    typedef int strcmp_func(const char* __lhs, const char* __rhs);
+    DECLARE_FUNC(strcmp_func, strcmp_a15);
+
+    const CpuVariantNames* cpu_variant = cpu_variant_names;
+    while (cpu_variant->variant != kUnknown) {
+        if (strcmp_a15(cpu_variant->name, name) == 0) {
+            return cpu_variant->variant;
+        }
+        cpu_variant++;
+    }
+    return kGeneric;
+}
+
+static CpuVariant get_cpu_variant() {
+    static CpuVariant cpu_variant = kUnknown;
+    if (cpu_variant == kUnknown) {
+        cpu_variant = init_cpu_variant();
+    }
+    return cpu_variant;
+}
+
+typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
+DEFINE_IFUNC(memmove) {
+    switch(get_cpu_variant()) {
+        case kCortexA7:
+            RETURN_FUNC(memmove_func, memmove_a7);
+        case kCortexA9:
+            RETURN_FUNC(memmove_func, memmove_a9);
+        case kKrait:
+            RETURN_FUNC(memmove_func, memmove_krait);
+        case kCortexA53:
+            RETURN_FUNC(memmove_func, memmove_a53);
+        case kCortexA55:
+        case kDenver:
+            RETURN_FUNC(memmove_func, memmove_denver);
+        case kKryo:
+            RETURN_FUNC(memmove_func, memmove_kryo);
+        default:
+            RETURN_FUNC(memmove_func, memmove_a15);
+    }
+}
+
+typedef void* memcpy_func(void*, const void*, size_t);
+DEFINE_IFUNC(memcpy) {
+    return memmove_resolver();
+}
+
+typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
+DEFINE_IFUNC(__memset_chk) {
+    switch(get_cpu_variant()) {
+        case kCortexA7:
+        case kCortexA53:
+        case kCortexA55:
+        case kKryo:
+            RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
+        case kCortexA9:
+            RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
+        case kKrait:
+            RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
+        case kDenver:
+            RETURN_FUNC(__memset_chk_func, __memset_chk_denver);
+        default:
+            RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
+    }
+}
+
+typedef void* memset_func(void* __dst, int __ch, size_t __n);
+DEFINE_IFUNC(memset) {
+    switch(get_cpu_variant()) {
+        case kCortexA7:
+        case kCortexA53:
+        case kCortexA55:
+        case kKryo:
+             RETURN_FUNC(memset_func, memset_a7);
+        case kCortexA9:
+             RETURN_FUNC(memset_func, memset_a9);
+        case kKrait:
+             RETURN_FUNC(memset_func, memset_krait);
+        case kDenver:
+             RETURN_FUNC(memset_func, memset_denver);
+        default:
+             RETURN_FUNC(memset_func, memset_a15);
+    }
+}
+
+typedef char* strcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC(strcpy) {
+    switch(get_cpu_variant()) {
+        case kCortexA9:
+            RETURN_FUNC(strcpy_func, strcpy_a9);
+        default:
+            RETURN_FUNC(strcpy_func, strcpy_a15);
+    }
+}
+
+typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
+DEFINE_IFUNC(__strcpy_chk) {
+    switch(get_cpu_variant()) {
+        case kCortexA7:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
+        case kCortexA9:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
+        case kKrait:
+        case kKryo:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
+        case kCortexA53:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
+        case kCortexA55:
+        case kDenver:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_denver);
+        default:
+            RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
+    }
+}
+
+typedef char* stpcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC(stpcpy) {
+    switch(get_cpu_variant()) {
+        case kCortexA9:
+            RETURN_FUNC(stpcpy_func, stpcpy_a9);
+        default:
+            RETURN_FUNC(stpcpy_func, stpcpy_a15);
+    }
+}
+
+typedef char* strcat_func(char* __dst, const char* __src);
+DEFINE_IFUNC(strcat) {
+    switch(get_cpu_variant()) {
+        case kCortexA9:
+            RETURN_FUNC(strcat_func, strcat_a9);
+        default:
+            RETURN_FUNC(strcat_func, strcat_a15);
+    }
+}
+
+typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
+DEFINE_IFUNC(__strcat_chk) {
+    switch(get_cpu_variant()) {
+        case kCortexA7:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
+        case kCortexA9:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
+        case kKrait:
+        case kKryo:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
+        case kCortexA53:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
+        case kCortexA55:
+        case kDenver:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_denver);
+        default:
+            RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
+    }
+}
+
+typedef int strcmp_func(const char* __lhs, const char* __rhs);
+DEFINE_IFUNC(strcmp) {
+    switch(get_cpu_variant()) {
+        case kCortexA9:
+            RETURN_FUNC(strcmp_func, strcmp_a9);
+        case kCortexA55:
+        case kKrait:
+        case kKryo:
+            RETURN_FUNC(strcmp_func, strcmp_krait);
+        default:
+            RETURN_FUNC(strcmp_func, strcmp_a15);
+    }
+}
+
+typedef size_t strlen_func(const char* __s);
+DEFINE_IFUNC(strlen) {
+    switch(get_cpu_variant()) {
+        case kCortexA9:
+            RETURN_FUNC(strlen_func, strlen_a9);
+        default:
+            RETURN_FUNC(strlen_func, strlen_a15);
+    }
+}
+
+}  // extern "C"
diff --git a/libc/arch-arm/generic/bionic/memmove.S b/libc/arch-arm/generic/bionic/memmove.S
index c52e17e..0cf82d1 100644
--- a/libc/arch-arm/generic/bionic/memmove.S
+++ b/libc/arch-arm/generic/bionic/memmove.S
@@ -464,10 +464,8 @@
 	b	.Lmemcpy_bl4
 END(bsd_safe_memcpy)
 
-ENTRY(memmove)
+ENTRY(memmove_generic)
         stmfd   sp!, {r0, lr}
         bl      bsd_safe_memcpy
         ldmfd   sp!, {r0, pc}
-END(memmove)
-
-ALIAS_SYMBOL(memcpy, memmove)
+END(memmove_generic)
diff --git a/libc/arch-arm/generic/bionic/memset.S b/libc/arch-arm/generic/bionic/memset.S
index 1fd0de1..e70002f 100644
--- a/libc/arch-arm/generic/bionic/memset.S
+++ b/libc/arch-arm/generic/bionic/memset.S
@@ -36,14 +36,14 @@
 
          .syntax unified
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_generic)
         cmp         r2, r3
         bls         memset
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_generic)
 
-ENTRY(memset)
+ENTRY(memset_generic)
         /* compute the offset to align the destination
          * offset = (4-(src&3))&3 = -src & 3
          */
@@ -108,4 +108,4 @@
         movs        r2, r2, lsl #2
         strbcs      r1, [r0]
         ldmfd       sp!, {r0, r4-r7, pc}
-END(memset)
+END(memset_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/generic/bionic/stpcpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/generic/bionic/stpcpy.c
index b60123c..0aabaa5 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/generic/bionic/stpcpy.c
@@ -26,13 +26,5 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define stpcpy stpcpy_generic
+#include <upstream-openbsd/lib/libc/string/stpcpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/generic/bionic/strcat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/generic/bionic/strcat.c
index b60123c..8e70531 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/generic/bionic/strcat.c
@@ -26,13 +26,5 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strcat strcat_generic
+#include <upstream-openbsd/lib/libc/string/strcat.c>
diff --git a/libc/arch-arm/generic/bionic/strcmp.S b/libc/arch-arm/generic/bionic/strcmp.S
index 10b6704..03225a0 100644
--- a/libc/arch-arm/generic/bionic/strcmp.S
+++ b/libc/arch-arm/generic/bionic/strcmp.S
@@ -31,6 +31,10 @@
 
 	.text
 
+        // To avoid warning about deprecated instructions, add an explicit
+        // arch. The code generated is exactly the same.
+        .arch armv7-a
+
 #ifdef __ARMEB__
 #define SHFT2LSB lsl
 #define SHFT2LSBEQ lsleq
@@ -50,7 +54,7 @@
 #define magic1(REG) REG
 #define magic2(REG) REG, lsl #7
 
-ENTRY(strcmp)
+ENTRY(strcmp_generic)
 	pld	[r0, #0]
 	pld	[r1, #0]
 	eor	r2, r0, r1
@@ -313,4 +317,4 @@
 	ldr	r4, [sp], #4
 	ldr	r5, [sp], #4
 	bx	lr
-END(strcmp)
+END(strcmp_generic)
diff --git a/libc/arch-arm/generic/bionic/strcpy.S b/libc/arch-arm/generic/bionic/strcpy.S
index c0ab9e5..89bd699 100644
--- a/libc/arch-arm/generic/bionic/strcpy.S
+++ b/libc/arch-arm/generic/bionic/strcpy.S
@@ -33,7 +33,11 @@
 
 .syntax unified
 
-ENTRY(strcpy)
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
+ENTRY(strcpy_generic)
 	pld	[r1, #0]
 	eor	r2, r0, r1
 	mov	ip, r0
@@ -131,4 +135,4 @@
 	cmp	r2, #0
 	bne	4b
 	bx	lr
-END(strcpy)
+END(strcpy_generic)
diff --git a/libc/arch-arm/generic/bionic/strlen.c b/libc/arch-arm/generic/bionic/strlen.c
index 44bd72f..43d9e51 100644
--- a/libc/arch-arm/generic/bionic/strlen.c
+++ b/libc/arch-arm/generic/bionic/strlen.c
@@ -29,7 +29,7 @@
 #include <string.h>
 #include <stdint.h>
 
-size_t strlen(const char *s)
+size_t strlen_generic(const char *s)
 {
     __builtin_prefetch(s);
     __builtin_prefetch(s+32);
diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S
index 32fa82d..9d4bffb 100644
--- a/libc/arch-arm/krait/bionic/__strcat_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcat_chk.S
@@ -40,7 +40,7 @@
 // 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)
+ENTRY(__strcat_chk_krait)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_adjust_cfa_offset 8
@@ -200,4 +200,4 @@
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
-END(__strcat_chk)
+END(__strcat_chk_krait)
diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S
index ca4cf7f..969e112 100644
--- a/libc/arch-arm/krait/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S
@@ -39,7 +39,7 @@
 
 // Get the length of the source string first, then do a memcpy of the data
 // instead of a strcpy.
-ENTRY(__strcpy_chk)
+ENTRY(__strcpy_chk_krait)
     pld     [r0, #0]
     push    {r0, lr}
     .cfi_adjust_cfa_offset 8
@@ -162,4 +162,4 @@
 
 #include "memcpy_base.S"
 
-END(__strcpy_chk)
+END(__strcpy_chk_krait)
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index 49fd040..6618b3a 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -42,7 +42,7 @@
         .thumb
         .thumb_func
 
-ENTRY(__memcpy)
+ENTRY(__memcpy_krait)
         pld     [r1, #64]
         stmfd   sp!, {r0, lr}
         .cfi_adjust_cfa_offset 8
@@ -50,4 +50,4 @@
         .cfi_rel_offset lr, 4
 
 #include "memcpy_base.S"
-END(__memcpy)
+END(__memcpy_krait)
diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S
index dc8ad2c..5b4b70d 100644
--- a/libc/arch-arm/krait/bionic/memcpy_base.S
+++ b/libc/arch-arm/krait/bionic/memcpy_base.S
@@ -41,8 +41,13 @@
 #endif
 
 	.text
+	.syntax unified
 	.fpu    neon
 
+	// To avoid warning about deprecated instructions, add an explicit
+	// arch. The code generated is exactly the same.
+	.arch armv7-a
+
 .L_memcpy_base:
 	cmp	r2, #4
 	blt	.L_neon_lt4
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/krait/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/krait/bionic/memmove.S
index b60123c..af85ea6 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/krait/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_krait
+#define MEMCPY __memcpy_krait
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index 228942c..675ab53 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -37,7 +37,7 @@
     .fpu    neon
     .syntax unified
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_krait)
         cmp         r2, r3
         bls         memset
 
@@ -47,10 +47,10 @@
         .cfi_rel_offset lr, 0
 
         bl          __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_krait)
 
 /* memset() returns its first argument.  */
-ENTRY(memset)
+ENTRY(memset_krait)
         mov         r3, r0
         vdup.8      q0, r1
 
@@ -82,4 +82,4 @@
         strbcs      r1, [r3], #1
         strbcs      r1, [r3], #1
         bx          lr
-END(memset)
+END(memset_krait)
diff --git a/libc/arch-arm/krait/bionic/strcmp.S b/libc/arch-arm/krait/bionic/strcmp.S
index b871c76..ec692e5 100644
--- a/libc/arch-arm/krait/bionic/strcmp.S
+++ b/libc/arch-arm/krait/bionic/strcmp.S
@@ -52,12 +52,16 @@
 
 .syntax         unified
 
+// To avoid warning about deprecated instructions, add an explicit
+// arch. The code generated is exactly the same.
+.arch armv7-a
+
 #if defined (__thumb__)
         .thumb
         .thumb_func
 #endif
 
-ENTRY(strcmp)
+ENTRY(strcmp_krait)
       /* Use LDRD whenever possible.  */
 
 /* The main thing to look out for when comparing large blocks is that
@@ -482,4 +486,4 @@
     .cfi_restore r7
 
 	bx	lr
-END(strcmp)
+END(strcmp_krait)
diff --git a/libc/arch-arm/kryo/bionic/memcpy.S b/libc/arch-arm/kryo/bionic/memcpy.S
index 74036ef..250f7bc 100644
--- a/libc/arch-arm/kryo/bionic/memcpy.S
+++ b/libc/arch-arm/kryo/bionic/memcpy.S
@@ -33,8 +33,14 @@
 #define PLDOFFS (16)
 #define PLDSIZE (128) /* L2 cache line size */
 
+        .syntax unified
+
+        // To avoid warning about deprecated instructions, add an explicit
+        // arch. The code generated is exactly the same.
+        .arch armv7-a
+
         .code 32
-ENTRY(__memcpy)
+ENTRY(__memcpy_kryo)
         push            {r0}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset r0, 0
@@ -123,4 +129,4 @@
         pop             {r0}
         bx              lr
 
-END(__memcpy)
+END(__memcpy_kryo)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/kryo/bionic/memmove.S
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/kryo/bionic/memmove.S
index b60123c..d0fdd8f 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/kryo/bionic/memmove.S
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#define MEMMOVE memmove_kryo
+#define MEMCPY __memcpy_kryo
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#include <arch-arm/denver/bionic/memmove.S>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-arm/static_function_dispatch.S
similarity index 68%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-arm/static_function_dispatch.S
index b60123c..a8235c2 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-arm/static_function_dispatch.S
@@ -26,13 +26,21 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#include <private/bionic_asm.h>
 
-#include <sys/cdefs.h>
+#define FUNCTION_DELEGATE(name, impl) \
+ENTRY(name); \
+    b impl; \
+END(name)
 
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+FUNCTION_DELEGATE(memmove, memmove_generic)
+FUNCTION_DELEGATE(memcpy, memmove_generic)
+FUNCTION_DELEGATE(memset, memset_generic)
+FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic)
+FUNCTION_DELEGATE(strcpy, strcpy_generic)
+FUNCTION_DELEGATE(__strcpy_chk, __strcpy_chk_generic)
+FUNCTION_DELEGATE(stpcpy, stpcpy_generic)
+FUNCTION_DELEGATE(strcat, strcat_generic)
+FUNCTION_DELEGATE(__strcat_chk, __strcat_chk_generic)
+FUNCTION_DELEGATE(strcmp, strcmp_generic)
+FUNCTION_DELEGATE(strlen, strlen_generic)
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index 5e62c28..a2b2370 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_constants.h>
 
 // According to AARCH64 PCS document we need to save the following
 // registers:
@@ -44,10 +45,12 @@
 // 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      core_base       base of core registers (x19-x30, sp)
-// 15     float_base      base of float registers (d8-d15)
-// 23     checksum        checksum of core registers
-// 24     reserved        reserved entries (room to grow)
+// 2      core_base       base of core registers (x18-x30, sp)
+//                        (We only store the low bits of x18 to avoid leaking the
+//                        shadow call stack address into memory.)
+// 16     float_base      base of float registers (d8-d15)
+// 24     checksum        checksum of core registers
+// 25     reserved        reserved entries (room to grow)
 // 32
 
 #define _JB_SIGFLAG     0
@@ -58,18 +61,20 @@
 #define _JB_X24_X25     (_JB_X26_X27 + 2)
 #define _JB_X22_X23     (_JB_X24_X25 + 2)
 #define _JB_X20_X21     (_JB_X22_X23 + 2)
-#define _JB_X19         (_JB_X20_X21 + 2)
-#define _JB_D14_D15     (_JB_X19 + 1)
+#define _JB_SCS_X19     (_JB_X20_X21 + 2)
+#define _JB_D14_D15     (_JB_SCS_X19 + 2)
 #define _JB_D12_D13     (_JB_D14_D15 + 2)
 #define _JB_D10_D11     (_JB_D12_D13 + 2)
 #define _JB_D8_D9       (_JB_D10_D11 + 2)
 #define _JB_CHECKSUM    (_JB_D8_D9 + 2)
 
+#define SCS_MASK (SCS_SIZE - 1)
 #define MANGLE_REGISTERS 1
 #define USE_CHECKSUM 1
 
 .macro m_mangle_registers reg, sp_reg
 #if MANGLE_REGISTERS
+  eor x3, x3, \reg
   eor x19, x19, \reg
   eor x20, x20, \reg
   eor x21, x21, \reg
@@ -88,7 +93,7 @@
 
 .macro m_calculate_checksum dst, src, scratch
   mov \dst, #0
-  .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22
+  .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
     ldr \scratch, [\src, #(\i * 8)]
     eor \dst, \dst, \scratch
   .endr
@@ -151,6 +156,9 @@
   // Mask off the signal flag bit.
   bic x1, x1, #1
 
+  // Mask off the high bits of the shadow call stack pointer.
+  and x3, x18, #SCS_MASK
+
   // Save core registers.
   mov x10, sp
   m_mangle_registers x1, sp_reg=x10
@@ -160,7 +168,7 @@
   stp x24, x25, [x0, #(_JB_X24_X25 * 8)]
   stp x22, x23, [x0, #(_JB_X22_X23 * 8)]
   stp x20, x21, [x0, #(_JB_X20_X21 * 8)]
-  str x19,      [x0, #(_JB_X19     * 8)]
+  stp x3,  x19, [x0, #(_JB_SCS_X19 * 8)]
   m_unmangle_registers x1, sp_reg=x10
 
   // Save floating point registers.
@@ -248,10 +256,14 @@
   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)]
+  ldp x3,  x19, [x0, #(_JB_SCS_X19 * 8)]
   m_unmangle_registers x2, sp_reg=x10
   mov sp, x10
 
+  // Restore the low bits of the shadow call stack pointer.
+  and x18, x18, #~SCS_MASK
+  orr x18, x3, x18
+
   stp x0, x1, [sp, #-16]!
   .cfi_adjust_cfa_offset 16
   .cfi_rel_offset x0, 0
diff --git a/libc/arch-x86/atom/string/sse2-memset-atom.S b/libc/arch-x86/atom/string/sse2-memset-atom.S
index 4e211ca..016c49e 100644
--- a/libc/arch-x86/atom/string/sse2-memset-atom.S
+++ b/libc/arch-x86/atom/string/sse2-memset-atom.S
@@ -86,7 +86,7 @@
 	movl	(%esp), %ebx
 	ret
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_atom)
   ENTRANCE
 
   movl LEN(%esp), %ecx
@@ -95,11 +95,11 @@
 
   POP(%ebx) // Undo ENTRANCE without returning.
   jmp __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_atom)
 
 	.section .text.sse2,"ax",@progbits
 	ALIGN(4)
-ENTRY(memset)
+ENTRY(memset_atom)
 	ENTRANCE
 
 	movl	LEN(%esp), %ecx
@@ -839,4 +839,4 @@
 	SETRTNVAL
 	RETURN_END
 
-END(memset)
+END(memset_atom)
diff --git a/libc/arch-x86/atom/string/sse2-strlen-atom.S b/libc/arch-x86/atom/string/sse2-strlen-atom.S
index 81768fb..6a1acfb 100644
--- a/libc/arch-x86/atom/string/sse2-strlen-atom.S
+++ b/libc/arch-x86/atom/string/sse2-strlen-atom.S
@@ -31,7 +31,7 @@
 #ifndef USE_AS_STRCAT
 
 # ifndef STRLEN
-#  define STRLEN strlen
+#  define STRLEN strlen_atom
 # endif
 
 # ifndef L
diff --git a/libc/arch-x86/atom/string/ssse3-memcmp-atom.S b/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
index 0387084..be2c4f6 100644
--- a/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-memcmp-atom.S
@@ -76,7 +76,7 @@
 #endif
 
 #ifndef MEMCMP
-# define MEMCMP	memcmp
+# define MEMCMP	memcmp_atom
 #endif
 
 #define CFI_PUSH(REG)	\
diff --git a/libc/arch-x86/atom/string/ssse3-memcpy-atom.S b/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
index 2b3b7a5..5532e2e 100644
--- a/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-memcpy-atom.S
@@ -31,11 +31,7 @@
 #include "cache.h"
 
 #ifndef MEMCPY
-# define MEMCPY	memcpy
-#endif
-
-#ifndef USE_AS_MEMMOVE
-# define USE_AS_MEMMOVE
+# define MEMCPY	memcpy_atom
 #endif
 
 #ifndef L
@@ -71,12 +67,6 @@
 	cfi_startproc
 #endif
 
-#ifndef ALIAS_SYMBOL
-# define ALIAS_SYMBOL(alias, original) \
-	.globl alias; \
-	.equ alias, original
-#endif
-
 #ifndef END
 # define END(name)		\
 	cfi_endproc;		\
@@ -3132,5 +3122,3 @@
 #endif
 
 END (MEMCPY)
-
-ALIAS_SYMBOL(memmove, MEMCPY)
diff --git a/libc/arch-x86/atom/string/ssse3-memmove-atom.S b/libc/arch-x86/atom/string/ssse3-memmove-atom.S
new file mode 100644
index 0000000..3572eac
--- /dev/null
+++ b/libc/arch-x86/atom/string/ssse3-memmove-atom.S
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define MEMCPY memmove_atom
+#define USE_AS_MEMMOVE
+#include "ssse3-memcpy-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strcat-atom.S b/libc/arch-x86/atom/string/ssse3-strcat-atom.S
index d9b6129..8d8e89d 100644
--- a/libc/arch-x86/atom/string/ssse3-strcat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcat-atom.S
@@ -87,7 +87,7 @@
 #define POP(REG)	popl REG; CFI_POP (REG)
 
 #ifndef STRCAT
-# define STRCAT	strcat
+# define STRCAT	strcat_ssse3
 #endif
 
 #define PARMS	4
@@ -617,4 +617,4 @@
 	RETURN1
 
 #endif
-END (STRCAT)
+END (STRCAT_ssse3)
diff --git a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
index ee253b9..08f6d4a 100644
--- a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
@@ -108,7 +108,7 @@
 #endif
 
 #ifndef STRCMP
-# define STRCMP strcmp
+# define STRCMP strcmp_ssse3
 #endif
 
 	.section .text.ssse3,"ax",@progbits
diff --git a/libc/arch-x86/atom/string/ssse3-strcpy-atom.S b/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
index 3690b0d..45b0c02 100644
--- a/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcpy-atom.S
@@ -81,7 +81,7 @@
 # define POP(REG)	popl REG; CFI_POP (REG)
 
 # ifndef STRCPY
-#  define STRCPY  strcpy
+#  define STRCPY  strcpy_atom
 # endif
 
 # ifdef USE_AS_STRNCPY
diff --git a/libc/arch-x86/atom/string/ssse3-strlcat-atom.S b/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
index daaf254..055b489 100644
--- a/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strlcat-atom.S
@@ -82,7 +82,7 @@
 #define LEN	SRC+4
 
 	.text
-ENTRY (strlcat)
+ENTRY (strlcat_ssse3)
 	mov	DST(%esp), %edx
 	PUSH	(%ebx)
 	mov	LEN(%esp), %ebx
diff --git a/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S b/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
index cdb17cc..1671da6 100644
--- a/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S
@@ -29,8 +29,8 @@
 */
 
 #define USE_AS_STRNCPY
-#define STRCPY strlcpy
-#define STRLEN strlcpy
+#define STRCPY strlcpy_ssse3
+#define STRLEN strlcpy_ssse3
 #define USE_AS_STRLCPY
 #include "ssse3-strcpy-atom.S"
 
diff --git a/libc/arch-x86/atom/string/ssse3-strncat-atom.S b/libc/arch-x86/atom/string/ssse3-strncat-atom.S
index 5618771..ccb08a7 100644
--- a/libc/arch-x86/atom/string/ssse3-strncat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncat-atom.S
@@ -28,7 +28,7 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#define STRCAT  strncat
+#define STRCAT  strncat_ssse3
 #define USE_AS_STRNCAT
 
 #include "ssse3-strcat-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-strncmp-atom.S b/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
index 4762d7e..2bf5002 100644
--- a/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncmp-atom.S
@@ -30,6 +30,6 @@
 
 
 #define USE_AS_STRNCMP
-#define STRCMP  strncmp
+#define STRCMP  strncmp_ssse3
 #include "ssse3-strcmp-atom.S"
 
diff --git a/libc/arch-x86/atom/string/ssse3-strncpy-atom.S b/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
index 0948b6d..0c27ffe 100644
--- a/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strncpy-atom.S
@@ -29,5 +29,5 @@
 */
 
 #define USE_AS_STRNCPY
-#define STRCPY strncpy
+#define STRCPY strncpy_atom
 #include "ssse3-strcpy-atom.S"
diff --git a/libc/arch-x86/atom/string/ssse3-wcscat-atom.S b/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
index 8a389a3..a307983 100644
--- a/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wcscat-atom.S
@@ -85,7 +85,7 @@
 #define USE_AS_WCSCAT
 
 .text
-ENTRY (wcscat)
+ENTRY (wcscat_ssse3)
 	PUSH    (%edi)
 	mov	STR1(%esp), %edi
 	mov	%edi, %edx
@@ -111,4 +111,4 @@
 #define RETURN  POP(%edi);	ret;	CFI_PUSH(%edi)
 #include "ssse3-wcscpy-atom.S"
 
-END (wcscat)
+END (wcscat_ssse3)
diff --git a/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S b/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
index 27cb61e..80aa15f 100644
--- a/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S
@@ -88,7 +88,7 @@
 # define LEN	STR2+4
 
 .text
-ENTRY (wcscpy)
+ENTRY (wcscpy_ssse3)
 	mov	STR1(%esp), %edx
 	mov	STR2(%esp), %ecx
 
@@ -648,5 +648,5 @@
 	ret
 
 #ifndef USE_AS_WCSCAT
-END (wcscpy)
+END (wcscpy_ssse3)
 #endif
diff --git a/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S b/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
index 2c3fa02..a81b78b 100644
--- a/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S
@@ -28,7 +28,7 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#define MEMCMP  wmemcmp
+#define MEMCMP  wmemcmp_atom
 
 #define USE_WCHAR
 #define USE_AS_WMEMCMP 1
diff --git a/libc/arch-x86/dynamic_function_dispatch.cpp b/libc/arch-x86/dynamic_function_dispatch.cpp
new file mode 100644
index 0000000..6624385
--- /dev/null
+++ b/libc/arch-x86/dynamic_function_dispatch.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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 <stddef.h>
+
+extern "C" {
+
+struct __processor_model {
+    unsigned int __cpu_vendor;
+    unsigned int __cpu_type;
+    unsigned int __cpu_subtype;
+    unsigned int __cpu_features[1];
+};
+
+__attribute__((visibility("hidden")))
+extern struct __processor_model __cpu_model;
+
+// These definitions have to match the values in
+// llvm/include/llvm/Support/X86TargetParser.def
+static constexpr int SSSE3  = 6;
+static constexpr int SSE4_1 = 7;
+static constexpr int ATOM   = 1;
+
+// __builtin_cpu_supports and __builtin_cpu_is can not be used here. They
+// don't access __cpu_model directly but use GOT.
+// See https://reviews.llvm.org/D53850
+static bool cpu_supports(unsigned int feature) {
+    return (__cpu_model.__cpu_features[0] & (1U << feature)) != 0;
+}
+
+static bool cpu_is(unsigned int type) {
+    return (__cpu_model.__cpu_type == type);
+}
+
+#define DEFINE_IFUNC_FOR(name) \
+    name##_func name __attribute__((ifunc(#name "_resolver"))); \
+    __attribute__((visibility("hidden"))) \
+    name##_func* name##_resolver()
+
+#define DECLARE_FUNC(type, name) \
+    __attribute__((visibility("hidden"))) \
+    type name
+
+#define RETURN_FUNC(type, name) { \
+        DECLARE_FUNC(type, name); \
+        return name; \
+    }
+
+typedef int memcmp_func(const void* __lhs, const void* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(memcmp) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(memcmp_func, memcmp_atom);
+    if (cpu_supports(SSE4_1)) RETURN_FUNC(memcmp_func, memcmp_sse4);
+    RETURN_FUNC(memcmp_func, memcmp_generic);
+}
+
+typedef void* memset_func(void* __dst, int __ch, size_t __n);
+DEFINE_IFUNC_FOR(memset) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(memset_func, memset_atom);
+    RETURN_FUNC(memset_func, memset_generic);
+}
+
+typedef void* __memset_chk_func(void *s, int c, size_t n, size_t n2);
+DEFINE_IFUNC_FOR(__memset_chk) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(__memset_chk_func, __memset_chk_atom);
+    RETURN_FUNC(__memset_chk_func, __memset_chk_generic);
+}
+
+typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
+DEFINE_IFUNC_FOR(memmove) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(memmove_func, memmove_atom);
+    RETURN_FUNC(memmove_func, memmove_generic);
+}
+
+typedef void* memcpy_func(void*, const void*, size_t);
+DEFINE_IFUNC_FOR(memcpy) {
+    return memmove_resolver();
+}
+
+typedef char* strcpy_func(char* __dst, const char* __src);
+DEFINE_IFUNC_FOR(strcpy) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(strcpy_func, strcpy_atom);
+    RETURN_FUNC(strcpy_func, strcpy_generic);
+}
+
+typedef char* strncpy_func(char* __dst, const char* __src, size_t __n);
+DEFINE_IFUNC_FOR(strncpy) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(strncpy_func, strncpy_atom);
+    RETURN_FUNC(strncpy_func, strncpy_generic);
+}
+
+typedef size_t strlen_func(const char* __s);
+DEFINE_IFUNC_FOR(strlen) {
+    __builtin_cpu_init();
+    if (cpu_is(ATOM)) RETURN_FUNC(strlen_func, strlen_atom);
+    RETURN_FUNC(strlen_func, strlen_generic);
+}
+
+typedef int wmemcmp_func(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(wmemcmp) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSE4_1)) RETURN_FUNC(wmemcmp_func, wmemcmp_sse4);
+    if (cpu_is(ATOM)) RETURN_FUNC(wmemcmp_func, wmemcmp_atom);
+    RETURN_FUNC(wmemcmp_func, wmemcmp_freebsd);
+}
+
+typedef int strcmp_func(const char* __lhs, const char* __rhs);
+DEFINE_IFUNC_FOR(strcmp) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strcmp_func, strcmp_ssse3);
+    RETURN_FUNC(strcmp_func, strcmp_generic);
+}
+
+typedef int strncmp_func(const char* __lhs, const char* __rhs, size_t __n);
+DEFINE_IFUNC_FOR(strncmp) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strncmp_func, strncmp_ssse3);
+    RETURN_FUNC(strncmp_func, strncmp_generic);
+}
+
+typedef char* strcat_func(char* __dst, const char* __src);
+DEFINE_IFUNC_FOR(strcat) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strcat_func, strcat_ssse3);
+    RETURN_FUNC(strcat_func, strcat_generic);
+}
+
+typedef char* strncat_func(char* __dst, const char* __src, size_t __n);
+DEFINE_IFUNC_FOR(strncat) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strncat_func, strncat_ssse3);
+    RETURN_FUNC(strncat_func, strncat_openbsd);
+}
+
+typedef size_t strlcat_func(char *dst, const char *src, size_t dsize);
+DEFINE_IFUNC_FOR(strlcat) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strlcat_func, strlcat_ssse3);
+    RETURN_FUNC(strlcat_func, strlcat_openbsd);
+}
+
+typedef size_t strlcpy_func(char *dst, const char *src, size_t dsize);
+DEFINE_IFUNC_FOR(strlcpy) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(strlcpy_func, strlcpy_ssse3);
+    RETURN_FUNC(strlcpy_func, strlcpy_openbsd);
+}
+
+typedef wchar_t* wcscat_func(wchar_t *s1, const wchar_t *s2);
+DEFINE_IFUNC_FOR(wcscat) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(wcscat_func, wcscat_ssse3);
+    RETURN_FUNC(wcscat_func, wcscat_freebsd);
+}
+
+typedef wchar_t* wcscpy_func(wchar_t *s1, const wchar_t *s2);
+DEFINE_IFUNC_FOR(wcscpy) {
+    __builtin_cpu_init();
+    if (cpu_supports(SSSE3)) RETURN_FUNC(wcscpy_func, wcscpy_ssse3);
+    RETURN_FUNC(wcscpy_func, wcscpy_freebsd);
+}
+
+}  // extern "C"
diff --git a/libc/arch-x86/generic/string/memcmp.S b/libc/arch-x86/generic/string/memcmp.S
index ef36b4f..1d327c7 100644
--- a/libc/arch-x86/generic/string/memcmp.S
+++ b/libc/arch-x86/generic/string/memcmp.S
@@ -6,7 +6,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(memcmp)
+ENTRY(memcmp_generic)
 	pushl	%edi
 	pushl	%esi
 	movl	12(%esp),%edi
@@ -41,4 +41,4 @@
 	popl	%esi
 	popl	%edi
 	ret
-END(memcmp)
+END(memcmp_generic)
diff --git a/libc/arch-x86/generic/string/strcat.S b/libc/arch-x86/generic/string/strcat.S
index 49e8eee..e2e9623 100644
--- a/libc/arch-x86/generic/string/strcat.S
+++ b/libc/arch-x86/generic/string/strcat.S
@@ -19,7 +19,7 @@
  * cache.
  */
 
-ENTRY(strcat)
+ENTRY(strcat_generic)
 	pushl	%edi			/* save edi */
 	movl	8(%esp),%edi		/* dst address */
 	movl	12(%esp),%edx		/* src address */
@@ -71,4 +71,4 @@
 L2:	popl	%eax			/* pop destination address */
 	popl	%edi			/* restore edi */
 	ret
-END(strcat)
+END(strcat_generic)
diff --git a/libc/arch-x86/generic/string/strcmp.S b/libc/arch-x86/generic/string/strcmp.S
index 580f4d5..7b003e8 100644
--- a/libc/arch-x86/generic/string/strcmp.S
+++ b/libc/arch-x86/generic/string/strcmp.S
@@ -12,7 +12,7 @@
  * cache.
  */
 
-ENTRY(strcmp)
+ENTRY(strcmp_generic)
 	movl	0x04(%esp),%eax
 	movl	0x08(%esp),%edx
 	jmp	L2			/* Jump into the loop! */
@@ -79,4 +79,4 @@
 	movzbl	(%edx),%edx
 	subl	%edx,%eax
 	ret
-END(strcmp)
+END(strcmp_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strlcat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strlcat.c
index b60123c..95c34a3 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strlcat.c
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strlcat strlcat_openbsd
+#include <upstream-openbsd/lib/libc/string/strlcat.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strlcpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strlcpy.c
index b60123c..8d4047c 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strlcpy.c
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strlcpy strlcpy_openbsd
+#include <upstream-openbsd/lib/libc/string/strlcpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/strncat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/strncat.c
index b60123c..687e560 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/strncat.c
@@ -26,13 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#include <upstream-openbsd/android/include/openbsd-compat.h>
 
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define strncat strncat_openbsd
+#include <upstream-openbsd/lib/libc/string/strncat.c>
diff --git a/libc/arch-x86/generic/string/strncmp.S b/libc/arch-x86/generic/string/strncmp.S
index 9ba83a1..6d9f23c 100644
--- a/libc/arch-x86/generic/string/strncmp.S
+++ b/libc/arch-x86/generic/string/strncmp.S
@@ -12,7 +12,7 @@
  * cache.
  */
 
-ENTRY(strncmp)
+ENTRY(strncmp_generic)
 	pushl	%ebx
 	movl	8(%esp),%eax
 	movl	12(%esp),%ecx
@@ -111,4 +111,4 @@
 L4:	xorl	%eax,%eax
 	popl	%ebx
 	ret
-END(strncmp)
+END(strncmp_generic)
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wcscat.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/wcscat.c
index b60123c..a102551 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wcscat.c
@@ -26,13 +26,5 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wcscat wcscat_freebsd
+#include <upstream-freebsd/lib/libc/string/wcscat.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wcscpy.c
similarity index 86%
copy from libc/include/android/legacy_get_device_api_level_inlines.h
copy to libc/arch-x86/generic/string/wcscpy.c
index b60123c..10fb66d 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wcscpy.c
@@ -26,13 +26,5 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wcscpy wcscpy_freebsd
+#include <upstream-freebsd/lib/libc/string/wcscpy.c>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/arch-x86/generic/string/wmemcmp.c
similarity index 86%
rename from libc/include/android/legacy_get_device_api_level_inlines.h
rename to libc/arch-x86/generic/string/wmemcmp.c
index b60123c..9d5e929 100644
--- a/libc/include/android/legacy_get_device_api_level_inlines.h
+++ b/libc/arch-x86/generic/string/wmemcmp.c
@@ -26,13 +26,5 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <sys/cdefs.h>
-
-#if __ANDROID_API__ < __ANDROID_API_Q__
-
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
-#include <bits/get_device_api_level_inlines.h>
-
-#endif
+#define wmemcmp wmemcmp_freebsd
+#include <upstream-freebsd/lib/libc/string/wmemcmp.c>
diff --git a/libc/arch-x86/silvermont/string/sse2-memmove-slm.S b/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
index ceada1b..da6456c 100644
--- a/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-memmove-slm.S
@@ -31,7 +31,7 @@
 #include "cache.h"
 
 #ifndef MEMMOVE
-# define MEMMOVE	memmove
+# define MEMMOVE	memmove_generic
 #endif
 
 #ifndef L
@@ -67,12 +67,6 @@
 	cfi_startproc
 #endif
 
-#ifndef ALIAS_SYMBOL
-# define ALIAS_SYMBOL(alias, original) \
-	.globl alias; \
-	.equ alias, original
-#endif
-
 #ifndef END
 # define END(name)		\
 	cfi_endproc;		\
@@ -543,5 +537,3 @@
 	jmp	L(mm_recalc_len)
 
 END (MEMMOVE)
-
-ALIAS_SYMBOL(memcpy, MEMMOVE)
diff --git a/libc/arch-x86/silvermont/string/sse2-memset-slm.S b/libc/arch-x86/silvermont/string/sse2-memset-slm.S
index 03a552d..adaccae 100644
--- a/libc/arch-x86/silvermont/string/sse2-memset-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-memset-slm.S
@@ -86,7 +86,7 @@
 	movl	(%esp), %ebx
 	ret
 
-ENTRY(__memset_chk)
+ENTRY(__memset_chk_generic)
   ENTRANCE
 
   movl LEN(%esp), %ecx
@@ -95,11 +95,11 @@
 
   POP(%ebx) // Undo ENTRANCE without returning.
   jmp __memset_chk_fail
-END(__memset_chk)
+END(__memset_chk_generic)
 
 	.section .text.sse2,"ax",@progbits
 	ALIGN(4)
-ENTRY(memset)
+ENTRY(memset_generic)
 	ENTRANCE
 
 	movl	LEN(%esp), %ecx
@@ -758,4 +758,4 @@
 	SETRTNVAL
 	RETURN_END
 
-END(memset)
+END(memset_generic)
diff --git a/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S b/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
index b5d84b5..22ceeab 100755
--- a/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S
@@ -79,7 +79,7 @@
 #define POP(REG) popl REG; CFI_POP (REG)
 
 #ifndef STRCPY
-# define STRCPY  strcpy
+# define STRCPY  strcpy_generic
 #endif
 
 #ifdef USE_AS_STPNCPY
diff --git a/libc/arch-x86/silvermont/string/sse2-strlen-slm.S b/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
index 27cc025..b805ad6 100755
--- a/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strlen-slm.S
@@ -29,7 +29,7 @@
 */
 
 #ifndef STRLEN
-# define STRLEN strlen
+# define STRLEN strlen_generic
 #endif
 
 #ifndef L
diff --git a/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S b/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
index 591419f..aff7fb9 100755
--- a/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
+++ b/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S
@@ -29,5 +29,5 @@
 */

 

 #define USE_AS_STRNCPY

-#define STRCPY strncpy

+#define STRCPY strncpy_generic

 #include "sse2-strcpy-slm.S"

diff --git a/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S b/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
index e5028ff..f151168 100755
--- a/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
+++ b/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S
@@ -76,7 +76,7 @@
 #endif
 
 #ifndef MEMCMP
-# define MEMCMP	memcmp
+# define MEMCMP	memcmp_sse4
 #endif
 
 #define CFI_PUSH(REG)	\
diff --git a/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S b/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
index 2c350bb..2bf92f5 100755
--- a/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
+++ b/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S
@@ -29,5 +29,5 @@
 */
 
 #define USE_AS_WMEMCMP
-#define MEMCMP wmemcmp
+#define MEMCMP wmemcmp_sse4
 #include "sse4-memcmp-slm.S"
diff --git a/libc/include/android/get_device_api_level.h b/libc/arch-x86/static_function_dispatch.S
similarity index 61%
rename from libc/include/android/get_device_api_level.h
rename to libc/arch-x86/static_function_dispatch.S
index 39609da..7e8e63d 100644
--- a/libc/include/android/get_device_api_level.h
+++ b/libc/arch-x86/static_function_dispatch.S
@@ -26,29 +26,27 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#include <private/bionic_asm.h>
 
-/**
- * @file android/get_device_api_level.h
- * @brief Check the API level of the device we're actually running on.
- */
+#define FUNCTION_DELEGATE(name, impl) \
+ENTRY(name); \
+    jmp impl; \
+END(name)
 
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-#if __ANDROID_API__ >= __ANDROID_API_Q__
-// This file is implemented as static inlines before API level 29.
-
-/**
- * Returns the API level of the device we're actually running on, or -1 on failure.
- * The returned values correspond to the named constants in <android/api-level.h>,
- * and is equivalent to the Java `Build.VERSION.SDK_INT` API.
- */
-int android_get_device_api_level() __INTRODUCED_IN(29);
-
-#endif
-
-__END_DECLS
-
-#include <android/legacy_get_device_api_level_inlines.h>
+FUNCTION_DELEGATE(memcmp, memcmp_generic)
+FUNCTION_DELEGATE(memset, memset_generic)
+FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic)
+FUNCTION_DELEGATE(memcpy, memmove_generic)
+FUNCTION_DELEGATE(memmove, memmove_generic)
+FUNCTION_DELEGATE(strcpy, strcpy_generic)
+FUNCTION_DELEGATE(strncpy, strncpy_generic)
+FUNCTION_DELEGATE(strlen, strlen_generic)
+FUNCTION_DELEGATE(strcmp, strcmp_generic)
+FUNCTION_DELEGATE(strncmp, strncmp_generic)
+FUNCTION_DELEGATE(strcat, strcat_generic)
+FUNCTION_DELEGATE(wmemcmp, wmemcmp_freebsd)
+FUNCTION_DELEGATE(wcscat, wcscat_freebsd)
+FUNCTION_DELEGATE(strncat, strncat_openbsd)
+FUNCTION_DELEGATE(strlcat, strlcat_openbsd)
+FUNCTION_DELEGATE(strlcpy, strlcpy_openbsd)
+FUNCTION_DELEGATE(wcscpy, wcscpy_freebsd)
diff --git a/libc/bionic/NetdClient.cpp b/libc/bionic/NetdClient.cpp
index a5c519e..87eec27 100644
--- a/libc/bionic/NetdClient.cpp
+++ b/libc/bionic/NetdClient.cpp
@@ -58,6 +58,8 @@
     netdClientInitFunction(netdClientHandle, "netdClientInitNetIdForResolv",
                            &__netdClientDispatch.netIdForResolv);
     netdClientInitFunction(netdClientHandle, "netdClientInitSocket", &__netdClientDispatch.socket);
+    netdClientInitFunction(netdClientHandle, "netdClientInitDnsOpenProxy",
+                           &__netdClientDispatch.dnsOpenProxy);
 }
 
 static pthread_once_t netdClientInitOnce = PTHREAD_ONCE_INIT;
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index 67fa197..a873173 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -30,6 +30,10 @@
     return netId;
 }
 
+static int fallBackDnsOpenProxy() {
+    return -1;
+}
+
 // This structure is modified only at startup (when libc.so is loaded) and never
 // afterwards, so it's okay that it's read later at runtime without a lock.
 __LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = {
@@ -37,4 +41,5 @@
     __connect,
     __socket,
     fallBackNetIdForResolv,
+    fallBackDnsOpenProxy,
 };
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 758b295..be9d32e 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -101,5 +101,5 @@
 
   __init_thread(&main_thread);
 
-  __init_alternate_signal_stack(&main_thread);
+  __init_additional_stacks(&main_thread);
 }
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 4b94573..20e265e 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -454,9 +454,14 @@
   return write(fd, buf, count);
 }
 
-#if !defined(NO___STRCAT_CHK)
+#if defined(RENAME___STRCAT_CHK)
+#define __STRCAT_CHK __strcat_chk_generic
+#else
+#define __STRCAT_CHK __strcat_chk
+#endif // RENAME___STRCAT_CHK
+
 // Runtime implementation of __builtin____strcat_chk (used directly by compiler, not in headers).
-extern "C" char* __strcat_chk(char* dst, const char* src, size_t dst_buf_size) {
+extern "C" char* __STRCAT_CHK(char* dst, const char* src, size_t dst_buf_size) {
   char* save = dst;
   size_t dst_len = __strlen_chk(dst, dst_buf_size);
 
@@ -472,17 +477,20 @@
 
   return save;
 }
-#endif // NO___STRCAT_CHK
 
-#if !defined(NO___STRCPY_CHK)
+#if defined(RENAME___STRCPY_CHK)
+#define __STRCPY_CHK __strcpy_chk_generic
+#else
+#define __STRCPY_CHK __strcpy_chk
+#endif // RENAME___STRCPY_CHK
+
 // Runtime implementation of __builtin____strcpy_chk (used directly by compiler, not in headers).
-extern "C" char* __strcpy_chk(char* dst, const char* src, size_t dst_len) {
+extern "C" char* __STRCPY_CHK(char* dst, const char* src, size_t dst_len) {
   // TODO: optimize so we don't scan src twice.
   size_t src_len = strlen(src) + 1;
   __check_buffer_access("strcpy", "write into", src_len, dst_len);
   return strcpy(dst, src);
 }
-#endif // NO___STRCPY_CHK
 
 #if !defined(NO___MEMCPY_CHK)
 // Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index 40f2a66..ef0d384 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -52,11 +52,11 @@
   // The only parameter we currently understand is M_DECAY_TIME.
   if (param == M_DECAY_TIME) {
     // Only support setting the value to 1 or 0.
-    ssize_t decay_time;
+    ssize_t decay_time_ms;
     if (value) {
-      decay_time = 1;
+      decay_time_ms = 1000;
     } else {
-      decay_time = 0;
+      decay_time_ms = 0;
     }
     // First get the total number of arenas.
     unsigned narenas;
@@ -66,15 +66,22 @@
     }
 
     // Set the decay time for any arenas that will be created in the future.
-    if (je_mallctl("arenas.decay_time", nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+    if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
+      return 0;
+    }
+    if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
       return 0;
     }
 
     // Change the decay on the already existing arenas.
     char buffer[100];
     for (unsigned i = 0; i < narenas; i++) {
-      snprintf(buffer, sizeof(buffer), "arena.%d.decay_time", i);
-      if (je_mallctl(buffer, nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+      snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i);
+      if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
+        break;
+      }
+      snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i);
+      if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) {
         break;
       }
     }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index f943402..a860b98 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -62,13 +62,9 @@
 const char* __progname;
 
 void __libc_init_globals(KernelArgumentBlock& args) {
-#if defined(__i386__)
-  __libc_init_sysinfo(args);
-#endif
   // 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;
   __libc_globals.initialize();
   __libc_globals.mutate([&args](libc_globals* globals) {
     __libc_init_vdso(globals, args);
@@ -275,7 +271,6 @@
 }
 
 static void __sanitize_environment_variables(char** env) {
-  bool is_AT_SECURE = getauxval(AT_SECURE);
   char** src = env;
   char** dst = env;
   for (; src[0] != nullptr; ++src) {
@@ -283,7 +278,7 @@
       continue;
     }
     // Remove various unsafe environment variables if we're loading a setuid program.
-    if (is_AT_SECURE && __is_unsafe_environment_variable(src[0])) {
+    if (__is_unsafe_environment_variable(src[0])) {
       continue;
     }
     dst[0] = src[0];
@@ -306,20 +301,14 @@
 }
 
 void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
-  __libc_auxv = args.auxv;
   __abort_message_ptr = args.abort_message_ptr;
 
   // Check that the kernel provided a value for AT_SECURE.
-  bool found_AT_SECURE = false;
-  for (ElfW(auxv_t)* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
-    if (v->a_type == AT_SECURE) {
-      found_AT_SECURE = true;
-      break;
-    }
-  }
-  if (!found_AT_SECURE) __early_abort(__LINE__);
+  errno = 0;
+  unsigned long is_AT_SECURE = getauxval(AT_SECURE);
+  if (errno != 0) __early_abort(__LINE__);
 
-  if (getauxval(AT_SECURE)) {
+  if (is_AT_SECURE) {
     // If this is a setuid/setgid program, close the security hole described in
     // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
     __nullify_closed_stdio();
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 5f76354..08d3df4 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -51,6 +51,7 @@
 #include <elf.h>
 #include "libc_init_common.h"
 
+#include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_ssp.h"
@@ -78,8 +79,12 @@
 // protector.
 __attribute__((noinline))
 static void __libc_preinit_impl(KernelArgumentBlock& args) {
-  __libc_shared_globals = args.shared_globals;
+  __libc_auxv = args.auxv;
+#if defined(__i386__)
+  __libc_init_sysinfo(args);
+#endif
 
+  __libc_shared_globals = args.shared_globals;
   __libc_init_globals(args);
   __libc_init_common(args);
 
@@ -137,9 +142,3 @@
                  args.argv + __libc_shared_globals->initial_linker_arg_count,
                  args.envp));
 }
-
-extern "C" uint32_t android_get_application_target_sdk_version();
-
-uint32_t bionic_get_application_target_sdk_version() {
-  return android_get_application_target_sdk_version();
-}
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 38a04f8..ef1c393 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -146,16 +146,12 @@
   __real_libc_init(raw_args, onexit, slingshot, structors);
 }
 
-static uint32_t g_target_sdk_version{__ANDROID_API__};
+static int g_target_sdk_version{__ANDROID_API__};
 
-extern "C" uint32_t android_get_application_target_sdk_version() {
+extern "C" int android_get_application_target_sdk_version() {
   return g_target_sdk_version;
 }
 
-uint32_t bionic_get_application_target_sdk_version() {
-  return android_get_application_target_sdk_version();
-}
-
-extern "C" void android_set_application_target_sdk_version(uint32_t target) {
+extern "C" void android_set_application_target_sdk_version(int target) {
   g_target_sdk_version = target;
 }
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 3a94084..9a80767 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -271,6 +271,7 @@
 
 static const char* HEAPPROFD_SHARED_LIB = "heapprofd_client.so";
 static const char* HEAPPROFD_PREFIX = "heapprofd";
+static const char* HEAPPROFD_PROPERTY_ENABLE = "heapprofd.enable";
 static const int HEAPPROFD_SIGNAL = __SIGRTMIN + 4;
 
 enum FunctionEnum : uint8_t {
@@ -365,12 +366,6 @@
 }
 
 static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const char* prefix) {
-  // We initialize free first to prevent the following situation:
-  // Heapprofd's MallocMalloc is installed, and an allocation is observed
-  // and logged to the heap dump. The corresponding free happens before
-  // heapprofd's MallocFree is installed, and is not logged in the heap
-  // dump. This leads to the allocation wrongly being active in the heap
-  // dump indefinitely.
   if (!InitMallocFunction<MallocFree>(impl_handler, &table->free, prefix, "free")) {
     return false;
   }
@@ -469,6 +464,39 @@
   return true;
 }
 
+static bool CheckLoadHeapprofd() {
+  // First check for heapprofd.enable. If it is set to "all", enable
+  // heapprofd for all processes. Otherwise, check heapprofd.enable.${prog},
+  // if it is set and not 0, enable heap profiling for this process.
+  char property_value[PROP_VALUE_MAX];
+  if (__system_property_get(HEAPPROFD_PROPERTY_ENABLE, property_value) == 0) {
+    return false;
+  }
+  if (strcmp(property_value, "all") == 0) {
+    return true;
+  }
+
+  char program_property[128];
+  int ret = snprintf(program_property, sizeof(program_property), "%s.%s",
+                     HEAPPROFD_PROPERTY_ENABLE, getprogname());
+
+  if (ret < 0 || static_cast<size_t>(ret) >= sizeof(program_property)) {
+    if (ret < 0) {
+      error_log("Failed to concatenate heapprofd property %s.%s: %s",
+                HEAPPROFD_PROPERTY_ENABLE, getprogname(), strerror(errno));
+    } else {
+      error_log("Overflow in concatenating heapprofd property");
+    }
+    return false;
+  }
+
+  if (__system_property_get(program_property, property_value) == 0) {
+    return false;
+  }
+
+  return program_property[0] != '\0';
+}
+
 static void ClearGlobalFunctions() {
   for (size_t i = 0; i < FUNC_LAST; i++) {
     g_functions[i] = nullptr;
@@ -538,6 +566,16 @@
   }
 
   atomic_store(&g_heapprofd_init_func, init_func);
+  // We assign free  first explicitly to prevent the case where we observe a
+  // alloc, but miss the corresponding free because of initialization order.
+  //
+  // This is safer than relying on the declaration order inside
+  // MallocDispatch at the cost of an extra atomic pointer write on
+  // initialization.
+  atomic_store(&globals->malloc_dispatch.free, dispatch_table.free);
+  // The struct gets assigned elementwise and each of the elements is an
+  // _Atomic. Assigning to an _Atomic is an atomic_store operation.
+  // The assignment is done in declaration order.
   globals->malloc_dispatch = dispatch_table;
 
   info_log("%s: malloc %s enabled", getprogname(), prefix);
@@ -572,6 +610,9 @@
   } else if (CheckLoadMallocHooks(&options)) {
     prefix = "hooks";
     shared_lib = HOOKS_SHARED_LIB;
+  } else if (CheckLoadHeapprofd()) {
+    prefix = "heapprofd";
+    shared_lib = HEAPPROFD_SHARED_LIB;
   } else {
     return;
   }
@@ -642,7 +683,7 @@
 extern "C" void InstallInitHeapprofdHook(int) {
   if (!atomic_exchange(&g_heapprofd_init_in_progress, true)) {
     __libc_globals.mutate([](libc_globals* globals) {
-      globals->malloc_dispatch.malloc = InitHeapprofdHook;
+      atomic_store(&globals->malloc_dispatch.malloc, InitHeapprofdHook);
     });
   }
 }
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 543fdc5..6f632e8 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -32,12 +32,14 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
+#include <sys/random.h>
 #include <unistd.h>
 
 #include "pthread_internal.h"
 
 #include <async_safe/log.h>
 
+#include "private/bionic_constants.h"
 #include "private/bionic_defs.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_ssp.h"
@@ -86,7 +88,7 @@
   thread->tls[TLS_SLOT_STACK_GUARD] = reinterpret_cast<void*>(__stack_chk_guard);
 }
 
-void __init_alternate_signal_stack(pthread_internal_t* thread) {
+static void __init_alternate_signal_stack(pthread_internal_t* thread) {
   // Create and set an alternate signal stack.
   void* stack_base = mmap(nullptr, SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
   if (stack_base != MAP_FAILED) {
@@ -109,6 +111,30 @@
   }
 }
 
+static void __init_shadow_call_stack(pthread_internal_t* thread __unused) {
+#ifdef __aarch64__
+  // Allocate the stack and store its address in register x18. The address is aligned to SCS_SIZE so
+  // that we only need to store the lower log2(SCS_SIZE) bits in jmp_buf.
+  // TODO(pcc): We ought to allocate a larger guard region here and then allocate the SCS at a
+  // random location within it. This will provide greater security since it would mean that an
+  // attacker who can read the pthread_internal_t won't be able to discover the address of the SCS.
+  // However, doing so is blocked on a solution to b/118642754.
+  char* scs_guard_region = reinterpret_cast<char*>(
+      mmap(nullptr, SCS_GUARD_REGION_SIZE, 0, MAP_PRIVATE | MAP_ANON, -1, 0));
+  thread->shadow_call_stack_guard_region = scs_guard_region;
+
+  char* scs =
+      reinterpret_cast<char*>(align_up(reinterpret_cast<uintptr_t>(scs_guard_region), SCS_SIZE));
+  mprotect(scs, SCS_SIZE, PROT_READ | PROT_WRITE);
+  __asm__ __volatile__("mov x18, %0" ::"r"(scs));
+#endif
+}
+
+void __init_additional_stacks(pthread_internal_t* thread) {
+  __init_alternate_signal_stack(thread);
+  __init_shadow_call_stack(thread);
+}
+
 int __init_thread(pthread_internal_t* thread) {
   thread->cleanup_stack = nullptr;
 
@@ -252,7 +278,7 @@
   // accesses previously made by the creating thread are visible to us.
   thread->startup_handshake_lock.lock();
 
-  __init_alternate_signal_stack(thread);
+  __init_additional_stacks(thread);
 
   void* result = thread->start_routine(thread->start_routine_arg);
   pthread_exit(result);
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index 220f7a0..2d4d6cf 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <sys/mman.h>
 
+#include "private/bionic_constants.h"
 #include "private/bionic_defs.h"
 #include "private/ScopedSignalBlocker.h"
 #include "pthread_internal.h"
@@ -103,6 +104,11 @@
     thread->alternate_signal_stack = nullptr;
   }
 
+#ifdef __aarch64__
+  // Free the shadow call stack and guard pages.
+  munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE);
+#endif
+
   ThreadJoinState old_state = THREAD_NOT_JOINED;
   while (old_state == THREAD_NOT_JOINED &&
          !atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_EXITED_NOT_JOINED)) {
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 92786fe..2b7a99a 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -36,7 +36,6 @@
 #include <async_safe/log.h>
 
 #include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
 #include "private/bionic_tls.h"
 
 static pthread_internal_t* g_thread_list = nullptr;
@@ -114,7 +113,7 @@
   }
 
   // Historically we'd return null, but
-  if (bionic_get_application_target_sdk_version() >= __ANDROID_API_O__) {
+  if (android_get_application_target_sdk_version() >= __ANDROID_API_O__) {
     if (thread == nullptr) {
       // This seems to be a common mistake, and it's relatively harmless because
       // there will never be a valid thread at address 0, whereas other invalid
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 6dd2f9c..81b885a 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -106,6 +106,29 @@
 
   void* alternate_signal_stack;
 
+  // The start address of the shadow call stack's guard region (arm64 only).
+  // This address is only used to deallocate the shadow call stack on thread
+  // exit; the address of the stack itself is stored only in the x18 register.
+  // Because the protection offered by SCS relies on the secrecy of the stack
+  // address, storing the address here weakens the protection, but only
+  // slightly, because it is relatively easy for an attacker to discover the
+  // address of the guard region anyway (e.g. it can be discovered by reference
+  // to other allocations), but not the stack itself, which is <0.1% of the size
+  // of the guard region.
+  //
+  // There are at least two other options for discovering the start address of
+  // the guard region on thread exit, but they are not as simple as storing in
+  // TLS.
+  // 1) Derive it from the value of the x18 register. This is only possible in
+  //    processes that do not contain legacy code that might clobber x18,
+  //    therefore each process must declare early during process startup whether
+  //    it might load legacy code.
+  // 2) Mark the guard region as such using prctl(PR_SET_VMA_ANON_NAME) and
+  //    discover its address by reading /proc/self/maps. One issue with this is
+  //    that reading /proc/self/maps can race with allocations, so we may need
+  //    code to handle retries.
+  void* shadow_call_stack_guard_region;
+
   Lock startup_handshake_lock;
 
   size_t mmap_size;
@@ -132,7 +155,7 @@
 __LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread);
 __LIBC_HIDDEN__ bool __init_tls(pthread_internal_t* thread);
 __LIBC_HIDDEN__ void __init_thread_stack_guard(pthread_internal_t* thread);
-__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
+__LIBC_HIDDEN__ void __init_additional_stacks(pthread_internal_t*);
 
 __LIBC_HIDDEN__ pthread_t           __pthread_internal_add(pthread_internal_t* thread);
 __LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id);
@@ -167,9 +190,14 @@
 
 // SIGSTKSZ (8KiB) is not big enough.
 // An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack.
-// Also, on 64-bit, logging uses more than 8KiB by itself:
-// https://code.google.com/p/android/issues/detail?id=187064
+// On 64-bit, logging uses more than 8KiB by itself, ucontext is comically
+// large on aarch64, and we have effectively infinite address space, so double
+// the signal stack size.
+#if defined(__LP64__)
+#define SIGNAL_STACK_SIZE_WITHOUT_GUARD (32 * 1024)
+#else
 #define SIGNAL_STACK_SIZE_WITHOUT_GUARD (16 * 1024)
+#endif
 
 // Traditionally we gave threads a 1MiB stack. When we started
 // allocating per-thread alternate signal stacks to ease debugging of
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index fda0b93..d9ddf10 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -42,7 +42,6 @@
 #include "private/bionic_constants.h"
 #include "private/bionic_fortify.h"
 #include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
 #include "private/bionic_systrace.h"
 #include "private/bionic_time_conversions.h"
 #include "private/bionic_tls.h"
@@ -789,7 +788,7 @@
 // ARM64. So make it noinline.
 static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
                                                                const char* function_name) {
-    if (bionic_get_application_target_sdk_version() >= __ANDROID_API_P__) {
+    if (android_get_application_target_sdk_version() >= __ANDROID_API_P__) {
         __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
     }
     return EBUSY;
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index d401b66..e0486b4 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -41,7 +41,6 @@
 
 #include "private/bionic_constants.h"
 #include "private/bionic_futex.h"
-#include "private/bionic_sdk_version.h"
 #include "private/bionic_time_conversions.h"
 
 // In this implementation, a semaphore contains a
@@ -222,7 +221,7 @@
     }
 
     int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
-    if (bionic_get_application_target_sdk_version() >= __ANDROID_API_N__) {
+    if (android_get_application_target_sdk_version() >= __ANDROID_API_N__) {
       if (result ==-EINTR) {
         errno = EINTR;
         return -1;
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 29d902c..326d4b1 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -170,16 +170,6 @@
   return __code_string_lookup(_sys_error_strings, error_number);
 }
 
-static const Pair _sys_signal_strings[] = {
-#define  __BIONIC_SIGDEF(signal_number, signal_description)  { signal_number, signal_description },
-#include "private/bionic_sigdefs.h"
-  { 0, nullptr }
-};
-
-extern "C" __LIBC_HIDDEN__ const char* __strsignal_lookup(int signal_number) {
-  return __code_string_lookup(_sys_signal_strings, signal_number);
-}
-
 int strerror_r(int error_number, char* buf, size_t buf_len) {
   ErrnoRestorer errno_restorer;
   size_t length;
@@ -203,21 +193,3 @@
   strerror_r(error_number, buf, buf_len);
   return buf; // ...and just returns whatever fit.
 }
-
-extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
-  const char* signal_name = __strsignal_lookup(signal_number);
-  if (signal_name != nullptr) {
-    return signal_name;
-  }
-
-  const char* prefix = "Unknown";
-  if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
-    prefix = "Real-time";
-    signal_number -= SIGRTMIN;
-  }
-  size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
-  if (length >= buf_len) {
-    return nullptr;
-  }
-  return buf;
-}
diff --git a/libc/bionic/strsignal.cpp b/libc/bionic/strsignal.cpp
index 1cdfec1..5637431 100644
--- a/libc/bionic/strsignal.cpp
+++ b/libc/bionic/strsignal.cpp
@@ -26,20 +26,43 @@
  * SUCH DAMAGE.
  */
 
+#include <signal.h>
 #include <string.h>
 
 #include "bionic/pthread_internal.h"
 
-extern "C" const char* __strsignal_lookup(int);
-extern "C" const char* __strsignal(int, char*, size_t);
+const char* const sys_siglist[NSIG] = {
+#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description,
+#include "private/bionic_sigdefs.h"
+};
 
-char* strsignal(int signal_number) {
-  // Just return the original constant in the easy cases.
-  char* result = const_cast<char*>(__strsignal_lookup(signal_number));
-  if (result != nullptr) {
-    return result;
+const char* const sys_signame[NSIG] = {
+#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
+#include "private/bionic_sigdefs.h"
+};
+
+extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
+  const char* signal_name = nullptr;
+  if (signal_number >= 0 && signal_number < NSIG) {
+    signal_name = sys_siglist[signal_number];
+  }
+  if (signal_name != nullptr) {
+    return signal_name;
   }
 
+  const char* prefix = "Unknown";
+  if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
+    prefix = "Real-time";
+    signal_number -= SIGRTMIN;
+  }
+  size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
+  if (length >= buf_len) {
+    return nullptr;
+  }
+  return buf;
+}
+
+char* strsignal(int signal_number) {
   bionic_tls& tls = __get_bionic_tls();
   return const_cast<char*>(__strsignal(signal_number, tls.strsignal_buf, sizeof(tls.strsignal_buf)));
 }
diff --git a/libc/bionic/sys_siglist.c b/libc/bionic/sys_siglist.c
deleted file mode 100644
index 8e33d64..0000000
--- a/libc/bionic/sys_siglist.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 <signal.h>
-
-const char* const sys_siglist[NSIG] = {
-#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description,
-#include "private/bionic_sigdefs.h"
-};
diff --git a/libc/bionic/sys_signame.c b/libc/bionic/sys_signame.c
deleted file mode 100644
index 5158b83..0000000
--- a/libc/bionic/sys_signame.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <signal.h>
-
-const char* const sys_signame[NSIG] = {
-#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
-#include "private/bionic_sigdefs.h"
-};
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index c7e2823..aa31596 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -107,7 +107,6 @@
 /* Internal use only. */
 struct hostent *android_gethostbyaddrfornetcontext_proxy(const void *, socklen_t, int , const struct android_net_context *) __LIBC_HIDDEN__;
 int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, unsigned, unsigned) __LIBC_HIDDEN__;
-FILE* android_open_proxy(void) __LIBC_HIDDEN__;
 
 __END_DECLS
 
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index f1488a9..4e1aa61 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -422,11 +422,10 @@
 		return EAI_NODATA;
 	}
 
-	FILE* proxy = android_open_proxy();
+	FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
 	if (proxy == NULL) {
 		return EAI_SYSTEM;
 	}
-
 	netid = __netdClientDispatch.netIdForResolv(netid);
 
 	// Send the request.
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 7589380..7e18840 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -565,34 +565,6 @@
 	return h_errno_to_result(errorp);
 }
 
-__LIBC_HIDDEN__ FILE* android_open_proxy() {
-	const char* cache_mode = getenv("ANDROID_DNS_MODE");
-	bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
-	if (!use_proxy) {
-		return NULL;
-	}
-
-	int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-	if (s == -1) {
-		return NULL;
-	}
-
-	const int one = 1;
-	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-
-	struct sockaddr_un proxy_addr;
-	memset(&proxy_addr, 0, sizeof(proxy_addr));
-	proxy_addr.sun_family = AF_UNIX;
-	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
-
-	if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
-		close(s);
-		return NULL;
-	}
-
-	return fdopen(s, "r+");
-}
-
 static struct hostent *
 android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
 {
@@ -816,18 +788,16 @@
 	return hp;
 }
 
-// very similar in proxy-ness to android_getaddrinfo_proxy
 static struct hostent *
 gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
                        size_t hbuflen, int *errorp, const struct android_net_context *netcontext)
 {
-	FILE* proxy = android_open_proxy();
+	FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
 	if (proxy == NULL) {
 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
 		res_setnetcontext(res, netcontext);
 		return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
 	}
-
 	unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid);
 
 	// This is writing to system/netd/server/DnsProxyListener.cpp and changes
@@ -925,12 +895,11 @@
                              struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
                              const struct android_net_context *netcontext)
 {
-	FILE* proxy = android_open_proxy();
+	FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
 	if (proxy == NULL) {
 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
 		return android_gethostbyaddrfornetcontext_real(addr,len, af, hp, hbuf, hbuflen, he, netcontext);
 	}
-
 	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
 	const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
 	if (addrStr == NULL) {
diff --git a/libc/dns/net/getnameinfo.c b/libc/dns/net/getnameinfo.c
index 5fa4e37..31d07c5 100644
--- a/libc/dns/net/getnameinfo.c
+++ b/libc/dns/net/getnameinfo.c
@@ -68,6 +68,13 @@
 #include <stddef.h>
 #include <string.h>
 
+/* This macro is modelled after the ones in <netinet/in6.h>. */
+/* RFC 6052, section 2.1 */
+#define IN6_IS_ADDR_WKP(a) \
+  ((((a)->s6_addr32[0]) == ntohl(0x0064ff9b)) && \
+   (((a)->s6_addr32[1]) == 0) && \
+   (((a)->s6_addr32[2]) == 0))
+
 static const struct afd {
 	int		a_af;
 	socklen_t	a_addrlen;
@@ -248,6 +255,8 @@
 				;
 			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
 				;
+			else if (IN6_IS_ADDR_WKP(&sin6->sin6_addr))
+				;
 			else
 				flags |= NI_NUMERICHOST;
 			break;
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index d0673ef..f4c590f 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -2068,14 +2068,19 @@
             // max_samples actually change, in practice the overhead of checking is higher than the
             // cost, and overflows are unlikely
             ++cache_info->revision_id;
-        } else if (cache_info->params.max_samples != old_max_samples) {
-            // If the maximum number of samples changes, the overhead of keeping the most recent
-            // samples around is not considered worth the effort, so they are cleared instead. All
-            // other parameters do not affect shared state: Changing these parameters does not
-            // invalidate the samples, as they only affect aggregation and the conditions under
-            // which servers are considered usable.
-            _res_cache_clear_stats_locked(cache_info);
-            ++cache_info->revision_id;
+        } else {
+            if (cache_info->params.max_samples != old_max_samples) {
+                // If the maximum number of samples changes, the overhead of keeping the most recent
+                // samples around is not considered worth the effort, so they are cleared instead.
+                // All other parameters do not affect shared state: Changing these parameters does
+                // not invalidate the samples, as they only affect aggregation and the conditions
+                // under which servers are considered usable.
+                _res_cache_clear_stats_locked(cache_info);
+                ++cache_info->revision_id;
+            }
+            for (unsigned j = 0; j < numservers; j++) {
+                freeaddrinfo(nsaddrinfo[j]);
+            }
         }
 
         // Always update the search paths, since determining whether they actually changed is
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 3a8f926..a175857 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -35,6 +35,8 @@
 
 #include <sys/cdefs.h>
 
+__BEGIN_DECLS
+
 #ifndef __ANDROID_API_FUTURE__
 /**
  * Magic version number for an Android OS build which has
@@ -97,3 +99,39 @@
 
 /** Names the "Q" API level (29), for comparisons against __ANDROID_API__. */
 #define __ANDROID_API_Q__ 29
+
+/**
+ * Returns the `targetSdkVersion` of the caller, or `__ANDROID_API_FUTURE__`
+ * if there is no known target SDK version (for code not running in the
+ * context of an app).
+ *
+ * The returned values correspond to the named constants in `<android/api-level.h>`,
+ * and is equivalent to the AndroidManifest.xml `targetSdkVersion`.
+ *
+ * See also android_get_device_api_level().
+ *
+ * Available since API level 24.
+ */
+int android_get_application_target_sdk_version() __INTRODUCED_IN(24);
+
+#if __ANDROID_API__ < __ANDROID_API_Q__
+
+// android_get_device_api_level is a static inline before API level 29.
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#include <bits/get_device_api_level_inlines.h>
+#undef __BIONIC_GET_DEVICE_API_LEVEL_INLINE
+
+#else
+
+/**
+ * Returns the API level of the device we're actually running on, or -1 on failure.
+ * The returned values correspond to the named constants in `<android/api-level.h>`,
+ * and is equivalent to the Java `Build.VERSION.SDK_INT` API.
+ *
+ * See also android_get_application_target_sdk_version().
+ */
+int android_get_device_api_level() __INTRODUCED_IN(29);
+
+#endif
+
+__END_DECLS
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index 431e5ce..e78be39 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -100,34 +100,11 @@
    */
   ANDROID_DLEXT_FORCE_LOAD = 0x40,
 
-  /**
-   * When set, if the minimum `p_vaddr` of the ELF file's `PT_LOAD` segments is non-zero,
-   * the dynamic linker will load it at that address.
-   *
-   * This flag is for ART internal use only.
-   */
-  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 the
-   * minimum `p_vaddr` of all `PT_LOAD` segments) this flag is ignored 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 the minimum
-   * `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,
+  // Historically we had two other options for ART.
+  // They were last available in Android P.
+  // Reuse these bits last!
+  // ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80
+  // ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100
 
   /**
    * This flag used to load library in a different namespace. The namespace is
@@ -145,8 +122,6 @@
                                         ANDROID_DLEXT_USE_LIBRARY_FD |
                                         ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
                                         ANDROID_DLEXT_FORCE_LOAD |
-                                        ANDROID_DLEXT_FORCE_FIXED_VADDR |
-                                        ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS |
                                         ANDROID_DLEXT_USE_NAMESPACE,
 };
 
diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h
index 6e4b8ab..01fa348 100644
--- a/libc/include/android/versioning.h
+++ b/libc/include/android/versioning.h
@@ -14,23 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_VERSIONING_H
-#define ANDROID_VERSIONING_H
+#pragma once
 
-#ifndef __STRING
-#define __STRING(x) #x
-#endif
-
-#define __INTRODUCED_IN(api_level) __attribute__((annotate("introduced_in=" __STRING(api_level))))
+#define __INTRODUCED_IN(api_level) __attribute__((annotate("introduced_in=" #api_level)))
 #define __INTRODUCED_IN_FUTURE __attribute__((annotate("introduced_in_future")))
-#define __DEPRECATED_IN(api_level) __attribute__((annotate("deprecated_in=" __STRING(api_level))))
-#define __REMOVED_IN(api_level) __attribute__((annotate("obsoleted_in=" __STRING(api_level))))
-#define __INTRODUCED_IN_32(api_level) __attribute__((annotate("introduced_in_32=" __STRING(api_level))))
-#define __INTRODUCED_IN_64(api_level) __attribute__((annotate("introduced_in_64=" __STRING(api_level))))
-#define __INTRODUCED_IN_ARM(api_level) __attribute__((annotate("introduced_in_arm=" __STRING(api_level))))
-#define __INTRODUCED_IN_X86(api_level) __attribute__((annotate("introduced_in_x86=" __STRING(api_level))))
-#define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" __STRING(api_level))))
+#define __DEPRECATED_IN(api_level) __attribute__((annotate("deprecated_in=" #api_level)))
+#define __REMOVED_IN(api_level) __attribute__((annotate("obsoleted_in=" #api_level)))
+#define __INTRODUCED_IN_32(api_level) __attribute__((annotate("introduced_in_32=" #api_level)))
+#define __INTRODUCED_IN_64(api_level) __attribute__((annotate("introduced_in_64=" #api_level)))
+#define __INTRODUCED_IN_ARM(api_level) __attribute__((annotate("introduced_in_arm=" #api_level)))
+#define __INTRODUCED_IN_X86(api_level) __attribute__((annotate("introduced_in_x86=" #api_level)))
+#define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" #api_level)))
 
 #define __VERSIONER_NO_GUARD __attribute__((annotate("versioner_no_guard")))
-
-#endif /* ANDROID_VERSIONING_H */
diff --git a/libc/include/bits/get_device_api_level_inlines.h b/libc/include/bits/get_device_api_level_inlines.h
index 8e17814..9c6e243 100644
--- a/libc/include/bits/get_device_api_level_inlines.h
+++ b/libc/include/bits/get_device_api_level_inlines.h
@@ -28,18 +28,20 @@
 
 #pragma once
 
-#include <stdlib.h>
 #include <sys/cdefs.h>
-#include <sys/system_properties.h>
 
 #if !defined(__BIONIC_GET_DEVICE_API_LEVEL_INLINE)
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static inline /* for versioner */
 #endif
 
 __BEGIN_DECLS
 
+// Avoid circular dependencies since this is exposed from <sys/cdefs.h>.
+int __system_property_get(const char* __name, char* __value);
+int atoi(const char* __s) __attribute_pure__;
+
 __BIONIC_GET_DEVICE_API_LEVEL_INLINE int android_get_device_api_level() {
-  char value[PROP_VALUE_MAX] = { 0 };
+  char value[92] = { 0 };
   if (__system_property_get("ro.build.version.sdk", value) < 1) return -1;
   int api_level = atoi(value);
   return (api_level > 0) ? api_level : -1;
diff --git a/libc/include/bits/ioctl.h b/libc/include/bits/ioctl.h
index 9ed1292..fd31a58 100644
--- a/libc/include/bits/ioctl.h
+++ b/libc/include/bits/ioctl.h
@@ -54,11 +54,8 @@
  *   type of the ioctl you prefer, ...), or
  * - defining BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD, which will make the
  *   overloading go away.
- *
- * FIXME: __has_extension is more or less a clang version check. Remove it when
- * we don't need to support old clang code.
  */
-#if __has_extension(overloadable_unmarked) && !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
+#if !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
 /* enable_if(1) just exists to break overloading ties. */
 int ioctl(int __fd, unsigned __request, ...) __overloadable __enable_if(1, "") __RENAME(ioctl);
 #endif
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 42237d0..eba18a8 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -31,12 +31,7 @@
 
 __BEGIN_DECLS
 
-// Remove this workaround once b/37423073 is fixed.
-#if !__has_attribute(alloc_size)
-#define __BIONIC_ALLOC_SIZE(...)
-#else
 #define __BIONIC_ALLOC_SIZE(...) __attribute__((__alloc_size__(__VA_ARGS__)))
-#endif
 
 /**
  * [malloc(3)](http://man7.org/linux/man-pages/man3/malloc.3.html) allocates
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 9d1030a..c788ca6 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -114,7 +114,7 @@
 
 int pthread_kill(pthread_t __pthread, int __signal);
 #if defined(__USE_GNU)
-int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(__ANDROID_API_Q__);
+int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(29);
 #endif
 
 int pthread_sigmask(int __how, const sigset_t* __new_set, sigset_t* __old_set);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 26a05c8..e9d0e4b 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -34,36 +34,10 @@
  *	@(#)cdefs.h	8.8 (Berkeley) 1/9/95
  */
 
-#ifndef	_SYS_CDEFS_H_
-#define	_SYS_CDEFS_H_
-
-#include <android/api-level.h>
+#pragma once
 
 #define __BIONIC__ 1
 
-/*
- * Testing against Clang-specific extensions.
- */
-#ifndef __has_extension
-#define __has_extension         __has_feature
-#endif
-#ifndef __has_feature
-#define __has_feature(x)        0
-#endif
-#ifndef __has_include
-#define __has_include(x)        0
-#endif
-#ifndef __has_builtin
-#define __has_builtin(x)        0
-#endif
-#ifndef __has_attribute
-#define __has_attribute(x)      0
-#endif
-
-#define __strong_alias(alias, sym) \
-    __asm__(".global " #alias "\n" \
-            #alias " = " #sym);
-
 #if defined(__cplusplus)
 #define __BEGIN_DECLS extern "C" {
 #define __END_DECLS }
@@ -72,6 +46,10 @@
 #define __END_DECLS
 #endif
 
+#define __strong_alias(alias, sym) \
+    __asm__(".global " #alias "\n" \
+            #alias " = " #sym);
+
 #if defined(__cplusplus)
 #define __BIONIC_CAST(_k,_t,_v) (_k<_t>(_v))
 #else
@@ -88,22 +66,19 @@
  * strings produced by the __STRING macro, but this only works with ANSI C.
  */
 
-#define	___STRING(x)	__STRING(x)
-#define	___CONCAT(x,y)	__CONCAT(x,y)
-
 #define	__P(protos)	protos		/* full-blown ANSI C */
+
 #define	__CONCAT1(x,y)	x ## y
 #define	__CONCAT(x,y)	__CONCAT1(x,y)
+#define	___CONCAT(x,y)	__CONCAT(x,y)
+
 #define	__STRING(x)	#x
+#define	___STRING(x)	__STRING(x)
 
 #if defined(__cplusplus)
 #define	__inline	inline		/* convert to C++ keyword */
 #endif /* !__cplusplus */
 
-#include <android/versioning.h>
-
-#include <android/versioning.h>
-
 #define __always_inline __attribute__((__always_inline__))
 #define __attribute_const__ __attribute__((__const__))
 #define __attribute_pure__ __attribute__((__pure__))
@@ -359,4 +334,5 @@
  */
 #define __unsafe_check_mul_overflow(x, y) ((__SIZE_TYPE__)-1 / (x) < (y))
 
-#endif /* !_SYS_CDEFS_H_ */
+#include <android/versioning.h>
+#include <android/api-level.h>
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 01f42b7..0961a94 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -63,11 +63,6 @@
         },
     },
 
-    // Clang lld link flags do not work with special link rules
-    // for libunwind_llvm yet. Linked aosp_arm-eng image failed to
-    // boot up in the emulator. http://b/78118944.
-    use_clang_lld: false,
-
     static_libs: [
         "libasync_safe",
         "libbase",
diff --git a/libc/private/NetdClientDispatch.h b/libc/private/NetdClientDispatch.h
index 8d8947d..20e7f25 100644
--- a/libc/private/NetdClientDispatch.h
+++ b/libc/private/NetdClientDispatch.h
@@ -27,6 +27,7 @@
     int (*connect)(int, const struct sockaddr*, socklen_t);
     int (*socket)(int, int, int);
     unsigned (*netIdForResolv)(unsigned);
+    int (*dnsOpenProxy)();
 };
 
 extern __LIBC_HIDDEN__ struct NetdClientDispatch __netdClientDispatch;
diff --git a/libc/private/bionic_constants.h b/libc/private/bionic_constants.h
index 9ae1c8d..e64c826 100644
--- a/libc/private/bionic_constants.h
+++ b/libc/private/bionic_constants.h
@@ -19,4 +19,14 @@
 
 #define NS_PER_S 1000000000
 
+// Size of the shadow call stack. This must be a power of 2.
+#define SCS_SIZE (8 * 1024)
+
+// The shadow call stack is allocated at an aligned address within a guard region of this size. The
+// guard region must be large enough that we can allocate an SCS_SIZE-aligned SCS while ensuring
+// that there is at least one guard page after the SCS so that a stack overflow results in a SIGSEGV
+// instead of corrupting the allocation that comes after it.
+// TODO(b/118642754): Use a larger guard region.
+#define SCS_GUARD_REGION_SIZE (SCS_SIZE * 2)
+
 #endif // _BIONIC_CONSTANTS_H_
diff --git a/libc/private/bionic_sdk_version.h b/libc/private/bionic_sdk_version.h
deleted file mode 100644
index 871d25c..0000000
--- a/libc/private/bionic_sdk_version.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2016 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_SDK_VERSION_H_
-#define _BIONIC_SDK_VERSION_H_
-
-#include <stdint.h>
-
-uint32_t bionic_get_application_target_sdk_version();
-
-#endif  // _BIONIC_SDK_VERSION_H_
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 01c580f..d78a5e7 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -489,6 +489,14 @@
         if arch_list == "all":
             for arch in all_arches:
                 t[arch] = True
+        elif arch_list == "lp32":
+            for arch in all_arches:
+                if "64" not in arch:
+                    t[arch] = True
+        elif arch_list == "lp64":
+            for arch in all_arches:
+                if "64" in arch:
+                    t[arch] = True
         else:
             for arch in string.split(arch_list, ','):
                 if arch in all_arches:
diff --git a/libc/tzcode/bionic.cpp b/libc/tzcode/bionic.cpp
index 9b59183..51fd39a 100644
--- a/libc/tzcode/bionic.cpp
+++ b/libc/tzcode/bionic.cpp
@@ -200,11 +200,15 @@
   int fd;
 
 #if defined(__ANDROID__)
-  // On Android, try the two hard-coded locations.
+  // On Android, try the three hard-coded locations.
   fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/current/tzdata",
                                  olson_id, entry_length);
   if (fd >= 0) return fd;
 
+  fd = __bionic_open_tzdata_path("/apex/com.android.tzdata/etc/tzdata",
+                                 olson_id, entry_length);
+  if (fd >= 0) return fd;
+
   fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata",
                                  olson_id, entry_length);
   if (fd >= 0) return fd;
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fcfc58..28f0601 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -31,6 +31,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -45,7 +46,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.cpp b/libdl/libdl.cpp
index 402804e..a468f81 100644
--- a/libdl/libdl.cpp
+++ b/libdl/libdl.cpp
@@ -67,10 +67,10 @@
                                   const void* caller_addr);
 
 __attribute__((__weak__, visibility("default")))
-void __loader_android_set_application_target_sdk_version(uint32_t target);
+void __loader_android_set_application_target_sdk_version(int target);
 
 __attribute__((__weak__, visibility("default")))
-uint32_t __loader_android_get_application_target_sdk_version();
+int __loader_android_get_application_target_sdk_version();
 
 __attribute__((__weak__, visibility("default")))
 bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
@@ -165,12 +165,12 @@
 }
 
 __attribute__((__weak__))
-void android_set_application_target_sdk_version(uint32_t target) {
+void android_set_application_target_sdk_version(int target) {
   __loader_android_set_application_target_sdk_version(target);
 }
 
 __attribute__((__weak__))
-uint32_t android_get_application_target_sdk_version() {
+int android_get_application_target_sdk_version() {
   return __loader_android_get_application_target_sdk_version();
 }
 
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 002e9f8..c5d1be4 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8d4019c..a03e9e1 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -30,6 +30,7 @@
 
 LIBC_N {
   global:
+    android_get_application_target_sdk_version; # introduced=24 versioned=29
     dlvsym; # introduced=24
 } LIBC;
 
@@ -44,7 +45,6 @@
   global:
     __cfi_init;
     android_dlwarning;
-    android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
diff --git a/libm/Android.bp b/libm/Android.bp
index 6d55967..e4ba20d 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -514,6 +514,9 @@
         integer_overflow: false,
     },
     stl: "none",
+
+    // TODO(ivanlozano): Remove after b/118321713
+    xom: false,
 }
 
 ndk_library {
diff --git a/linker/Android.bp b/linker/Android.bp
index 779cd3f..a9907ca 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -167,10 +167,6 @@
         "-Wl,-soname,ld-android.so",
     ],
 
-    // lld bug: https://bugs.llvm.org/show_bug.cgi?id=36295
-    // error: symbol __aeabi_*@@LIBC_N has undefined version LIBC_N
-    use_clang_lld: false,
-
     cflags: [
         "-fno-stack-protector",
         "-Wstrict-overflow=5",
@@ -293,6 +289,7 @@
         },
     },
     compile_multilib: "both",
+    xom: false,
 }
 
 cc_library {
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index dfe8e8c..45ae6ed 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -57,7 +57,7 @@
                            const android_dlextinfo* extinfo,
                            const void* caller_addr) __LINKER_PUBLIC__;
 void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*)) __LINKER_PUBLIC__;
-uint32_t __loader_android_get_application_target_sdk_version() __LINKER_PUBLIC__;
+int __loader_android_get_application_target_sdk_version() __LINKER_PUBLIC__;
 void __loader_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) __LINKER_PUBLIC__;
 android_namespace_t* __loader_android_get_exported_namespace(const char* name) __LINKER_PUBLIC__;
 bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
@@ -67,7 +67,7 @@
                                       const char* shared_libs_sonames) __LINKER_PUBLIC__;
 bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
                                                android_namespace_t* namespace_to) __LINKER_PUBLIC__;
-void __loader_android_set_application_target_sdk_version(uint32_t target) __LINKER_PUBLIC__;
+void __loader_android_set_application_target_sdk_version(int target) __LINKER_PUBLIC__;
 void __loader_android_update_LD_LIBRARY_PATH(const char* ld_library_path) __LINKER_PUBLIC__;
 void __loader_cfi_fail(uint64_t CallSiteTypeId,
                        void* Ptr,
@@ -204,13 +204,13 @@
 }
 #endif
 
-void __loader_android_set_application_target_sdk_version(uint32_t target) {
+void __loader_android_set_application_target_sdk_version(int target) {
   // lock to avoid modification in the middle of dlopen.
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
   set_application_target_sdk_version(target);
 }
 
-uint32_t __loader_android_get_application_target_sdk_version() {
+int __loader_android_get_application_target_sdk_version() {
   return get_application_target_sdk_version();
 }
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6d646a2..b437f06 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2088,13 +2088,6 @@
       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");
diff --git a/linker/linker.h b/linker/linker.h
index dd45f67..91d3ddf 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -131,8 +131,8 @@
 // void ___cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData, void *Ret);
 void ___cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *Ret);
 
-void set_application_target_sdk_version(uint32_t target);
-uint32_t get_application_target_sdk_version();
+void set_application_target_sdk_version(int target);
+int get_application_target_sdk_version();
 
 enum {
   /* A regular namespace is the namespace with a custom search path that does
diff --git a/linker/linker_allocator.cpp b/linker/linker_allocator.cpp
index de3309b..8b05a7e 100644
--- a/linker/linker_allocator.cpp
+++ b/linker/linker_allocator.cpp
@@ -222,6 +222,8 @@
   first_block->free_blocks_cnt = free_blocks_cnt;
 
   free_blocks_list_ = first_block;
+
+  free_pages_cnt_++;
 }
 
 
diff --git a/linker/linker_config.h b/linker/linker_config.h
index 24c44f4..49739ee 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -140,7 +140,7 @@
     return it == namespace_configs_map_.end() ? nullptr : it->second;
   }
 
-  uint32_t target_sdk_version() const {
+  int target_sdk_version() const {
     return target_sdk_version_;
   }
 
@@ -159,7 +159,7 @@
  private:
   void clear();
 
-  void set_target_sdk_version(uint32_t target_sdk_version) {
+  void set_target_sdk_version(int target_sdk_version) {
     target_sdk_version_ = target_sdk_version;
   }
 
@@ -167,7 +167,7 @@
 
   std::vector<std::unique_ptr<NamespaceConfig>> namespace_configs_;
   std::unordered_map<std::string, NamespaceConfig*> namespace_configs_map_;
-  uint32_t target_sdk_version_;
+  int target_sdk_version_;
 
   DISALLOW_COPY_AND_ASSIGN(Config);
 };
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index d88fc75..82b10b7 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -28,6 +28,9 @@
 
 #include "linker_main.h"
 
+#include <link.h>
+#include <sys/auxv.h>
+
 #include "linker_debug.h"
 #include "linker_cfi.h"
 #include "linker_gdb_support.h"
@@ -35,7 +38,6 @@
 #include "linker_phdr.h"
 #include "linker_utils.h"
 
-#include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
@@ -48,12 +50,10 @@
 #endif
 
 #include <async_safe/log.h>
+#include <bionic/libc_init_common.h>
 
 #include <vector>
 
-extern void __libc_init_globals(KernelArgumentBlock&);
-extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
-
 __LIBC_HIDDEN__ extern "C" void _start();
 
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 741d4e0..34ac606 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -525,14 +525,10 @@
 
 // Reserve a virtual address range such that if it's limits were extended to the next 2**align
 // boundary, it would not overlap with any existing mappings.
-static void* ReserveAligned(void* hint, size_t size, size_t align) {
+static void* ReserveAligned(size_t size, size_t align) {
   int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
-  // Address hint is only used in Art for the image mapping, and it is pretty important. Don't mess
-  // with it.
-  // FIXME: try an aligned allocation and fall back to plain mmap() if the former does not provide a
-  // mapping at the requested address?
-  if (align == PAGE_SIZE || hint != nullptr) {
-    void* mmap_ptr = mmap(hint, size, PROT_NONE, mmap_flags, -1, 0);
+  if (align == PAGE_SIZE) {
+    void* mmap_ptr = mmap(nullptr, size, PROT_NONE, mmap_flags, -1, 0);
     if (mmap_ptr == MAP_FAILED) {
       return nullptr;
     }
@@ -575,9 +571,6 @@
   void* start;
   size_t reserved_size = 0;
   bool reserved_hint = true;
-  bool strict_hint = false;
-  // Assume position independent executable by default.
-  void* mmap_hint = nullptr;
 
   if (extinfo != nullptr) {
     if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -586,13 +579,6 @@
     } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
       reserved_size = extinfo->reserved_size;
     }
-
-    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) {
@@ -601,17 +587,11 @@
              reserved_size - load_size_, load_size_, name_.c_str());
       return false;
     }
-    start = ReserveAligned(mmap_hint, load_size_, kLibraryAlignment);
+    start = ReserveAligned(load_size_, kLibraryAlignment);
     if (start == nullptr) {
       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 {
     start = extinfo->reserved_addr;
     mapped_by_caller_ = true;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index 7bfa26c..b06f3e6 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -30,9 +30,9 @@
 #include <android/api-level.h>
 #include <atomic>
 
-static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
+static std::atomic<int> g_target_sdk_version(__ANDROID_API__);
 
-void set_application_target_sdk_version(uint32_t target) {
+void set_application_target_sdk_version(int target) {
   // translate current sdk_version to platform sdk_version
   if (target == 0) {
     target = __ANDROID_API__;
@@ -40,7 +40,7 @@
   g_target_sdk_version = target;
 }
 
-uint32_t get_application_target_sdk_version() {
+int get_application_target_sdk_version() {
   return g_target_sdk_version;
 }
 
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index e630297..93079ca 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -44,7 +44,7 @@
 // TODO(dimitry): These functions are currently located in linker.cpp - find a better place for it
 bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym);
 ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr);
-uint32_t get_application_target_sdk_version();
+int get_application_target_sdk_version();
 
 soinfo::soinfo(android_namespace_t* ns, const char* realpath,
                const struct stat* file_stat, off64_t file_offset,
@@ -719,7 +719,7 @@
 // This function returns api-level at the time of
 // dlopen/load. Note that libraries opened by system
 // will always have 'current' api level.
-uint32_t soinfo::get_target_sdk_version() const {
+int soinfo::get_target_sdk_version() const {
   if (!has_min_version(2)) {
     return __ANDROID_API__;
   }
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 7331b2f..44bff28 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -276,7 +276,7 @@
   ElfW(Addr) get_verdef_ptr() const;
   size_t get_verdef_cnt() const;
 
-  uint32_t get_target_sdk_version() const;
+  int get_target_sdk_version() const;
 
   void set_dt_runpath(const char *);
   const std::vector<std::string>& get_dt_runpath() const;
@@ -353,7 +353,7 @@
   ElfW(Addr) verneed_ptr_;
   size_t verneed_cnt_;
 
-  uint32_t target_sdk_version_;
+  int target_sdk_version_;
 
   // version >= 3
   std::vector<std::string> dt_runpath_;
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 72a8fa8..e926671 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -235,6 +235,13 @@
         }
 
         resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
+      } else {
+        struct stat s;
+        if (stat(normalized_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) {
+          // Path is not a zip path, but an existing directory. Then add it
+          // although we failed to resolve it. b/119656753
+          resolved_paths->push_back(normalized_path);
+        }
       }
     }
   }
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 8284bea..9268e31 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -51,6 +51,6 @@
   ../linker_config.cpp \
   ../linker_utils.cpp \
 
-LOCAL_STATIC_LIBRARIES += libasync_safe libbase
+LOCAL_STATIC_LIBRARIES += libasync_safe libbase liblog
 
 include $(BUILD_NATIVE_TEST)
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 9208d9d..14fd132 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -37,10 +37,9 @@
 
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
 
 #if defined(__LP64__)
 #define ARCH_SUFFIX "64"
@@ -144,7 +143,7 @@
   ASSERT_TRUE(config != nullptr);
   ASSERT_TRUE(error_msg.empty());
 
-  ASSERT_EQ(113U, config->target_sdk_version());
+  ASSERT_EQ(113, config->target_sdk_version());
 
   const NamespaceConfig* default_ns_config = config->default_namespace_config();
   ASSERT_TRUE(default_ns_config != nullptr);
diff --git a/tests/Android.bp b/tests/Android.bp
index 4ad51da..899fc66 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -102,6 +102,7 @@
         "limits_test.cpp",
         "linux_swab_test.cpp",
         "locale_test.cpp",
+        "malloc_iterate_test.cpp",
         "malloc_test.cpp",
         "math_test.cpp",
         "math_force_long_double_test.cpp",
@@ -120,6 +121,7 @@
         "regex_test.cpp",
         "resolv_test.cpp",
         "sched_test.cpp",
+        "scs_test.cpp",
         "scsi_sg_test.cpp",
         "search_test.cpp",
         "semaphore_test.cpp",
@@ -196,6 +198,7 @@
         bionic: {
             whole_static_libs: [
                 "libasync_safe",
+                "libprocinfo",
                 "libsystemproperties",
             ],
         },
@@ -628,6 +631,10 @@
 
     static_executable: true,
     stl: "libc++_static",
+
+    // libclang_rt.builtins does not work with libm
+    // http://b/117167374
+    no_libcrt: true,
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/TemporaryFile.h b/tests/TemporaryFile.h
deleted file mode 100644
index 7853781..0000000
--- a/tests/TemporaryFile.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 <fcntl.h>
-#include <unistd.h>
-
-#include <android-base/macros.h>
-
-template <typename T = int (*)(char*)>
-class GenericTemporaryFile {
- public:
-  explicit GenericTemporaryFile(T mk_fn = mkstemp) : mk_fn(mk_fn) {
-    // Since we might be running on the host or the target, and if we're
-    // running on the host we might be running under bionic or glibc,
-    // let's just try both possible temporary directories and take the
-    // first one that works.
-    init("/data/local/tmp");
-    if (fd == -1) {
-      init("/tmp");
-    }
-  }
-
-  explicit GenericTemporaryFile(const char* dirpath, T mk_fn = mkstemp) : mk_fn(mk_fn) {
-    init(dirpath);
-  }
-
-  ~GenericTemporaryFile() {
-    close(fd);
-    unlink(filename);
-  }
-
-  void reopen() {
-    close(fd);
-    fd = open(filename, O_RDWR);
-  }
-
-  int fd;
-  char filename[1024];
-
- private:
-  T mk_fn;
-
-  void init(const char* tmp_dir) {
-    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
-    fd = mk_fn(filename);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(GenericTemporaryFile);
-};
-
-typedef GenericTemporaryFile<> TemporaryFile;
-
-class TemporaryDir {
- public:
-  TemporaryDir() {
-    if (!init("/data/local/tmp")) {
-      init("/tmp");
-    }
-  }
-
-  ~TemporaryDir() {
-    rmdir(dirname);
-  }
-
-  char dirname[1024];
-
- private:
-  bool init(const char* tmp_dir) {
-    snprintf(dirname, sizeof(dirname), "%s/TemporaryDir-XXXXXX", tmp_dir);
-    return (mkdtemp(dirname) != nullptr);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
-};
diff --git a/tests/android_get_device_api_level.cpp b/tests/android_get_device_api_level.cpp
index 5272a48..0662404 100644
--- a/tests/android_get_device_api_level.cpp
+++ b/tests/android_get_device_api_level.cpp
@@ -29,7 +29,7 @@
 #include <gtest/gtest.h>
 
 #if __BIONIC__
-#include <android/get_device_api_level.h>
+#include <android/api-level.h>
 #endif
 
 TEST(android_get_device_api_level, smoke) {
diff --git a/tests/buffer_tests.cpp b/tests/buffer_tests.cpp
index a5a0c2a..7563448 100644
--- a/tests/buffer_tests.cpp
+++ b/tests/buffer_tests.cpp
@@ -227,6 +227,18 @@
   }
 }
 
+// Malloc can return a tagged pointer, which is not accepted in mm system calls like mprotect.
+// Clear top 8 bits of the address on 64-bit platforms.
+static int MprotectHeap(void* addr, size_t len, int prot) {
+#if defined(__LP64__)
+  constexpr uintptr_t mask = (static_cast<uintptr_t>(1) << 56) - 1;
+  void* untagged_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & mask);
+#else
+  void* untagged_addr = addr;
+#endif
+  return mprotect(untagged_addr, len, prot);
+}
+
 void RunSingleBufferAlignTest(
     size_t max_test_size, void (*test_func)(uint8_t*, size_t),
     size_t (*set_incr)(size_t)) {
@@ -358,14 +370,14 @@
   memset(memory, 0x23, 2*pagesize);
 
   // Make the second page unreadable and unwritable.
-  ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
 
   for (size_t i = 0; i < pagesize; i++) {
     uint8_t* buf = &memory[pagesize-i];
 
     test_func(buf, i);
   }
-  ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
   free(memory);
 }
 
@@ -379,7 +391,7 @@
   memset(memory, 0x23, 2*pagesize);
 
   // Make the second page unreadable and unwritable.
-  ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_NONE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0);
 
   uint8_t* dst_buffer = new uint8_t[2*pagesize];
   // Change the dst alignment as we change the source.
@@ -391,7 +403,7 @@
       test_func(src, dst, j);
     }
   }
-  ASSERT_TRUE(mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
   free(memory);
   delete[] dst_buffer;
 }
@@ -409,7 +421,7 @@
   memset(memory1, 0x23, 2*pagesize);
 
   // Make the second page unreadable and unwritable.
-  ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_NONE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_NONE) == 0);
 
   uint8_t* memory2;
   ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory2), pagesize,
@@ -417,7 +429,7 @@
   memset(memory2, 0x23, 2*pagesize);
 
   // Make the second page unreadable and unwritable.
-  ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_NONE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_NONE) == 0);
 
   for (size_t i = 0; i < pagesize; i++) {
     uint8_t* buf1 = &memory1[pagesize-i];
@@ -445,8 +457,8 @@
     }
   }
 
-  ASSERT_TRUE(mprotect(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
-  ASSERT_TRUE(mprotect(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
+  ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0);
   free(memory1);
   free(memory2);
 }
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index cb98cae..18ba011 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -31,7 +31,7 @@
 #include <fstream>
 
 #include "gtest_globals.h"
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 #include "utils.h"
 
 extern "C" int main_global_default_serial() {
@@ -136,6 +136,7 @@
 
 TEST(dl, preinit_system_calls) {
 #if defined(__BIONIC__)
+  SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array
   std::string helper = GetTestlibRoot() +
       "/preinit_syscall_test_helper/preinit_syscall_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
@@ -153,6 +154,9 @@
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
   eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
+#else
+  // Force a failure when not compiled for bionic so the test is considered a pass.
+  ASSERT_TRUE(false);
 #endif
 }
 
@@ -235,6 +239,7 @@
 // whose search paths include the 'ns2/' subdir.
 TEST(dl, exec_with_ld_config_file) {
 #if defined(__BIONIC__)
+  SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
   if (!is_debuggable_build()) {
     // LD_CONFIG_FILE is not supported on user build
     return;
@@ -242,8 +247,8 @@
   std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
-  create_ld_config_file(config_file.filename);
-  std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+  create_ld_config_file(config_file.path);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
@@ -257,6 +262,7 @@
 // additional namespaces other than the default namespace.
 TEST(dl, exec_with_ld_config_file_with_ld_preload) {
 #if defined(__BIONIC__)
+  SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
   if (!is_debuggable_build()) {
     // LD_CONFIG_FILE is not supported on user build
     return;
@@ -264,8 +270,8 @@
   std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
-  create_ld_config_file(config_file.filename);
-  std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+  create_ld_config_file(config_file.path);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
   std::string env2 = std::string("LD_PRELOAD=") + GetTestlibRoot() + "/ld_config_test_helper_lib3.so";
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
@@ -294,8 +300,8 @@
   std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
-  create_ld_config_file(config_file.filename);
-  std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
+  create_ld_config_file(config_file.path);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file.path;
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
diff --git a/tests/dlext_private.h b/tests/dlext_private.h
index 2621a68..b338ae0 100644
--- a/tests/dlext_private.h
+++ b/tests/dlext_private.h
@@ -98,7 +98,7 @@
 extern bool android_link_namespaces_all_libs(android_namespace_t* from,
                                              android_namespace_t* to);
 
-extern void android_set_application_target_sdk_version(uint32_t target);
+extern void android_set_application_target_sdk_version(int target);
 
 __END_DECLS
 
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index b33cf68..34013a7 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -40,7 +40,6 @@
 #include <ziparchive/zip_archive.h>
 
 #include "gtest_globals.h"
-#include "TemporaryFile.h"
 #include "utils.h"
 #include "dlext_private.h"
 #include "dlfcn_symlink_support.h"
@@ -367,48 +366,6 @@
   EXPECT_EQ(4, f());
 }
 
-TEST_F(DlExtTest, LoadAtFixedAddress) {
-  void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  ASSERT_TRUE(start != MAP_FAILED);
-  munmap(start, kLibSize);
-
-  android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
-  extinfo.reserved_addr = start;
-
-  handle_ = android_dlopen_ext(kLibName, 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) + kLibSize);
-
-  EXPECT_EQ(4, f());
-  dlclose(handle_);
-  handle_ = nullptr;
-
-  // Check that dlclose unmapped the file
-  void* addr = mmap(start, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  ASSERT_EQ(start, addr) << "dlclose did not unmap the memory";
-}
-
-TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
-  void* start = mmap(nullptr, kLibSize + PAGE_SIZE, PROT_NONE,
-                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  ASSERT_TRUE(start != MAP_FAILED);
-  munmap(start, kLibSize + PAGE_SIZE);
-  void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, kLibSize, 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(kLibName, RTLD_NOW, &extinfo);
-  ASSERT_TRUE(handle_ == nullptr);
-}
-
 class DlExtRelroSharingTest : public DlExtTest {
 protected:
   virtual void SetUp() {
@@ -477,7 +434,7 @@
   TemporaryFile tf; // Use tf to get an unique filename.
   ASSERT_NOERROR(close(tf.fd));
 
-  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
+  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path));
   ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName));
 
   // Use destructor of tf to close and unlink the file.
@@ -488,7 +445,7 @@
   TemporaryFile tf; // // Use tf to get an unique filename.
   ASSERT_NOERROR(close(tf.fd));
 
-  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.filename));
+  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.path));
   ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibNameNoRelro));
 
   // Use destructor of tf to close and unlink the file.
@@ -508,14 +465,14 @@
   TemporaryFile tf; // Use tf to get an unique filename.
   ASSERT_NOERROR(close(tf.fd));
 
-  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
+  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path));
 
   int pipefd[2];
   ASSERT_NOERROR(pipe(pipefd));
 
   size_t without_sharing, with_sharing;
-  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, false, &without_sharing));
-  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, true, &with_sharing));
+  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, false, &without_sharing));
+  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, true, &with_sharing));
   ASSERT_LT(with_sharing, without_sharing);
 
   // We expect the sharing to save at least 50% of the library's total PSS.
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index da44fee..d7dce31 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -22,8 +22,7 @@
 #include <sys/utsname.h>
 #include <sys/vfs.h>
 
-#include "TemporaryFile.h"
-
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 
 // Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
@@ -307,7 +306,7 @@
   // Without O_EXCL, we're allowed to give this a name later.
   // (This is unrelated to the O_CREAT interaction with O_EXCL.)
   const mode_t perms = S_IRUSR | S_IWUSR;
-  int fd = open(dir.dirname, O_TMPFILE | O_RDWR, perms);
+  int fd = open(dir.path, O_TMPFILE | O_RDWR, perms);
 
   // Ignore kernels without O_TMPFILE support (< 3.11).
   if (fd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) return;
@@ -322,7 +321,7 @@
   // On Android if we're not root, we won't be able to create links anyway...
   if (getuid() != 0) return;
 
-  std::string final_path = android::base::StringPrintf("%s/named_now", dir.dirname);
+  std::string final_path = android::base::StringPrintf("%s/named_now", dir.path);
   ASSERT_EQ(0, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
                       AT_FDCWD, final_path.c_str(),
                       AT_SYMLINK_FOLLOW));
@@ -333,11 +332,11 @@
   ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT));
 
   // With O_EXCL, you're not allowed to add a name later.
-  fd = open(dir.dirname, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
+  fd = open(dir.path, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
   ASSERT_TRUE(fd != -1) << strerror(errno);
   errno = 0;
   ASSERT_EQ(-1, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
-                       AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.dirname).c_str(),
+                       AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.path).c_str(),
                        AT_SYMLINK_FOLLOW));
   ASSERT_EQ(ENOENT, errno);
   ASSERT_EQ(0, close(fd));
diff --git a/tests/ftw_test.cpp b/tests/ftw_test.cpp
index 22ab399..dfc4d72 100644
--- a/tests/ftw_test.cpp
+++ b/tests/ftw_test.cpp
@@ -16,6 +16,7 @@
 
 #include <ftw.h>
 
+#include <fcntl.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -23,8 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "TemporaryFile.h"
-
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
@@ -102,26 +102,26 @@
 
 TEST(ftw, ftw) {
   TemporaryDir root;
-  MakeTree(root.dirname);
-  ASSERT_EQ(0, ftw(root.dirname, check_ftw, 128));
+  MakeTree(root.path);
+  ASSERT_EQ(0, ftw(root.path, check_ftw, 128));
 }
 
 TEST(ftw, ftw64) {
   TemporaryDir root;
-  MakeTree(root.dirname);
-  ASSERT_EQ(0, ftw64(root.dirname, check_ftw64, 128));
+  MakeTree(root.path);
+  ASSERT_EQ(0, ftw64(root.path, check_ftw64, 128));
 }
 
 TEST(ftw, nftw) {
   TemporaryDir root;
-  MakeTree(root.dirname);
-  ASSERT_EQ(0, nftw(root.dirname, check_nftw, 128, 0));
+  MakeTree(root.path);
+  ASSERT_EQ(0, nftw(root.path, check_nftw, 128, 0));
 }
 
 TEST(ftw, nftw64) {
   TemporaryDir root;
-  MakeTree(root.dirname);
-  ASSERT_EQ(0, nftw64(root.dirname, check_nftw64, 128, 0));
+  MakeTree(root.path);
+  ASSERT_EQ(0, nftw64(root.path, check_nftw64, 128, 0));
 }
 
 template <typename StatT>
@@ -145,13 +145,13 @@
 
   TemporaryDir root;
 
-  std::string path = android::base::StringPrintf("%s/unreadable-directory", root.dirname);
+  std::string path = android::base::StringPrintf("%s/unreadable-directory", root.path);
   ASSERT_EQ(0, mkdir(path.c_str(), 0000)) << path;
 
-  ASSERT_EQ(0, ftw(root.dirname, bug_28197840_ftw<struct stat>, 128));
-  ASSERT_EQ(0, ftw64(root.dirname, bug_28197840_ftw<struct stat64>, 128));
-  ASSERT_EQ(0, nftw(root.dirname, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
-  ASSERT_EQ(0, nftw64(root.dirname, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
+  ASSERT_EQ(0, ftw(root.path, bug_28197840_ftw<struct stat>, 128));
+  ASSERT_EQ(0, ftw64(root.path, bug_28197840_ftw<struct stat64>, 128));
+  ASSERT_EQ(0, nftw(root.path, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
+  ASSERT_EQ(0, nftw64(root.path, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
 }
 
 template <typename StatT>
diff --git a/tests/getcwd_test.cpp b/tests/getcwd_test.cpp
index f8f205e..791ffae 100644
--- a/tests/getcwd_test.cpp
+++ b/tests/getcwd_test.cpp
@@ -20,6 +20,8 @@
 #include <limits.h>
 #include <unistd.h>
 
+#include "utils.h"
+
 TEST(getcwd, auto_full) {
   // If we let the library do all the work, everything's fine.
   errno = 0;
@@ -49,6 +51,7 @@
 }
 
 TEST(getcwd, auto_too_large) {
+  SKIP_WITH_HWASAN; // allocation size too large
   // If we ask the library to allocate an unreasonably large buffer, ERANGE.
   errno = 0;
   char* cwd = getcwd(nullptr, static_cast<size_t>(-1));
diff --git a/tests/glob_test.cpp b/tests/glob_test.cpp
index 623a2a3..b48f2af 100644
--- a/tests/glob_test.cpp
+++ b/tests/glob_test.cpp
@@ -22,7 +22,7 @@
 #include <string>
 #include <vector>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 #if defined(__BIONIC__)
 #define ASSERT_MATCH_COUNT(n_,g_) ASSERT_EQ(n_, g_.gl_matchc)
@@ -140,22 +140,22 @@
 TEST(glob, glob_GLOB_MARK) {
   TemporaryDir td;
   // The pattern we're about to pass doesn't have a trailing '/'...
-  ASSERT_NE('/', std::string(td.dirname).back());
+  ASSERT_NE('/', std::string(td.path).back());
 
   glob_t g = {};
   // Using GLOB_MARK gets you a trailing '/' on a directory...
-  ASSERT_EQ(0, glob(td.dirname, GLOB_MARK, nullptr, &g));
+  ASSERT_EQ(0, glob(td.path, GLOB_MARK, nullptr, &g));
   ASSERT_EQ(1U, g.gl_pathc);
   ASSERT_MATCH_COUNT(1U, g);
-  ASSERT_EQ(std::string(td.dirname) + "/", g.gl_pathv[0]);
+  ASSERT_EQ(std::string(td.path) + "/", g.gl_pathv[0]);
   ASSERT_EQ(nullptr, g.gl_pathv[1]);
 
   TemporaryFile tf;
   // But not on a file...
-  ASSERT_EQ(0, glob(tf.filename, GLOB_MARK, nullptr, &g));
+  ASSERT_EQ(0, glob(tf.path, GLOB_MARK, nullptr, &g));
   ASSERT_EQ(1U, g.gl_pathc);
   ASSERT_MATCH_COUNT(1U, g);
-  ASSERT_STREQ(tf.filename, g.gl_pathv[0]);
+  ASSERT_STREQ(tf.path, g.gl_pathv[0]);
   ASSERT_EQ(nullptr, g.gl_pathv[1]);
 
   globfree(&g);
diff --git a/tests/grp_pwd_file_test.cpp b/tests/grp_pwd_file_test.cpp
index 8721805..2cbad62 100644
--- a/tests/grp_pwd_file_test.cpp
+++ b/tests/grp_pwd_file_test.cpp
@@ -18,7 +18,7 @@
 
 #include <gtest/gtest.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 #if defined(__BIONIC__)
 #include "../libc/bionic/grp_pwd_file.cpp"
@@ -94,7 +94,7 @@
   static const char test_string[] = "name:password:1:2:user_info:dir:shell\n";
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  PasswdFile passwd_file(file.filename, nullptr);
+  PasswdFile passwd_file(file.path, nullptr);
   FileUnmapper unmapper(passwd_file);
 
   FindAndCheckPasswdEntry(&passwd_file, "name", 1, 2, "dir", "shell");
@@ -114,7 +114,7 @@
   static const char test_string[] = "name:password:1:one,two,three\n";
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  GroupFile group_file(file.filename, nullptr);
+  GroupFile group_file(file.path, nullptr);
   FileUnmapper unmapper(group_file);
 
   FindAndCheckGroupEntry(&group_file, "name", 1);
@@ -150,7 +150,7 @@
 
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  PasswdFile passwd_file(file.filename, nullptr);
+  PasswdFile passwd_file(file.path, nullptr);
   FileUnmapper unmapper(passwd_file);
 
   FindAndCheckPasswdEntry(&passwd_file, "first", 1, 2, "dir", "shell");
@@ -186,7 +186,7 @@
 
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  GroupFile group_file(file.filename, nullptr);
+  GroupFile group_file(file.path, nullptr);
   FileUnmapper unmapper(group_file);
 
   FindAndCheckGroupEntry(&group_file, "first", 1);
@@ -210,7 +210,7 @@
       "vendor_name:password:3:4:user_info:dir:shell\n";
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  PasswdFile passwd_file(file.filename, "vendor_");
+  PasswdFile passwd_file(file.path, "vendor_");
   FileUnmapper unmapper(passwd_file);
 
   EXPECT_FALSE(passwd_file.FindByName("name", nullptr));
@@ -232,7 +232,7 @@
       "vendor_name:password:2:one,two,three\n";
   write(file.fd, test_string, sizeof(test_string) - 1);
 
-  GroupFile group_file(file.filename, "vendor_");
+  GroupFile group_file(file.path, "vendor_");
   FileUnmapper unmapper(group_file);
 
   EXPECT_FALSE(group_file.FindByName("name", nullptr));
diff --git a/tests/libdl_test.cpp b/tests/libdl_test.cpp
index b162edc..6774f1d 100644
--- a/tests/libdl_test.cpp
+++ b/tests/libdl_test.cpp
@@ -18,17 +18,16 @@
 
 #include <android/api-level.h>
 
-extern "C" uint32_t android_get_application_target_sdk_version();
-extern "C" void android_set_application_target_sdk_version(uint32_t target);
+extern "C" void android_set_application_target_sdk_version(int target);
 
 TEST(libdl, application_sdk_versions_smoke) {
   // Check initial values
-  ASSERT_EQ(static_cast<uint32_t>(__ANDROID_API__), android_get_application_target_sdk_version());
+  ASSERT_EQ(__ANDROID_API__, android_get_application_target_sdk_version());
 
-  android_set_application_target_sdk_version(20U);
-  ASSERT_EQ(20U, android_get_application_target_sdk_version());
+  android_set_application_target_sdk_version(20);
+  ASSERT_EQ(20, android_get_application_target_sdk_version());
 
-  android_set_application_target_sdk_version(22U);
-  ASSERT_EQ(22U, android_get_application_target_sdk_version());
+  android_set_application_target_sdk_version(22);
+  ASSERT_EQ(22, android_get_application_target_sdk_version());
 }
 
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 5c4eb42..79c9a06 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -531,8 +531,6 @@
     defaults: ["bionic_testlib_defaults"],
     srcs: ["dl_df_1_global.cpp"],
     ldflags: ["-Wl,-z,global"],
-    // b/80109858, clang lld ignores -z,global
-    use_clang_lld: false,
 
     target: {
         host: {
@@ -561,8 +559,6 @@
     defaults: ["bionic_testlib_defaults"],
     srcs: ["dl_df_1_global_dummy.cpp"],
     ldflags: ["-Wl,-z,global"],
-    // b/80109858, clang lld ignores -z,global
-    use_clang_lld: false,
 
     target: {
         host: {
diff --git a/tests/libs/cfi_test_helper.cpp b/tests/libs/cfi_test_helper.cpp
index ff313a2..c1a7b6d 100644
--- a/tests/libs/cfi_test_helper.cpp
+++ b/tests/libs/cfi_test_helper.cpp
@@ -27,11 +27,13 @@
 static int g_count;
 
 // Mock a CFI-enabled library without relying on the compiler.
-extern "C" __attribute__((aligned(4096))) void __cfi_check(uint64_t /*CallSiteTypeId*/,
-                                                           void* /*TargetAddr*/, void* /*Diag*/) {
+extern "C" __attribute__((no_sanitize("hwaddress")))  __attribute__((aligned(4096)))
+void __cfi_check(uint64_t /*CallSiteTypeId*/, void* /*TargetAddr*/, void* /*Diag*/) {
   ++g_count;
 }
 
+// This code runs before hwasan is initialized.
+__attribute__((no_sanitize("hwaddress")))
 void preinit_ctor() {
   CHECK(g_count == 0);
   __cfi_slowpath(42, reinterpret_cast<void*>(&preinit_ctor));
diff --git a/tests/malloc_iterate_test.cpp b/tests/malloc_iterate_test.cpp
new file mode 100644
index 0000000..5e60a6d
--- /dev/null
+++ b/tests/malloc_iterate_test.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+
+#include <vector>
+
+#include <procinfo/process_map.h>
+
+#include "utils.h"
+
+extern "C" void malloc_disable();
+extern "C" void malloc_enable();
+extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base,
+                              size_t size, void* arg), void* arg);
+
+struct AllocDataType {
+  void* ptr;
+  size_t size;
+  size_t size_reported;
+  size_t count;
+};
+
+struct TestDataType {
+  size_t total_allocated_bytes;
+  std::vector<AllocDataType> allocs;
+};
+
+static void AllocPtr(TestDataType* test_data, size_t size) {
+  test_data->allocs.resize(test_data->allocs.size() + 1);
+  AllocDataType* alloc = &test_data->allocs.back();
+  void* ptr = malloc(size);
+  ASSERT_TRUE(ptr != nullptr);
+  alloc->ptr = ptr;
+  alloc->size = malloc_usable_size(ptr);
+  alloc->size_reported = 0;
+  alloc->count = 0;
+}
+
+static void FreePtrs(TestDataType* test_data) {
+  for (size_t i = 0; i < test_data->allocs.size(); i++) {
+    free(test_data->allocs[i].ptr);
+  }
+}
+
+static void SavePointers(uintptr_t base, size_t size, void* data) {
+  TestDataType* test_data = reinterpret_cast<TestDataType*>(data);
+
+  test_data->total_allocated_bytes += size;
+
+  uintptr_t end;
+  if (__builtin_add_overflow(base, size, &end)) {
+    // Skip this entry.
+    return;
+  }
+
+  for (size_t i = 0; i < test_data->allocs.size(); i++) {
+    uintptr_t ptr = reinterpret_cast<uintptr_t>(test_data->allocs[i].ptr);
+    if (ptr >= base && ptr < end) {
+      test_data->allocs[i].count++;
+
+      uintptr_t max_size = end - ptr;
+      if (max_size > test_data->allocs[i].size) {
+        test_data->allocs[i].size_reported = test_data->allocs[i].size;
+      } else {
+        test_data->allocs[i].size_reported = max_size;
+      }
+    }
+  }
+}
+
+static void VerifyPtrs(TestDataType* test_data) {
+  test_data->total_allocated_bytes = 0;
+
+  // Find all of the maps that are [anon:libc_malloc].
+  ASSERT_TRUE(android::procinfo::ReadMapFile("/proc/self/maps",
+    [&](uint64_t start, uint64_t end, uint16_t, uint64_t, const char* name) {
+    if (std::string(name) == "[anon:libc_malloc]") {
+      malloc_disable();
+      malloc_iterate(start, end - start, SavePointers, test_data);
+      malloc_enable();
+    }
+  }));
+
+  for (size_t i = 0; i < test_data->allocs.size(); i++) {
+    EXPECT_EQ(1UL, test_data->allocs[i].count) << "Failed on size " << test_data->allocs[i].size;
+    if (test_data->allocs[i].count == 1) {
+      EXPECT_EQ(test_data->allocs[i].size, test_data->allocs[i].size_reported);
+    }
+  }
+}
+
+static void AllocateSizes(TestDataType* test_data, const std::vector<size_t>& sizes) {
+  static constexpr size_t kInitialAllocations = 40;
+  static constexpr size_t kNumAllocs = 50;
+  for (size_t size : sizes) {
+    // Verify that if the tcache is enabled, that tcache pointers
+    // are found by allocating and freeing 20 pointers (should be larger
+    // than the total number of cache entries).
+    for (size_t i = 0; i < kInitialAllocations; i++) {
+      void* ptr = malloc(size);
+      ASSERT_TRUE(ptr != nullptr);
+      memset(ptr, 0, size);
+      free(ptr);
+    }
+    for (size_t i = 0; i < kNumAllocs; i++) {
+      AllocPtr(test_data, size);
+    }
+  }
+}
+#endif
+
+// Verify that small allocs can be found properly.
+TEST(malloc_iterate, small_allocs) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN;
+  TestDataType test_data;
+
+  // Try to cycle through all of the different small bins.
+  // This is specific to the implementation of jemalloc and should be
+  // adjusted if a different native memory allocator is used.
+  std::vector<size_t> sizes{8,    16,   32,   48,    64,    80,    96,    112,   128,  160,
+                            192,  224,  256,  320,   384,   448,   512,   640,   768,  896,
+                            1024, 1280, 1536, 1792,  2048,  2560,  3072,  3584,  4096, 5120,
+                            6144, 7168, 8192, 10240, 12288, 14336, 16384, 32768, 65536};
+  AllocateSizes(&test_data, sizes);
+
+  SCOPED_TRACE("");
+  VerifyPtrs(&test_data);
+
+  FreePtrs(&test_data);
+#else
+  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+// Verify that large allocs can be found properly.
+TEST(malloc_iterate, large_allocs) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN;
+  TestDataType test_data;
+
+  // Try some larger sizes.
+  std::vector<size_t> sizes{131072, 262144, 524288, 1048576, 2097152};
+  AllocateSizes(&test_data, sizes);
+
+  SCOPED_TRACE("");
+  VerifyPtrs(&test_data);
+
+  FreePtrs(&test_data);
+#else
+  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+// Verify that there are no crashes attempting to get pointers from
+// non-allocated pointers.
+TEST(malloc_iterate, invalid_pointers) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN;
+  TestDataType test_data = {};
+
+  // Find all of the maps that are not [anon:libc_malloc].
+  ASSERT_TRUE(android::procinfo::ReadMapFile("/proc/self/maps",
+    [&](uint64_t start, uint64_t end, uint16_t, uint64_t, const char* name) {
+    if (std::string(name) != "[anon:libc_malloc]") {
+      malloc_disable();
+      malloc_iterate(start, end - start, SavePointers, &test_data);
+      malloc_enable();
+    }
+  }));
+
+  ASSERT_EQ(0UL, test_data.total_allocated_bytes);
+#else
+  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
+
+TEST(malloc_iterate, malloc_disable_prevents_allocs) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN;
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    malloc_disable();
+    void* ptr = malloc(1024);
+    if (ptr == nullptr) {
+      exit(1);
+    }
+    memset(ptr, 0, 1024);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  // Expect that the malloc will hang forever, and that if the process
+  // does not return for two seconds, it is hung.
+  sleep(2);
+  pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG));
+  if (wait_pid <= 0) {
+    kill(pid, SIGKILL);
+  }
+  ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid.";
+  ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls.";
+#else
+  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+#endif
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index c4f13f6..4a01278 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -25,6 +25,7 @@
 #include <tinyxml2.h>
 
 #include "private/bionic_config.h"
+#include "utils.h"
 
 #if defined(__BIONIC__)
 #define HAVE_REALLOCARRAY 1
@@ -41,6 +42,7 @@
 }
 
 TEST(malloc, malloc_overflow) {
+  SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, malloc(SIZE_MAX));
   ASSERT_EQ(ENOMEM, errno);
@@ -59,12 +61,14 @@
 }
 
 TEST(malloc, calloc_illegal) {
+  SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, calloc(-1, 100));
   ASSERT_EQ(ENOMEM, errno);
 }
 
 TEST(malloc, calloc_overflow) {
+  SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, calloc(1, SIZE_MAX));
   ASSERT_EQ(ENOMEM, errno);
@@ -80,6 +84,7 @@
 }
 
 TEST(malloc, memalign_multiple) {
+  SKIP_WITH_HWASAN; // hwasan requires power of 2 alignment.
   // Memalign test where the alignment is any value.
   for (size_t i = 0; i <= 12; i++) {
     for (size_t alignment = 1 << i; alignment < (1U << (i+1)); alignment++) {
@@ -94,10 +99,12 @@
 }
 
 TEST(malloc, memalign_overflow) {
+  SKIP_WITH_HWASAN;
   ASSERT_EQ(nullptr, memalign(4096, SIZE_MAX));
 }
 
 TEST(malloc, memalign_non_power2) {
+  SKIP_WITH_HWASAN;
   void* ptr;
   for (size_t align = 0; align <= 256; align++) {
     ptr = memalign(align, 1024);
@@ -280,6 +287,7 @@
 }
 
 TEST(malloc, realloc_overflow) {
+  SKIP_WITH_HWASAN;
   errno = 0;
   ASSERT_EQ(nullptr, realloc(nullptr, SIZE_MAX));
   ASSERT_EQ(ENOMEM, errno);
@@ -504,6 +512,27 @@
   ASSERT_EQ(0, errno);
 }
 
+TEST(malloc, mallopt_decay) {
+#if defined(__BIONIC__)
+  errno = 0;
+  ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
+  ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
+  ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
+  ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
+#else
+  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+#endif
+}
+
+TEST(malloc, mallopt_purge) {
+#if defined(__BIONIC__)
+  errno = 0;
+  ASSERT_EQ(1, mallopt(M_PURGE, 0));
+#else
+  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+#endif
+}
+
 TEST(malloc, reallocarray_overflow) {
 #if HAVE_REALLOCARRAY
   // Values that cause overflow to a result small enough (8 on LP64) that malloc would "succeed".
@@ -531,3 +560,44 @@
   GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
 #endif
 }
+
+TEST(malloc, mallinfo) {
+#if defined(__BIONIC__)
+  static size_t sizes[] = {
+    8, 32, 128, 4096, 32768, 131072, 1024000, 10240000, 20480000, 300000000
+  };
+
+  constexpr static size_t kMaxAllocs = 50;
+
+  for (size_t size : sizes) {
+    // If some of these allocations are stuck in a thread cache, then keep
+    // looping until we make an allocation that changes the total size of the
+    // memory allocated.
+    // jemalloc implementations counts the thread cache allocations against
+    // total memory allocated.
+    void* ptrs[kMaxAllocs] = {};
+    bool pass = false;
+    for (size_t i = 0; i < kMaxAllocs; i++) {
+      size_t allocated = mallinfo().uordblks;
+      ptrs[i] = malloc(size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+      size_t new_allocated = mallinfo().uordblks;
+      if (allocated != new_allocated) {
+        size_t usable_size = malloc_usable_size(ptrs[i]);
+        ASSERT_GE(new_allocated, allocated + usable_size)
+            << "Failed at size " << size << " usable size " << usable_size;
+        pass = true;
+        break;
+      }
+    }
+    for (void* ptr : ptrs) {
+      free(ptr);
+    }
+    ASSERT_TRUE(pass)
+        << "For size " << size << " allocated bytes did not increase after "
+        << kMaxAllocs << " allocations.";
+  }
+#else
+  GTEST_LOG_(INFO) << "Host glibc does not pass this test, skipping.\n";
+#endif
+}
diff --git a/tests/scs_test.cpp b/tests/scs_test.cpp
new file mode 100644
index 0000000..24cb347
--- /dev/null
+++ b/tests/scs_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#if __has_feature(shadow_call_stack)
+
+#include <gtest/gtest.h>
+
+#include "private/bionic_constants.h"
+
+int recurse2(int count);
+
+__attribute__((weak, noinline)) int recurse1(int count) {
+  if (count != 0) return recurse2(count - 1) + 1;
+  return 0;
+}
+
+__attribute__((weak, noinline)) int recurse2(int count) {
+  if (count != 0) return recurse1(count - 1) + 1;
+  return 0;
+}
+
+TEST(scs_test, stack_overflow) {
+  ASSERT_EXIT(recurse1(SCS_SIZE), testing::KilledBySignal(SIGSEGV), "");
+}
+
+#endif
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 10d99ea..690e886 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -174,7 +174,7 @@
   ASSERT_EQ(1, i);
 }
 
-extern "C" void android_set_application_target_sdk_version(uint32_t target);
+extern "C" void android_set_application_target_sdk_version(int target);
 
 static void sem_wait_test_signal_handler(int) {
 }
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index dde0be1..44d8af1 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -264,3 +264,14 @@
     fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
   }
 }
+
+__attribute__((noinline)) void call_longjmp(jmp_buf buf) {
+  longjmp(buf, 123);
+}
+
+TEST(setjmp, setjmp_stack) {
+  jmp_buf buf;
+  int value = setjmp(buf);
+  if (value == 0) call_longjmp(buf);
+  EXPECT_EQ(123, value);
+}
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index d4616ef..d84fda0 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -29,7 +29,8 @@
 #include <wchar.h>
 #include <locale.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+
 #include "utils.h"
 
 TEST(stdio_ext, __fbufsize) {
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 54b913a..e9ec499 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -31,8 +31,9 @@
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
+
 #include "BionicDeathTest.h"
-#include "TemporaryFile.h"
 #include "utils.h"
 
 #if defined(NOFORTIFY)
@@ -1412,7 +1413,7 @@
   fflush(fp);
   fclose(fp);
 
-  fp = fopen(tf.filename, "r");
+  fp = fopen(tf.path, "r");
   ASSERT_TRUE(fp != nullptr);
 
   // Store a valid position.
@@ -2041,7 +2042,7 @@
 TEST(STDIO_TEST, fread_after_fseek) {
   TemporaryFile tf;
 
-  FILE* fp = fopen(tf.filename, "w+");
+  FILE* fp = fopen(tf.path, "w+");
   ASSERT_TRUE(fp != nullptr);
 
   char file_data[12288];
@@ -2051,7 +2052,7 @@
   ASSERT_EQ(12288U, fwrite(file_data, 1, 12288, fp));
   fclose(fp);
 
-  fp = fopen(tf.filename, "r");
+  fp = fopen(tf.path, "r");
   ASSERT_TRUE(fp != nullptr);
 
   char buffer[8192];
@@ -2080,10 +2081,10 @@
   TemporaryFile tf;
   char buf[6] = {0};
 
-  FILE* fw = fopen(tf.filename, "w");
+  FILE* fw = fopen(tf.path, "w");
   ASSERT_TRUE(fw != nullptr);
 
-  FILE* fr = fopen(tf.filename, "r");
+  FILE* fr = fopen(tf.path, "r");
   ASSERT_TRUE(fr != nullptr);
 
   fwrite("a", 1, 1, fw);
@@ -2197,7 +2198,7 @@
   for (size_t i = 0; i < 256; ++i) {
     TemporaryFile* tf = new TemporaryFile;
     tfs.push_back(tf);
-    FILE* fp = fopen(tf->filename, "w+");
+    FILE* fp = fopen(tf->path, "w+");
     fps.push_back(fp);
     fprintf(fp, "hello %zu!\n", i);
     fflush(fp);
@@ -2313,21 +2314,21 @@
   struct stat sb;
 
   TemporaryFile tf;
-  ASSERT_EQ(0, remove(tf.filename));
-  ASSERT_EQ(-1, lstat(tf.filename, &sb));
+  ASSERT_EQ(0, remove(tf.path));
+  ASSERT_EQ(-1, lstat(tf.path, &sb));
   ASSERT_EQ(ENOENT, errno);
 
   TemporaryDir td;
-  ASSERT_EQ(0, remove(td.dirname));
-  ASSERT_EQ(-1, lstat(td.dirname, &sb));
+  ASSERT_EQ(0, remove(td.path));
+  ASSERT_EQ(-1, lstat(td.path, &sb));
   ASSERT_EQ(ENOENT, errno);
 
   errno = 0;
-  ASSERT_EQ(-1, remove(tf.filename));
+  ASSERT_EQ(-1, remove(tf.path));
   ASSERT_EQ(ENOENT, errno);
 
   errno = 0;
-  ASSERT_EQ(-1, remove(td.dirname));
+  ASSERT_EQ(-1, remove(td.path));
   ASSERT_EQ(ENOENT, errno);
 }
 
@@ -2404,8 +2405,8 @@
 
 TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
   TemporaryFile tf;
-  SetFileTo(tf.filename, "0123456789");
-  FILE* fp = fopen(tf.filename, "a");
+  SetFileTo(tf.path, "0123456789");
+  FILE* fp = fopen(tf.path, "a");
   EXPECT_EQ(10, ftell(fp));
   ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
   EXPECT_EQ(2, ftell(fp));
@@ -2415,13 +2416,13 @@
   ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
   EXPECT_EQ(13, ftell(fp));
   ASSERT_EQ(0, fclose(fp));
-  AssertFileIs(tf.filename, "0123456789xxx");
+  AssertFileIs(tf.path, "0123456789xxx");
 }
 
 TEST(STDIO_TEST, fdopen_append_mode_and_ftell) {
   TemporaryFile tf;
-  SetFileTo(tf.filename, "0123456789");
-  int fd = open(tf.filename, O_RDWR);
+  SetFileTo(tf.path, "0123456789");
+  int fd = open(tf.path, O_RDWR);
   ASSERT_NE(-1, fd);
   // POSIX: "The file position indicator associated with the new stream is set to the position
   // indicated by the file offset associated with the file descriptor."
@@ -2436,14 +2437,14 @@
   ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
   EXPECT_EQ(13, ftell(fp));
   ASSERT_EQ(0, fclose(fp));
-  AssertFileIs(tf.filename, "0123456789xxx");
+  AssertFileIs(tf.path, "0123456789xxx");
 }
 
 TEST(STDIO_TEST, freopen_append_mode_and_ftell) {
   TemporaryFile tf;
-  SetFileTo(tf.filename, "0123456789");
+  SetFileTo(tf.path, "0123456789");
   FILE* other_fp = fopen("/proc/version", "r");
-  FILE* fp = freopen(tf.filename, "a", other_fp);
+  FILE* fp = freopen(tf.path, "a", other_fp);
   EXPECT_EQ(10, ftell(fp));
   ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
   EXPECT_EQ(2, ftell(fp));
@@ -2453,7 +2454,7 @@
   ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
   EXPECT_EQ(13, ftell(fp));
   ASSERT_EQ(0, fclose(fp));
-  AssertFileIs(tf.filename, "0123456789xxx");
+  AssertFileIs(tf.path, "0123456789xxx");
 }
 
 TEST(STDIO_TEST, constants) {
@@ -2476,7 +2477,7 @@
 TEST(STDIO_TEST, unlocked) {
   TemporaryFile tf;
 
-  FILE* fp = fopen(tf.filename, "w+");
+  FILE* fp = fopen(tf.path, "w+");
   ASSERT_TRUE(fp != nullptr);
 
   clearerr_unlocked(fp);
@@ -2521,7 +2522,7 @@
 
 TEST(STDIO_TEST, fseek_64bit) {
   TemporaryFile tf;
-  FILE* fp = fopen64(tf.filename, "w+");
+  FILE* fp = fopen64(tf.path, "w+");
   ASSERT_TRUE(fp != nullptr);
   ASSERT_EQ(0, fseeko64(fp, 0x2'0000'0000, SEEK_SET));
   ASSERT_EQ(0x2'0000'0000, ftello64(fp));
@@ -2534,7 +2535,7 @@
 // isn't representable in long/off_t.
 TEST(STDIO_TEST, fseek_overflow_32bit) {
   TemporaryFile tf;
-  FILE* fp = fopen64(tf.filename, "w+");
+  FILE* fp = fopen64(tf.path, "w+");
   ASSERT_EQ(0, ftruncate64(fileno(fp), 0x2'0000'0000));
 
   // Bionic implements overflow checking for SEEK_CUR, but glibc doesn't.
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 1c3e1d1..00850f6 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
-#include "BionicDeathTest.h"
-#include "math_data_test.h"
-#include "TemporaryFile.h"
-#include "utils.h"
-
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
@@ -31,10 +24,18 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include <limits>
 #include <string>
 
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+
+#include "BionicDeathTest.h"
+#include "math_data_test.h"
+#include "utils.h"
+
 #if defined(__BIONIC__)
   #define ALIGNED_ALLOC_AVAILABLE 1
 #elif defined(__GLIBC_PREREQ)
@@ -43,6 +44,41 @@
   #endif
 #endif
 
+template <typename T = int (*)(char*)>
+class GenericTemporaryFile {
+ public:
+  explicit GenericTemporaryFile(T mk_fn = mkstemp) : mk_fn_(mk_fn) {
+    // Since we might be running on the host or the target, and if we're
+    // running on the host we might be running under bionic or glibc,
+    // let's just try both possible temporary directories and take the
+    // first one that works.
+    init("/data/local/tmp");
+    if (fd == -1) {
+      init("/tmp");
+    }
+  }
+
+  ~GenericTemporaryFile() {
+    close(fd);
+    unlink(path);
+  }
+
+  int fd;
+  char path[1024];
+
+ private:
+  T mk_fn_;
+
+  void init(const char* tmp_dir) {
+    snprintf(path, sizeof(path), "%s/TemporaryFile-XXXXXX", tmp_dir);
+    fd = mk_fn_(path);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(GenericTemporaryFile);
+};
+
+typedef GenericTemporaryFile<> MyTemporaryFile;
+
 // The random number generator tests all set the seed, get four values, reset the seed and check
 // that they get the first two values repeated, and then reset the seed and check two more values
 // to rule out the possibility that we're just going round a cycle of four values.
@@ -191,6 +227,7 @@
 }
 
 TEST(stdlib, posix_memalign_sweep) {
+  SKIP_WITH_HWASAN;
   void* ptr;
 
   // These should all fail.
@@ -230,11 +267,13 @@
 }
 
 TEST(stdlib, posix_memalign_overflow) {
+  SKIP_WITH_HWASAN;
   void* ptr;
   ASSERT_NE(0, posix_memalign(&ptr, 16, SIZE_MAX));
 }
 
 TEST(stdlib, aligned_alloc_sweep) {
+  SKIP_WITH_HWASAN;
 #if defined(ALIGNED_ALLOC_AVAILABLE)
   // Verify powers of 2 up to 2048 allocate, and verify that all other
   // alignment values between the powers of 2 fail.
@@ -259,6 +298,7 @@
 }
 
 TEST(stdlib, aligned_alloc_overflow) {
+  SKIP_WITH_HWASAN;
 #if defined(ALIGNED_ALLOC_AVAILABLE)
   ASSERT_TRUE(aligned_alloc(16, SIZE_MAX) == nullptr);
 #else
@@ -267,6 +307,7 @@
 }
 
 TEST(stdlib, aligned_alloc_size_not_multiple_of_alignment) {
+  SKIP_WITH_HWASAN;
 #if defined(ALIGNED_ALLOC_AVAILABLE)
   for (size_t size = 1; size <= 2048; size++) {
     void* ptr = aligned_alloc(2048, size);
@@ -379,24 +420,24 @@
 }
 
 TEST(stdlib, mkostemp64) {
-  TemporaryFile tf([](char* path) { return mkostemp64(path, O_CLOEXEC); });
+  MyTemporaryFile tf([](char* path) { return mkostemp64(path, O_CLOEXEC); });
   AssertCloseOnExec(tf.fd, true);
 }
 
 TEST(stdlib, mkostemp) {
-  TemporaryFile tf([](char* path) { return mkostemp(path, O_CLOEXEC); });
+  MyTemporaryFile tf([](char* path) { return mkostemp(path, O_CLOEXEC); });
   AssertCloseOnExec(tf.fd, true);
 }
 
 TEST(stdlib, mkstemp64) {
-  TemporaryFile tf(mkstemp64);
+  MyTemporaryFile tf(mkstemp64);
   struct stat64 sb;
   ASSERT_EQ(0, fstat64(tf.fd, &sb));
   ASSERT_EQ(O_LARGEFILE, fcntl(tf.fd, F_GETFL) & O_LARGEFILE);
 }
 
 TEST(stdlib, mkstemp) {
-  TemporaryFile tf;
+  MyTemporaryFile tf(mkstemp);
   struct stat sb;
   ASSERT_EQ(0, fstat(tf.fd, &sb));
 }
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 22dc383..0b98198 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
+#include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
 
 TEST(sys_mman, mmap_std) {
   void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
@@ -82,7 +82,7 @@
 
   ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
 
-  tf.reopen();
+  tf.fd = open(tf.path, O_RDWR);
   char buf[sizeof(STRING_MSG)];
   memset(buf, 0, sizeof(STRING_MSG));
   ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG)));
@@ -153,7 +153,7 @@
   memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG));
   ASSERT_EQ(0, munmap(map, pagesize));
 
-  tf.reopen();
+  tf.fd = open(tf.path, O_RDWR);
   map = mmap(nullptr, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
   ASSERT_NE(MAP_FAILED, map);
   close(tf.fd);
@@ -161,7 +161,7 @@
   memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG));
   ASSERT_EQ(0, munmap(map, pagesize));
 
-  tf.reopen();
+  tf.fd = open(tf.path, O_RDWR);
   char buf[pagesize];
   ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
   ASSERT_STREQ(PAGE0_MSG, buf);
diff --git a/tests/sys_msg_test.cpp b/tests/sys_msg_test.cpp
index 4eb5a14..8b3623e 100644
--- a/tests/sys_msg_test.cpp
+++ b/tests/sys_msg_test.cpp
@@ -31,7 +31,7 @@
 #include <errno.h>
 #include <sys/msg.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 TEST(sys_msg, smoke) {
   if (msgctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
@@ -41,7 +41,7 @@
 
   // Create a queue.
   TemporaryDir dir;
-  key_t key = ftok(dir.dirname, 1);
+  key_t key = ftok(dir.path, 1);
   int id = msgget(key, IPC_CREAT|0666);
   ASSERT_NE(id, -1);
 
diff --git a/tests/sys_sem_test.cpp b/tests/sys_sem_test.cpp
index eaf2b8f..dff34c8 100644
--- a/tests/sys_sem_test.cpp
+++ b/tests/sys_sem_test.cpp
@@ -31,7 +31,7 @@
 #include <errno.h>
 #include <sys/sem.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 TEST(sys_sem, smoke) {
   if (semctl(-1, 0, IPC_RMID) == -1 && errno == ENOSYS) {
@@ -41,7 +41,7 @@
 
   // Create a semaphore.
   TemporaryDir dir;
-  key_t key = ftok(dir.dirname, 1);
+  key_t key = ftok(dir.path, 1);
   int id = semget(key, 1, IPC_CREAT|0666);
   ASSERT_NE(id, -1);
 
diff --git a/tests/sys_sendfile_test.cpp b/tests/sys_sendfile_test.cpp
index 3d6b5cc..4cddd0d 100644
--- a/tests/sys_sendfile_test.cpp
+++ b/tests/sys_sendfile_test.cpp
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-#include "TemporaryFile.h"
 
-#include <sys/sendfile.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <sys/sendfile.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
 
 TEST(sys_sendfile, sendfile) {
   TemporaryFile src_file;
diff --git a/tests/sys_shm_test.cpp b/tests/sys_shm_test.cpp
index ca2d01a..15abe05 100644
--- a/tests/sys_shm_test.cpp
+++ b/tests/sys_shm_test.cpp
@@ -26,12 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#include <gtest/gtest.h>
-
 #include <errno.h>
 #include <sys/shm.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
 
 TEST(sys_shm, smoke) {
   if (shmctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
@@ -41,7 +40,7 @@
 
   // Create a segment.
   TemporaryDir dir;
-  key_t key = ftok(dir.dirname, 1);
+  key_t key = ftok(dir.path, 1);
   int id = shmget(key, 1234, IPC_CREAT|0666);
   ASSERT_NE(id, -1);
 
diff --git a/tests/sys_stat_test.cpp b/tests/sys_stat_test.cpp
index c0a576d..70ad451 100644
--- a/tests/sys_stat_test.cpp
+++ b/tests/sys_stat_test.cpp
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
 
 TEST(sys_stat, futimens) {
   FILE* fp = tmpfile();
@@ -73,7 +72,7 @@
     std::string path;
     {
       TemporaryFile tf;
-      path = tf.filename;
+      path = tf.path;
     }
 
     ASSERT_EQ(0, mkfifo(path.c_str(), 0666));
@@ -148,19 +147,19 @@
 TEST(sys_stat, fchmodat_file) {
   TemporaryFile tf;
 
-  ASSERT_EQ(0, fchmodat(AT_FDCWD, tf.filename, 0751, 0));
-  AssertFileModeEquals(0751, tf.filename);
+  ASSERT_EQ(0, fchmodat(AT_FDCWD, tf.path, 0751, 0));
+  AssertFileModeEquals(0751, tf.path);
 }
 
 TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_file) {
   TemporaryFile tf;
   errno = 0;
-  int result = fchmodat(AT_FDCWD, tf.filename, 0751, AT_SYMLINK_NOFOLLOW);
+  int result = fchmodat(AT_FDCWD, tf.path, 0751, AT_SYMLINK_NOFOLLOW);
 
 #if defined(__BIONIC__)
   ASSERT_EQ(0, result);
   ASSERT_EQ(0, errno);
-  AssertFileModeEquals(0751, tf.filename);
+  AssertFileModeEquals(0751, tf.path);
 #else
   // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
   // returns ENOTSUP
@@ -173,11 +172,11 @@
   TemporaryFile tf;
   char linkname[255];
 
-  snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
+  snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
 
-  ASSERT_EQ(0, symlink(tf.filename, linkname));
+  ASSERT_EQ(0, symlink(tf.path, linkname));
   ASSERT_EQ(0, fchmodat(AT_FDCWD, linkname, 0751, 0));
-  AssertFileModeEquals(0751, tf.filename);
+  AssertFileModeEquals(0751, tf.path);
   unlink(linkname);
 }
 
@@ -186,8 +185,8 @@
   char linkname[255];
   char target[255];
 
-  snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
-  snprintf(target, sizeof(target), "%s.doesnotexist", tf.filename);
+  snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
+  snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
 
   ASSERT_EQ(0, symlink(target, linkname));
   ASSERT_EQ(-1, fchmodat(AT_FDCWD, linkname, 0751, 0));
@@ -205,12 +204,12 @@
 TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_with_symlink) {
   TemporaryFile tf;
   struct stat tf_sb;
-  ASSERT_EQ(0, stat(tf.filename, &tf_sb));
+  ASSERT_EQ(0, stat(tf.path, &tf_sb));
 
   char linkname[255];
-  snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
+  snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
 
-  ASSERT_EQ(0, symlink(tf.filename, linkname));
+  ASSERT_EQ(0, symlink(tf.path, linkname));
   int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
   // It depends on the kernel whether chmod operation on symlink is allowed.
   if (result == 0) {
@@ -221,7 +220,7 @@
   }
 
   // Target file mode shouldn't be modified.
-  AssertFileModeEquals(tf_sb.st_mode, tf.filename);
+  AssertFileModeEquals(tf_sb.st_mode, tf.path);
   unlink(linkname);
 }
 
@@ -230,8 +229,8 @@
 
   char linkname[255];
   char target[255];
-  snprintf(linkname, sizeof(linkname), "%s.link", tf.filename);
-  snprintf(target, sizeof(target), "%s.doesnotexist", tf.filename);
+  snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
+  snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
 
   ASSERT_EQ(0, symlink(target, linkname));
   int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
diff --git a/tests/sys_time_test.cpp b/tests/sys_time_test.cpp
index b3ec161..16187eb 100644
--- a/tests/sys_time_test.cpp
+++ b/tests/sys_time_test.cpp
@@ -17,15 +17,16 @@
 #include <gtest/gtest.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 // http://b/11383777
 TEST(sys_time, utimes_nullptr) {
   TemporaryFile tf;
-  ASSERT_EQ(0, utimes(tf.filename, nullptr));
+  ASSERT_EQ(0, utimes(tf.path, nullptr));
 }
 
 TEST(sys_time, utimes_EINVAL) {
@@ -34,19 +35,19 @@
   timeval tv[2] = {};
 
   tv[0].tv_usec = -123;
-  ASSERT_EQ(-1, utimes(tf.filename, tv));
+  ASSERT_EQ(-1, utimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[0].tv_usec = 1234567;
-  ASSERT_EQ(-1, utimes(tf.filename, tv));
+  ASSERT_EQ(-1, utimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
-  ASSERT_EQ(-1, utimes(tf.filename, tv));
+  ASSERT_EQ(-1, utimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[1].tv_usec = 1234567;
-  ASSERT_EQ(-1, utimes(tf.filename, tv));
+  ASSERT_EQ(-1, utimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 }
 
@@ -79,7 +80,7 @@
 
 TEST(sys_time, futimesat_nullptr) {
   TemporaryFile tf;
-  ASSERT_EQ(0, futimesat(AT_FDCWD, tf.filename, nullptr));
+  ASSERT_EQ(0, futimesat(AT_FDCWD, tf.path, nullptr));
 }
 
 TEST(sys_time, futimesat_EINVAL) {
@@ -88,25 +89,25 @@
   timeval tv[2] = {};
 
   tv[0].tv_usec = -123;
-  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[0].tv_usec = 1234567;
-  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
-  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[1].tv_usec = 1234567;
-  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.filename, tv));
+  ASSERT_EQ(-1, futimesat(AT_FDCWD, tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 }
 
 TEST(sys_time, lutimes_nullptr) {
   TemporaryFile tf;
-  ASSERT_EQ(0, lutimes(tf.filename, nullptr));
+  ASSERT_EQ(0, lutimes(tf.path, nullptr));
 }
 
 TEST(sys_time, lutimes_EINVAL) {
@@ -115,19 +116,19 @@
   timeval tv[2] = {};
 
   tv[0].tv_usec = -123;
-  ASSERT_EQ(-1, lutimes(tf.filename, tv));
+  ASSERT_EQ(-1, lutimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[0].tv_usec = 1234567;
-  ASSERT_EQ(-1, lutimes(tf.filename, tv));
+  ASSERT_EQ(-1, lutimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 
   tv[0].tv_usec = 0;
 
   tv[1].tv_usec = -123;
-  ASSERT_EQ(-1, lutimes(tf.filename, tv));
+  ASSERT_EQ(-1, lutimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
   tv[1].tv_usec = 1234567;
-  ASSERT_EQ(-1, lutimes(tf.filename, tv));
+  ASSERT_EQ(-1, lutimes(tf.path, tv));
   ASSERT_EQ(EINVAL, errno);
 }
 
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index 60bd224..8460041 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -18,7 +18,7 @@
 
 #include <sys/uio.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
 
 TEST(sys_uio, readv_writev) {
   TemporaryFile tf;
diff --git a/tests/sys_xattr_test.cpp b/tests/sys_xattr_test.cpp
index 006e840..8f4a336 100644
--- a/tests/sys_xattr_test.cpp
+++ b/tests/sys_xattr_test.cpp
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/xattr.h>
 
-#include "TemporaryFile.h"
+#include <android-base/file.h>
+#include <gtest/gtest.h>
 
 TEST(sys_xattr, setxattr) {
   TemporaryFile tf;
   char buf[10];
-  ASSERT_EQ(0, setxattr(tf.filename, "user.foo", "bar", 4, 0));
-  ASSERT_EQ(4, getxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+  ASSERT_EQ(0, setxattr(tf.path, "user.foo", "bar", 4, 0));
+  ASSERT_EQ(4, getxattr(tf.path, "user.foo", buf, sizeof(buf)));
   ASSERT_STREQ("bar", buf);
   buf[0] = '\0';
-  ASSERT_EQ(4, lgetxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+  ASSERT_EQ(4, lgetxattr(tf.path, "user.foo", buf, sizeof(buf)));
   ASSERT_STREQ("bar", buf);
 }
 
@@ -67,7 +67,7 @@
 
 TEST(sys_xattr, fsetxattr_with_opath) {
   TemporaryFile tf;
-  int fd = open(tf.filename, O_PATH);
+  int fd = open(tf.path, O_PATH);
   ASSERT_NE(-1, fd);
 
   int res = fsetxattr(fd, "user.foo", "bar", 4, 0);
@@ -85,7 +85,7 @@
 
 TEST(sys_xattr, fsetxattr_with_opath_toosmall) {
   TemporaryFile tf;
-  int fd = open(tf.filename, O_PATH);
+  int fd = open(tf.path, O_PATH);
   ASSERT_NE(-1, fd);
 
   int res = fsetxattr(fd, "user.foo", "01234567890123456789", 21, 0);
@@ -114,7 +114,7 @@
   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);
+  int fd = open(tf.path, O_PATH);
   ASSERT_NE(-1, fd);
   ssize_t res = flistxattr(fd, buf, sizeof(buf));
 #if defined(__BIONIC__)
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 949019f..3b50896 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -24,7 +24,7 @@
 #include <string>
 #include <thread>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 
 using namespace std::literals;
 
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index e82f15d..4ec5976 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -488,23 +488,6 @@
   ASSERT_EQ(EINVAL, errno);
 }
 
-TEST(time, timer_delete_multiple) {
-  timer_t timer_id;
-  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, nullptr, &timer_id));
-  ASSERT_EQ(0, timer_delete(timer_id));
-  ASSERT_EQ(-1, timer_delete(timer_id));
-  ASSERT_EQ(EINVAL, errno);
-
-  sigevent_t se;
-  memset(&se, 0, sizeof(se));
-  se.sigev_notify = SIGEV_THREAD;
-  se.sigev_notify_function = NoOpNotifyFunction;
-  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
-  ASSERT_EQ(0, timer_delete(timer_id));
-  ASSERT_EQ(-1, timer_delete(timer_id));
-  ASSERT_EQ(EINVAL, errno);
-}
-
 TEST(time, timer_create_multiple) {
   Counter counter1(Counter::CountNotifyFunction);
   Counter counter2(Counter::CountNotifyFunction);
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index da083de..f4a7f1f 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -18,7 +18,6 @@
 
 #include "BionicDeathTest.h"
 #include "SignalUtils.h"
-#include "TemporaryFile.h"
 #include "utils.h"
 
 #include <errno.h>
@@ -166,20 +165,20 @@
 TEST(UNISTD_TEST, truncate) {
   TemporaryFile tf;
   ASSERT_EQ(0, close(tf.fd));
-  ASSERT_EQ(0, truncate(tf.filename, 123));
+  ASSERT_EQ(0, truncate(tf.path, 123));
 
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(123, sb.st_size);
 }
 
 TEST(UNISTD_TEST, truncate64) {
   TemporaryFile tf;
   ASSERT_EQ(0, close(tf.fd));
-  ASSERT_EQ(0, truncate64(tf.filename, 123));
+  ASSERT_EQ(0, truncate64(tf.path, 123));
 
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(123, sb.st_size);
 }
 
@@ -189,7 +188,7 @@
   ASSERT_EQ(0, close(tf.fd));
 
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(123, sb.st_size);
 }
 
@@ -199,7 +198,7 @@
   ASSERT_EQ(0, close(tf.fd));
 
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(123, sb.st_size);
 }
 
@@ -389,11 +388,11 @@
 
   EXPECT_EQ(0, fn(tf.fd));
 
-  ASSERT_NE(-1, fd = open(tf.filename, O_RDONLY));
+  ASSERT_NE(-1, fd = open(tf.path, O_RDONLY));
   EXPECT_EQ(0, fn(fd));
   close(fd);
 
-  ASSERT_NE(-1, fd = open(tf.filename, O_RDWR));
+  ASSERT_NE(-1, fd = open(tf.path, O_RDWR));
   EXPECT_EQ(0, fn(fd));
   close(fd);
 
@@ -671,11 +670,11 @@
   long rc = 0L;
   // As a file system's block size is always power of 2, the configure values
   // for ALLOC and XFER should be power of 2 as well.
-  rc = pathconf(tf.filename, _PC_ALLOC_SIZE_MIN);
+  rc = pathconf(tf.path, _PC_ALLOC_SIZE_MIN);
   ASSERT_TRUE(rc > 0 && powerof2(rc));
-  rc = pathconf(tf.filename, _PC_REC_MIN_XFER_SIZE);
+  rc = pathconf(tf.path, _PC_REC_MIN_XFER_SIZE);
   ASSERT_TRUE(rc > 0 && powerof2(rc));
-  rc = pathconf(tf.filename, _PC_REC_XFER_ALIGN);
+  rc = pathconf(tf.path, _PC_REC_XFER_ALIGN);
   ASSERT_TRUE(rc > 0 && powerof2(rc));
 
   rc = fpathconf(tf.fd, _PC_ALLOC_SIZE_MIN);
@@ -1343,38 +1342,38 @@
 TEST(UNISTD_TEST, execvpe_ENOEXEC) {
   // Create a shell script with #!.
   TemporaryFile tf;
-  ASSERT_TRUE(android::base::WriteStringToFile("#!" BIN_DIR "sh\necho script\n", tf.filename));
+  ASSERT_TRUE(android::base::WriteStringToFile("#!" BIN_DIR "sh\necho script\n", tf.path));
 
   // Set $PATH so we can find it.
-  setenv("PATH", dirname(tf.filename), 1);
+  setenv("PATH", dirname(tf.path), 1);
 
   ExecTestHelper eth;
-  eth.SetArgs({basename(tf.filename), nullptr});
+  eth.SetArgs({basename(tf.path), nullptr});
 
   // It's not inherently executable.
   errno = 0;
-  ASSERT_EQ(-1, execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()));
+  ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
   ASSERT_EQ(EACCES, errno);
 
   // Make it executable (and keep it writable because we're going to rewrite it below).
-  ASSERT_EQ(0, chmod(tf.filename, 0777));
+  ASSERT_EQ(0, chmod(tf.path, 0777));
 
   // TemporaryFile will have a writable fd, so we can test ETXTBSY while we're here...
   errno = 0;
-  ASSERT_EQ(-1, execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()));
+  ASSERT_EQ(-1, execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()));
   ASSERT_EQ(ETXTBSY, errno);
 
   // 1. The simplest test: the kernel should handle this.
   ASSERT_EQ(0, close(tf.fd));
-  eth.Run([&]() { execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+  eth.Run([&]() { execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
 
   // 2. Try again without a #!. We should have to handle this ourselves.
-  ASSERT_TRUE(android::base::WriteStringToFile("echo script\n", tf.filename));
-  eth.Run([&]() { execvpe(basename(tf.filename), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+  ASSERT_TRUE(android::base::WriteStringToFile("echo script\n", tf.path));
+  eth.Run([&]() { execvpe(basename(tf.path), eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
 
   // 3. Again without a #!, but also with a leading '/', since that's a special case in the
   // implementation.
-  eth.Run([&]() { execvpe(tf.filename, eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
+  eth.Run([&]() { execvpe(tf.path, eth.GetArgs(), eth.GetEnv()); }, 0, "script\n");
 }
 
 TEST(UNISTD_TEST, execvp_libcore_test_55017) {
diff --git a/tests/utils.h b/tests/utils.h
index c8656dc..5fc1d93 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -58,6 +58,14 @@
   return (dlopen("libc.so", 0) != nullptr);
 }
 
+extern "C" void __hwasan_init() __attribute__((weak));
+
+static inline bool running_with_hwasan() {
+  return &__hwasan_init != 0;
+}
+
+#define SKIP_WITH_HWASAN if (running_with_hwasan()) { return; }
+
 #if defined(__linux__)
 
 #include <sys/sysmacros.h>
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 7c4aa23..8ba3d42 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -29,7 +29,6 @@
 #include <clang/AST/ASTConsumer.h>
 #include <clang/Basic/Diagnostic.h>
 #include <clang/Basic/TargetInfo.h>
-#include <clang/Basic/VirtualFileSystem.h>
 #include <clang/Driver/Compilation.h>
 #include <clang/Driver/Driver.h>
 #include <clang/Frontend/CompilerInstance.h>
@@ -42,6 +41,7 @@
 #include <llvm/ADT/IntrusiveRefCntPtr.h>
 #include <llvm/ADT/SmallVector.h>
 #include <llvm/ADT/StringRef.h>
+#include <llvm/Support/VirtualFileSystem.h>
 
 #include "Arch.h"
 #include "DeclarationDatabase.h"
@@ -93,7 +93,7 @@
 // Run it once to generate flags for each target, and memoize the results.
 static std::unordered_map<CompilationType, std::vector<std::string>> cc1_flags;
 static const char* filename_placeholder = "__VERSIONER_PLACEHOLDER__";
-static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
                                    CompilationType type,
                                    const std::vector<std::string>& include_dirs) {
   std::vector<std::string> cmd = { "versioner" };
@@ -207,7 +207,7 @@
   return result;
 }
 
-void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
                                   const std::set<CompilationType>& types,
                                   const std::unordered_map<Arch, CompilationRequirements>& reqs) {
   if (!cc1_flags.empty()) {
@@ -242,7 +242,7 @@
   }
 }
 
-void compileHeader(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void compileHeader(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
                    HeaderDatabase* header_database, CompilationType type,
                    const std::string& filename) {
   auto diags = constructDiags();
diff --git a/tools/versioner/src/Driver.h b/tools/versioner/src/Driver.h
index 48683e4..99e57ae 100644
--- a/tools/versioner/src/Driver.h
+++ b/tools/versioner/src/Driver.h
@@ -31,10 +31,10 @@
   std::vector<std::string> dependencies;
 };
 
-void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
                                   const std::set<CompilationType>& types,
                                   const std::unordered_map<Arch, CompilationRequirements>& reqs);
 
-void compileHeader(llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> vfs,
+void compileHeader(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
                    HeaderDatabase* header_database, CompilationType type,
                    const std::string& filename);
diff --git a/tools/versioner/src/VFS.cpp b/tools/versioner/src/VFS.cpp
index 8f9de88..d797f82 100644
--- a/tools/versioner/src/VFS.cpp
+++ b/tools/versioner/src/VFS.cpp
@@ -25,14 +25,14 @@
 #include <string>
 
 #include <android-base/unique_fd.h>
-#include <clang/Basic/VirtualFileSystem.h>
 #include <llvm/ADT/IntrusiveRefCntPtr.h>
 #include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/VirtualFileSystem.h>
 
 #include "Utils.h"
 
 using android::base::unique_fd;
-using namespace clang::vfs;
+using namespace llvm::vfs;
 
 static void addDirectoryToVFS(InMemoryFileSystem* vfs, const std::string& path) {
   char* paths[] = { const_cast<char*>(path.c_str()), nullptr };
diff --git a/tools/versioner/src/VFS.h b/tools/versioner/src/VFS.h
index e2ab002..e4aac75 100644
--- a/tools/versioner/src/VFS.h
+++ b/tools/versioner/src/VFS.h
@@ -20,8 +20,8 @@
 #include <string>
 
 #include <llvm/ADT/IntrusiveRefCntPtr.h>
-#include <clang/Basic/VirtualFileSystem.h>
+#include <llvm/Support/VirtualFileSystem.h>
 
-llvm::IntrusiveRefCntPtr<clang::vfs::FileSystem> createCommonVFS(const std::string& header_dir,
-                                                                 const std::string& dependency_dir,
-                                                                 bool add_versioning_header);
+llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> createCommonVFS(const std::string& header_dir,
+                                                                const std::string& dependency_dir,
+                                                                bool add_versioning_header);