Merge "16k: bionic: Re-align libtest_empty.so to 16kb for arm64 and x86_64" into main
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 8d507d1..e9cfbac 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -445,6 +445,18 @@
 | No `dlclose`      | Works                      | Works   | Works |
 
 
+## ELF TLS (Available for API level >= 29)
+
+Android supports [ELF TLS](docs/elf-tls.md) starting at API level 29. Since
+NDK r26, clang will automatically enable ELF TLS for `minSdkVersion 29` or
+higher. Otherwise, the existing emutls implementation (which uses
+`pthread_key_create()` behind the scenes) will continue to be used. This
+means that convenient C/C++ thread-local syntax is available at any API level;
+at worst it will perform similarly to "roll your own" thread locals using
+`pthread_key_create()` but at best you'll get the performance benefit of
+ELF TLS, and the NDK will take care of the details.
+
+
 ## Use of IFUNC in libc (True for all API levels on devices running Android 10)
 
 On devices running API level 29, libc uses
diff --git a/benchmarks/README.md b/benchmarks/README.md
index 3819b1a..6b6c448 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -19,6 +19,12 @@
 By default, `bionic-benchmarks` runs all of the benchmarks in alphabetical order. Pass
 `--benchmark_filter=getpid` to run just the benchmarks with "getpid" in their name.
 
+Note that we also build _static_ benchmark binaries.
+They're useful for testing on devices running different versions of Android, or running non-Android OSes.
+Those binaries are called `bionic-benchmarks-static` instead.
+Copy from `out/target/product/<device>/symbols/data/benchmarktest64/bionic-benchmarks-static` instead of
+`out/target/product/<device>/data/benchmarktest64/bionic-benchmarks-static` if you want symbols for perf(1).
+
 ### Host benchmarks
 
 See the `benchmarks/run-on-host.sh` script. The host benchmarks can be run with 32-bit or 64-bit
diff --git a/benchmarks/bionic_benchmarks.cpp b/benchmarks/bionic_benchmarks.cpp
index 81f1842..b88c6e5 100644
--- a/benchmarks/bionic_benchmarks.cpp
+++ b/benchmarks/bionic_benchmarks.cpp
@@ -372,7 +372,7 @@
 
 void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts,
                               const std::string& fn_name, args_vector_t* run_args) {
-  if (g_str_to_func.find(fn_name) == g_str_to_func.end()) {
+  if (!g_str_to_func.contains(fn_name)) {
     errx(1, "ERROR: No benchmark for function %s", fn_name.c_str());
   }
   long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
diff --git a/benchmarks/ctype_benchmark.cpp b/benchmarks/ctype_benchmark.cpp
index c6c23b0..b162ea7 100644
--- a/benchmarks/ctype_benchmark.cpp
+++ b/benchmarks/ctype_benchmark.cpp
@@ -16,81 +16,47 @@
 
 #include <ctype.h>
 
+#include <array>
+#include <numeric>
+#include <random>
+
 #include <benchmark/benchmark.h>
 #include "util.h"
 
-// Avoid optimization.
-volatile int A = 'A';
-volatile int a = 'a';
-volatile int X = 'X';
-volatile int x = 'x';
-volatile int backspace = '\b';
-volatile int del = '\x7f';
-volatile int space = ' ';
-volatile int tab = '\t';
-volatile int zero = '0';
-volatile int underscore = '_';
-volatile int top_bit_set = 0x88;
+static std::array<int, 128> RandomAscii() {
+  std::array<int, 128> result;
+  std::iota(result.begin(), result.end(), 0);
+  std::shuffle(result.begin(), result.end(), std::mt19937{std::random_device{}()});
+  return result;
+}
 
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalnum_y1, isalnum(A));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalnum_y2, isalnum(a));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalnum_y3, isalnum(zero));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalnum_n, isalnum(underscore));
+#define CTYPE_BENCHMARK(__benchmark, fn)                        \
+  static void __benchmark##_##fn(benchmark::State& state) {     \
+    auto chars = RandomAscii();                                 \
+    for (auto _ : state) {                                      \
+      for (char ch : chars) {                                   \
+        benchmark::DoNotOptimize(fn(ch));                       \
+      }                                                         \
+    }                                                           \
+    state.SetBytesProcessed(state.iterations() * chars.size()); \
+  }                                                             \
+  BIONIC_BENCHMARK(__benchmark##_##fn)
 
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalpha_y1, isalpha(A));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalpha_y2, isalpha(a));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isalpha_n, isalpha(underscore));
+CTYPE_BENCHMARK(BM_ctype, isalpha);
+CTYPE_BENCHMARK(BM_ctype, isalnum);
+CTYPE_BENCHMARK(BM_ctype, isascii);
+CTYPE_BENCHMARK(BM_ctype, isblank);
+CTYPE_BENCHMARK(BM_ctype, iscntrl);
+CTYPE_BENCHMARK(BM_ctype, isgraph);
+CTYPE_BENCHMARK(BM_ctype, islower);
+CTYPE_BENCHMARK(BM_ctype, isprint);
+CTYPE_BENCHMARK(BM_ctype, ispunct);
+CTYPE_BENCHMARK(BM_ctype, isspace);
+CTYPE_BENCHMARK(BM_ctype, isupper);
+CTYPE_BENCHMARK(BM_ctype, isxdigit);
 
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isascii_y, isascii(x));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isascii_n, isascii(top_bit_set));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isblank_y1, isblank(space));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isblank_y2, isblank(tab));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isblank_n, isblank(underscore));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_iscntrl_y1, iscntrl(backspace));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_iscntrl_y2, iscntrl(del));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_iscntrl_n, iscntrl(underscore));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isdigit_y, iscntrl(zero));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isdigit_n, iscntrl(underscore));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isgraph_y1, isgraph(A));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isgraph_y2, isgraph(a));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isgraph_y3, isgraph(zero));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isgraph_y4, isgraph(underscore));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isgraph_n, isgraph(space));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_islower_y, islower(x));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_islower_n, islower(X));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_y1, isprint(A));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_y2, isprint(a));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_y3, isprint(zero));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_y4, isprint(underscore));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_y5, isprint(space));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isprint_n, isprint(backspace));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_ispunct_y, ispunct(underscore));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_ispunct_n, ispunct(A));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isspace_y1, isspace(space));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isspace_y2, isspace(tab));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isspace_n, isspace(A));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isupper_y, isupper(X));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isupper_n, isupper(x));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isxdigit_y1, isxdigit(zero));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isxdigit_y2, isxdigit(a));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isxdigit_y3, isxdigit(A));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_isxdigit_n, isxdigit(underscore));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_toascii_y, isascii(x));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_toascii_n, isascii(top_bit_set));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_tolower_y, tolower(X));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_tolower_n, tolower(x));
-
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_toupper_y, toupper(x));
-BIONIC_TRIVIAL_BENCHMARK(BM_ctype_toupper_n, toupper(X));
+CTYPE_BENCHMARK(BM_ctype, toascii);
+CTYPE_BENCHMARK(BM_ctype, tolower);
+CTYPE_BENCHMARK(BM_ctype, _tolower);
+CTYPE_BENCHMARK(BM_ctype, toupper);
+CTYPE_BENCHMARK(BM_ctype, _toupper);
diff --git a/benchmarks/wctype_benchmark.cpp b/benchmarks/wctype_benchmark.cpp
index cdf5568..cf96057 100644
--- a/benchmarks/wctype_benchmark.cpp
+++ b/benchmarks/wctype_benchmark.cpp
@@ -16,17 +16,73 @@
 
 #include <wctype.h>
 
+#include <numeric>
+#include <random>
+#include <vector>
+
 #include <benchmark/benchmark.h>
 #include "util.h"
 
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towlower_ascii_y, towlower('X'));
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towlower_ascii_n, towlower('x'));
+static std::vector<wint_t> RandomAscii() {
+  std::vector<wint_t> result(128);
+  std::iota(result.begin(), result.end(), 0);
+  std::shuffle(result.begin(), result.end(), std::mt19937{std::random_device{}()});
+  return result;
+}
 
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towlower_unicode_y, towlower(0x0391));
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towlower_unicode_n, towlower(0x03b1));
+static std::vector<wint_t> RandomNonAscii() {
+  std::vector<wint_t> result;
+  std::mt19937 rng{std::random_device{}()};
+  std::uniform_int_distribution<> d(0x80, 0xffff);
+  for (size_t i = 0; i < 128; i++) result.push_back(d(rng));
+  return result;
+}
 
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towupper_ascii_y, towupper('x'));
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towupper_ascii_n, towupper('X'));
+#define WCTYPE_BENCHMARK(__benchmark, fn, random_fn)            \
+  static void __benchmark##_##fn(benchmark::State& state) {     \
+    auto chars = random_fn();                                   \
+    for (auto _ : state) {                                      \
+      for (char ch : chars) {                                   \
+        benchmark::DoNotOptimize(fn(ch));                       \
+      }                                                         \
+    }                                                           \
+    state.SetBytesProcessed(state.iterations() * chars.size()); \
+  }                                                             \
+  BIONIC_BENCHMARK(__benchmark##_##fn)
 
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towupper_unicode_y, towupper(0x03b1));
-BIONIC_TRIVIAL_BENCHMARK(BM_wctype_towupper_unicode_n, towupper(0x0391));
+#define WCTYPE_BENCHMARK_ASCII(__benchmark, fn) WCTYPE_BENCHMARK(__benchmark, fn, RandomAscii)
+
+#define WCTYPE_BENCHMARK_NON_ASCII(__benchmark, fn) \
+  WCTYPE_BENCHMARK(__benchmark, fn, RandomNonAscii)
+
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswalnum);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswalpha);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswblank);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswcntrl);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswdigit);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswgraph);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswlower);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswprint);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswpunct);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswspace);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswupper);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii, iswxdigit);
+
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii_transform, towlower);
+WCTYPE_BENCHMARK_ASCII(BM_wctype_ascii_transform, towupper);
+
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswalnum);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswalpha);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswblank);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswcntrl);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswdigit);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswgraph);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswlower);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswprint);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswpunct);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswspace);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswupper);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii, iswxdigit);
+
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii_transform, towlower);
+WCTYPE_BENCHMARK_NON_ASCII(BM_wctype_non_ascii_transform, towupper);
diff --git a/docs/elf-tls.md b/docs/elf-tls.md
index 6b03841..450f362 100644
--- a/docs/elf-tls.md
+++ b/docs/elf-tls.md
@@ -1,5 +1,11 @@
 # Android ELF TLS
 
+App developers probably just want to read the
+[quick ELS TLS status summary](../android-changes-for-ndk-developers.md#elf-tls-available-for-api-level-29)
+instead.
+
+This document covers the detailed design and implementation choices.
+
 [TOC]
 
 # Overview
@@ -210,7 +216,7 @@
  * 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.
+Neither bionic nor musl 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
@@ -484,19 +490,6 @@
 [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
@@ -510,13 +503,14 @@
 
 ## TLS Allocator
 
-The prototype currently allocates a `pthread_internal_t` object and static TLS in a single mmap'ed
+bionic 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.
+`LinkerMemoryAllocator`, adapted to avoid the STL and to provide `memalign`.
+The implementation 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`
@@ -524,10 +518,10 @@
  * 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.
+the implementation 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
+The implementation 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`.
@@ -536,7 +530,7 @@
 
 ## Async-Signal Safety
 
-The prototype's `__tls_get_addr` might be async-signal safe. Making it AS-safe is a good idea if
+The implementation'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
@@ -545,7 +539,7 @@
 
 ## Out-of-Memory Handling (abort)
 
-The prototype lazily allocates TLS memory for dlopen'ed modules (see `__tls_get_addr`), and an
+The implementation 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.
@@ -567,7 +561,7 @@
 
 FWIW: emutls also aborts on out-of-memory.
 
-## ELF TLS Not Usable in libc
+## ELF TLS Not Usable in libc Itself
 
 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
@@ -644,7 +638,7 @@
 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
+The TLS prototype used 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
@@ -816,8 +810,8 @@
 
 ### 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
+Most Android executables do not use any `thread_local` variables. In the prototype, with the
+AOSP hikey960 build, only `/system/bin/netd` had a TLS segment, and it was 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.
 
@@ -842,6 +836,12 @@
  * 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
 
+## TODO: Other
+
+Missing:
+ * `dlsym` of a TLS variable
+ * debugger support
+
 # References
 
 General (and x86/x86-64)
diff --git a/docs/fdsan.md b/docs/fdsan.md
index f5d1ab5..5aeb7de 100644
--- a/docs/fdsan.md
+++ b/docs/fdsan.md
@@ -62,7 +62,9 @@
  - fatal (`ANDROID_FDSAN_ERROR_LEVEL_FATAL`)
    - Abort upon detecting an error.
 
-In Android Q, fdsan has a global default of warn-once. fdsan can be made more or less strict at runtime via the `android_fdsan_set_error_level` function in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/main/libc/include/android/fdsan.h).
+In API level 29, fdsan had a global default of warn-once.
+In API level 30 and higher, fdsan has a global default of fatal.
+fdsan can be made more or less strict at runtime via the `android_fdsan_set_error_level` function in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/main/libc/include/android/fdsan.h).
 
 The likelihood of fdsan catching a file descriptor error is proportional to the percentage of file descriptors in your process that are tagged with an owner.
 
@@ -344,7 +346,8 @@
 
     // These functions are marked with __attribute__((weak)), so that their
     // availability can be determined at runtime. These wrappers will use them
