Merge "System property for heapprofd at process startup."
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/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 2ba4f78..6209374 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",
@@ -268,23 +268,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",
-                ],
-            },
         },
     },
 
@@ -603,14 +591,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: {
@@ -1136,6 +1120,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 +1152,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 +1182,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: [
@@ -1597,7 +1567,7 @@
         "libc_syscalls",
         "libc_tzcode",
         "libm",
-        "libjemalloc",
+        "libjemalloc5",
         "libstdc++",
     ],
 }
@@ -1656,6 +1626,46 @@
 }
 
 // ========================================================
+// 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"],
+        },
+    },
+
+    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"],
+        },
+    },
+
+    whole_static_libs: [
+        "libc_common",
+    ],
+}
+
+// ========================================================
 // libc_nomalloc.a
 // ========================================================
 //
@@ -1679,7 +1689,7 @@
     cflags: ["-DLIBC_STATIC"],
 
     whole_static_libs: [
-        "libc_common",
+        "libc_common_static",
         "libc_init_static",
     ],
 }
@@ -1714,7 +1724,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: [
@@ -1725,7 +1738,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"],
@@ -1752,8 +1768,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-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/__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/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_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 5f76354..fc68b8a 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -137,9 +137,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/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/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/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/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/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/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.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_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_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 795b01d..71e8a4d 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/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 c334032..899fc66 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -121,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",
@@ -630,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/dl_test.cpp b/tests/dl_test.cpp
index c1681ea..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() {
@@ -247,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 });
@@ -270,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;
@@ -300,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 bea18e5..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"
@@ -435,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.
@@ -446,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.
@@ -466,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/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/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 14848ae..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,16 @@
 #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__)
@@ -45,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.
@@ -386,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/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) {