-    // if available, and fall back to no-ops or regular close on pre-Q devices.
+    // if available, and fall back to no-ops or regular close on devices older
+    // than API level 29.
     static void exchange_tag(int fd, uint64_t old_tag, uint64_t new_tag) {
         if (android_fdsan_exchange_owner_tag) {
             android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
diff --git a/docs/status.md b/docs/status.md
index e0364a8..7ebd195 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -283,23 +283,31 @@
 
 libc function count over time:
 
-| OS    | API level | Function count |
-|-------|-----------|----------------|
-| J     | 16        | 842            |
-| J MR1 | 17        | 870            |
-| J MR2 | 18        | 878            |
-| K     | 19        | 893            |
-| L     | 21        | 1118           |
-| M     | 23        | 1183           |
-| N     | 24        | 1228           |
-| O     | 26        | 1280           |
-| P     | 28        | 1378           |
-| Q     | 29        | 1394           |
+| API level | Function count |
+|-----------|----------------|
+| 16        | 842            |
+| 17        | 870            |
+| 18        | 878            |
+| 19        | 893            |
+| 21        | 1016           |
+| 22        | 1038           |
+| 23        | 1103           |
+| 24        | 1147           |
+| 25        | 1147           |
+| 26        | 1199           |
+| 27        | 1199           |
+| 28        | 1298           |
+| 29        | 1312           |
+| 30        | 1368           |
+| 31        | 1379           |
+| 32        | 1379           |
+| 33        | 1386           |
+| 34        | 1392           |
 
 Data collected by:
 ```
-ndk-r21$ for i in `ls -1v platforms/android-*/arch-arm/usr/lib/libc.so` ; do \
-  echo $i; nm $i | grep -w T | wc -l ; done
+ndk-r26c$ for i in `ls -1v toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/*/libc.so` ; \
+  do echo $i; nm $i | grep -w T | wc -l ; done
 ```
 
 ### libm
diff --git a/libc/Android.bp b/libc/Android.bp
index 5063364..7788a48 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -87,10 +87,6 @@
     recovery_available: true,
     native_bridge_supported: true,
 
-    // lld complains about duplicate symbols in libcrt and libgcc. Suppress the
-    // warning since this is intended right now.
-    ldflags: ["-Wl,-z,muldefs"],
-
     product_variables: {
         malloc_zero_contents: {
             cflags: ["-DSCUDO_ZERO_CONTENTS"],
@@ -132,6 +128,45 @@
     },
 }
 
+// Leave the symbols in the shared library so that stack unwinders can produce
+// meaningful name resolution. This is a bit more ugly than it sounds because
+// arm32 is a bit broken.
+// ========================================================
+cc_defaults {
+    name: "keep_symbols",
+    arch: {
+        arm: {
+            // arm32 does not produce complete exidx unwind information,
+            // so keep the .debug_frame which is relatively small and does
+            // include needed unwind information.
+            // See b/132992102 for details.
+            strip: {
+                keep_symbols_and_debug_frame: true,
+            },
+        },
+        arm64: {
+            strip: {
+                keep_symbols: true,
+            },
+        },
+        riscv64: {
+            strip: {
+                keep_symbols: true,
+            },
+        },
+        x86: {
+            strip: {
+                keep_symbols: true,
+            },
+        },
+        x86_64: {
+            strip: {
+                keep_symbols: true,
+            },
+        },
+    },
+}
+
 // Defaults for native allocator libs/includes to make it
 // easier to change.
 // ========================================================
@@ -1020,11 +1055,6 @@
         "stdio/stdio_ext.cpp",
         "stdio/vfscanf.cpp",
         "stdio/vfwscanf.cpp",
-
-        // TODO: why isn't this in a static-libc-only module?
-        // This contains a weak stub implementation of __find_icu_symbol for wctype.cpp,
-        // which will be overridden by the actual one in libc.so.
-        "bionic/icu_static.cpp",
     ],
 
     arch: {
@@ -1527,6 +1557,7 @@
     srcs: [
         "bionic/gwp_asan_wrappers.cpp",
         "bionic/heap_tagging.cpp",
+        "bionic/icu_static.cpp",
         "bionic/malloc_common.cpp",
         "bionic/malloc_limit.cpp",
     ],
@@ -1548,6 +1579,7 @@
         "libc_defaults",
         "libc_native_allocator_defaults",
         "bug_24465209_workaround",
+        "keep_symbols",
     ],
     name: "libc_library_defaults",
     product_variables: {
@@ -1560,7 +1592,6 @@
         cflags: ["-DLIBC_STATIC"],
         whole_static_libs: [
             "gwp_asan",
-            "gwp_asan_crash_handler",
             "libc_init_static",
             "libc_common_static",
             "libc_unwind_static",
@@ -1570,7 +1601,6 @@
         srcs: [":libc_sources_shared"],
         whole_static_libs: [
             "gwp_asan",
-            "gwp_asan_crash_handler",
             "libc_init_dynamic",
             "libc_common_shared",
             "libunwind-exported",
@@ -1597,12 +1627,6 @@
 
     arch: {
         arm: {
-            ldflags: [
-                // Since we are preserving the debug_frame, do not compress
-                // in this case to make unwinds as fast as possible.
-                "-Wl,--compress-debug-sections=none",
-            ],
-
             version_script: ":libc.arm.map",
             no_libcrt: true,
 
@@ -1610,59 +1634,33 @@
                 srcs: [":libc_sources_shared_arm"],
                 // special for arm
                 cflags: ["-DCRT_LEGACY_WORKAROUND"],
-                // For backwards-compatibility, some arm32 builtins are exported from libc.so.
+                // For backwards compatibility, some arm32 builtins are exported from libc.so.
                 static_libs: ["libclang_rt.builtins-exported"],
             },
 
-            // Arm 32 bit does not produce complete exidx unwind information
-            // so keep the .debug_frame which is relatively small and does
-            // include needed unwind information.
-            // See b/132992102 for details.
-            strip: {
-                keep_symbols_and_debug_frame: true,
-            },
+            ldflags: [
+                // Since we preserve the debug_frame for libc, do not compress
+                // in this case to make unwinds as fast as possible.
+                "-Wl,--compress-debug-sections=none",
+            ],
         },
         arm64: {
             version_script: ":libc.arm64.map",
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         riscv64: {
             version_script: ":libc.riscv64.map",
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         x86: {
             version_script: ":libc.x86.map",
             no_libcrt: true,
 
             shared: {
-                // For backwards-compatibility, some x86 builtins are exported from libc.so.
+                // For backwards compatibility, some x86 builtins are exported from libc.so.
                 static_libs: ["libclang_rt.builtins-exported"],
             },
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         x86_64: {
             version_script: ":libc.x86_64.map",
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
     },
 
diff --git a/libc/SECCOMP_ALLOWLIST_APP.TXT b/libc/SECCOMP_ALLOWLIST_APP.TXT
index 7e1ecde..80b15b2 100644
--- a/libc/SECCOMP_ALLOWLIST_APP.TXT
+++ b/libc/SECCOMP_ALLOWLIST_APP.TXT
@@ -4,36 +4,36 @@
 # This file is processed by a python script named genseccomp.py.
 
 # Needed for debugging 32-bit Chrome
-int	pipe:pipe(int pipefd[2])	lp32
+int	pipe(int pipefd[2])	lp32
 
 # b/34651972
-int	access:access(const char *pathname, int mode)	lp32
-int	stat64:stat64(const char*, struct stat64*)	lp32
+int	access(const char *pathname, int mode)	lp32
+int	stat64(const char*, struct stat64*)	lp32
 
 # b/34813887
-int	open:open(const char *path, int oflag, ... ) lp32,x86_64
-int	getdents:getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) lp32,x86_64
+int	open(const char *path, int oflag, ... ) lp32,x86_64
+int	getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) lp32,x86_64
 
 # b/34719286
-int	eventfd:eventfd(unsigned int initval, int flags)	lp32
+int	eventfd(unsigned int initval, int flags)	lp32
 
 # b/34817266
-int	epoll_wait:epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)	lp32
+int	epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)	lp32
 
 # b/34908783
-int	epoll_create:epoll_create(int size)	lp32
+int	epoll_create(int size)	lp32
 
 # b/34979910
-int	creat:creat(const char *pathname, mode_t mode)	lp32
-int	unlink:unlink(const char *pathname)	lp32
+int	creat(const char *pathname, mode_t mode)	lp32
+int	unlink(const char *pathname)	lp32
 
 # b/35059702
-int	lstat64:lstat64(const char*, struct stat64*)	lp32
+int	lstat64(const char*, struct stat64*)	lp32
 
 # b/35217603
-int	fcntl:fcntl(int fd, int cmd, ... /* arg */ )	lp32
-pid_t	fork:fork()	lp32
-int	poll:poll(struct pollfd *fds, nfds_t nfds, int timeout)	lp32
+int	fcntl(int fd, int cmd, ... /* arg */ )	lp32
+pid_t	fork()	lp32
+int	poll(struct pollfd *fds, nfds_t nfds, int timeout)	lp32
 
 # b/35906875
 int	inotify_init()	lp32
diff --git a/libc/SECCOMP_BLOCKLIST_APP.TXT b/libc/SECCOMP_BLOCKLIST_APP.TXT
index 049d577..b9ecc02 100644
--- a/libc/SECCOMP_BLOCKLIST_APP.TXT
+++ b/libc/SECCOMP_BLOCKLIST_APP.TXT
@@ -6,40 +6,39 @@
 #
 # This file is processed by a python script named genseccomp.py.
 
-# Note: Some privileged syscalls are still needed in app process after fork before uid change,
-# including capset and setresuid. This is because the seccomp filter must be installed while
-# the process still has CAP_SYS_ADMIN; changing the uid would remove that capability.
-
-# syscalls to modify IDs
-int     setgid:setgid32(gid_t)     lp32
-int     setgid:setgid(gid_t)       lp64
-int     setuid:setuid32(uid_t)    lp32
-int     setuid:setuid(uid_t)      lp64
-int     setregid:setregid32(gid_t, gid_t)  lp32
-int     setregid:setregid(gid_t, gid_t)    lp64
-int     setreuid:setreuid32(uid_t, uid_t)   lp32
-int     setreuid:setreuid(uid_t, uid_t)     lp64
-int     setresgid:setresgid32(gid_t, gid_t, gid_t)   lp32
-int     setresgid:setresgid(gid_t, gid_t, gid_t)     lp64
+# Syscalls to modify IDs.
+# Note: Some privileged syscalls are still needed in app_process after fork but
+# before uid change, including capset and setresuid. This is because the seccomp
+# filter must be installed while the process still has CAP_SYS_ADMIN; changing
+# the uid would remove that capability.
+int     setgid32(gid_t)     lp32
+int     setgid(gid_t)       lp64
+int     setuid32(uid_t)    lp32
+int     setuid(uid_t)      lp64
+int     setregid32(gid_t, gid_t)  lp32
+int     setregid(gid_t, gid_t)    lp64
+int     setreuid32(uid_t, uid_t)   lp32
+int     setreuid(uid_t, uid_t)     lp64
+int     setresgid32(gid_t, gid_t, gid_t)   lp32
+int     setresgid(gid_t, gid_t, gid_t)     lp64
 # setresuid is explicitly allowed, see above.
-int     setfsgid:setfsgid32(gid_t) lp32
-int     setfsgid:setfsgid(gid_t)   lp64
-int     setfsuid:setfsuid32(uid_t) lp32
-int     setfsuid:setfsuid(uid_t)   lp64
-int     setgroups:setgroups32(int, const gid_t*)   lp32
-int     setgroups:setgroups(int, const gid_t*)     lp64
+int     setfsgid32(gid_t) lp32
+int     setfsgid(gid_t)   lp64
+int     setfsuid32(uid_t) lp32
+int     setfsuid(uid_t)   lp64
+int     setgroups32(int, const gid_t*)   lp32
+int     setgroups(int, const gid_t*)     lp64
 
-# syscalls to modify times
+# Syscalls to modify times.
 int     adjtimex(struct timex*)   all
 int     clock_adjtime(clockid_t, struct timex*)   all
 int     clock_settime(clockid_t, const struct timespec*)  all
 int     settimeofday(const struct timeval*, const struct timezone*)   all
 
 int     acct(const char*  filepath)  all
-int     klogctl:syslog(int, char*, int)   all
+int     syslog(int, char*, int)   all
 int     chroot(const char*)  all
 
-# syscalls to change machine various configurations
 int     init_module(void*, unsigned long, const char*)  all
 int     delete_module(const char*, unsigned int)   all
 int     mount(const char*, const char*, const char*, unsigned long, const void*)  all
@@ -48,4 +47,4 @@
 int     swapoff(const char*) all
 int     setdomainname(const char*, size_t)  all
 int     sethostname(const char*, size_t)  all
-int     __reboot:reboot(int, int, int, void*)  all
+int     reboot(int, int, int, void*)  all
diff --git a/libc/arch-arm64/dynamic_function_dispatch.cpp b/libc/arch-arm64/dynamic_function_dispatch.cpp
index a42c361..f9e4263 100644
--- a/libc/arch-arm64/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm64/dynamic_function_dispatch.cpp
@@ -66,7 +66,9 @@
 
 typedef void* memcpy_func(void*, const void*, size_t);
 DEFINE_IFUNC_FOR(memcpy) {
-    if (__bionic_is_oryon(arg->_hwcap)) {
+    if (arg->_hwcap2 & HWCAP2_MOPS) {
+        RETURN_FUNC(memcpy_func, __memmove_aarch64_mops);
+    } else if (__bionic_is_oryon(arg->_hwcap)) {
         RETURN_FUNC(memcpy_func, __memcpy_aarch64_nt);
     } else if (arg->_hwcap & HWCAP_ASIMD) {
         RETURN_FUNC(memcpy_func, __memcpy_aarch64_simd);
@@ -77,7 +79,9 @@
 
 typedef void* memmove_func(void*, const void*, size_t);
 DEFINE_IFUNC_FOR(memmove) {
-  if (__bionic_is_oryon(arg->_hwcap)) {
+  if (arg->_hwcap2 & HWCAP2_MOPS) {
+    RETURN_FUNC(memmove_func, __memmove_aarch64_mops);
+  } else if (__bionic_is_oryon(arg->_hwcap)) {
     RETURN_FUNC(memcpy_func, __memmove_aarch64_nt);
   } else if (arg->_hwcap & HWCAP_ASIMD) {
     RETURN_FUNC(memmove_func, __memmove_aarch64_simd);
@@ -93,7 +97,9 @@
 
 typedef int memset_func(void*, int, size_t);
 DEFINE_IFUNC_FOR(memset) {
-    if (__bionic_is_oryon(arg->_hwcap)) {
+    if (arg->_hwcap2 & HWCAP2_MOPS) {
+        RETURN_FUNC(memset_func, __memset_aarch64_mops);
+    } else if (__bionic_is_oryon(arg->_hwcap)) {
         RETURN_FUNC(memset_func, __memset_aarch64_nt);
     } else {
         RETURN_FUNC(memset_func, __memset_aarch64);
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index e6f4a97..be5fb11 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -20,18 +20,12 @@
 
 #include "private/bionic_fdtrack.h"
 
-#ifdef __i386__
-#define __socketcall __attribute__((__cdecl__))
-#else
-#define __socketcall
-#endif
-
-extern "C" __socketcall int __accept4(int, sockaddr*, socklen_t*, int);
-extern "C" __socketcall int __connect(int, const sockaddr*, socklen_t);
-extern "C" __socketcall int __sendmmsg(int, const mmsghdr*, unsigned int, int);
-extern "C" __socketcall ssize_t __sendmsg(int, const msghdr*, unsigned int);
-extern "C" __socketcall int __sendto(int, const void*, size_t, int, const sockaddr*, socklen_t);
-extern "C" __socketcall int __socket(int, int, int);
+extern "C" int __accept4(int, sockaddr*, socklen_t*, int);
+extern "C" int __connect(int, const sockaddr*, socklen_t);
+extern "C" int __sendmmsg(int, const mmsghdr*, unsigned int, int);
+extern "C" ssize_t __sendmsg(int, const msghdr*, unsigned int);
+extern "C" int __sendto(int, const void*, size_t, int, const sockaddr*, socklen_t);
+extern "C" int __socket(int, int, int);
 
 static unsigned fallBackNetIdForResolv(unsigned netId) {
     return netId;
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index 3d92404..6741be3 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -53,6 +53,8 @@
   heap_tagging_level = __libc_shared_globals()->initial_heap_tagging_level;
 #endif
 
+  __libc_memtag_stack_abi = __libc_shared_globals()->initial_memtag_stack_abi;
+
   __libc_globals.mutate([](libc_globals* globals) {
     switch (heap_tagging_level) {
       case M_HEAP_TAGGING_LEVEL_TBI:
diff --git a/libc/bionic/icu_static.cpp b/libc/bionic/icu_static.cpp
index e81e291..cf24a38 100644
--- a/libc/bionic/icu_static.cpp
+++ b/libc/bionic/icu_static.cpp
@@ -29,6 +29,6 @@
 #include "private/icu.h"
 
 // We don't have dlopen/dlsym for static binaries yet.
-__attribute__((weak)) void* __find_icu_symbol(const char*) {
+void* __find_icu_symbol(const char*) {
   return nullptr;
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index c82c52e..939e4e1 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -58,6 +58,7 @@
 
 __LIBC_HIDDEN__ constinit WriteProtected<libc_globals> __libc_globals;
 __LIBC_HIDDEN__ constinit _Atomic(bool) __libc_memtag_stack;
+__LIBC_HIDDEN__ constinit bool __libc_memtag_stack_abi;
 
 // Not public, but well-known in the BSDs.
 __BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 3da0a92..ac97376 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -289,11 +289,7 @@
 
   // We can't short-circuit the environment override, as `stack` is still inherited from the
   // binary's settings.
-  if (get_environment_memtag_setting(&level)) {
-    if (level == M_HEAP_TAGGING_LEVEL_NONE || level == M_HEAP_TAGGING_LEVEL_TBI) {
-      *stack = false;
-    }
-  }
+  get_environment_memtag_setting(&level);
   return level;
 }
 
@@ -329,13 +325,14 @@
   bool memtag_stack = false;
   HeapTaggingLevel level =
       __get_tagging_level(memtag_dynamic_entries, phdr_start, phdr_ct, load_bias, &memtag_stack);
-  // This is used by the linker (in linker.cpp) to communicate than any library linked by this
-  // executable enables memtag-stack.
-  if (__libc_shared_globals()->initial_memtag_stack) {
-    if (!memtag_stack) {
-      async_safe_format_log(ANDROID_LOG_INFO, "libc", "enabling PROT_MTE as requested by linker");
-    }
+  // initial_memtag_stack is used by the linker (in linker.cpp) to communicate than any library
+  // linked by this executable enables memtag-stack.
+  // memtag_stack is also set for static executables if they request memtag stack via the note,
+  // in which case it will differ from initial_memtag_stack.
+  if (__libc_shared_globals()->initial_memtag_stack || memtag_stack) {
     memtag_stack = true;
+    __libc_shared_globals()->initial_memtag_stack_abi = true;
+    __get_bionic_tcb()->tls_slot(TLS_SLOT_STACK_MTE) = __allocate_stack_mte_ringbuffer(0, nullptr);
   }
   if (int64_t timed_upgrade = __get_memtag_upgrade_secs()) {
     if (level == M_HEAP_TAGGING_LEVEL_ASYNC) {
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 5bd4f16..a8d09eb 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -65,6 +65,7 @@
 }
 
 void __init_bionic_tls_ptrs(bionic_tcb* tcb, bionic_tls* tls) {
+  tcb->thread()->bionic_tcb = tcb;
   tcb->thread()->bionic_tls = tls;
   tcb->tls_slot(TLS_SLOT_BIONIC_TLS) = tls;
 }
@@ -443,6 +444,14 @@
 
   ScopedReadLock locker(&g_thread_creation_lock);
 
+// This has to be done under g_thread_creation_lock or g_thread_list_lock to avoid racing with
+// __pthread_internal_remap_stack_with_mte.
+#ifdef __aarch64__
+  if (__libc_memtag_stack_abi) {
+    tcb->tls_slot(TLS_SLOT_STACK_MTE) = __allocate_stack_mte_ringbuffer(0, thread);
+  }
+#endif
+
   sigset64_t block_all_mask;
   sigfillset64(&block_all_mask);
   __rt_sigprocmask(SIG_SETMASK, &block_all_mask, &thread->start_mask, sizeof(thread->start_mask));
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 8b9573f..14cc7da 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -33,9 +33,12 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 
 #include <async_safe/log.h>
+#include <bionic/mte.h>
 #include <bionic/reserved_signals.h>
+#include <bionic/tls_defines.h>
 
 #include "private/ErrnoRestorer.h"
 #include "private/ScopedRWLock.h"
@@ -73,6 +76,15 @@
 }
 
 static void __pthread_internal_free(pthread_internal_t* thread) {
+#ifdef __aarch64__
+  if (void* stack_mte_tls = thread->bionic_tcb->tls_slot(TLS_SLOT_STACK_MTE)) {
+    size_t size =
+        stack_mte_ringbuffer_size_from_pointer(reinterpret_cast<uintptr_t>(stack_mte_tls));
+    void* ptr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(stack_mte_tls) &
+                                        ((1ULL << 56ULL) - 1ULL));
+    munmap(ptr, size);
+  }
+#endif
   if (thread->mmap_size != 0) {
     // Free mapped space, including thread stack and pthread_internal_t.
     munmap(thread->mmap_base, thread->mmap_size);
@@ -176,12 +188,40 @@
   async_safe_fatal("stack not found in /proc/self/maps");
 }
 
+#if defined(__aarch64__)
+__LIBC_HIDDEN__ void* __allocate_stack_mte_ringbuffer(size_t n, pthread_internal_t* thread) {
+  const char* name;
+  if (thread == nullptr) {
+    name = "stack_mte_ring:main";
+  } else {
+    // The kernel doesn't copy the name string, but this variable will last at least as long as the
+    // mapped area. We unmap the ring buffer before unmapping the rest of the thread storage.
+    auto& name_buffer = thread->stack_mte_ringbuffer_vma_name_buffer;
+    static_assert(arraysize(name_buffer) >= arraysize("stack_mte_ring:") + 11 + 1);
+    async_safe_format_buffer(name_buffer, arraysize(name_buffer), "stack_mte_ring:%d", thread->tid);
+    name = name_buffer;
+  }
+  void* ret = stack_mte_ringbuffer_allocate(n, name);
+  if (!ret) async_safe_fatal("error: failed to allocate stack mte ring buffer");
+  return ret;
+}
+#endif
+
 bool __pthread_internal_remap_stack_with_mte() {
 #if defined(__aarch64__)
-  // If process doesn't have MTE enabled, we don't need to do anything.
+  ScopedWriteLock creation_locker(&g_thread_creation_lock);
+  ScopedReadLock list_locker(&g_thread_list_lock);
+  // If process already uses memtag-stack ABI, we don't need to do anything.
+  if (__libc_memtag_stack_abi) return false;
+  __libc_memtag_stack_abi = true;
+
+  for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) {
+    if (t->terminating) continue;
+    t->bionic_tcb->tls_slot(TLS_SLOT_STACK_MTE) =
+        __allocate_stack_mte_ringbuffer(0, t->is_main() ? nullptr : t);
+  }
   if (!atomic_load(&__libc_globals->memtag)) return false;
-  bool prev = atomic_exchange(&__libc_memtag_stack, true);
-  if (prev) return false;
+  if (atomic_exchange(&__libc_memtag_stack, true)) return false;
   uintptr_t lo, hi;
   __find_main_stack_limits(&lo, &hi);
 
@@ -189,8 +229,6 @@
                PROT_READ | PROT_WRITE | PROT_MTE | PROT_GROWSDOWN)) {
     async_safe_fatal("error: failed to set PROT_MTE on main thread");
   }
-  ScopedWriteLock creation_locker(&g_thread_creation_lock);
-  ScopedReadLock list_locker(&g_thread_list_lock);
   for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) {
     if (t->terminating || t->is_main()) continue;
     if (mprotect(t->mmap_base_unguarded, t->mmap_size_unguarded,
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index b0e9461..5db42ab 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -178,6 +178,10 @@
   bionic_tls* bionic_tls;
 
   int errno_value;
+
+  bionic_tcb* bionic_tcb;
+  char stack_mte_ringbuffer_vma_name_buffer[32];
+
   bool is_main() { return start_routine == nullptr; }
 };
 
@@ -209,6 +213,9 @@
 __LIBC_HIDDEN__ void __pthread_internal_remove(pthread_internal_t* thread);
 __LIBC_HIDDEN__ void __pthread_internal_remove_and_free(pthread_internal_t* thread);
 __LIBC_HIDDEN__ void __find_main_stack_limits(uintptr_t* low, uintptr_t* high);
+#if defined(__aarch64__)
+__LIBC_HIDDEN__ void* __allocate_stack_mte_ringbuffer(size_t n, pthread_internal_t* thread);
+#endif
 
 static inline __always_inline bionic_tcb* __get_bionic_tcb() {
   return reinterpret_cast<bionic_tcb*>(&__get_tls()[MIN_TLS_SLOT]);
diff --git a/libc/bionic/sys_msg.cpp b/libc/bionic/sys_msg.cpp
index 462c83b..9780d38 100644
--- a/libc/bionic/sys_msg.cpp
+++ b/libc/bionic/sys_msg.cpp
@@ -36,33 +36,17 @@
   // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit.
   cmd |= IPC_64;
 #endif
-#if defined(SYS_msgctl)
   return syscall(SYS_msgctl, id, cmd, buf);
-#else
-  return syscall(SYS_ipc, MSGCTL, id, cmd, 0, buf, 0);
-#endif
 }
 
 int msgget(key_t key, int flags) {
-#if defined(SYS_msgget)
   return syscall(SYS_msgget, key, flags);
-#else
-  return syscall(SYS_ipc, MSGGET, key, flags, 0, 0, 0);
-#endif
 }
 
 ssize_t msgrcv(int id, void* msg, size_t n, long type, int flags) {
-#if defined(SYS_msgrcv)
   return syscall(SYS_msgrcv, id, msg, n, type, flags);
-#else
-  return syscall(SYS_ipc, IPCCALL(1, MSGRCV), id, n, flags, msg, type);
-#endif
 }
 
 int msgsnd(int id, const void* msg, size_t n, int flags) {
-#if defined(SYS_msgsnd)
   return syscall(SYS_msgsnd, id, msg, n, flags);
-#else
-  return syscall(SYS_ipc, MSGSND, id, n, flags, msg, 0);
-#endif
 }
diff --git a/libc/bionic/sys_sem.cpp b/libc/bionic/sys_sem.cpp
index 058cfef..b97bf46 100644
--- a/libc/bionic/sys_sem.cpp
+++ b/libc/bionic/sys_sem.cpp
@@ -41,19 +41,11 @@
   va_start(ap, cmd);
   semun arg = va_arg(ap, semun);
   va_end(ap);
-#if defined(SYS_semctl)
   return syscall(SYS_semctl, id, num, cmd, arg);
-#else
-  return syscall(SYS_ipc, SEMCTL, id, num, cmd, &arg, 0);
-#endif
 }
 
 int semget(key_t key, int n, int flags) {
-#if defined(SYS_semget)
   return syscall(SYS_semget, key, n, flags);
-#else
-  return syscall(SYS_ipc, SEMGET, key, n, flags, 0, 0);
-#endif
 }
 
 int semop(int id, sembuf* ops, size_t op_count) {
@@ -64,6 +56,9 @@
 #if defined(SYS_semtimedop)
   return syscall(SYS_semtimedop, id, ops, op_count, ts);
 #else
+  // 32-bit x86 -- the only architecture without semtimedop(2) -- only has
+  // semtimedop_time64(2), but since we don't have any timespec64 stuff,
+  // it's less painful for us to just stick with the legacy ipc(2) here.
   return syscall(SYS_ipc, SEMTIMEDOP, id, op_count, 0, ops, ts);
 #endif
 }
diff --git a/libc/bionic/sys_shm.cpp b/libc/bionic/sys_shm.cpp
index f780e04..777b3ad 100644
--- a/libc/bionic/sys_shm.cpp
+++ b/libc/bionic/sys_shm.cpp
@@ -32,16 +32,7 @@
 #include <unistd.h>
 
 void* shmat(int id, const void* address, int flags) {
-#if defined(SYS_shmat)
   return reinterpret_cast<void*>(syscall(SYS_shmat, id, address, flags));
-#else
-  // See the kernel's ipc/syscall.c for the other side of this dance.
-  void* result = nullptr;
-  if (syscall(SYS_ipc, SHMAT, id, flags, &result, address, 0) == -1) {
-    return reinterpret_cast<void*>(-1);
-  }
-  return result;
-#endif
 }
 
 int shmctl(int id, int cmd, struct shmid_ds* buf) {
@@ -49,25 +40,13 @@
   // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit.
   cmd |= IPC_64;
 #endif
-#if defined(SYS_shmctl)
   return syscall(SYS_shmctl, id, cmd, buf);
-#else
-  return syscall(SYS_ipc, SHMCTL, id, cmd, 0, buf, 0);
-#endif
 }
 
 int shmdt(const void* address) {
-#if defined(SYS_shmdt)
   return syscall(SYS_shmdt, address);
-#else
-  return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0);
-#endif
 }
 
 int shmget(key_t key, size_t size, int flags) {
-#if defined(SYS_shmget)
   return syscall(SYS_shmget, key, size, flags);
-#else
-  return syscall(SYS_ipc, SHMGET, key, size, flags, 0, 0);
-#endif
 }
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index 082dada..b37f17b 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -34,6 +34,7 @@
 #include <string.h>
 #include <wchar.h>
 
+#include "bionic/macros.h"
 #include "private/icu.h"
 
 enum {
@@ -95,21 +96,12 @@
 int iswxdigit_l(wint_t c, locale_t) { return iswxdigit(c); }
 
 int iswctype(wint_t wc, wctype_t char_class) {
-  switch (char_class) {
-    case WC_TYPE_ALNUM: return iswalnum(wc);
-    case WC_TYPE_ALPHA: return iswalpha(wc);
-    case WC_TYPE_BLANK: return iswblank(wc);
-    case WC_TYPE_CNTRL: return iswcntrl(wc);
-    case WC_TYPE_DIGIT: return iswdigit(wc);
-    case WC_TYPE_GRAPH: return iswgraph(wc);
-    case WC_TYPE_LOWER: return iswlower(wc);
-    case WC_TYPE_PRINT: return iswprint(wc);
-    case WC_TYPE_PUNCT: return iswpunct(wc);
-    case WC_TYPE_SPACE: return iswspace(wc);
-    case WC_TYPE_UPPER: return iswupper(wc);
-    case WC_TYPE_XDIGIT: return iswxdigit(wc);
-    default: return 0;
-  }
+  if (char_class < WC_TYPE_ALNUM || char_class > WC_TYPE_XDIGIT) return 0;
+  static int (*fns[])(wint_t) = {
+    iswalnum, iswalpha, iswblank, iswcntrl, iswdigit, iswgraph,
+    iswlower, iswprint, iswpunct, iswspace, iswupper, iswxdigit
+  };
+  return fns[char_class - WC_TYPE_ALNUM](wc);
 }
 
 int iswctype_l(wint_t wc, wctype_t char_class, locale_t) {
@@ -117,10 +109,7 @@
 }
 
 wint_t towlower(wint_t wc) {
-  if (wc < 0x80) {
-    if (wc >= 'A' && wc <= 'Z') return wc | 0x20;
-    return wc;
-  }
+  if (wc < 0x80) return tolower(wc);
 
   typedef UChar32 (*FnT)(UChar32);
   static auto u_tolower = reinterpret_cast<FnT>(__find_icu_symbol("u_tolower"));
@@ -128,12 +117,7 @@
 }
 
 wint_t towupper(wint_t wc) {
-  if (wc < 0x80) {
-    // Using EOR rather than AND makes no difference on arm, but saves an
-    // instruction on arm64.
-    if (wc >= 'a' && wc <= 'z') return wc ^ 0x20;
-    return wc;
-  }
+  if (wc < 0x80) return toupper(wc);
 
   typedef UChar32 (*FnT)(UChar32);
   static auto u_toupper = reinterpret_cast<FnT>(__find_icu_symbol("u_toupper"));
@@ -144,14 +128,13 @@
 wint_t towlower_l(wint_t c, locale_t) { return towlower(c); }
 
 wctype_t wctype(const char* property) {
-  static const char* const  properties[WC_TYPE_MAX] = {
-    "<invalid>",
+  static const char* const  properties[WC_TYPE_MAX - 1] = {
     "alnum", "alpha", "blank", "cntrl", "digit", "graph",
     "lower", "print", "punct", "space", "upper", "xdigit"
   };
-  for (size_t i = 0; i < WC_TYPE_MAX; ++i) {
+  for (size_t i = 0; i < arraysize(properties); ++i) {
     if (!strcmp(properties[i], property)) {
-      return static_cast<wctype_t>(i);
+      return static_cast<wctype_t>(WC_TYPE_ALNUM + i);
     }
   }
   return static_cast<wctype_t>(0);
@@ -167,6 +150,7 @@
 wctrans_t wctrans(const char* name) {
   if (strcmp(name, "tolower") == 0) return wctrans_tolower;
   if (strcmp(name, "toupper") == 0) return wctrans_toupper;
+  errno = EINVAL;
   return nullptr;
 }
 
@@ -178,7 +162,7 @@
   if (t == wctrans_tolower) return towlower(c);
   if (t == wctrans_toupper) return towupper(c);
   errno = EINVAL;
-  return 0;
+  return c;
 }
 
 wint_t towctrans_l(wint_t c, wctrans_t t, locale_t) {
diff --git a/libc/dns/include/resolv_private.h b/libc/dns/include/resolv_private.h
index 3054555..1593aca 100644
--- a/libc/dns/include/resolv_private.h
+++ b/libc/dns/include/resolv_private.h
@@ -504,15 +504,7 @@
 // ...but NetBSD calls it res_randomid.
 #define res_randomid __res_randomid
 
-#ifdef __i386__
-# define __socketcall extern __attribute__((__cdecl__))
-#else
-# define __socketcall extern
-#endif
-
-__socketcall int __connect(int, const struct sockaddr*, socklen_t);
-
-#undef __socketcall
+int __connect(int, const struct sockaddr*, socklen_t);
 
 // Symbols that are supposed to be in resolv.h, but that we aren't exporting.
 int ns_parserr2(ns_msg*, ns_sect, int, ns_rr2*);
diff --git a/libc/include/ctype.h b/libc/include/ctype.h
index c15ee56..cb926a4 100644
--- a/libc/include/ctype.h
+++ b/libc/include/ctype.h
@@ -73,9 +73,35 @@
 /** Internal implementation detail. Do not use. */
 extern const char* _ctype_;
 
+/**
+ * Returns the corresponding lower-case character if `ch` is upper-case, or undefined otherwise.
+ *
+ * Prefer tolower() instead.
+ */
+__BIONIC_CTYPE_INLINE int _tolower(int __ch) {
+  return __ch | 0x20;
+}
+
+/**
+ * Returns the corresponding upper-case character if `ch` is lower-case, or undefined otherwise.
+ *
+ * Prefer toupper() instead.
+ */
+__BIONIC_CTYPE_INLINE int _toupper(int __ch) {
+  // Using EOR rather than AND makes no difference on arm, but saves an
+  // instruction on arm64.
+  return __ch ^ 0x20;
+}
+
+/** Internal implementation detail. Do not use. */
+__attribute__((__no_sanitize__("unsigned-integer-overflow")))
+static inline int __bionic_ctype_in_range(unsigned __lo, int __ch, unsigned __hi) {
+  return (__BIONIC_CAST(static_cast, unsigned, __ch) - __lo) < (__hi - __lo + 1);
+}
+
 /** Returns true if `ch` is in `[A-Za-z]`. */
 __BIONIC_CTYPE_INLINE int isalpha(int __ch) {
-  return (__ch >= 'A' && __ch <= 'Z') || (__ch >= 'a' && __ch <= 'z');
+  return __bionic_ctype_in_range('a', _tolower(__ch), 'z');
 }
 
 /** Returns true if `ch` is a space or tab. */
@@ -90,37 +116,37 @@
 
 /** Returns true if `ch` is in `[0-9]`. */
 __BIONIC_CTYPE_INLINE int isdigit(int __ch) {
-  return (__ch >= '0' && __ch <= '9');
+  return __bionic_ctype_in_range('0', __ch, '9');
 }
 
 /** Returns true if `ch` is `[A-Za-z0-9]` or punctuation. */
 __BIONIC_CTYPE_INLINE int isgraph(int __ch) {
-  return (__ch >= '!' && __ch <= '~');
+  return __bionic_ctype_in_range('!', __ch, '~');
 }
 
 /** Returns true if `ch` is in `[a-z]`. */
 __BIONIC_CTYPE_INLINE int islower(int __ch) {
-  return (__ch >= 'a' && __ch <= 'z');
+  return __bionic_ctype_in_range('a', __ch, 'z');
 }
 
 /** Returns true if `ch` is `[A-Za-z0-9]` or punctuation or space. */
 __BIONIC_CTYPE_INLINE int isprint(int __ch) {
-  return (__ch >= ' ' && __ch <= '~');
+  return __bionic_ctype_in_range(' ', __ch, '~');
 }
 
 /** Returns true if `ch` is in `[ \f\n\r\t\v]`. */
 __BIONIC_CTYPE_INLINE int isspace(int __ch) {
-  return __ch == ' ' || (__ch >= '\t' && __ch <= '\r');
+  return __ch == ' ' || __bionic_ctype_in_range('\t', __ch, '\r');
 }
 
 /** Returns true if `ch` is in `[A-Z]`. */
 __BIONIC_CTYPE_INLINE int isupper(int __ch) {
-  return (__ch >= 'A' && __ch <= 'Z');
+  return __bionic_ctype_in_range('A', __ch, 'Z');
 }
 
 /** Returns true if `ch` is in `[0-9A-Fa-f]`. */
 __BIONIC_CTYPE_INLINE int isxdigit(int __ch) {
-  return (__ch >= '0' && __ch <= '9') || (__ch >= 'a' && __ch <= 'f') || (__ch >= 'A' && __ch <= 'F');
+  return isdigit(__ch) || __bionic_ctype_in_range('a', _tolower(__ch), 'f') ;
 }
 
 /** Returns true if `ch` is in `[A-Za-z0-9]`. */
@@ -133,36 +159,14 @@
   return isgraph(__ch) && !isalnum(__ch);
 }
 
-/**
- * Returns the corresponding lower-case character if `ch` is upper-case, or undefined otherwise.
- *
- * Prefer tolower() instead.
- */
-__BIONIC_CTYPE_INLINE int _tolower(int __ch) {
-  return __ch | 0x20;
-}
-
 /** Returns the corresponding lower-case character if `ch` is upper-case, or `ch` otherwise. */
 __BIONIC_CTYPE_INLINE int tolower(int __ch) {
-  if (__ch >= 'A' && __ch <= 'Z') return _tolower(__ch);
-  return __ch;
-}
-
-/**
- * Returns the corresponding upper-case character if `ch` is lower-case, or undefined otherwise.
- *
- * Prefer toupper() instead.
- */
-__BIONIC_CTYPE_INLINE int _toupper(int __ch) {
-  // Using EOR rather than AND makes no difference on arm, but saves an
-  // instruction on arm64.
-  return __ch ^ 0x20;
+  return (__bionic_ctype_in_range('A', __ch, 'Z')) ? _tolower(__ch) : __ch;
 }
 
 /** Returns the corresponding upper-case character if `ch` is lower-case, or `ch` otherwise. */
 __BIONIC_CTYPE_INLINE int toupper(int __ch) {
-  if (__ch >= 'a' && __ch <= 'z') return _toupper(__ch);
-  return __ch;
+  return (__bionic_ctype_in_range('a', __ch, 'z')) ? _toupper(__ch) : __ch;
 }
 
 /** Returns true if `ch` is less than 0x80. */
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index a90c4f8..d65a409 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -146,7 +146,11 @@
  */
 #define RTLD_LOCAL    0
 
-/** Not supported on Android; Android always uses RTLD_NOW. */
+/**
+ * Not supported on Android. Android always uses RTLD_NOW for security reasons.
+ * Resolving all undefined symbols before dlopen() returns means that RELRO
+ * protections can be applied to the PLT before dlopen() returns.
+ */
 #define RTLD_LAZY     0x00001
 
 /** A dlopen() flag to resolve all undefined symbols before dlopen() returns. */
diff --git a/libc/include/fts.h b/libc/include/fts.h
index 8dfd213..aabe2db 100644
--- a/libc/include/fts.h
+++ b/libc/include/fts.h
@@ -119,7 +119,7 @@
 
 FTSENT* _Nullable fts_children(FTS* _Nonnull __fts, int __options);
 int fts_close(FTS* _Nonnull __fts);
-FTS* _Nullable fts_open(char* _Nonnull const* _Nonnull __path, int __options, int (* _Nullable __comparator)(const FTSENT* _Nonnull * _Nonnull  __lhs, const FTSENT* _Nonnull * _Nonnull __rhs));
+FTS* _Nullable fts_open(char* _Nullable const* _Nonnull __path, int __options, int (* _Nullable __comparator)(const FTSENT* _Nonnull * _Nonnull  __lhs, const FTSENT* _Nonnull * _Nonnull __rhs));
 FTSENT* _Nullable fts_read(FTS* _Nonnull __fts);
 int fts_set(FTS* _Nonnull __fts, FTSENT* _Nonnull __entry, int __options);
 
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 9402e70..47ddce0 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -277,41 +277,33 @@
 
 #define IPX_TYPE 1
 
-#ifdef __i386__
-# define __socketcall extern __attribute__((__cdecl__))
-#else
-# define __socketcall extern
-#endif
-
-__socketcall int accept(int __fd, struct sockaddr* _Nullable __addr, socklen_t* _Nullable __addr_length);
-__socketcall int accept4(int __fd, struct sockaddr* _Nullable __addr, socklen_t* _Nullable __addr_length, int __flags);
-__socketcall int bind(int __fd, const struct sockaddr* _Nonnull __addr, socklen_t __addr_length);
-__socketcall int connect(int __fd, const struct sockaddr* _Nonnull __addr, socklen_t __addr_length);
-__socketcall int getpeername(int __fd, struct sockaddr* _Nonnull __addr, socklen_t* _Nonnull __addr_length);
-__socketcall int getsockname(int __fd, struct sockaddr* _Nonnull __addr, socklen_t* _Nonnull __addr_length);
-__socketcall int getsockopt(int __fd, int __level, int __option, void* _Nullable __value, socklen_t* _Nonnull __value_length);
-__socketcall int listen(int __fd, int __backlog);
-__socketcall int recvmmsg(int __fd, struct mmsghdr* _Nonnull __msgs, unsigned int __msg_count, int __flags, const struct timespec* _Nullable __timeout);
-__socketcall ssize_t recvmsg(int __fd, struct msghdr* _Nonnull __msg, int __flags);
-__socketcall int sendmmsg(int __fd, const struct mmsghdr* _Nonnull __msgs, unsigned int __msg_count, int __flags);
-__socketcall ssize_t sendmsg(int __fd, const struct msghdr* _Nonnull __msg, int __flags);
-__socketcall int setsockopt(int __fd, int __level, int __option, const void* _Nullable __value, socklen_t __value_length);
-__socketcall int shutdown(int __fd, int __how);
-__socketcall int socket(int __af, int __type, int __protocol);
-__socketcall int socketpair(int __af, int __type, int __protocol, int __fds[_Nonnull 2]);
+int accept(int __fd, struct sockaddr* _Nullable __addr, socklen_t* _Nullable __addr_length);
+int accept4(int __fd, struct sockaddr* _Nullable __addr, socklen_t* _Nullable __addr_length, int __flags);
+int bind(int __fd, const struct sockaddr* _Nonnull __addr, socklen_t __addr_length);
+int connect(int __fd, const struct sockaddr* _Nonnull __addr, socklen_t __addr_length);
+int getpeername(int __fd, struct sockaddr* _Nonnull __addr, socklen_t* _Nonnull __addr_length);
+int getsockname(int __fd, struct sockaddr* _Nonnull __addr, socklen_t* _Nonnull __addr_length);
+int getsockopt(int __fd, int __level, int __option, void* _Nullable __value, socklen_t* _Nonnull __value_length);
+int listen(int __fd, int __backlog);
+int recvmmsg(int __fd, struct mmsghdr* _Nonnull __msgs, unsigned int __msg_count, int __flags, const struct timespec* _Nullable __timeout);
+ssize_t recvmsg(int __fd, struct msghdr* _Nonnull __msg, int __flags);
+int sendmmsg(int __fd, const struct mmsghdr* _Nonnull __msgs, unsigned int __msg_count, int __flags);
+ssize_t sendmsg(int __fd, const struct msghdr* _Nonnull __msg, int __flags);
+int setsockopt(int __fd, int __level, int __option, const void* _Nullable __value, socklen_t __value_length);
+int shutdown(int __fd, int __how);
+int socket(int __af, int __type, int __protocol);
+int socketpair(int __af, int __type, int __protocol, int __fds[_Nonnull 2]);
 
 ssize_t recv(int __fd, void* _Nullable __buf, size_t __n, int __flags);
 ssize_t send(int __fd, const void* _Nonnull __buf, size_t __n, int __flags);
 
-__socketcall ssize_t sendto(int __fd, const void* _Nonnull __buf, size_t __n, int __flags, const struct sockaddr* _Nullable __dst_addr, socklen_t __dst_addr_length);
-__socketcall ssize_t recvfrom(int __fd, void* _Nullable __buf, size_t __n, int __flags, struct sockaddr* _Nullable __src_addr, socklen_t* _Nullable __src_addr_length);
+ssize_t sendto(int __fd, const void* _Nonnull __buf, size_t __n, int __flags, const struct sockaddr* _Nullable __dst_addr, socklen_t __dst_addr_length);
+ssize_t recvfrom(int __fd, void* _Nullable __buf, size_t __n, int __flags, struct sockaddr* _Nullable __src_addr, socklen_t* _Nullable __src_addr_length);
 
 #if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
 #include <bits/fortify/socket.h>
 #endif
 
-#undef __socketcall
-
 __END_DECLS
 
 #endif
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 0d442b4..6be899d 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -212,6 +212,10 @@
         "log_allocator_stats_on_signal",
         {LOG_ALLOCATOR_STATS_ON_SIGNAL, &Config::VerifyValueEmpty},
     },
+    {
+        "log_allocator_stats_on_exit",
+        {LOG_ALLOCATOR_STATS_ON_EXIT, &Config::VerifyValueEmpty},
+    },
 };
 
 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 8551712..4840d43 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -49,6 +49,7 @@
 constexpr uint64_t CHECK_UNREACHABLE_ON_SIGNAL = 0x2000;
 constexpr uint64_t BACKTRACE_SPECIFIC_SIZES = 0x4000;
 constexpr uint64_t LOG_ALLOCATOR_STATS_ON_SIGNAL = 0x8000;
+constexpr uint64_t LOG_ALLOCATOR_STATS_ON_EXIT = 0x10000;
 
 // In order to guarantee posix compliance, set the minimum alignment
 // to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
diff --git a/libc/malloc_debug/LogAllocatorStats.cpp b/libc/malloc_debug/LogAllocatorStats.cpp
index 6d1434e..ee6bfdf 100644
--- a/libc/malloc_debug/LogAllocatorStats.cpp
+++ b/libc/malloc_debug/LogAllocatorStats.cpp
@@ -43,13 +43,17 @@
   g_call_mallopt = true;
 }
 
+void Log() {
+  info_log("Logging allocator stats...");
+  if (mallopt(M_LOG_STATS, 0) == 0) {
+    error_log("mallopt(M_LOG_STATS, 0) call failed.");
+  }
+}
+
 void CheckIfShouldLog() {
   bool expected = true;
   if (g_call_mallopt.compare_exchange_strong(expected, false)) {
-    info_log("Logging allocator stats...");
-    if (mallopt(M_LOG_STATS, 0) == 0) {
-      error_log("mallopt(M_LOG_STATS, 0) call failed.");
-    }
+    Log();
   }
 }
 
diff --git a/libc/malloc_debug/LogAllocatorStats.h b/libc/malloc_debug/LogAllocatorStats.h
index 99e0738..ded4f94 100644
--- a/libc/malloc_debug/LogAllocatorStats.h
+++ b/libc/malloc_debug/LogAllocatorStats.h
@@ -35,6 +35,8 @@
 
 bool Initialize(const Config& config);
 
+void Log();
+
 void CheckIfShouldLog();
 
 }  // namespace LogAllocatorStats
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 6d88092..3743852 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -461,6 +461,10 @@
                                                 getpid()).c_str());
   }
 
+  if (g_debug->config().options() & LOG_ALLOCATOR_STATS_ON_EXIT) {
+    LogAllocatorStats::Log();
+  }
+
   backtrace_shutdown();
 
   // In order to prevent any issues of threads freeing previous pointers
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index c79d052..d33f9cd 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -861,6 +861,24 @@
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugConfigTest, log_allocator_stats_on_exit) {
+  ASSERT_TRUE(InitConfig("log_allocator_stats_on_exit")) << getFakeLogPrint();
+  ASSERT_EQ(LOG_ALLOCATOR_STATS_ON_EXIT, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_log_allocator_stats_on_exit_fail) {
+  ASSERT_FALSE(InitConfig("log_allocator_stats_on_exit=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'log_allocator_stats_on_exit' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugConfigTest, size) {
   ASSERT_TRUE(InitConfig("backtrace_size=37")) << getFakeLogPrint();
   ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index aee2572..d7a7a4f 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -77,7 +77,7 @@
       // This avoids accidentally grabbing data from a previous process with
       // the same pid.
       log_start_time_ = {};
-      logger_list* list = android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, 1000, 0);
+      logger_list* list = android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, INT_MAX, 0);
       if (list == nullptr) {
         return;
       }
@@ -111,7 +111,7 @@
       while (true) {
         // Do not use non-blocking mode so that the two threads
         // are essentially asleep and not consuming any cpu.
-        list = android_logger_list_open(log, 0, 1000, pid);
+        list = android_logger_list_open(log, 0, INT_MAX, pid);
         if (list != nullptr) {
           break;
         }
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index ef8d235..c808dc0 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -426,7 +426,7 @@
   Init(
       "guard backtrace backtrace_enable_on_signal fill expand_alloc free_track leak_track "
       "record_allocs verify_pointers abort_on_error verbose check_unreachable_on_signal "
-      "log_allocator_stats_on_signal");
+      "log_allocator_stats_on_signal log_allocator_stats_on_exit");
   VerifyAllocCalls(true);
 }
 
@@ -2844,6 +2844,25 @@
   }
 }
 
+TEST_F(MallocDebugTest, log_allocator_stats_on_exit) {
+  Init("log_allocator_stats_on_exit");
+
+  void* pointer = debug_malloc(110);
+  ASSERT_TRUE(pointer != nullptr);
+  debug_free(pointer);
+
+  debug_finalize();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  if (!running_with_hwasan()) {
+    // Do an exact match because the mallopt should not fail in normal operation.
+    ASSERT_STREQ("4 malloc_debug Logging allocator stats...\n", getFakeLogPrint().c_str());
+  } else {
+    // mallopt fails with hwasan, so just verify that the message is present.
+    ASSERT_MATCH(getFakeLogPrint(), "4 malloc_debug Logging allocator stats...\\n");
+  }
+}
+
 TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_size) {
   Init("leak_track backtrace backtrace_size=120");
 
diff --git a/libc/platform/bionic/mte.h b/libc/platform/bionic/mte.h
index 73cd821..98b3d27 100644
--- a/libc/platform/bionic/mte.h
+++ b/libc/platform/bionic/mte.h
@@ -29,8 +29,11 @@
 #pragma once
 
 #include <sys/auxv.h>
+#include <sys/mman.h>
 #include <sys/prctl.h>
 
+#include "page.h"
+
 // Note: Most PR_MTE_* constants come from the upstream kernel. This tag mask
 // allows for the hardware to provision any nonzero tag. Zero tags are reserved
 // for scudo to use for the chunk headers in order to prevent linear heap
@@ -63,6 +66,65 @@
     }
   }
 };
+
+// N.B. that this is NOT the pagesize, but 4096. This is hardcoded in the codegen.
+// See
+// https://github.com/search?q=repo%3Allvm/llvm-project%20AArch64StackTagging%3A%3AinsertBaseTaggedPointer&type=code
+constexpr size_t kStackMteRingbufferSizeMultiplier = 4096;
+
+inline size_t stack_mte_ringbuffer_size(uintptr_t size_cls) {
+  return kStackMteRingbufferSizeMultiplier * (1 << size_cls);
+}
+
+inline size_t stack_mte_ringbuffer_size_from_pointer(uintptr_t ptr) {
+  // The size in the top byte is not the size_cls, but the number of "pages" (not OS pages, but
+  // kStackMteRingbufferSizeMultiplier).
+  return kStackMteRingbufferSizeMultiplier * (ptr >> 56ULL);
+}
+
+inline uintptr_t stack_mte_ringbuffer_size_add_to_pointer(uintptr_t ptr, uintptr_t size_cls) {
+  return ptr | ((1ULL << size_cls) << 56ULL);
+}
+
+inline void* stack_mte_ringbuffer_allocate(size_t n, const char* name) {
+  if (n > 7) return nullptr;
+  // Allocation needs to be aligned to 2*size to make the fancy code-gen work.
+  // So we allocate 3*size - pagesz bytes, which will always contain size bytes
+  // aligned to 2*size, and unmap the unneeded part.
+  // See
+  // https://github.com/search?q=repo%3Allvm/llvm-project%20AArch64StackTagging%3A%3AinsertBaseTaggedPointer&type=code
+  //
+  // In the worst case, we get an allocation that is one page past the properly
+  // aligned address, in which case we have to unmap the previous
+  // 2*size - pagesz bytes. In that case, we still have size properly aligned
+  // bytes left.
+  size_t size = stack_mte_ringbuffer_size(n);
+  size_t pgsize = page_size();
+
+  size_t alloc_size = __BIONIC_ALIGN(3 * size - pgsize, pgsize);
+  void* allocation_ptr =
+      mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (allocation_ptr == MAP_FAILED)
+    return nullptr;
+  uintptr_t allocation = reinterpret_cast<uintptr_t>(allocation_ptr);
+
+  size_t alignment = 2 * size;
+  uintptr_t aligned_allocation = __BIONIC_ALIGN(allocation, alignment);
+  if (allocation != aligned_allocation) {
+    munmap(reinterpret_cast<void*>(allocation), aligned_allocation - allocation);
+  }
+  if (aligned_allocation + size != allocation + alloc_size) {
+    munmap(reinterpret_cast<void*>(aligned_allocation + size),
+           (allocation + alloc_size) - (aligned_allocation + size));
+  }
+
+  if (name) {
+    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<void*>(aligned_allocation), size, name);
+  }
+
+  // We store the size in the top byte of the pointer (which is ignored)
+  return reinterpret_cast<void*>(stack_mte_ringbuffer_size_add_to_pointer(aligned_allocation, n));
+}
 #else
 struct ScopedDisableMTE {
   // Silence unused variable warnings in non-aarch64 builds.
diff --git a/libc/platform/bionic/tls_defines.h b/libc/platform/bionic/tls_defines.h
index 8fe8701..06c6617 100644
--- a/libc/platform/bionic/tls_defines.h
+++ b/libc/platform/bionic/tls_defines.h
@@ -85,7 +85,8 @@
 // [1] "Addenda to, and Errata in, the ABI for the ARM Architecture". Section 3.
 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf
 
-#define MIN_TLS_SLOT (-2)  // update this value when reserving a slot
+#define MIN_TLS_SLOT (-3)  // update this value when reserving a slot
+#define TLS_SLOT_STACK_MTE (-3)
 #define TLS_SLOT_NATIVE_BRIDGE_GUEST_STATE (-2)
 #define TLS_SLOT_BIONIC_TLS     (-1)
 #define TLS_SLOT_DTV              0
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 0949056..a1bebda 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -76,10 +76,23 @@
 };
 
 __LIBC_HIDDEN__ extern WriteProtected<libc_globals> __libc_globals;
-// This cannot be in __libc_globals, because we cannot access the
+// These cannot be in __libc_globals, because we cannot access the
 // WriteProtected in a thread-safe way.
 // See b/328256432.
+//
+// __libc_memtag_stack says whether stack MTE is enabled on the process, i.e.
+// whether the stack pages are mapped with PROT_MTE. This is always false if
+// MTE is disabled for the process (i.e. libc_globals.memtag is false).
 __LIBC_HIDDEN__ extern _Atomic(bool) __libc_memtag_stack;
+// __libc_memtag_stack_abi says whether the process contains any code that was
+// compiled with memtag-stack. This is true even if the process does not have
+// MTE enabled (e.g. because it was overridden using MEMTAG_OPTIONS, or because
+// MTE is disabled for the device).
+// Code compiled with memtag-stack needs a stack history buffer in
+// TLS_SLOT_STACK_MTE, because the codegen will emit an unconditional
+// (to keep the code branchless) write to it.
+// Protected by g_heap_creation_lock.
+__LIBC_HIDDEN__ extern bool __libc_memtag_stack_abi;
 
 struct abort_msg_t;
 struct crash_detail_page_t;
@@ -133,7 +146,9 @@
   size_t scudo_stack_depot_size = 0;
 
   HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
+  // See comments for __libc_memtag_stack / __libc_memtag_stack_abi above.
   bool initial_memtag_stack = false;
+  bool initial_memtag_stack_abi = false;
   int64_t heap_tagging_upgrade_timer_sec = 0;
 
   void (*memtag_stack_dlopen_callback)() = nullptr;
diff --git a/libc/system_properties/prop_area.cpp b/libc/system_properties/prop_area.cpp
index a816a38..9b153ca 100644
--- a/libc/system_properties/prop_area.cpp
+++ b/libc/system_properties/prop_area.cpp
@@ -339,8 +339,7 @@
 
   uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
   if (left_offset != 0) {
-    const int err = foreach_property(to_prop_trie_node(&trie->left), propfn, cookie);
-    if (err < 0) return false;
+    if (!foreach_property(to_prop_trie_node(&trie->left), propfn, cookie)) return false;
   }
   uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
   if (prop_offset != 0) {
@@ -350,13 +349,11 @@
   }
   uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
   if (children_offset != 0) {
-    const int err = foreach_property(to_prop_trie_node(&trie->children), propfn, cookie);
-    if (err < 0) return false;
+    if (!foreach_property(to_prop_trie_node(&trie->children), propfn, cookie)) return false;
   }
   uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
   if (right_offset != 0) {
-    const int err = foreach_property(to_prop_trie_node(&trie->right), propfn, cookie);
-    if (err < 0) return false;
+    if (!foreach_property(to_prop_trie_node(&trie->right), propfn, cookie)) return false;
   }
 
   return true;
@@ -371,6 +368,6 @@
   return find_property(root_node(), name, namelen, value, valuelen, true);
 }
 
-bool prop_area::foreach (void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
+bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
   return foreach_property(root_node(), propfn, cookie);
 }
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 8c457c8..d7afe2a 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -27,7 +27,7 @@
 # ARM assembler templates for each syscall stub
 #
 
-arm_eabi_call_default = syscall_stub_header + """\
+arm_call_default = syscall_stub_header + """\
     mov     ip, r7
     .cfi_register r7, ip
     ldr     r7, =%(__NR_name)s
@@ -41,7 +41,7 @@
 END(%(func)s)
 """
 
-arm_eabi_call_long = syscall_stub_header + """\
+arm_call_long = syscall_stub_header + """\
     mov     ip, sp
     stmfd   sp!, {r4, r5, r6, r7}
     .cfi_def_cfa_offset 16
@@ -230,11 +230,11 @@
     return stub
 
 
-def arm_eabi_genstub(syscall):
+def arm_genstub(syscall):
     num_regs = count_arm_param_registers(syscall["params"])
     if num_regs > 4:
-        return arm_eabi_call_long % syscall
-    return arm_eabi_call_default % syscall
+        return arm_call_long % syscall
+    return arm_call_default % syscall
 
 
 def arm64_genstub(syscall):
@@ -456,7 +456,7 @@
         syscall["__NR_name"] = make__NR_name(syscall["name"])
 
         if "arm" in syscall:
-            syscall["asm-arm"] = add_footer(32, arm_eabi_genstub(syscall), syscall)
+            syscall["asm-arm"] = add_footer(32, arm_genstub(syscall), syscall)
 
         if "arm64" in syscall:
             syscall["asm-arm64"] = add_footer(64, arm64_genstub(syscall), syscall)
diff --git a/libm/NOTICE b/libm/NOTICE
index 424725e..3c0e783 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -140,15 +140,6 @@
 -------------------------------------------------------------------
 
 ====================================================
-Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
-
-Permission to use, copy, modify, and distribute this
-software is freely granted, provided that this notice
-is preserved.
-
--------------------------------------------------------------------
-
-====================================================
 Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
 
 Permission to use, copy, modify, and distribute this
@@ -423,32 +414,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2007 David Schultz
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
 Copyright (c) 2007 The NetBSD Foundation, Inc.
 All rights reserved.
 
@@ -1273,33 +1238,3 @@
 
 -------------------------------------------------------------------
 
-SPDX-License-Identifier: BSD-3-Clause
-
-Copyright (c) 2003 Dag-Erling Smørgrav
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer
-   in this position and unchanged.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
diff --git a/libm/upstream-freebsd/lib/msun/src/e_exp.c b/libm/upstream-freebsd/lib/msun/src/e_exp.c
deleted file mode 100644
index 59da392..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_exp.c
+++ /dev/null
@@ -1,164 +0,0 @@
-
-/* @(#)e_exp.c 1.6 04/04/22 */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/* exp(x)
- * Returns the exponential of x.
- *
- * Method
- *   1. Argument reduction:
- *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
- *	Given x, find r and integer k such that
- *
- *               x = k*ln2 + r,  |r| <= 0.5*ln2.  
- *
- *      Here r will be represented as r = hi-lo for better 
- *	accuracy.
- *
- *   2. Approximation of exp(r) by a special rational function on
- *	the interval [0,0.34658]:
- *	Write
- *	    R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
- *      We use a special Remes algorithm on [0,0.34658] to generate 
- * 	a polynomial of degree 5 to approximate R. The maximum error 
- *	of this polynomial approximation is bounded by 2**-59. In
- *	other words,
- *	    R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
- *  	(where z=r*r, and the values of P1 to P5 are listed below)
- *	and
- *	    |                  5          |     -59
- *	    | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 
- *	    |                             |
- *	The computation of exp(r) thus becomes
- *                             2*r
- *		exp(r) = 1 + -------
- *		              R - r
- *                                 r*R1(r)	
- *		       = 1 + r + ----------- (for better accuracy)
- *		                  2 - R1(r)
- *	where
- *			         2       4             10
- *		R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
- *	
- *   3. Scale back to obtain exp(x):
- *	From step 1, we have
- *	   exp(x) = 2^k * exp(r)
- *
- * Special cases:
- *	exp(INF) is INF, exp(NaN) is NaN;
- *	exp(-INF) is 0, and
- *	for finite argument, only exp(0)=1 is exact.
- *
- * Accuracy:
- *	according to an error analysis, the error is always less than
- *	1 ulp (unit in the last place).
- *
- * Misc. info.
- *	For IEEE double 
- *	    if x >  7.09782712893383973096e+02 then exp(x) overflow
- *	    if x < -7.45133219101941108420e+02 then exp(x) underflow
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following 
- * constants. The decimal values may be used, provided that the 
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-
-static const double
-one	= 1.0,
-halF[2]	= {0.5,-0.5,},
-o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */
-u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */
-ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */
-	     -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
-ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */
-	     -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
-invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
-P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
-
-static volatile double
-huge	= 1.0e+300,
-twom1000= 9.33263618503218878990e-302;     /* 2**-1000=0x01700000,0*/
-
-double
-exp(double x)	/* default IEEE double exp */
-{
-	double y,hi=0.0,lo=0.0,c,t,twopk;
-	int32_t k=0,xsb;
-	u_int32_t hx;
-
-	GET_HIGH_WORD(hx,x);
-	xsb = (hx>>31)&1;		/* sign bit of x */
-	hx &= 0x7fffffff;		/* high word of |x| */
-
-    /* filter out non-finite argument */
-	if(hx >= 0x40862E42) {			/* if |x|>=709.78... */
-            if(hx>=0x7ff00000) {
-	        u_int32_t lx;
-		GET_LOW_WORD(lx,x);
-		if(((hx&0xfffff)|lx)!=0)
-		     return x+x; 		/* NaN */
-		else return (xsb==0)? x:0.0;	/* exp(+-inf)={inf,0} */
-	    }
-	    if(x > o_threshold) return huge*huge; /* overflow */
-	    if(x < u_threshold) return twom1000*twom1000; /* underflow */
-	}
-
-    /* argument reduction */
-	if(hx > 0x3fd62e42) {		/* if  |x| > 0.5 ln2 */ 
-	    if(hx < 0x3FF0A2B2) {	/* and |x| < 1.5 ln2 */
-		hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
-	    } else {
-		k  = (int)(invln2*x+halF[xsb]);
-		t  = k;
-		hi = x - t*ln2HI[0];	/* t*ln2HI is exact here */
-		lo = t*ln2LO[0];
-	    }
-	    STRICT_ASSIGN(double, x, hi - lo);
-	} 
-	else if(hx < 0x3e300000)  {	/* when |x|<2**-28 */
-	    if(huge+x>one) return one+x;/* trigger inexact */
-	}
-	else k = 0;
-
-    /* x is now in primary range */
-	t  = x*x;
-	if(k >= -1021)
-	    INSERT_WORDS(twopk,((u_int32_t)(0x3ff+k))<<20, 0);
-	else
-	    INSERT_WORDS(twopk,((u_int32_t)(0x3ff+(k+1000)))<<20, 0);
-	c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
-	if(k==0) 	return one-((x*c)/(c-2.0)-x); 
-	else 		y = one-((lo-(x*c)/(2.0-c))-hi);
-	if(k >= -1021) {
-	    if (k==1024) return y*2.0*0x1p1023;
-	    return y*twopk;
-	} else {
-	    return y*twopk*twom1000;
-	}
-}
-
-#if (LDBL_MANT_DIG == 53)
-__weak_reference(exp, expl);
-#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/e_expf.c b/libm/upstream-freebsd/lib/msun/src/e_expf.c
deleted file mode 100644
index 620d341..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_expf.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* e_expf.c -- float version of e_exp.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-
-static const float
-one	= 1.0,
-halF[2]	= {0.5,-0.5,},
-o_threshold=  8.8721679688e+01,  /* 0x42b17180 */
-u_threshold= -1.0397208405e+02,  /* 0xc2cff1b5 */
-ln2HI[2]   ={ 6.9314575195e-01,		/* 0x3f317200 */
-	     -6.9314575195e-01,},	/* 0xbf317200 */
-ln2LO[2]   ={ 1.4286067653e-06,  	/* 0x35bfbe8e */
-	     -1.4286067653e-06,},	/* 0xb5bfbe8e */
-invln2 =  1.4426950216e+00, 		/* 0x3fb8aa3b */
-/*
- * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
- * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
- */
-P1 =  1.6666625440e-1,		/*  0xaaaa8f.0p-26 */
-P2 = -2.7667332906e-3;		/* -0xb55215.0p-32 */
-
-static volatile float
-huge	= 1.0e+30,
-twom100 = 7.8886090522e-31;      /* 2**-100=0x0d800000 */
-
-float
-expf(float x)
-{
-	float y,hi=0.0,lo=0.0,c,t,twopk;
-	int32_t k=0,xsb;
-	u_int32_t hx;
-
-	GET_FLOAT_WORD(hx,x);
-	xsb = (hx>>31)&1;		/* sign bit of x */
-	hx &= 0x7fffffff;		/* high word of |x| */
-
-    /* filter out non-finite argument */
-	if(hx >= 0x42b17218) {			/* if |x|>=88.721... */
-	    if(hx>0x7f800000)
-		 return x+x;	 		/* NaN */
-            if(hx==0x7f800000)
-		return (xsb==0)? x:0.0;		/* exp(+-inf)={inf,0} */
-	    if(x > o_threshold) return huge*huge; /* overflow */
-	    if(x < u_threshold) return twom100*twom100; /* underflow */
-	}
-
-    /* argument reduction */
-	if(hx > 0x3eb17218) {		/* if  |x| > 0.5 ln2 */
-	    if(hx < 0x3F851592) {	/* and |x| < 1.5 ln2 */
-		hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
-	    } else {
-		k  = invln2*x+halF[xsb];
-		t  = k;
-		hi = x - t*ln2HI[0];	/* t*ln2HI is exact here */
-		lo = t*ln2LO[0];
-	    }
-	    STRICT_ASSIGN(float, x, hi - lo);
-	}
-	else if(hx < 0x39000000)  {	/* when |x|<2**-14 */
-	    if(huge+x>one) return one+x;/* trigger inexact */
-	}
-	else k = 0;
-
-    /* x is now in primary range */
-	t  = x*x;
-	if(k >= -125)
-	    SET_FLOAT_WORD(twopk,((u_int32_t)(0x7f+k))<<23);
-	else
-	    SET_FLOAT_WORD(twopk,((u_int32_t)(0x7f+(k+100)))<<23);
-	c  = x - t*(P1+t*P2);
-	if(k==0) 	return one-((x*c)/(c-(float)2.0)-x);
-	else 		y = one-((lo-(x*c)/((float)2.0-c))-hi);
-	if(k >= -125) {
-	    if(k==128) return y*2.0F*0x1p127F;
-	    return y*twopk;
-	} else {
-	    return y*twopk*twom100;
-	}
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log.c b/libm/upstream-freebsd/lib/msun/src/e_log.c
deleted file mode 100644
index 03ce820..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_log.c
+++ /dev/null
@@ -1,147 +0,0 @@
-
-/* @(#)e_log.c 1.3 95/01/18 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/* log(x)
- * Return the logrithm of x
- *
- * Method :                  
- *   1. Argument Reduction: find k and f such that 
- *			x = 2^k * (1+f), 
- *	   where  sqrt(2)/2 < 1+f < sqrt(2) .
- *
- *   2. Approximation of log(1+f).
- *	Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
- *		 = 2s + 2/3 s**3 + 2/5 s**5 + .....,
- *	     	 = 2s + s*R
- *      We use a special Reme algorithm on [0,0.1716] to generate 
- * 	a polynomial of degree 14 to approximate R The maximum error 
- *	of this polynomial approximation is bounded by 2**-58.45. In
- *	other words,
- *		        2      4      6      8      10      12      14
- *	    R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
- *  	(the values of Lg1 to Lg7 are listed in the program)
- *	and
- *	    |      2          14          |     -58.45
- *	    | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
- *	    |                             |
- *	Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
- *	In order to guarantee error in log below 1ulp, we compute log
- *	by
- *		log(1+f) = f - s*(f - R)	(if f is not too large)
- *		log(1+f) = f - (hfsq - s*(hfsq+R)).	(better accuracy)
- *	
- *	3. Finally,  log(x) = k*ln2 + log(1+f).  
- *			    = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
- *	   Here ln2 is split into two floating point number: 
- *			ln2_hi + ln2_lo,
- *	   where n*ln2_hi is always exact for |n| < 2000.
- *
- * Special cases:
- *	log(x) is NaN with signal if x < 0 (including -INF) ; 
- *	log(+INF) is +INF; log(0) is -INF with signal;
- *	log(NaN) is that NaN with no signal.
- *
- * Accuracy:
- *	according to an error analysis, the error is always less than
- *	1 ulp (unit in the last place).
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following 
- * constants. The decimal values may be used, provided that the 
- * compiler will convert from decimal to binary accurately enough 
- * to produce the hexadecimal values shown.
- */
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-
-static const double
-ln2_hi  =  6.93147180369123816490e-01,	/* 3fe62e42 fee00000 */
-ln2_lo  =  1.90821492927058770002e-10,	/* 3dea39ef 35793c76 */
-two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
-Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
-Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
-Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
-Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
-Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
-Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
-Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
-
-static const double zero   =  0.0;
-static volatile double vzero = 0.0;
-
-double
-log(double x)
-{
-	double hfsq,f,s,z,R,w,t1,t2,dk;
-	int32_t k,hx,i,j;
-	u_int32_t lx;
-
-	EXTRACT_WORDS(hx,lx,x);
-
-	k=0;
-	if (hx < 0x00100000) {			/* x < 2**-1022  */
-	    if (((hx&0x7fffffff)|lx)==0) 
-		return -two54/vzero;		/* log(+-0)=-inf */
-	    if (hx<0) return (x-x)/zero;	/* log(-#) = NaN */
-	    k -= 54; x *= two54; /* subnormal number, scale up x */
-	    GET_HIGH_WORD(hx,x);
-	} 
-	if (hx >= 0x7ff00000) return x+x;
-	k += (hx>>20)-1023;
-	hx &= 0x000fffff;
-	i = (hx+0x95f64)&0x100000;
-	SET_HIGH_WORD(x,hx|(i^0x3ff00000));	/* normalize x or x/2 */
-	k += (i>>20);
-	f = x-1.0;
-	if((0x000fffff&(2+hx))<3) {	/* -2**-20 <= f < 2**-20 */
-	    if(f==zero) {
-		if(k==0) {
-		    return zero;
-		} else {
-		    dk=(double)k;
-		    return dk*ln2_hi+dk*ln2_lo;
-		}
-	    }
-	    R = f*f*(0.5-0.33333333333333333*f);
-	    if(k==0) return f-R; else {dk=(double)k;
-	    	     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
-	}
- 	s = f/(2.0+f); 
-	dk = (double)k;
-	z = s*s;
-	i = hx-0x6147a;
-	w = z*z;
-	j = 0x6b851-hx;
-	t1= w*(Lg2+w*(Lg4+w*Lg6)); 
-	t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); 
-	i |= j;
-	R = t2+t1;
-	if(i>0) {
-	    hfsq=0.5*f*f;
-	    if(k==0) return f-(hfsq-s*(hfsq+R)); else
-		     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
-	} else {
-	    if(k==0) return f-s*(f-R); else
-		     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
-	}
-}
-
-#if (LDBL_MANT_DIG == 53)
-__weak_reference(log, logl);
-#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2.c b/libm/upstream-freebsd/lib/msun/src/e_log2.c
deleted file mode 100644
index 10b1c00..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_log2.c
+++ /dev/null
@@ -1,117 +0,0 @@
-
-/* @(#)e_log10.c 1.3 95/01/18 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Return the base 2 logarithm of x.  See e_log.c and k_log.h for most
- * comments.
- *
- * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel,
- * then does the combining and scaling steps
- *    log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k
- * in not-quite-routine extra precision.
- */
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-#include "k_log.h"
-
-static const double
-two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
-ivln2hi    =  1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */
-ivln2lo    =  1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */
-
-static const double zero   =  0.0;
-static volatile double vzero = 0.0;
-
-double
-log2(double x)
-{
-	double f,hfsq,hi,lo,r,val_hi,val_lo,w,y;
-	int32_t i,k,hx;
-	u_int32_t lx;
-
-	EXTRACT_WORDS(hx,lx,x);
-
-	k=0;
-	if (hx < 0x00100000) {			/* x < 2**-1022  */
-	    if (((hx&0x7fffffff)|lx)==0)
-		return -two54/vzero;		/* log(+-0)=-inf */
-	    if (hx<0) return (x-x)/zero;	/* log(-#) = NaN */
-	    k -= 54; x *= two54; /* subnormal number, scale up x */
-	    GET_HIGH_WORD(hx,x);
-	}
-	if (hx >= 0x7ff00000) return x+x;
-	if (hx == 0x3ff00000 && lx == 0)
-	    return zero;			/* log(1) = +0 */
-	k += (hx>>20)-1023;
-	hx &= 0x000fffff;
-	i = (hx+0x95f64)&0x100000;
-	SET_HIGH_WORD(x,hx|(i^0x3ff00000));	/* normalize x or x/2 */
-	k += (i>>20);
-	y = (double)k;
-	f = x - 1.0;
-	hfsq = 0.5*f*f;
-	r = k_log1p(f);
-
-	/*
-	 * f-hfsq must (for args near 1) be evaluated in extra precision
-	 * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2).
-	 * This is fairly efficient since f-hfsq only depends on f, so can
-	 * be evaluated in parallel with R.  Not combining hfsq with R also
-	 * keeps R small (though not as small as a true `lo' term would be),
-	 * so that extra precision is not needed for terms involving R.
-	 *
-	 * Compiler bugs involving extra precision used to break Dekker's
-	 * theorem for spitting f-hfsq as hi+lo, unless double_t was used
-	 * or the multi-precision calculations were avoided when double_t
-	 * has extra precision.  These problems are now automatically
-	 * avoided as a side effect of the optimization of combining the
-	 * Dekker splitting step with the clear-low-bits step.
-	 *
-	 * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra
-	 * precision to avoid a very large cancellation when x is very near
-	 * these values.  Unlike the above cancellations, this problem is
-	 * specific to base 2.  It is strange that adding +-1 is so much
-	 * harder than adding +-ln2 or +-log10_2.
-	 *
-	 * This uses Dekker's theorem to normalize y+val_hi, so the
-	 * compiler bugs are back in some configurations, sigh.  And I
-	 * don't want to used double_t to avoid them, since that gives a
-	 * pessimization and the support for avoiding the pessimization
-	 * is not yet available.
-	 *
-	 * The multi-precision calculations for the multiplications are
-	 * routine.
-	 */
-	hi = f - hfsq;
-	SET_LOW_WORD(hi,0);
-	lo = (f - hi) - hfsq + r;
-	val_hi = hi*ivln2hi;
-	val_lo = (lo+hi)*ivln2lo + lo*ivln2hi;
-
-	/* spadd(val_hi, val_lo, y), except for not using double_t: */
-	w = y + val_hi;
-	val_lo += (y - w) + val_hi;
-	val_hi = w;
-
-	return val_lo + val_hi;
-}
-
-#if (LDBL_MANT_DIG == 53)
-__weak_reference(log2, log2l);
-#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2f.c b/libm/upstream-freebsd/lib/msun/src/e_log2f.c
deleted file mode 100644
index 956f33a..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_log2f.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Float version of e_log2.c.  See the latter for most comments.
- */
-
-#include "math.h"
-#include "math_private.h"
-#include "k_logf.h"
-
-static const float
-two25      =  3.3554432000e+07, /* 0x4c000000 */
-ivln2hi    =  1.4428710938e+00, /* 0x3fb8b000 */
-ivln2lo    = -1.7605285393e-04; /* 0xb9389ad4 */
-
-static const float zero   =  0.0;
-static volatile float vzero = 0.0;
-
-float
-log2f(float x)
-{
-	float f,hfsq,hi,lo,r,y;
-	int32_t i,k,hx;
-
-	GET_FLOAT_WORD(hx,x);
-
-	k=0;
-	if (hx < 0x00800000) {			/* x < 2**-126  */
-	    if ((hx&0x7fffffff)==0)
-		return -two25/vzero;		/* log(+-0)=-inf */
-	    if (hx<0) return (x-x)/zero;	/* log(-#) = NaN */
-	    k -= 25; x *= two25; /* subnormal number, scale up x */
-	    GET_FLOAT_WORD(hx,x);
-	}
-	if (hx >= 0x7f800000) return x+x;
-	if (hx == 0x3f800000)
-	    return zero;			/* log(1) = +0 */
-	k += (hx>>23)-127;
-	hx &= 0x007fffff;
-	i = (hx+(0x4afb0d))&0x800000;
-	SET_FLOAT_WORD(x,hx|(i^0x3f800000));	/* normalize x or x/2 */
-	k += (i>>23);
-	y = (float)k;
-	f = x - (float)1.0;
-	hfsq = (float)0.5*f*f;
-	r = k_log1pf(f);
-
-	/*
-	 * We no longer need to avoid falling into the multi-precision
-	 * calculations due to compiler bugs breaking Dekker's theorem.
-	 * Keep avoiding this as an optimization.  See e_log2.c for more
-	 * details (some details are here only because the optimization
-	 * is not yet available in double precision).
-	 *
-	 * Another compiler bug turned up.  With gcc on i386,
-	 * (ivln2lo + ivln2hi) would be evaluated in float precision
-	 * despite runtime evaluations using double precision.  So we
-	 * must cast one of its terms to float_t.  This makes the whole
-	 * expression have type float_t, so return is forced to waste
-	 * time clobbering its extra precision.
-	 */
-	if (sizeof(float_t) > sizeof(float))
-		return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y;
-
-	hi = f - hfsq;
-	GET_FLOAT_WORD(hx,hi);
-	SET_FLOAT_WORD(hi,hx&0xfffff000);
-	lo = (f - hi) - hfsq + r;
-	return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/e_logf.c b/libm/upstream-freebsd/lib/msun/src/e_logf.c
deleted file mode 100644
index 68a4d5d..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_logf.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* e_logf.c -- float version of e_log.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "math.h"
-#include "math_private.h"
-
-static const float
-ln2_hi =   6.9313812256e-01,	/* 0x3f317180 */
-ln2_lo =   9.0580006145e-06,	/* 0x3717f7d1 */
-two25 =    3.355443200e+07,	/* 0x4c000000 */
-/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
-Lg1 =      0xaaaaaa.0p-24,	/* 0.66666662693 */
-Lg2 =      0xccce13.0p-25,	/* 0.40000972152 */
-Lg3 =      0x91e9ee.0p-25,	/* 0.28498786688 */
-Lg4 =      0xf89e26.0p-26;	/* 0.24279078841 */
-
-static const float zero   =  0.0;
-static volatile float vzero = 0.0;
-
-float
-logf(float x)
-{
-	float hfsq,f,s,z,R,w,t1,t2,dk;
-	int32_t k,ix,i,j;
-
-	GET_FLOAT_WORD(ix,x);
-
-	k=0;
-	if (ix < 0x00800000) {			/* x < 2**-126  */
-	    if ((ix&0x7fffffff)==0)
-		return -two25/vzero;		/* log(+-0)=-inf */
-	    if (ix<0) return (x-x)/zero;	/* log(-#) = NaN */
-	    k -= 25; x *= two25; /* subnormal number, scale up x */
-	    GET_FLOAT_WORD(ix,x);
-	}
-	if (ix >= 0x7f800000) return x+x;
-	k += (ix>>23)-127;
-	ix &= 0x007fffff;
-	i = (ix+(0x95f64<<3))&0x800000;
-	SET_FLOAT_WORD(x,ix|(i^0x3f800000));	/* normalize x or x/2 */
-	k += (i>>23);
-	f = x-(float)1.0;
-	if((0x007fffff&(0x8000+ix))<0xc000) {	/* -2**-9 <= f < 2**-9 */
-	    if(f==zero) {
-		if(k==0) {
-		    return zero;
-		} else {
-		    dk=(float)k;
-		    return dk*ln2_hi+dk*ln2_lo;
-		}
-	    }
-	    R = f*f*((float)0.5-(float)0.33333333333333333*f);
-	    if(k==0) return f-R; else {dk=(float)k;
-	    	     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
-	}
- 	s = f/((float)2.0+f);
-	dk = (float)k;
-	z = s*s;
-	i = ix-(0x6147a<<3);
-	w = z*z;
-	j = (0x6b851<<3)-ix;
-	t1= w*(Lg2+w*Lg4);
-	t2= z*(Lg1+w*Lg3);
-	i |= j;
-	R = t2+t1;
-	if(i>0) {
-	    hfsq=(float)0.5*f*f;
-	    if(k==0) return f-(hfsq-s*(hfsq+R)); else
-		     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
-	} else {
-	    if(k==0) return f-s*(f-R); else
-		     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
-	}
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/e_pow.c b/libm/upstream-freebsd/lib/msun/src/e_pow.c
deleted file mode 100644
index adc64c9..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_pow.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* @(#)e_pow.c 1.5 04/04/22 SMI */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/* pow(x,y) return x**y
- *
- *		      n
- * Method:  Let x =  2   * (1+f)
- *	1. Compute and return log2(x) in two pieces:
- *		log2(x) = w1 + w2,
- *	   where w1 has 53-24 = 29 bit trailing zeros.
- *	2. Perform y*log2(x) = n+y' by simulating multi-precision
- *	   arithmetic, where |y'|<=0.5.
- *	3. Return x**y = 2**n*exp(y'*log2)
- *
- * Special cases:
- *	1.  (anything) ** 0  is 1
- *	2.  (anything) ** 1  is itself
- *	3.  (anything) ** NAN is NAN except 1 ** NAN = 1
- *	4.  NAN ** (anything except 0) is NAN
- *	5.  +-(|x| > 1) **  +INF is +INF
- *	6.  +-(|x| > 1) **  -INF is +0
- *	7.  +-(|x| < 1) **  +INF is +0
- *	8.  +-(|x| < 1) **  -INF is +INF
- *	9.  +-1         ** +-INF is 1
- *	10. +0 ** (+anything except 0, NAN)               is +0
- *	11. -0 ** (+anything except 0, NAN, odd integer)  is +0
- *	12. +0 ** (-anything except 0, NAN)               is +INF
- *	13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
- *	14. -0 ** (odd integer) = -( +0 ** (odd integer) )
- *	15. +INF ** (+anything except 0,NAN) is +INF
- *	16. +INF ** (-anything except 0,NAN) is +0
- *	17. -INF ** (anything)  = -0 ** (-anything)
- *	18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
- *	19. (-anything except 0 and inf) ** (non-integer) is NAN
- *
- * Accuracy:
- *	pow(x,y) returns x**y nearly rounded. In particular
- *			pow(integer,integer)
- *	always returns the correct integer provided it is
- *	representable.
- *
- * Constants :
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#include <float.h>
-#include "math.h"
-#include "math_private.h"
-
-static const double
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
-dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
-zero    =  0.0,
-half    =  0.5,
-qrtr    =  0.25,
-thrd    =  3.3333333333333331e-01, /* 0x3fd55555, 0x55555555 */
-one	=  1.0,
-two	=  2.0,
-two53	=  9007199254740992.0,	/* 0x43400000, 0x00000000 */
-huge	=  1.0e300,
-tiny    =  1.0e-300,
-	/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
-L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
-L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
-L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
-L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
-L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
-P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
-lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
-lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
-lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
-ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
-cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
-cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
-cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
-ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
-ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
-ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
-
-double
-pow(double x, double y)
-{
-	double z,ax,z_h,z_l,p_h,p_l;
-	double y1,t1,t2,r,s,t,u,v,w;
-	int32_t i,j,k,yisint,n;
-	int32_t hx,hy,ix,iy;
-	u_int32_t lx,ly;
-
-	EXTRACT_WORDS(hx,lx,x);
-	EXTRACT_WORDS(hy,ly,y);
-	ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
-
-    /* y==zero: x**0 = 1 */
-	if((iy|ly)==0) return one;
-
-    /* x==1: 1**y = 1, even if y is NaN */
-	if (hx==0x3ff00000 && lx == 0) return one;
-
-    /* y!=zero: result is NaN if either arg is NaN */
-	if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
-	   iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
-	    return nan_mix(x, y);
-
-    /* determine if y is an odd int when x < 0
-     * yisint = 0	... y is not an integer
-     * yisint = 1	... y is an odd int
-     * yisint = 2	... y is an even int
-     */
-	yisint  = 0;
-	if(hx<0) {
-	    if(iy>=0x43400000) yisint = 2; /* even integer y */
-	    else if(iy>=0x3ff00000) {
-		k = (iy>>20)-0x3ff;	   /* exponent */
-		if(k>20) {
-		    j = ly>>(52-k);
-		    if(((u_int32_t)j<<(52-k))==ly) yisint = 2-(j&1);
-		} else if(ly==0) {
-		    j = iy>>(20-k);
-		    if((j<<(20-k))==iy) yisint = 2-(j&1);
-		}
-	    }
-	}
-
-    /* special value of y */
-	if(ly==0) {
-	    if (iy==0x7ff00000) {	/* y is +-inf */
-	        if(((ix-0x3ff00000)|lx)==0)
-		    return  one;	/* (-1)**+-inf is 1 */
-	        else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
-		    return (hy>=0)? y: zero;
-	        else			/* (|x|<1)**-,+inf = inf,0 */
-		    return (hy<0)?-y: zero;
-	    }
-	    if(iy==0x3ff00000) {	/* y is  +-1 */
-		if(hy<0) return one/x; else return x;
-	    }
-	    if(hy==0x40000000) return x*x; /* y is  2 */
-	    if(hy==0x3fe00000) {	/* y is  0.5 */
-		if(hx>=0)	/* x >= +0 */
-		return sqrt(x);
-	    }
-	}
-
-	ax   = fabs(x);
-    /* special value of x */
-	if(lx==0) {
-	    if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
-		z = ax;			/*x is +-0,+-inf,+-1*/
-		if(hy<0) z = one/z;	/* z = (1/|x|) */
-		if(hx<0) {
-		    if(((ix-0x3ff00000)|yisint)==0) {
-			z = (z-z)/(z-z); /* (-1)**non-int is NaN */
-		    } else if(yisint==1)
-			z = -z;		/* (x<0)**odd = -(|x|**odd) */
-		}
-		return z;
-	    }
-	}
-
-    /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be
-	n = (hx>>31)+1;
-       but ANSI C says a right shift of a signed negative quantity is
-       implementation defined.  */
-	n = ((u_int32_t)hx>>31)-1;
-
-    /* (x<0)**(non-int) is NaN */
-	if((n|yisint)==0) return (x-x)/(x-x);
-
-	s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
-	if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
-
-    /* |y| is huge */
-	if(iy>0x41e00000) { /* if |y| > 2**31 */
-	    if(iy>0x43f00000){	/* if |y| > 2**64, must o/uflow */
-		if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
-		if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
-	    }
-	/* over/underflow if x is not close to one */
-	    if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
-	    if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
-	/* now |1-x| is tiny <= 2**-20, suffice to compute
-	   log(x) by x-x^2/2+x^3/3-x^4/4 */
-	    t = ax-one;		/* t has 20 trailing zeros */
-	    w = (t*t)*(half-t*(thrd-t*qrtr));
-	    u = ivln2_h*t;	/* ivln2_h has 21 sig. bits */
-	    v = t*ivln2_l-w*ivln2;
-	    t1 = u+v;
-	    SET_LOW_WORD(t1,0);
-	    t2 = v-(t1-u);
-	} else {
-	    double ss,s2,s_h,s_l,t_h,t_l;
-	    n = 0;
-	/* take care subnormal number */
-	    if(ix<0x00100000)
-		{ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); }
-	    n  += ((ix)>>20)-0x3ff;
-	    j  = ix&0x000fffff;
-	/* determine interval */
-	    ix = j|0x3ff00000;		/* normalize ix */
-	    if(j<=0x3988E) k=0;		/* |x|<sqrt(3/2) */
-	    else if(j<0xBB67A) k=1;	/* |x|<sqrt(3)   */
-	    else {k=0;n+=1;ix -= 0x00100000;}
-	    SET_HIGH_WORD(ax,ix);
-
-	/* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
-	    u = ax-bp[k];		/* bp[0]=1.0, bp[1]=1.5 */
-	    v = one/(ax+bp[k]);
-	    ss = u*v;
-	    s_h = ss;
-	    SET_LOW_WORD(s_h,0);
-	/* t_h=ax+bp[k] High */
-	    t_h = zero;
-	    SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18));
-	    t_l = ax - (t_h-bp[k]);
-	    s_l = v*((u-s_h*t_h)-s_h*t_l);
-	/* compute log(ax) */
-	    s2 = ss*ss;
-	    r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
-	    r += s_l*(s_h+ss);
-	    s2  = s_h*s_h;
-	    t_h = 3+s2+r;
-	    SET_LOW_WORD(t_h,0);
-	    t_l = r-((t_h-3)-s2);
-	/* u+v = ss*(1+...) */
-	    u = s_h*t_h;
-	    v = s_l*t_h+t_l*ss;
-	/* 2/(3log2)*(ss+...) */
-	    p_h = u+v;
-	    SET_LOW_WORD(p_h,0);
-	    p_l = v-(p_h-u);
-	    z_h = cp_h*p_h;		/* cp_h+cp_l = 2/(3*log2) */
-	    z_l = cp_l*p_h+p_l*cp+dp_l[k];
-	/* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
-	    t = n;
-	    t1 = (((z_h+z_l)+dp_h[k])+t);
-	    SET_LOW_WORD(t1,0);
-	    t2 = z_l-(((t1-t)-dp_h[k])-z_h);
-	}
-
-    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
-	y1  = y;
-	SET_LOW_WORD(y1,0);
-	p_l = (y-y1)*t1+y*t2;
-	p_h = y1*t1;
-	z = p_l+p_h;
-	EXTRACT_WORDS(j,i,z);
-	if (j>=0x40900000) {				/* z >= 1024 */
-	    if(((j-0x40900000)|i)!=0)			/* if z > 1024 */
-		return s*huge*huge;			/* overflow */
-	    else {
-		if(p_l+ovt>z-p_h) return s*huge*huge;	/* overflow */
-	    }
-	} else if((j&0x7fffffff)>=0x4090cc00 ) {	/* z <= -1075 */
-	    if(((j-0xc090cc00)|i)!=0) 		/* z < -1075 */
-		return s*tiny*tiny;		/* underflow */
-	    else {
-		if(p_l<=z-p_h) return s*tiny*tiny;	/* underflow */
-	    }
-	}
-    /*
-     * compute 2**(p_h+p_l)
-     */
-	i = j&0x7fffffff;
-	k = (i>>20)-0x3ff;
-	n = 0;
-	if(i>0x3fe00000) {		/* if |z| > 0.5, set n = [z+0.5] */
-	    n = j+(0x00100000>>(k+1));
-	    k = ((n&0x7fffffff)>>20)-0x3ff;	/* new k for n */
-	    t = zero;
-	    SET_HIGH_WORD(t,n&~(0x000fffff>>k));
-	    n = ((n&0x000fffff)|0x00100000)>>(20-k);
-	    if(j<0) n = -n;
-	    p_h -= t;
-	}
-	t = p_l+p_h;
-	SET_LOW_WORD(t,0);
-	u = t*lg2_h;
-	v = (p_l-(t-p_h))*lg2+t*lg2_l;
-	z = u+v;
-	w = v-(z-u);
-	t  = z*z;
-	t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
-	r  = (z*t1)/(t1-two)-(w+z*w);
-	z  = one-(r-z);
-	GET_HIGH_WORD(j,z);
-	j += (n<<20);
-	if((j>>20)<=0) z = scalbn(z,n);	/* subnormal output */
-	else SET_HIGH_WORD(z,j);
-	return s*z;
-}
-
-#if (LDBL_MANT_DIG == 53)
-__weak_reference(pow, powl);
-#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/e_powf.c b/libm/upstream-freebsd/lib/msun/src/e_powf.c
deleted file mode 100644
index f5a2c70..0000000
--- a/libm/upstream-freebsd/lib/msun/src/e_powf.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/* e_powf.c -- float version of e_pow.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "math.h"
-#include "math_private.h"
-
-static const float
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
-dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
-zero    =  0.0,
-half    =  0.5,
-qrtr    =  0.25,
-thrd    =  3.33333343e-01, /* 0x3eaaaaab */
-one	=  1.0,
-two	=  2.0,
-two24	=  16777216.0,	/* 0x4b800000 */
-huge	=  1.0e30,
-tiny    =  1.0e-30,
-	/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1  =  6.0000002384e-01, /* 0x3f19999a */
-L2  =  4.2857143283e-01, /* 0x3edb6db7 */
-L3  =  3.3333334327e-01, /* 0x3eaaaaab */
-L4  =  2.7272811532e-01, /* 0x3e8ba305 */
-L5  =  2.3066075146e-01, /* 0x3e6c3255 */
-L6  =  2.0697501302e-01, /* 0x3e53f142 */
-P1   =  1.6666667163e-01, /* 0x3e2aaaab */
-P2   = -2.7777778450e-03, /* 0xbb360b61 */
-P3   =  6.6137559770e-05, /* 0x388ab355 */
-P4   = -1.6533901999e-06, /* 0xb5ddea0e */
-P5   =  4.1381369442e-08, /* 0x3331bb4c */
-lg2  =  6.9314718246e-01, /* 0x3f317218 */
-lg2_h  =  6.93145752e-01, /* 0x3f317200 */
-lg2_l  =  1.42860654e-06, /* 0x35bfbe8c */
-ovt =  4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
-cp    =  9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
-cp_h  =  9.6191406250e-01, /* 0x3f764000 =12b cp */
-cp_l  = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */
-ivln2    =  1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
-ivln2_h  =  1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
-ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
-
-float
-powf(float x, float y)
-{
-	float z,ax,z_h,z_l,p_h,p_l;
-	float y1,t1,t2,r,s,sn,t,u,v,w;
-	int32_t i,j,k,yisint,n;
-	int32_t hx,hy,ix,iy,is;
-
-	GET_FLOAT_WORD(hx,x);
-	GET_FLOAT_WORD(hy,y);
-	ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
-
-    /* y==zero: x**0 = 1 */
-	if(iy==0) return one;
-
-    /* x==1: 1**y = 1, even if y is NaN */
-	if (hx==0x3f800000) return one;
-
-    /* y!=zero: result is NaN if either arg is NaN */
-	if(ix > 0x7f800000 ||
-	   iy > 0x7f800000)
-	    return nan_mix(x, y);
-
-    /* determine if y is an odd int when x < 0
-     * yisint = 0	... y is not an integer
-     * yisint = 1	... y is an odd int
-     * yisint = 2	... y is an even int
-     */
-	yisint  = 0;
-	if(hx<0) {
-	    if(iy>=0x4b800000) yisint = 2; /* even integer y */
-	    else if(iy>=0x3f800000) {
-		k = (iy>>23)-0x7f;	   /* exponent */
-		j = iy>>(23-k);
-		if((j<<(23-k))==iy) yisint = 2-(j&1);
-	    }
-	}
-
-    /* special value of y */
-	if (iy==0x7f800000) {	/* y is +-inf */
-	    if (ix==0x3f800000)
-	        return  one;	/* (-1)**+-inf is NaN */
-	    else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */
-	        return (hy>=0)? y: zero;
-	    else			/* (|x|<1)**-,+inf = inf,0 */
-	        return (hy<0)?-y: zero;
-	}
-	if(iy==0x3f800000) {	/* y is  +-1 */
-	    if(hy<0) return one/x; else return x;
-	}
-	if(hy==0x40000000) return x*x; /* y is  2 */
-	if(hy==0x3f000000) {	/* y is  0.5 */
-	    if(hx>=0)	/* x >= +0 */
-	    return sqrtf(x);
-	}
-
-	ax   = fabsf(x);
-    /* special value of x */
-	if(ix==0x7f800000||ix==0||ix==0x3f800000){
-	    z = ax;			/*x is +-0,+-inf,+-1*/
-	    if(hy<0) z = one/z;	/* z = (1/|x|) */
-	    if(hx<0) {
-		if(((ix-0x3f800000)|yisint)==0) {
-		    z = (z-z)/(z-z); /* (-1)**non-int is NaN */
-		} else if(yisint==1)
-		    z = -z;		/* (x<0)**odd = -(|x|**odd) */
-	    }
-	    return z;
-	}
-
-	n = ((u_int32_t)hx>>31)-1;
-
-    /* (x<0)**(non-int) is NaN */
-	if((n|yisint)==0) return (x-x)/(x-x);
-
-	sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */
-	if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */
-
-    /* |y| is huge */
-	if(iy>0x4d000000) { /* if |y| > 2**27 */
-	/* over/underflow if x is not close to one */
-	    if(ix<0x3f7ffff6) return (hy<0)? sn*huge*huge:sn*tiny*tiny;
-	    if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny;
-	/* now |1-x| is tiny <= 2**-20, suffice to compute
-	   log(x) by x-x^2/2+x^3/3-x^4/4 */
-	    t = ax-1;		/* t has 20 trailing zeros */
-	    w = (t*t)*(half-t*(thrd-t*qrtr));
-	    u = ivln2_h*t;	/* ivln2_h has 16 sig. bits */
-	    v = t*ivln2_l-w*ivln2;
-	    t1 = u+v;
-	    GET_FLOAT_WORD(is,t1);
-	    SET_FLOAT_WORD(t1,is&0xfffff000);
-	    t2 = v-(t1-u);
-	} else {
-	    float s2,s_h,s_l,t_h,t_l;
-	    n = 0;
-	/* take care subnormal number */
-	    if(ix<0x00800000)
-		{ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); }
-	    n  += ((ix)>>23)-0x7f;
-	    j  = ix&0x007fffff;
-	/* determine interval */
-	    ix = j|0x3f800000;		/* normalize ix */
-	    if(j<=0x1cc471) k=0;	/* |x|<sqrt(3/2) */
-	    else if(j<0x5db3d7) k=1;	/* |x|<sqrt(3)   */
-	    else {k=0;n+=1;ix -= 0x00800000;}
-	    SET_FLOAT_WORD(ax,ix);
-
-	/* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
-	    u = ax-bp[k];		/* bp[0]=1.0, bp[1]=1.5 */
-	    v = one/(ax+bp[k]);
-	    s = u*v;
-	    s_h = s;
-	    GET_FLOAT_WORD(is,s_h);
-	    SET_FLOAT_WORD(s_h,is&0xfffff000);
-	/* t_h=ax+bp[k] High */
-	    is = ((ix>>1)&0xfffff000)|0x20000000;
-	    SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21));
-	    t_l = ax - (t_h-bp[k]);
-	    s_l = v*((u-s_h*t_h)-s_h*t_l);
-	/* compute log(ax) */
-	    s2 = s*s;
-	    r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
-	    r += s_l*(s_h+s);
-	    s2  = s_h*s_h;
-	    t_h = 3+s2+r;
-	    GET_FLOAT_WORD(is,t_h);
-	    SET_FLOAT_WORD(t_h,is&0xfffff000);
-	    t_l = r-((t_h-3)-s2);
-	/* u+v = s*(1+...) */
-	    u = s_h*t_h;
-	    v = s_l*t_h+t_l*s;
-	/* 2/(3log2)*(s+...) */
-	    p_h = u+v;
-	    GET_FLOAT_WORD(is,p_h);
-	    SET_FLOAT_WORD(p_h,is&0xfffff000);
-	    p_l = v-(p_h-u);
-	    z_h = cp_h*p_h;		/* cp_h+cp_l = 2/(3*log2) */
-	    z_l = cp_l*p_h+p_l*cp+dp_l[k];
-	/* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
-	    t = n;
-	    t1 = (((z_h+z_l)+dp_h[k])+t);
-	    GET_FLOAT_WORD(is,t1);
-	    SET_FLOAT_WORD(t1,is&0xfffff000);
-	    t2 = z_l-(((t1-t)-dp_h[k])-z_h);
-	}
-
-    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
-	GET_FLOAT_WORD(is,y);
-	SET_FLOAT_WORD(y1,is&0xfffff000);
-	p_l = (y-y1)*t1+y*t2;
-	p_h = y1*t1;
-	z = p_l+p_h;
-	GET_FLOAT_WORD(j,z);
-	if (j>0x43000000)				/* if z > 128 */
-	    return sn*huge*huge;			/* overflow */
-	else if (j==0x43000000) {			/* if z == 128 */
-	    if(p_l+ovt>z-p_h) return sn*huge*huge;	/* overflow */
-	}
-	else if ((j&0x7fffffff)>0x43160000)		/* z <= -150 */
-	    return sn*tiny*tiny;			/* underflow */
-	else if (j==0xc3160000){			/* z == -150 */
-	    if(p_l<=z-p_h) return sn*tiny*tiny;		/* underflow */
-	}
-    /*
-     * compute 2**(p_h+p_l)
-     */
-	i = j&0x7fffffff;
-	k = (i>>23)-0x7f;
-	n = 0;
-	if(i>0x3f000000) {		/* if |z| > 0.5, set n = [z+0.5] */
-	    n = j+(0x00800000>>(k+1));
-	    k = ((n&0x7fffffff)>>23)-0x7f;	/* new k for n */
-	    SET_FLOAT_WORD(t,n&~(0x007fffff>>k));
-	    n = ((n&0x007fffff)|0x00800000)>>(23-k);
-	    if(j<0) n = -n;
-	    p_h -= t;
-	}
-	t = p_l+p_h;
-	GET_FLOAT_WORD(is,t);
-	SET_FLOAT_WORD(t,is&0xffff8000);
-	u = t*lg2_h;
-	v = (p_l-(t-p_h))*lg2+t*lg2_l;
-	z = u+v;
-	w = v-(z-u);
-	t  = z*z;
-	t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
-	r  = (z*t1)/(t1-two)-(w+z*w);
-	z  = one-(r-z);
-	GET_FLOAT_WORD(j,z);
-	j += (n<<23);
-	if((j>>23)<=0) z = scalbnf(z,n);	/* subnormal output */
-	else SET_FLOAT_WORD(z,j);
-	return sn*z;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysign.c b/libm/upstream-freebsd/lib/msun/src/s_copysign.c
deleted file mode 100644
index a5f3870..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_copysign.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* @(#)s_copysign.c 5.1 93/09/24 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * copysign(double x, double y)
- * copysign(x,y) returns a value with the magnitude of x and
- * with the sign bit of y.
- */
-
-#include "math.h"
-#include "math_private.h"
-
-double
-copysign(double x, double y)
-{
-	u_int32_t hx,hy;
-	GET_HIGH_WORD(hx,x);
-	GET_HIGH_WORD(hy,y);
-	SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
-        return x;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysignf.c b/libm/upstream-freebsd/lib/msun/src/s_copysignf.c
deleted file mode 100644
index 05ca1e3..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_copysignf.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* s_copysignf.c -- float version of s_copysign.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * copysignf(float x, float y)
- * copysignf(x,y) returns a value with the magnitude of x and
- * with the sign bit of y.
- */
-
-#include "math.h"
-#include "math_private.h"
-
-float
-copysignf(float x, float y)
-{
-	u_int32_t ix,iy;
-	GET_FLOAT_WORD(ix,x);
-	GET_FLOAT_WORD(iy,y);
-	SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
-        return x;
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysignl.c b/libm/upstream-freebsd/lib/msun/src/s_copysignl.c
deleted file mode 100644
index 666a2ba..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_copysignl.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2004 Stefan Farfeleder
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <math.h>
-
-#include "fpmath.h"
-
-long double
-copysignl(long double x, long double y)
-{
-	union IEEEl2bits ux, uy;
-
-	ux.e = x;
-	uy.e = y;
-	ux.bits.sign = uy.bits.sign;
-	return (ux.e);
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cosf.c b/libm/upstream-freebsd/lib/msun/src/s_cosf.c
deleted file mode 100644
index b701fd2..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_cosf.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* s_cosf.c -- float version of s_cos.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- * Optimized by Bruce D. Evans.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#define	INLINE_KERNEL_COSDF
-#define	INLINE_KERNEL_SINDF
-#define INLINE_REM_PIO2F
-#include "math_private.h"
-#include "e_rem_pio2f.c"
-#include "k_cosf.c"
-#include "k_sinf.c"
-
-/* Small multiples of pi/2 rounded to double precision. */
-static const double
-c1pio2 = 1*M_PI_2,			/* 0x3FF921FB, 0x54442D18 */
-c2pio2 = 2*M_PI_2,			/* 0x400921FB, 0x54442D18 */
-c3pio2 = 3*M_PI_2,			/* 0x4012D97C, 0x7F3321D2 */
-c4pio2 = 4*M_PI_2;			/* 0x401921FB, 0x54442D18 */
-
-float
-cosf(float x)
-{
-	double y;
-	int32_t n, hx, ix;
-
-	GET_FLOAT_WORD(hx,x);
-	ix = hx & 0x7fffffff;
-
-	if(ix <= 0x3f490fda) {		/* |x| ~<= pi/4 */
-	    if(ix<0x39800000)		/* |x| < 2**-12 */
-		if(((int)x)==0) return 1.0;	/* 1 with inexact if x != 0 */
-	    return __kernel_cosdf(x);
-	}
-	if(ix<=0x407b53d1) {		/* |x| ~<= 5*pi/4 */
-	    if(ix>0x4016cbe3)		/* |x|  ~> 3*pi/4 */
-		return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2));
-	    else {
-		if(hx>0)
-		    return __kernel_sindf(c1pio2 - x);
-		else
-		    return __kernel_sindf(x + c1pio2);
-	    }
-	}
-	if(ix<=0x40e231d5) {		/* |x| ~<= 9*pi/4 */
-	    if(ix>0x40afeddf)		/* |x|  ~> 7*pi/4 */
-		return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2));
-	    else {
-		if(hx>0)
-		    return __kernel_sindf(x - c3pio2);
-		else
-		    return __kernel_sindf(-c3pio2 - x);
-	    }
-	}
-
-    /* cos(Inf or NaN) is NaN */
-	else if (ix>=0x7f800000) return x-x;
-
-    /* general argument reduction needed */
-	else {
-	    n = __ieee754_rem_pio2f(x,&y);
-	    switch(n&3) {
-		case 0: return  __kernel_cosdf(y);
-		case 1: return  __kernel_sindf(-y);
-		case 2: return -__kernel_cosdf(y);
-		default:
-		        return  __kernel_sindf(y);
-	    }
-	}
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2.c b/libm/upstream-freebsd/lib/msun/src/s_exp2.c
deleted file mode 100644
index 1dd9673..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_exp2.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-
-#define	TBLBITS	8
-#define	TBLSIZE	(1 << TBLBITS)
-
-static const double
-    redux    = 0x1.8p52 / TBLSIZE,
-    P1	     = 0x1.62e42fefa39efp-1,
-    P2	     = 0x1.ebfbdff82c575p-3,
-    P3	     = 0x1.c6b08d704a0a6p-5,
-    P4	     = 0x1.3b2ab88f70400p-7,
-    P5	     = 0x1.5d88003875c74p-10;
-
-static volatile double
-    huge     = 0x1p1000,
-    twom1000 = 0x1p-1000;
-
-static const double tbl[TBLSIZE * 2] = {
-/*	exp2(z + eps)		eps	*/
-	0x1.6a09e667f3d5dp-1,	 0x1.9880p-44,
-	0x1.6b052fa751744p-1,	 0x1.8000p-50,
-	0x1.6c012750bd9fep-1,	-0x1.8780p-45,
-	0x1.6cfdcddd476bfp-1,	 0x1.ec00p-46,
-	0x1.6dfb23c651a29p-1,	-0x1.8000p-50,
-	0x1.6ef9298593ae3p-1,	-0x1.c000p-52,
-	0x1.6ff7df9519386p-1,	-0x1.fd80p-45,
-	0x1.70f7466f42da3p-1,	-0x1.c880p-45,
-	0x1.71f75e8ec5fc3p-1,	 0x1.3c00p-46,
-	0x1.72f8286eacf05p-1,	-0x1.8300p-44,
-	0x1.73f9a48a58152p-1,	-0x1.0c00p-47,
-	0x1.74fbd35d7ccfcp-1,	 0x1.f880p-45,
-	0x1.75feb564267f1p-1,	 0x1.3e00p-47,
-	0x1.77024b1ab6d48p-1,	-0x1.7d00p-45,
-	0x1.780694fde5d38p-1,	-0x1.d000p-50,
-	0x1.790b938ac1d00p-1,	 0x1.3000p-49,
-	0x1.7a11473eb0178p-1,	-0x1.d000p-49,
-	0x1.7b17b0976d060p-1,	 0x1.0400p-45,
-	0x1.7c1ed0130c133p-1,	 0x1.0000p-53,
-	0x1.7d26a62ff8636p-1,	-0x1.6900p-45,
-	0x1.7e2f336cf4e3bp-1,	-0x1.2e00p-47,
-	0x1.7f3878491c3e8p-1,	-0x1.4580p-45,
-	0x1.80427543e1b4ep-1,	 0x1.3000p-44,
-	0x1.814d2add1071ap-1,	 0x1.f000p-47,
-	0x1.82589994ccd7ep-1,	-0x1.1c00p-45,
-	0x1.8364c1eb942d0p-1,	 0x1.9d00p-45,
-	0x1.8471a4623cab5p-1,	 0x1.7100p-43,
-	0x1.857f4179f5bbcp-1,	 0x1.2600p-45,
-	0x1.868d99b4491afp-1,	-0x1.2c40p-44,
-	0x1.879cad931a395p-1,	-0x1.3000p-45,
-	0x1.88ac7d98a65b8p-1,	-0x1.a800p-45,
-	0x1.89bd0a4785800p-1,	-0x1.d000p-49,
-	0x1.8ace5422aa223p-1,	 0x1.3280p-44,
-	0x1.8be05bad619fap-1,	 0x1.2b40p-43,
-	0x1.8cf3216b54383p-1,	-0x1.ed00p-45,
-	0x1.8e06a5e08664cp-1,	-0x1.0500p-45,
-	0x1.8f1ae99157807p-1,	 0x1.8280p-45,
-	0x1.902fed0282c0ep-1,	-0x1.cb00p-46,
-	0x1.9145b0b91ff96p-1,	-0x1.5e00p-47,
-	0x1.925c353aa2ff9p-1,	 0x1.5400p-48,
-	0x1.93737b0cdc64ap-1,	 0x1.7200p-46,
-	0x1.948b82b5f98aep-1,	-0x1.9000p-47,
-	0x1.95a44cbc852cbp-1,	 0x1.5680p-45,
-	0x1.96bdd9a766f21p-1,	-0x1.6d00p-44,
-	0x1.97d829fde4e2ap-1,	-0x1.1000p-47,
-	0x1.98f33e47a23a3p-1,	 0x1.d000p-45,
-	0x1.9a0f170ca0604p-1,	-0x1.8a40p-44,
-	0x1.9b2bb4d53ff89p-1,	 0x1.55c0p-44,
-	0x1.9c49182a3f15bp-1,	 0x1.6b80p-45,
-	0x1.9d674194bb8c5p-1,	-0x1.c000p-49,
-	0x1.9e86319e3238ep-1,	 0x1.7d00p-46,
-	0x1.9fa5e8d07f302p-1,	 0x1.6400p-46,
-	0x1.a0c667b5de54dp-1,	-0x1.5000p-48,
-	0x1.a1e7aed8eb8f6p-1,	 0x1.9e00p-47,
-	0x1.a309bec4a2e27p-1,	 0x1.ad80p-45,
-	0x1.a42c980460a5dp-1,	-0x1.af00p-46,
-	0x1.a5503b23e259bp-1,	 0x1.b600p-47,
-	0x1.a674a8af46213p-1,	 0x1.8880p-44,
-	0x1.a799e1330b3a7p-1,	 0x1.1200p-46,
-	0x1.a8bfe53c12e8dp-1,	 0x1.6c00p-47,
-	0x1.a9e6b5579fcd2p-1,	-0x1.9b80p-45,
-	0x1.ab0e521356fb8p-1,	 0x1.b700p-45,
-	0x1.ac36bbfd3f381p-1,	 0x1.9000p-50,
-	0x1.ad5ff3a3c2780p-1,	 0x1.4000p-49,
-	0x1.ae89f995ad2a3p-1,	-0x1.c900p-45,
-	0x1.afb4ce622f367p-1,	 0x1.6500p-46,
-	0x1.b0e07298db790p-1,	 0x1.fd40p-45,
-	0x1.b20ce6c9a89a9p-1,	 0x1.2700p-46,
-	0x1.b33a2b84f1a4bp-1,	 0x1.d470p-43,
-	0x1.b468415b747e7p-1,	-0x1.8380p-44,
-	0x1.b59728de5593ap-1,	 0x1.8000p-54,
-	0x1.b6c6e29f1c56ap-1,	 0x1.ad00p-47,
-	0x1.b7f76f2fb5e50p-1,	 0x1.e800p-50,
-	0x1.b928cf22749b2p-1,	-0x1.4c00p-47,
-	0x1.ba5b030a10603p-1,	-0x1.d700p-47,
-	0x1.bb8e0b79a6f66p-1,	 0x1.d900p-47,
-	0x1.bcc1e904bc1ffp-1,	 0x1.2a00p-47,
-	0x1.bdf69c3f3a16fp-1,	-0x1.f780p-46,
-	0x1.bf2c25bd71db8p-1,	-0x1.0a00p-46,
-	0x1.c06286141b2e9p-1,	-0x1.1400p-46,
-	0x1.c199bdd8552e0p-1,	 0x1.be00p-47,
-	0x1.c2d1cd9fa64eep-1,	-0x1.9400p-47,
-	0x1.c40ab5fffd02fp-1,	-0x1.ed00p-47,
-	0x1.c544778fafd15p-1,	 0x1.9660p-44,
-	0x1.c67f12e57d0cbp-1,	-0x1.a100p-46,
-	0x1.c7ba88988c1b6p-1,	-0x1.8458p-42,
-	0x1.c8f6d9406e733p-1,	-0x1.a480p-46,
-	0x1.ca3405751c4dfp-1,	 0x1.b000p-51,
-	0x1.cb720dcef9094p-1,	 0x1.1400p-47,
-	0x1.ccb0f2e6d1689p-1,	 0x1.0200p-48,
-	0x1.cdf0b555dc412p-1,	 0x1.3600p-48,
-	0x1.cf3155b5bab3bp-1,	-0x1.6900p-47,
-	0x1.d072d4a0789bcp-1,	 0x1.9a00p-47,
-	0x1.d1b532b08c8fap-1,	-0x1.5e00p-46,
-	0x1.d2f87080d8a85p-1,	 0x1.d280p-46,
-	0x1.d43c8eacaa203p-1,	 0x1.1a00p-47,
-	0x1.d5818dcfba491p-1,	 0x1.f000p-50,
-	0x1.d6c76e862e6a1p-1,	-0x1.3a00p-47,
-	0x1.d80e316c9834ep-1,	-0x1.cd80p-47,
-	0x1.d955d71ff6090p-1,	 0x1.4c00p-48,
-	0x1.da9e603db32aep-1,	 0x1.f900p-48,
-	0x1.dbe7cd63a8325p-1,	 0x1.9800p-49,
-	0x1.dd321f301b445p-1,	-0x1.5200p-48,
-	0x1.de7d5641c05bfp-1,	-0x1.d700p-46,
-	0x1.dfc97337b9aecp-1,	-0x1.6140p-46,
-	0x1.e11676b197d5ep-1,	 0x1.b480p-47,
-	0x1.e264614f5a3e7p-1,	 0x1.0ce0p-43,
-	0x1.e3b333b16ee5cp-1,	 0x1.c680p-47,
-	0x1.e502ee78b3fb4p-1,	-0x1.9300p-47,
-	0x1.e653924676d68p-1,	-0x1.5000p-49,
-	0x1.e7a51fbc74c44p-1,	-0x1.7f80p-47,
-	0x1.e8f7977cdb726p-1,	-0x1.3700p-48,
-	0x1.ea4afa2a490e8p-1,	 0x1.5d00p-49,
-	0x1.eb9f4867ccae4p-1,	 0x1.61a0p-46,
-	0x1.ecf482d8e680dp-1,	 0x1.5500p-48,
-	0x1.ee4aaa2188514p-1,	 0x1.6400p-51,
-	0x1.efa1bee615a13p-1,	-0x1.e800p-49,
-	0x1.f0f9c1cb64106p-1,	-0x1.a880p-48,
-	0x1.f252b376bb963p-1,	-0x1.c900p-45,
-	0x1.f3ac948dd7275p-1,	 0x1.a000p-53,
-	0x1.f50765b6e4524p-1,	-0x1.4f00p-48,
-	0x1.f6632798844fdp-1,	 0x1.a800p-51,
-	0x1.f7bfdad9cbe38p-1,	 0x1.abc0p-48,
-	0x1.f91d802243c82p-1,	-0x1.4600p-50,
-	0x1.fa7c1819e908ep-1,	-0x1.b0c0p-47,
-	0x1.fbdba3692d511p-1,	-0x1.0e00p-51,
-	0x1.fd3c22b8f7194p-1,	-0x1.0de8p-46,
-	0x1.fe9d96b2a23eep-1,	 0x1.e430p-49,
-	0x1.0000000000000p+0,	 0x0.0000p+0,
-	0x1.00b1afa5abcbep+0,	-0x1.3400p-52,
-	0x1.0163da9fb3303p+0,	-0x1.2170p-46,
-	0x1.02168143b0282p+0,	 0x1.a400p-52,
-	0x1.02c9a3e77806cp+0,	 0x1.f980p-49,
-	0x1.037d42e11bbcap+0,	-0x1.7400p-51,
-	0x1.04315e86e7f89p+0,	 0x1.8300p-50,
-	0x1.04e5f72f65467p+0,	-0x1.a3f0p-46,
-	0x1.059b0d315855ap+0,	-0x1.2840p-47,
-	0x1.0650a0e3c1f95p+0,	 0x1.1600p-48,
-	0x1.0706b29ddf71ap+0,	 0x1.5240p-46,
-	0x1.07bd42b72a82dp+0,	-0x1.9a00p-49,
-	0x1.0874518759bd0p+0,	 0x1.6400p-49,
-	0x1.092bdf66607c8p+0,	-0x1.0780p-47,
-	0x1.09e3ecac6f383p+0,	-0x1.8000p-54,
-	0x1.0a9c79b1f3930p+0,	 0x1.fa00p-48,
-	0x1.0b5586cf988fcp+0,	-0x1.ac80p-48,
-	0x1.0c0f145e46c8ap+0,	 0x1.9c00p-50,
-	0x1.0cc922b724816p+0,	 0x1.5200p-47,
-	0x1.0d83b23395dd8p+0,	-0x1.ad00p-48,
-	0x1.0e3ec32d3d1f3p+0,	 0x1.bac0p-46,
-	0x1.0efa55fdfa9a6p+0,	-0x1.4e80p-47,
-	0x1.0fb66affed2f0p+0,	-0x1.d300p-47,
-	0x1.1073028d7234bp+0,	 0x1.1500p-48,
-	0x1.11301d0125b5bp+0,	 0x1.c000p-49,
-	0x1.11edbab5e2af9p+0,	 0x1.6bc0p-46,
-	0x1.12abdc06c31d5p+0,	 0x1.8400p-49,
-	0x1.136a814f2047dp+0,	-0x1.ed00p-47,
-	0x1.1429aaea92de9p+0,	 0x1.8e00p-49,
-	0x1.14e95934f3138p+0,	 0x1.b400p-49,
-	0x1.15a98c8a58e71p+0,	 0x1.5300p-47,
-	0x1.166a45471c3dfp+0,	 0x1.3380p-47,
-	0x1.172b83c7d5211p+0,	 0x1.8d40p-45,
-	0x1.17ed48695bb9fp+0,	-0x1.5d00p-47,
-	0x1.18af9388c8d93p+0,	-0x1.c880p-46,
-	0x1.1972658375d66p+0,	 0x1.1f00p-46,
-	0x1.1a35beb6fcba7p+0,	 0x1.0480p-46,
-	0x1.1af99f81387e3p+0,	-0x1.7390p-43,
-	0x1.1bbe084045d54p+0,	 0x1.4e40p-45,
-	0x1.1c82f95281c43p+0,	-0x1.a200p-47,
-	0x1.1d4873168b9b2p+0,	 0x1.3800p-49,
-	0x1.1e0e75eb44031p+0,	 0x1.ac00p-49,
-	0x1.1ed5022fcd938p+0,	 0x1.1900p-47,
-	0x1.1f9c18438cdf7p+0,	-0x1.b780p-46,
-	0x1.2063b88628d8fp+0,	 0x1.d940p-45,
-	0x1.212be3578a81ep+0,	 0x1.8000p-50,
-	0x1.21f49917ddd41p+0,	 0x1.b340p-45,
-	0x1.22bdda2791323p+0,	 0x1.9f80p-46,
-	0x1.2387a6e7561e7p+0,	-0x1.9c80p-46,
-	0x1.2451ffb821427p+0,	 0x1.2300p-47,
-	0x1.251ce4fb2a602p+0,	-0x1.3480p-46,
-	0x1.25e85711eceb0p+0,	 0x1.2700p-46,
-	0x1.26b4565e27d16p+0,	 0x1.1d00p-46,
-	0x1.2780e341de00fp+0,	 0x1.1ee0p-44,
-	0x1.284dfe1f5633ep+0,	-0x1.4c00p-46,
-	0x1.291ba7591bb30p+0,	-0x1.3d80p-46,
-	0x1.29e9df51fdf09p+0,	 0x1.8b00p-47,
-	0x1.2ab8a66d10e9bp+0,	-0x1.27c0p-45,
-	0x1.2b87fd0dada3ap+0,	 0x1.a340p-45,
-	0x1.2c57e39771af9p+0,	-0x1.0800p-46,
-	0x1.2d285a6e402d9p+0,	-0x1.ed00p-47,
-	0x1.2df961f641579p+0,	-0x1.4200p-48,
-	0x1.2ecafa93e2ecfp+0,	-0x1.4980p-45,
-	0x1.2f9d24abd8822p+0,	-0x1.6300p-46,
-	0x1.306fe0a31b625p+0,	-0x1.2360p-44,
-	0x1.31432edeea50bp+0,	-0x1.0df8p-40,
-	0x1.32170fc4cd7b8p+0,	-0x1.2480p-45,
-	0x1.32eb83ba8e9a2p+0,	-0x1.5980p-45,
-	0x1.33c08b2641766p+0,	 0x1.ed00p-46,
-	0x1.3496266e3fa27p+0,	-0x1.c000p-50,
-	0x1.356c55f929f0fp+0,	-0x1.0d80p-44,
-	0x1.36431a2de88b9p+0,	 0x1.2c80p-45,
-	0x1.371a7373aaa39p+0,	 0x1.0600p-45,
-	0x1.37f26231e74fep+0,	-0x1.6600p-46,
-	0x1.38cae6d05d838p+0,	-0x1.ae00p-47,
-	0x1.39a401b713ec3p+0,	-0x1.4720p-43,
-	0x1.3a7db34e5a020p+0,	 0x1.8200p-47,
-	0x1.3b57fbfec6e95p+0,	 0x1.e800p-44,
-	0x1.3c32dc313a8f2p+0,	 0x1.f800p-49,
-	0x1.3d0e544ede122p+0,	-0x1.7a00p-46,
-	0x1.3dea64c1234bbp+0,	 0x1.6300p-45,
-	0x1.3ec70df1c4eccp+0,	-0x1.8a60p-43,
-	0x1.3fa4504ac7e8cp+0,	-0x1.cdc0p-44,
-	0x1.40822c367a0bbp+0,	 0x1.5b80p-45,
-	0x1.4160a21f72e95p+0,	 0x1.ec00p-46,
-	0x1.423fb27094646p+0,	-0x1.3600p-46,
-	0x1.431f5d950a920p+0,	 0x1.3980p-45,
-	0x1.43ffa3f84b9ebp+0,	 0x1.a000p-48,
-	0x1.44e0860618919p+0,	-0x1.6c00p-48,
-	0x1.45c2042a7d201p+0,	-0x1.bc00p-47,
-	0x1.46a41ed1d0016p+0,	-0x1.2800p-46,
-	0x1.4786d668b3326p+0,	 0x1.0e00p-44,
-	0x1.486a2b5c13c00p+0,	-0x1.d400p-45,
-	0x1.494e1e192af04p+0,	 0x1.c200p-47,
-	0x1.4a32af0d7d372p+0,	-0x1.e500p-46,
-	0x1.4b17dea6db801p+0,	 0x1.7800p-47,
-	0x1.4bfdad53629e1p+0,	-0x1.3800p-46,
-	0x1.4ce41b817c132p+0,	 0x1.0800p-47,
-	0x1.4dcb299fddddbp+0,	 0x1.c700p-45,
-	0x1.4eb2d81d8ab96p+0,	-0x1.ce00p-46,
-	0x1.4f9b2769d2d02p+0,	 0x1.9200p-46,
-	0x1.508417f4531c1p+0,	-0x1.8c00p-47,
-	0x1.516daa2cf662ap+0,	-0x1.a000p-48,
-	0x1.5257de83f51eap+0,	 0x1.a080p-43,
-	0x1.5342b569d4edap+0,	-0x1.6d80p-45,
-	0x1.542e2f4f6ac1ap+0,	-0x1.2440p-44,
-	0x1.551a4ca5d94dbp+0,	 0x1.83c0p-43,
-	0x1.56070dde9116bp+0,	 0x1.4b00p-45,
-	0x1.56f4736b529dep+0,	 0x1.15a0p-43,
-	0x1.57e27dbe2c40ep+0,	-0x1.9e00p-45,
-	0x1.58d12d497c76fp+0,	-0x1.3080p-45,
-	0x1.59c0827ff0b4cp+0,	 0x1.dec0p-43,
-	0x1.5ab07dd485427p+0,	-0x1.4000p-51,
-	0x1.5ba11fba87af4p+0,	 0x1.0080p-44,
-	0x1.5c9268a59460bp+0,	-0x1.6c80p-45,
-	0x1.5d84590998e3fp+0,	 0x1.69a0p-43,
-	0x1.5e76f15ad20e1p+0,	-0x1.b400p-46,
-	0x1.5f6a320dcebcap+0,	 0x1.7700p-46,
-	0x1.605e1b976dcb8p+0,	 0x1.6f80p-45,
-	0x1.6152ae6cdf715p+0,	 0x1.1000p-47,
-	0x1.6247eb03a5531p+0,	-0x1.5d00p-46,
-	0x1.633dd1d1929b5p+0,	-0x1.2d00p-46,
-	0x1.6434634ccc313p+0,	-0x1.a800p-49,
-	0x1.652b9febc8efap+0,	-0x1.8600p-45,
-	0x1.6623882553397p+0,	 0x1.1fe0p-40,
-	0x1.671c1c708328ep+0,	-0x1.7200p-44,
-	0x1.68155d44ca97ep+0,	 0x1.6800p-49,
-	0x1.690f4b19e9471p+0,	-0x1.9780p-45,
-};
-
-/*
- * exp2(x): compute the base 2 exponential of x
- *
- * Accuracy: Peak error < 0.503 ulp for normalized results.
- *
- * Method: (accurate tables)
- *
- *   Reduce x:
- *     x = 2**k + y, for integer k and |y| <= 1/2.
- *     Thus we have exp2(x) = 2**k * exp2(y).
- *
- *   Reduce y:
- *     y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE.
- *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]),
- *     with |z - eps[i]| <= 2**-9 + 2**-39 for the table used.
- *
- *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via
- *   a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61.
- *   The values in exp2t[] and eps[] are chosen such that
- *   exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such
- *   that exp2t[i] is accurate to 2**-64.
- *
- *   Note that the range of i is +-TBLSIZE/2, so we actually index the tables
- *   by i0 = i + TBLSIZE/2.  For cache efficiency, exp2t[] and eps[] are
- *   virtual tables, interleaved in the real table tbl[].
- *
- *   This method is due to Gal, with many details due to Gal and Bachelis:
- *
- *	Gal, S. and Bachelis, B.  An Accurate Elementary Mathematical Library
- *	for the IEEE Floating Point Standard.  TOMS 17(1), 26-46 (1991).
- */
-double
-exp2(double x)
-{
-	double r, t, twopk, twopkp1000, z;
-	uint32_t hx, ix, lx, i0;
-	int k;
-
-	/* Filter out exceptional cases. */
-	GET_HIGH_WORD(hx,x);
-	ix = hx & 0x7fffffff;		/* high word of |x| */
-	if(ix >= 0x40900000) {			/* |x| >= 1024 */
-		if(ix >= 0x7ff00000) {
-			GET_LOW_WORD(lx,x);
-			if(((ix & 0xfffff) | lx) != 0 || (hx & 0x80000000) == 0)
-				return (x + x);	/* x is NaN or +Inf */
-			else 
-				return (0.0);	/* x is -Inf */
-		}
-		if(x >= 0x1.0p10)
-			return (huge * huge); /* overflow */
-		if(x <= -0x1.0ccp10)
-			return (twom1000 * twom1000); /* underflow */
-	} else if (ix < 0x3c900000) {		/* |x| < 0x1p-54 */
-		return (1.0 + x);
-	}
-
-	/* Reduce x, computing z, i0, and k. */
-	STRICT_ASSIGN(double, t, x + redux);
-	GET_LOW_WORD(i0, t);
-	i0 += TBLSIZE / 2;
-	k = (i0 >> TBLBITS) << 20;
-	i0 = (i0 & (TBLSIZE - 1)) << 1;
-	t -= redux;
-	z = x - t;
-
-	/* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
-	t = tbl[i0];		/* exp2t[i0] */
-	z -= tbl[i0 + 1];	/* eps[i0]   */
-	if (k >= -(1021 << 20))
-		INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
-	else
-		INSERT_WORDS(twopkp1000, 0x3ff00000 + k + (1000 << 20), 0);
-	r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
-
-	/* Scale by 2**(k>>20). */
-	if(k >= -(1021 << 20)) {
-		if (k == 1024 << 20)
-			return (r * 2.0 * 0x1p1023);
-		return (r * twopk);
-	} else {
-		return (r * twopkp1000 * twom1000);
-	}
-}
-
-#if (LDBL_MANT_DIG == 53)
-__weak_reference(exp2, exp2l);
-#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2f.c b/libm/upstream-freebsd/lib/msun/src/s_exp2f.c
deleted file mode 100644
index c5b4c8e..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_exp2f.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#include "math_private.h"
-
-#define	TBLBITS	4
-#define	TBLSIZE	(1 << TBLBITS)
-
-static const float
-    redux   = 0x1.8p23f / TBLSIZE,
-    P1	    = 0x1.62e430p-1f,
-    P2	    = 0x1.ebfbe0p-3f,
-    P3	    = 0x1.c6b348p-5f,
-    P4	    = 0x1.3b2c9cp-7f;
-
-static volatile float
-    huge    = 0x1p100f,
-    twom100 = 0x1p-100f;
-
-static const double exp2ft[TBLSIZE] = {
-	0x1.6a09e667f3bcdp-1,
-	0x1.7a11473eb0187p-1,
-	0x1.8ace5422aa0dbp-1,
-	0x1.9c49182a3f090p-1,
-	0x1.ae89f995ad3adp-1,
-	0x1.c199bdd85529cp-1,
-	0x1.d5818dcfba487p-1,
-	0x1.ea4afa2a490dap-1,
-	0x1.0000000000000p+0,
-	0x1.0b5586cf9890fp+0,
-	0x1.172b83c7d517bp+0,
-	0x1.2387a6e756238p+0,
-	0x1.306fe0a31b715p+0,
-	0x1.3dea64c123422p+0,
-	0x1.4bfdad5362a27p+0,
-	0x1.5ab07dd485429p+0,
-};
-	
-/*
- * exp2f(x): compute the base 2 exponential of x
- *
- * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927.
- *
- * Method: (equally-spaced tables)
- *
- *   Reduce x:
- *     x = 2**k + y, for integer k and |y| <= 1/2.
- *     Thus we have exp2f(x) = 2**k * exp2(y).
- *
- *   Reduce y:
- *     y = i/TBLSIZE + z for integer i near y * TBLSIZE.
- *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
- *     with |z| <= 2**-(TBLSIZE+1).
- *
- *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
- *   degree-4 minimax polynomial with maximum error under 1.4 * 2**-33.
- *   Using double precision for everything except the reduction makes
- *   roundoff error insignificant and simplifies the scaling step.
- *
- *   This method is due to Tang, but I do not use his suggested parameters:
- *
- *	Tang, P.  Table-driven Implementation of the Exponential Function
- *	in IEEE Floating-Point Arithmetic.  TOMS 15(2), 144-157 (1989).
- */
-float
-exp2f(float x)
-{
-	double tv, twopk, u, z;
-	float t;
-	uint32_t hx, ix, i0;
-	int32_t k;
-
-	/* Filter out exceptional cases. */
-	GET_FLOAT_WORD(hx, x);
-	ix = hx & 0x7fffffff;		/* high word of |x| */
-	if(ix >= 0x43000000) {			/* |x| >= 128 */
-		if(ix >= 0x7f800000) {
-			if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0)
-				return (x + x);	/* x is NaN or +Inf */
-			else 
-				return (0.0);	/* x is -Inf */
-		}
-		if(x >= 0x1.0p7f)
-			return (huge * huge);	/* overflow */
-		if(x <= -0x1.2cp7f)
-			return (twom100 * twom100); /* underflow */
-	} else if (ix <= 0x33000000) {		/* |x| <= 0x1p-25 */
-		return (1.0f + x);
-	}
-
-	/* Reduce x, computing z, i0, and k. */
-	STRICT_ASSIGN(float, t, x + redux);
-	GET_FLOAT_WORD(i0, t);
-	i0 += TBLSIZE / 2;
-	k = (i0 >> TBLBITS) << 20;
-	i0 &= TBLSIZE - 1;
-	t -= redux;
-	z = x - t;
-	INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
-
-	/* Compute r = exp2(y) = exp2ft[i0] * p(z). */
-	tv = exp2ft[i0];
-	u = tv * z;
-	tv = tv + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4);
-
-	/* Scale by 2**(k>>20). */
-	return (tv * twopk);
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fabsl.c b/libm/upstream-freebsd/lib/msun/src/s_fabsl.c
deleted file mode 100644
index 5076d8a..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_fabsl.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2003 Dag-Erling Smørgrav
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer
- *    in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <math.h>
-
-#include "fpmath.h"
-
-long double
-fabsl(long double x)
-{
-	union IEEEl2bits u;
-
-	u.e = x;
-	u.bits.sign = 0;
-	return (u.e);
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_sincosf.c b/libm/upstream-freebsd/lib/msun/src/s_sincosf.c
deleted file mode 100644
index 755ff05..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_sincosf.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*-
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-/* s_sincosf.c -- float version of s_sincos.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- * Optimized by Bruce D. Evans.
- * Merged s_sinf.c and s_cosf.c by Steven G. Kargl.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#define INLINE_REM_PIO2F
-#include "math_private.h"
-#include "e_rem_pio2f.c"
-#include "k_sincosf.h"
-
-/* Small multiples of pi/2 rounded to double precision. */
-static const double
-p1pio2 = 1*M_PI_2,			/* 0x3FF921FB, 0x54442D18 */
-p2pio2 = 2*M_PI_2,			/* 0x400921FB, 0x54442D18 */
-p3pio2 = 3*M_PI_2,			/* 0x4012D97C, 0x7F3321D2 */
-p4pio2 = 4*M_PI_2;			/* 0x401921FB, 0x54442D18 */
-
-void
-sincosf(float x, float *sn, float *cs)
-{
-	float c, s;
-	double y;
-	int32_t n, hx, ix;
-
-	GET_FLOAT_WORD(hx, x);
-	ix = hx & 0x7fffffff;
-
-	if (ix <= 0x3f490fda) {		/* |x| ~<= pi/4 */
-		if (ix < 0x39800000) {	/* |x| < 2**-12 */
-			if ((int)x == 0) {
-				*sn = x;	/* x with inexact if x != 0 */
-				*cs = 1;
-				return;
-			}
-		}
-		__kernel_sincosdf(x, sn, cs);
-		return;
-	}
-
-	if (ix <= 0x407b53d1) {		/* |x| ~<= 5*pi/4 */
-		if (ix <= 0x4016cbe3) {	/* |x| ~<= 3pi/4 */
-			if (hx > 0) {
-				__kernel_sincosdf(x - p1pio2, cs, sn);
-				*cs = -*cs;
-			} else {
-				__kernel_sincosdf(x + p1pio2, cs, sn);
-				*sn = -*sn;
-			}
-		} else {
-			if (hx > 0)
-				__kernel_sincosdf(x - p2pio2, sn, cs);
-			else
-				__kernel_sincosdf(x + p2pio2, sn, cs);
-			*sn = -*sn;
-			*cs = -*cs;
-		}
-		return;
-	}
-
-	if (ix <= 0x40e231d5) {		/* |x| ~<= 9*pi/4 */
-		if (ix <= 0x40afeddf) {	/* |x| ~<= 7*pi/4 */
-			if (hx > 0) {
-				__kernel_sincosdf(x - p3pio2, cs, sn);
-				*sn = -*sn;
-			} else {
-				__kernel_sincosdf(x + p3pio2, cs, sn);
-				*cs = -*cs;
-			}
-		} else {
-			if (hx > 0)
-				__kernel_sincosdf(x - p4pio2, sn, cs);
-			else
-				__kernel_sincosdf(x + p4pio2, sn, cs);
-		}
-		return;
-	}
-
-	/* If x = Inf or NaN, then sin(x) = NaN and cos(x) = NaN. */
-	if (ix >= 0x7f800000) {
-		*sn = x - x;
-		*cs = x - x;
-		return;
-	}
-
-	/* Argument reduction. */
-	n = __ieee754_rem_pio2f(x, &y);
-	__kernel_sincosdf(y, &s, &c);
-
-	switch(n & 3) {
-	case 0:
-		*sn = s;
-		*cs = c;
-		break;
-	case 1:
-		*sn = c;
-		*cs = -s;
-		break;
-	case 2:
-		*sn = -s;
-		*cs = -c;
-		break;
-	default:
-		*sn = -c;
-		*cs = s;
-	}
-}
-
-
diff --git a/libm/upstream-freebsd/lib/msun/src/s_sinf.c b/libm/upstream-freebsd/lib/msun/src/s_sinf.c
deleted file mode 100644
index 41b5dc1..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_sinf.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* s_sinf.c -- float version of s_sin.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- * Optimized by Bruce D. Evans.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <float.h>
-
-#include "math.h"
-#define	INLINE_KERNEL_COSDF
-#define	INLINE_KERNEL_SINDF
-#define INLINE_REM_PIO2F
-#include "math_private.h"
-#include "e_rem_pio2f.c"
-#include "k_cosf.c"
-#include "k_sinf.c"
-
-/* Small multiples of pi/2 rounded to double precision. */
-static const double
-s1pio2 = 1*M_PI_2,			/* 0x3FF921FB, 0x54442D18 */
-s2pio2 = 2*M_PI_2,			/* 0x400921FB, 0x54442D18 */
-s3pio2 = 3*M_PI_2,			/* 0x4012D97C, 0x7F3321D2 */
-s4pio2 = 4*M_PI_2;			/* 0x401921FB, 0x54442D18 */
-
-float
-sinf(float x)
-{
-	double y;
-	int32_t n, hx, ix;
-
-	GET_FLOAT_WORD(hx,x);
-	ix = hx & 0x7fffffff;
-
-	if(ix <= 0x3f490fda) {		/* |x| ~<= pi/4 */
-	    if(ix<0x39800000)		/* |x| < 2**-12 */
-		if(((int)x)==0) return x;	/* x with inexact if x != 0 */
-	    return __kernel_sindf(x);
-	}
-	if(ix<=0x407b53d1) {		/* |x| ~<= 5*pi/4 */
-	    if(ix<=0x4016cbe3) {	/* |x| ~<= 3pi/4 */
-		if(hx>0)
-		    return __kernel_cosdf(x - s1pio2);
-		else
-		    return -__kernel_cosdf(x + s1pio2);
-	    } else
-		return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x);
-	}
-	if(ix<=0x40e231d5) {		/* |x| ~<= 9*pi/4 */
-	    if(ix<=0x40afeddf) {	/* |x| ~<= 7*pi/4 */
-		if(hx>0)
-		    return -__kernel_cosdf(x - s3pio2);
-		else
-		    return __kernel_cosdf(x + s3pio2);
-	    } else
-		return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2));
-	}
-
-    /* sin(Inf or NaN) is NaN */
-	else if (ix>=0x7f800000) return x-x;
-
-    /* general argument reduction needed */
-	else {
-	    n = __ieee754_rem_pio2f(x,&y);
-	    switch(n&3) {
-		case 0: return  __kernel_sindf(y);
-		case 1: return  __kernel_cosdf(y);
-		case 2: return  __kernel_sindf(-y);
-		default:
-			return -__kernel_cosdf(y);
-	    }
-	}
-}
diff --git a/linker/Android.bp b/linker/Android.bp
index da57f7a..d82e687 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -14,6 +14,16 @@
     ],
 }
 
+linker_common_flags = [
+    "-fno-stack-protector",
+    "-Wstrict-overflow=5",
+    "-fvisibility=hidden",
+    "-Wall",
+    "-Wextra",
+    "-Wunused",
+    "-Werror",
+]
+
 // ========================================================
 // linker_wrapper - Linux Bionic (on the host)
 // ========================================================
@@ -36,15 +46,7 @@
         },
     },
 
-    cflags: [
-        "-fno-stack-protector",
-        "-Wstrict-overflow=5",
-        "-fvisibility=hidden",
-        "-Wall",
-        "-Wextra",
-        "-Wno-unused",
-        "-Werror",
-    ],
+    cflags: linker_common_flags,
 
     srcs: [
         "linker_wrapper.cpp",
@@ -83,26 +85,8 @@
         },
     },
 
-    cflags: [
-        "-fno-stack-protector",
-        "-Wstrict-overflow=5",
-        "-fvisibility=hidden",
-        "-Wall",
-        "-Wextra",
-        "-Wunused",
-        "-Werror",
-    ],
-
-    // TODO: split out the asflags.
-    asflags: [
-        "-fno-stack-protector",
-        "-Wstrict-overflow=5",
-        "-fvisibility=hidden",
-        "-Wall",
-        "-Wextra",
-        "-Wunused",
-        "-Werror",
-    ],
+    cflags: linker_common_flags,
+    asflags: linker_common_flags,
 
     product_variables: {
         debuggable: {
@@ -273,57 +257,28 @@
 // A template for the linker binary. May be inherited by native bridge implementations.
 cc_defaults {
     name: "linker_bin_template",
-    defaults: ["linker_defaults"],
+    defaults: [
+        "linker_defaults",
+        "keep_symbols",
+    ],
 
     srcs: [":linker_sources"],
 
     arch: {
         arm: {
             srcs: [":linker_sources_arm"],
-
-            // Arm 32 bit does not produce complete exidx unwind information
-            // so keep the .debug_frame which is relatively small and does
-            // include needed unwind information.
-            // See b/242162222 for details.
-            strip: {
-                keep_symbols_and_debug_frame: true,
-            },
         },
         arm64: {
             srcs: [":linker_sources_arm64"],
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         riscv64: {
             srcs: [":linker_sources_riscv64"],
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         x86: {
             srcs: [":linker_sources_x86"],
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
         x86_64: {
             srcs: [":linker_sources_x86_64"],
-
-            // Leave the symbols in the shared library so that stack unwinders can produce
-            // meaningful name resolution.
-            strip: {
-                keep_symbols: true,
-            },
         },
     },
 
@@ -360,6 +315,7 @@
 
     sanitize: {
         hwaddress: false,
+        memtag_stack: false,
     },
 
     static_libs: [
@@ -438,6 +394,10 @@
     },
 
     afdo: true,
+
+    // FIXME: Workaround compat issue with obfuscation libraries.
+    // http://b/352456802
+    lto_O0: true,
 }
 
 // ========================================================
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8b467a3..e13d37d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3595,7 +3595,7 @@
   // 2. Initialize other namespaces
 
   for (auto& ns_config : namespace_configs) {
-    if (namespaces.find(ns_config->name()) != namespaces.end()) {
+    if (namespaces.contains(ns_config->name())) {
       continue;
     }
 
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index ad40c50..70430b8 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -304,7 +304,7 @@
     }
 
     if (result == ConfigParser::kPropertyAssign) {
-      if (properties->find(name) != properties->end()) {
+      if (properties->contains(name)) {
         DL_WARN("%s:%zd: warning: redefining property \"%s\" (overriding previous value)",
                 ld_config_file_path,
                 cp.lineno(),
@@ -313,7 +313,7 @@
 
       (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
     } else if (result == ConfigParser::kPropertyAppend) {
-      if (properties->find(name) == properties->end()) {
+      if (!properties->contains(name)) {
         DL_WARN("%s:%zd: warning: appending to undefined property \"%s\" (treating as assignment)",
                 ld_config_file_path,
                 cp.lineno(),
@@ -526,7 +526,7 @@
         properties.get_strings(property_name_prefix + ".links", &lineno);
 
     for (const auto& linked_ns_name : linked_namespaces) {
-      if (namespace_configs.find(linked_ns_name) == namespace_configs.end()) {
+      if (!namespace_configs.contains(linked_ns_name)) {
         *error_msg = create_error_msg(ld_config_file_path,
                                       lineno,
                                       std::string("undefined namespace: ") + linked_ns_name);
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 5182129..eb9dae9 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -100,7 +100,7 @@
     // be searched.
     if (allow_secondary) {
       const android_namespace_list_t& secondary_namespaces = si->get_secondary_namespaces();
-      if (secondary_namespaces.find(this) != secondary_namespaces.end()) {
+      if (secondary_namespaces.contains(this)) {
         return true;
       }
     }
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 802c06a..d915503 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -887,7 +887,7 @@
     handle_ = handle_ | 1;
   } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
            handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
-           g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end());
+           g_soinfo_handles_map.contains(handle_));
 
   g_soinfo_handles_map[handle_] = this;
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index 9f64393..d2a3110 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -361,8 +361,7 @@
 cc_test_library {
     name: "clang_diagnostic_tests",
     cflags: [
-        "-Xclang",
-        "-verify",
+        "-Xclang -verify",
     ],
     srcs: ["sys_ioctl_diag_test.cpp"],
 }
@@ -404,6 +403,7 @@
         "_FILE_OFFSET_BITS_test.cpp",
         "float_test.cpp",
         "fnmatch_test.cpp",
+        "fts_test.cpp",
         "ftw_test.cpp",
         "getauxval_test.cpp",
         "getcwd_test.cpp",
diff --git a/tests/ctype_test.cpp b/tests/ctype_test.cpp
index 826d39a..18fbfc0 100644
--- a/tests/ctype_test.cpp
+++ b/tests/ctype_test.cpp
@@ -293,40 +293,57 @@
 }
 
 TEST(ctype, toascii) {
-  EXPECT_EQ('a', toascii('a'));
-  EXPECT_EQ('a', toascii(0x80 | 'a'));
+  // POSIX explicitly says that toascii() returns (c & 0x7f),
+  // so there's no EOF-preserving behavior here and we start from 0.
+  for (int i = 0; i < kMax; ++i) {
+    if (i <= 0x7f) {
+      EXPECT_EQ(i, toascii(i));
+    } else {
+      EXPECT_EQ(i & 0x7f, toascii(i));
+    }
+  }
 }
 
 TEST(ctype, tolower) {
   EXPECT_EQ('!', tolower('!'));
   EXPECT_EQ('a', tolower('a'));
   EXPECT_EQ('a', tolower('A'));
+  EXPECT_EQ('z', tolower('z'));
+  EXPECT_EQ('z', tolower('Z'));
 }
 
 TEST(ctype, tolower_l) {
   EXPECT_EQ('!', tolower_l('!', LC_GLOBAL_LOCALE));
   EXPECT_EQ('a', tolower_l('a', LC_GLOBAL_LOCALE));
   EXPECT_EQ('a', tolower_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('z', tolower_l('z', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('z', tolower_l('Z', LC_GLOBAL_LOCALE));
 }
 
 TEST(ctype, _tolower) {
   // _tolower may mangle characters for which isupper is false.
   EXPECT_EQ('a', _tolower('A'));
+  EXPECT_EQ('z', _tolower('Z'));
 }
 
 TEST(ctype, toupper) {
   EXPECT_EQ('!', toupper('!'));
   EXPECT_EQ('A', toupper('a'));
   EXPECT_EQ('A', toupper('A'));
+  EXPECT_EQ('Z', toupper('z'));
+  EXPECT_EQ('Z', toupper('Z'));
 }
 
 TEST(ctype, toupper_l) {
   EXPECT_EQ('!', toupper_l('!', LC_GLOBAL_LOCALE));
   EXPECT_EQ('A', toupper_l('a', LC_GLOBAL_LOCALE));
   EXPECT_EQ('A', toupper_l('A', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('Z', toupper_l('z', LC_GLOBAL_LOCALE));
+  EXPECT_EQ('Z', toupper_l('Z', LC_GLOBAL_LOCALE));
 }
 
 TEST(ctype, _toupper) {
   // _toupper may mangle characters for which islower is false.
   EXPECT_EQ('A', _toupper('a'));
+  EXPECT_EQ('Z', _toupper('z'));
 }
diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp
index 4d21246..cde2d11 100644
--- a/tests/dirent_test.cpp
+++ b/tests/dirent_test.cpp
@@ -33,11 +33,11 @@
 
 static void CheckProcSelf(std::set<std::string>& names) {
   // We have a good idea of what should be in /proc/self.
-  ASSERT_TRUE(names.find(".") != names.end());
-  ASSERT_TRUE(names.find("..") != names.end());
-  ASSERT_TRUE(names.find("cmdline") != names.end());
-  ASSERT_TRUE(names.find("fd") != names.end());
-  ASSERT_TRUE(names.find("stat") != names.end());
+  ASSERT_TRUE(names.contains("."));
+  ASSERT_TRUE(names.contains(".."));
+  ASSERT_TRUE(names.contains("cmdline"));
+  ASSERT_TRUE(names.contains("fd"));
+  ASSERT_TRUE(names.contains("stat"));
 }
 
 template <typename DirEntT>
diff --git a/tests/fts_test.cpp b/tests/fts_test.cpp
new file mode 100644
index 0000000..39e570b
--- /dev/null
+++ b/tests/fts_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 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 <gtest/gtest.h>
+
+#if !defined(__GLIBC__)
+#include <fts.h>
+#endif
+
+TEST(fts, smoke) {
+#if !defined(__GLIBC__)
+  char* const paths[] = { const_cast<char*>("."), NULL };
+  FTS* fts = fts_open(paths, FTS_PHYSICAL, NULL);
+  ASSERT_TRUE(fts != NULL);
+  FTSENT* e;
+  while ((e = fts_read(fts)) != NULL) {
+    ASSERT_EQ(0, fts_set(fts, e, FTS_SKIP));
+  }
+  ASSERT_EQ(0, fts_close(fts));
+#else
+  GTEST_SKIP() << "no _FILE_OFFSET_BITS=64 <fts.h> in our old glibc";
+#endif
+}
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index b3ab94d..da64770 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -137,7 +137,7 @@
   sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
   in_addr_t addr = sock->sin_addr.s_addr;
 
-  EXPECT_TRUE(addrs.find(addr) != addrs.end()) << if_name << ' ' << std::hex << ntohl(addr);
+  EXPECT_TRUE(addrs.contains(addr)) << if_name << ' ' << std::hex << ntohl(addr);
 }
 
 TEST(ifaddrs, getifaddrs_INET) {
diff --git a/tests/libs/testbinary_is_stack_mte.cpp b/tests/libs/testbinary_is_stack_mte.cpp
index d8074d5..0cdc466 100644
--- a/tests/libs/testbinary_is_stack_mte.cpp
+++ b/tests/libs/testbinary_is_stack_mte.cpp
@@ -36,7 +36,9 @@
 #if defined(__BIONIC__) && defined(__aarch64__)
 
 extern "C" int main(int, char**) {
-  int ret = is_stack_mte_on() ? 0 : 1;
+  void* mte_tls_ptr = mte_tls();
+  *reinterpret_cast<uintptr_t*>(mte_tls_ptr) = 1;
+  int ret = is_stack_mte_on() && mte_tls_ptr != nullptr ? 0 : 1;
   printf("RAN\n");
   return ret;
 }
diff --git a/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp b/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp
index 937ac4c..35af8f4 100644
--- a/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp
+++ b/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp
@@ -96,6 +96,7 @@
   State state = kInit;
 
   bool is_early_thread_mte_on = false;
+  void* early_thread_mte_tls = nullptr;
   std::thread early_th([&] {
     {
       std::lock_guard lk(m);
@@ -107,6 +108,8 @@
       cv.wait(lk, [&] { return state == kStackRemapped; });
     }
     is_early_thread_mte_on = is_stack_mte_on();
+    early_thread_mte_tls = mte_tls();
+    *reinterpret_cast<uintptr_t*>(early_thread_mte_tls) = 1;
   });
   {
     std::unique_lock lk(m);
@@ -120,6 +123,7 @@
   cv.notify_one();
   CHECK(handle != nullptr);
   CHECK(is_stack_mte_on());
+  CHECK(mte_tls() != nullptr);
 
   bool new_stack_page_mte_on = false;
   uintptr_t low;
@@ -129,11 +133,18 @@
   CHECK(new_stack_page_mte_on);
 
   bool is_late_thread_mte_on = false;
-  std::thread late_th([&] { is_late_thread_mte_on = is_stack_mte_on(); });
+  void* late_thread_mte_tls = nullptr;
+  std::thread late_th([&] {
+    is_late_thread_mte_on = is_stack_mte_on();
+    late_thread_mte_tls = mte_tls();
+    *reinterpret_cast<uintptr_t*>(late_thread_mte_tls) = 1;
+  });
   late_th.join();
   early_th.join();
   CHECK(is_late_thread_mte_on);
   CHECK(is_early_thread_mte_on);
+  CHECK(late_thread_mte_tls != nullptr);
+  CHECK(early_thread_mte_tls != nullptr);
   printf("RAN\n");
   return 0;
 }
diff --git a/tests/link_test.cpp b/tests/link_test.cpp
index 127a3d9..ae3a1cd 100644
--- a/tests/link_test.cpp
+++ b/tests/link_test.cpp
@@ -195,7 +195,7 @@
     }
     void AddModule(dl_phdr_info* info, size_t s) {
       ASSERT_EQ(sizeof(dl_phdr_info), s);
-      ASSERT_TRUE(dl_iter_mods.find(info->dlpi_addr) == dl_iter_mods.end());
+      ASSERT_FALSE(dl_iter_mods.contains(info->dlpi_addr));
       ASSERT_TRUE(info->dlpi_name != nullptr);
       dl_iter_mods[info->dlpi_addr] = {
         .name = info->dlpi_name,
diff --git a/tests/mte_utils.h b/tests/mte_utils.h
index 6e8385c..020faec 100644
--- a/tests/mte_utils.h
+++ b/tests/mte_utils.h
@@ -40,4 +40,10 @@
   return p == p_cpy;
 }
 
+static void* mte_tls() {
+  void** dst;
+  __asm__("mrs %0, TPIDR_EL0" : "=r"(dst) :);
+  return dst[-3];
+}
+
 #endif
diff --git a/tests/stack_protector_test.cpp b/tests/stack_protector_test.cpp
index aea791c..5817a27 100644
--- a/tests/stack_protector_test.cpp
+++ b/tests/stack_protector_test.cpp
@@ -48,7 +48,7 @@
     printf("[thread %d] TLS stack guard = %p\n", tid, guard);
 
     // Duplicate tid. gettid(2) bug? Seeing this would be very upsetting.
-    ASSERT_TRUE(tids.find(tid) == tids.end());
+    ASSERT_FALSE(tids.contains(tid));
 
     // Uninitialized guard. Our bug. Note this is potentially flaky; we _could_
     // get four random zero bytes, but it should be vanishingly unlikely.
diff --git a/tests/struct_layout_test.cpp b/tests/struct_layout_test.cpp
index 0123ed9..1f04344 100644
--- a/tests/struct_layout_test.cpp
+++ b/tests/struct_layout_test.cpp
@@ -30,7 +30,7 @@
 #define CHECK_OFFSET(name, field, offset) \
     check_offset(#name, #field, offsetof(name, field), offset);
 #ifdef __LP64__
-  CHECK_SIZE(pthread_internal_t, 776);
+  CHECK_SIZE(pthread_internal_t, 816);
   CHECK_OFFSET(pthread_internal_t, next, 0);
   CHECK_OFFSET(pthread_internal_t, prev, 8);
   CHECK_OFFSET(pthread_internal_t, tid, 16);
@@ -55,6 +55,8 @@
   CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 248);
   CHECK_OFFSET(pthread_internal_t, bionic_tls, 760);
   CHECK_OFFSET(pthread_internal_t, errno_value, 768);
+  CHECK_OFFSET(pthread_internal_t, bionic_tcb, 776);
+  CHECK_OFFSET(pthread_internal_t, stack_mte_ringbuffer_vma_name_buffer, 784);
   CHECK_SIZE(bionic_tls, 12200);
   CHECK_OFFSET(bionic_tls, key_data, 0);
   CHECK_OFFSET(bionic_tls, locale, 2080);
@@ -72,7 +74,7 @@
   CHECK_OFFSET(bionic_tls, bionic_systrace_disabled, 12193);
   CHECK_OFFSET(bionic_tls, padding, 12194);
 #else
-  CHECK_SIZE(pthread_internal_t, 668);
+  CHECK_SIZE(pthread_internal_t, 704);
   CHECK_OFFSET(pthread_internal_t, next, 0);
   CHECK_OFFSET(pthread_internal_t, prev, 4);
   CHECK_OFFSET(pthread_internal_t, tid, 8);
@@ -97,6 +99,8 @@
   CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 148);
   CHECK_OFFSET(pthread_internal_t, bionic_tls, 660);
   CHECK_OFFSET(pthread_internal_t, errno_value, 664);
+  CHECK_OFFSET(pthread_internal_t, bionic_tcb, 668);
+  CHECK_OFFSET(pthread_internal_t, stack_mte_ringbuffer_vma_name_buffer, 672);
   CHECK_SIZE(bionic_tls, 11080);
   CHECK_OFFSET(bionic_tls, key_data, 0);
   CHECK_OFFSET(bionic_tls, locale, 1040);
diff --git a/tests/wctype_test.cpp b/tests/wctype_test.cpp
index 0f07956..f4b7a8f 100644
--- a/tests/wctype_test.cpp
+++ b/tests/wctype_test.cpp
@@ -109,6 +109,8 @@
   EXPECT_EQ(wint_t('!'), towlower(L'!'));
   EXPECT_EQ(wint_t('a'), towlower(L'a'));
   EXPECT_EQ(wint_t('a'), towlower(L'A'));
+  EXPECT_EQ(wint_t('z'), towlower(L'z'));
+  EXPECT_EQ(wint_t('z'), towlower(L'Z'));
   if (have_dl()) {
     EXPECT_EQ(wint_t(L'ç'), towlower(L'ç'));
     EXPECT_EQ(wint_t(L'ç'), towlower(L'Ç'));
@@ -125,6 +127,8 @@
   EXPECT_EQ(wint_t('!'), towlower_l(L'!', l.l));
   EXPECT_EQ(wint_t('a'), towlower_l(L'a', l.l));
   EXPECT_EQ(wint_t('a'), towlower_l(L'A', l.l));
+  EXPECT_EQ(wint_t('z'), towlower_l(L'z', l.l));
+  EXPECT_EQ(wint_t('z'), towlower_l(L'Z', l.l));
   if (have_dl()) {
     EXPECT_EQ(wint_t(L'ç'), towlower_l(L'ç', l.l));
     EXPECT_EQ(wint_t(L'ç'), towlower_l(L'Ç', l.l));
@@ -140,6 +144,8 @@
   EXPECT_EQ(wint_t('!'), towupper(L'!'));
   EXPECT_EQ(wint_t('A'), towupper(L'a'));
   EXPECT_EQ(wint_t('A'), towupper(L'A'));
+  EXPECT_EQ(wint_t('Z'), towupper(L'z'));
+  EXPECT_EQ(wint_t('Z'), towupper(L'Z'));
   if (have_dl()) {
     EXPECT_EQ(wint_t(L'Ç'), towupper(L'ç'));
     EXPECT_EQ(wint_t(L'Ç'), towupper(L'Ç'));
@@ -156,6 +162,8 @@
   EXPECT_EQ(wint_t('!'), towupper_l(L'!', l.l));
   EXPECT_EQ(wint_t('A'), towupper_l(L'a', l.l));
   EXPECT_EQ(wint_t('A'), towupper_l(L'A', l.l));
+  EXPECT_EQ(wint_t('Z'), towupper_l(L'z', l.l));
+  EXPECT_EQ(wint_t('Z'), towupper_l(L'Z', l.l));
   if (have_dl()) {
     EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'ç', l.l));
     EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'Ç', l.l));
@@ -218,34 +226,64 @@
   EXPECT_EQ(0, iswctype_l(WEOF, wctype_l("alnum", l.l), l.l));
 }
 
-TEST(wctype, towctrans) {
+TEST(wctype, wctrans) {
   EXPECT_TRUE(wctrans("tolower") != nullptr);
   EXPECT_TRUE(wctrans("toupper") != nullptr);
 
+  errno = 0;
   EXPECT_TRUE(wctrans("monkeys") == nullptr);
-}
-
-TEST(wctype, towctrans_l) {
-  UtfLocale l;
-  EXPECT_TRUE(wctrans_l("tolower", l.l) != nullptr);
-  EXPECT_TRUE(wctrans_l("toupper", l.l) != nullptr);
-
-  EXPECT_TRUE(wctrans_l("monkeys", l.l) == nullptr);
-}
-
-TEST(wctype, wctrans) {
-  EXPECT_EQ(wint_t('a'), towctrans(L'A', wctrans("tolower")));
-  EXPECT_EQ(WEOF, towctrans(WEOF, wctrans("tolower")));
-
-  EXPECT_EQ(wint_t('A'), towctrans(L'a', wctrans("toupper")));
-  EXPECT_EQ(WEOF, towctrans(WEOF, wctrans("toupper")));
+  #if defined(__BIONIC__)
+  // Android/FreeBSD/iOS set errno, but musl/glibc don't.
+  EXPECT_ERRNO(EINVAL);
+  #endif
 }
 
 TEST(wctype, wctrans_l) {
   UtfLocale l;
-  EXPECT_EQ(wint_t('a'), towctrans_l(L'A', wctrans_l("tolower", l.l), l.l));
-  EXPECT_EQ(WEOF, towctrans_l(WEOF, wctrans_l("tolower", l.l), l.l));
+  EXPECT_TRUE(wctrans_l("tolower", l.l) != nullptr);
+  EXPECT_TRUE(wctrans_l("toupper", l.l) != nullptr);
 
-  EXPECT_EQ(wint_t('A'), towctrans_l(L'a', wctrans_l("toupper", l.l), l.l));
-  EXPECT_EQ(WEOF, towctrans_l(WEOF, wctrans_l("toupper", l.l), l.l));
+  errno = 0;
+  EXPECT_TRUE(wctrans_l("monkeys", l.l) == nullptr);
+  #if defined(__BIONIC__)
+  // Android/FreeBSD/iOS set errno, but musl/glibc don't.
+  EXPECT_ERRNO(EINVAL);
+  #endif
+}
+
+TEST(wctype, towctrans) {
+  wctrans_t lower = wctrans("tolower");
+  EXPECT_EQ(wint_t('a'), towctrans(L'A', lower));
+  EXPECT_EQ(WEOF, towctrans(WEOF, lower));
+
+  wctrans_t upper = wctrans("toupper");
+  EXPECT_EQ(wint_t('A'), towctrans(L'a', upper));
+  EXPECT_EQ(WEOF, towctrans(WEOF, upper));
+
+  wctrans_t invalid = wctrans("monkeys");
+  errno = 0;
+  EXPECT_EQ(wint_t('a'), towctrans(L'a', invalid));
+  #if defined(__BIONIC__)
+  // Android/FreeBSD/iOS set errno, but musl/glibc don't.
+  EXPECT_ERRNO(EINVAL);
+  #endif
+}
+
+TEST(wctype, towctrans_l) {
+  UtfLocale l;
+  wctrans_t lower = wctrans_l("tolower", l.l);
+  EXPECT_EQ(wint_t('a'), towctrans_l(L'A', lower, l.l));
+  EXPECT_EQ(WEOF, towctrans_l(WEOF, lower, l.l));
+
+  wctrans_t upper = wctrans_l("toupper", l.l);
+  EXPECT_EQ(wint_t('A'), towctrans_l(L'a', upper, l.l));
+  EXPECT_EQ(WEOF, towctrans_l(WEOF, upper, l.l));
+
+  wctrans_t invalid = wctrans_l("monkeys", l.l);
+  errno = 0;
+  EXPECT_EQ(wint_t('a'), towctrans_l(L'a', invalid, l.l));
+  #if defined(__BIONIC__)
+  // Android/FreeBSD/iOS set errno, but musl/glibc don't.
+  EXPECT_ERRNO(EINVAL);
+  #endif
 }
diff --git a/tools/versioner/src/DeclarationDatabase.cpp b/tools/versioner/src/DeclarationDatabase.cpp
index a029c3b..9794286 100644
--- a/tools/versioner/src/DeclarationDatabase.cpp
+++ b/tools/versioner/src/DeclarationDatabase.cpp
@@ -103,7 +103,7 @@
     }
 
     std::string declaration_name = getDeclName(named_decl);
-    bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
+    bool is_extern = named_decl->getFormalLinkage() == Linkage::External;
     bool is_definition = false;
     bool no_guard = false;
     bool fortify_inline = false;
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 24dc5ec..79672ac 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -42,7 +42,7 @@
 #include <llvm/ADT/SmallVector.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Option/Option.h>
-#include <llvm/Support/Host.h>
+#include <llvm/TargetParser/Host.h>
 #include <llvm/Support/VirtualFileSystem.h>
 
 #include "Arch.h"
diff --git a/tools/versioner/src/Preprocessor.cpp b/tools/versioner/src/Preprocessor.cpp
index 47b9017..74d5ba0 100644
--- a/tools/versioner/src/Preprocessor.cpp
+++ b/tools/versioner/src/Preprocessor.cpp
@@ -448,7 +448,7 @@
 
   while (FTSENT* ent = fts_read(fts.get())) {
     llvm::StringRef path = ent->fts_path;
-    if (!path.startswith(src_dir)) {
+    if (!path.starts_with(src_dir)) {
       err(1, "path '%s' doesn't start with source dir '%s'", ent->fts_path, src_dir.c_str());
     }
 
@@ -489,7 +489,7 @@
     // TODO: Merge adjacent non-identical guards.
     mergeGuards(file_lines[file_path.str()], guard_map);
 
-    if (!file_path.startswith(src_dir)) {
+    if (!file_path.starts_with(src_dir)) {
       errx(1, "input file %s is not in %s\n", file_path.str().c_str(), src_dir.c_str());
     }
 
diff --git a/tools/versioner/src/Utils.cpp b/tools/versioner/src/Utils.cpp
index dc6b5dd..d2bb1a8 100644
--- a/tools/versioner/src/Utils.cpp
+++ b/tools/versioner/src/Utils.cpp
@@ -83,7 +83,7 @@
 }
 
 llvm::StringRef StripPrefix(llvm::StringRef string, llvm::StringRef prefix) {
-  if (string.startswith(prefix)) {
+  if (string.starts_with(prefix)) {
     return string.drop_front(prefix.size());
   }
   return string;
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index 5afa00b..37c8bac 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -142,11 +142,11 @@
 
   auto new_end = std::remove_if(headers.begin(), headers.end(), [&arch](llvm::StringRef header) {
     for (const auto& it : ignored_headers) {
-      if (it.second.find(arch) == it.second.end()) {
+      if (!it.second.contains(arch)) {
         continue;
       }
 
-      if (header.endswith("/" + it.first)) {
+      if (header.ends_with("/" + it.first)) {
         return true;
       }
     }