Merge "linker_block_alloctor: Remove 4k page size assumption" into main
diff --git a/README.md b/README.md
index 113ffd7..aafbcff 100644
--- a/README.md
+++ b/README.md
@@ -374,6 +374,19 @@
 
     $ ./tests/run-on-host.sh glibc
 
+### Against musl
+
+Another way to verify test behavior is to run against musl on the host. glibc
+musl don't always match, so this can be a good way to find the more complicated
+corners of the spec. If they *do* match, bionic probably should too!
+
+    $ OUT_DIR=$(ANDROID_BUILD_TOP)/musl-out ./tests/run-on-host.sh musl
+
+Note: the alternate OUT_DIR is used to avoid causing excessive rebuilding when
+switching between glibc and musl. The first musl test run will be expensive
+because it will not reuse any already built artifacts, but subsequent runs will
+be cheaper than if you hadn't used it.
+
 ## Gathering test coverage
 
 To get test coverage for bionic, use `//bionic/build/coverage.sh`. Before
diff --git a/docs/status.md b/docs/status.md
index fc68b80..5514935 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -62,7 +62,8 @@
     functions for avoiding $TZ if you need to use multiple timezones in
     multi-threaded C).
   * `mbsrtowcs_l` and `wcsrtombs_l` aliases for `mbsrtowcs` and `wcsrtombs`.
-  * New system call wrapper: `__riscv_flush_icache` (`<sys/cachectl.h>`).
+  * New system call wrappers: `__riscv_flush_icache` (`<sys/cachectl.h>`),
+    `__riscv_hwprobe` (`<sys/hwprobe.h>`).
 
 New libc functions in U (API level 34):
   * `close_range` and `copy_file_range` (Linux-specific GNU extensions).
diff --git a/libc/Android.bp b/libc/Android.bp
index dc3c73f..fe263fd 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -133,6 +133,8 @@
     lto: {
         never: true,
     },
+
+    apex_available: ["com.android.runtime"],
 }
 
 libc_scudo_product_variables = {
@@ -334,10 +336,16 @@
 // automatically included.
 
 cc_library_static {
+    name: "libc_freebsd_ldexp",
+    defaults: ["libc_defaults"],
+    cflags: ["-Dscalbn=ldexp"],
+    srcs: [":libc_ldexp_srcs"],
+}
+
+cc_library_static {
     defaults: ["libc_defaults"],
     tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
-        "upstream-freebsd/lib/libc/gen/ldexp.c",
         "upstream-freebsd/lib/libc/stdlib/getopt_long.c",
         "upstream-freebsd/lib/libc/stdlib/hcreate.c",
         "upstream-freebsd/lib/libc/stdlib/hcreate_r.c",
@@ -1276,9 +1284,6 @@
     srcs: [
         "bionic/bionic_systrace.cpp",
     ],
-    apex_available: [
-        "com.android.runtime",
-    ],
 }
 
 // ========================================================
@@ -1475,6 +1480,7 @@
         "libc_fortify",
         "libc_freebsd",
         "libc_freebsd_large_stack",
+        "libc_freebsd_ldexp",
         "libc_gdtoa",
         "libc_netbsd",
         "libc_openbsd_large_stack",
@@ -1509,6 +1515,7 @@
         "libc_fortify",
         "libc_freebsd",
         "libc_freebsd_large_stack",
+        "libc_freebsd_ldexp",
         "libc_gdtoa",
         "libc_netbsd",
         "libc_openbsd",
@@ -1831,7 +1838,6 @@
         },
     },
 
-
     apex_available: [
         "//apex_available:platform",
         "com.android.runtime",
@@ -2095,6 +2101,9 @@
     name: "libstdc++",
     static_ndk_lib: true,
     static_libs: ["libasync_safe"],
+    apex_available: [
+        "//apex_available:platform",
+    ],
 
     static: {
         system_shared_libs: [],
@@ -2478,8 +2487,6 @@
     name: "libc",
     symbol_file: "libc.map.txt",
     first_version: "9",
-    // APIs implemented in asm don't have debug info: http://b/190554910.
-    allow_untyped_symbols: true,
     export_header_libs: [
         "common_libc",
         "libc_uapi",
diff --git a/libc/SECCOMP_ALLOWLIST_COMMON.TXT b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
index 4a8d501..67b662e 100644
--- a/libc/SECCOMP_ALLOWLIST_COMMON.TXT
+++ b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
@@ -74,5 +74,3 @@
 int rt_sigtimedwait_time64(const sigset64_t*, siginfo_t*, const timespec64*, size_t) lp32
 int futex_time64(int*, int, int, const timespec64*, int*, int) lp32
 int sched_rr_get_interval_time64(pid_t, timespec64*) lp32
-# Since Linux 6.4, not in glibc (https://www.openwall.com/lists/libc-coord/2023/07/13/1).
-int riscv_hwprobe(riscv_hwprobe*, size_t, size_t, unsigned long*, unsigned) riscv64
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index e8dde7c..f4f9e1b 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -357,6 +357,7 @@
 
 # riscv64-specific
 int __riscv_flush_icache:riscv_flush_icache(void*, void*, unsigned long) riscv64
+int riscv_hwprobe(riscv_hwprobe*, size_t, size_t, unsigned long*, unsigned) riscv64
 
 # x86-specific
 int     __set_thread_area:set_thread_area(void*) x86
diff --git a/libc/arch-riscv64/string/memchr_vext.S b/libc/arch-riscv64/string/memchr_vext.S
index 3761265..ed76a05 100644
--- a/libc/arch-riscv64/string/memchr_vext.S
+++ b/libc/arch-riscv64/string/memchr_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define iResult a0
 
diff --git a/libc/arch-riscv64/string/memcmp_vext.S b/libc/arch-riscv64/string/memcmp_vext.S
index d8e7a06..1bb381c 100644
--- a/libc/arch-riscv64/string/memcmp_vext.S
+++ b/libc/arch-riscv64/string/memcmp_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define iResult a0
 
diff --git a/libc/arch-riscv64/string/memcpy_vext.S b/libc/arch-riscv64/string/memcpy_vext.S
index 100f538..668973f 100644
--- a/libc/arch-riscv64/string/memcpy_vext.S
+++ b/libc/arch-riscv64/string/memcpy_vext.S
@@ -52,9 +52,10 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/memmove_vext.S b/libc/arch-riscv64/string/memmove_vext.S
index 722ffd1..03f10c5 100644
--- a/libc/arch-riscv64/string/memmove_vext.S
+++ b/libc/arch-riscv64/string/memmove_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/memset_vext.S b/libc/arch-riscv64/string/memset_vext.S
index ef8387d..554d6bd 100644
--- a/libc/arch-riscv64/string/memset_vext.S
+++ b/libc/arch-riscv64/string/memset_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define iValue a1
diff --git a/libc/arch-riscv64/string/strcat_vext.S b/libc/arch-riscv64/string/strcat_vext.S
index 790c07a..05e0dfc 100644
--- a/libc/arch-riscv64/string/strcat_vext.S
+++ b/libc/arch-riscv64/string/strcat_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/strchr_vext.S b/libc/arch-riscv64/string/strchr_vext.S
index 89828ea..4c7bac1 100644
--- a/libc/arch-riscv64/string/strchr_vext.S
+++ b/libc/arch-riscv64/string/strchr_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pStr a0
 #define iCh a1
diff --git a/libc/arch-riscv64/string/strcmp_vext.S b/libc/arch-riscv64/string/strcmp_vext.S
index d6ad96e..b793c9a 100644
--- a/libc/arch-riscv64/string/strcmp_vext.S
+++ b/libc/arch-riscv64/string/strcmp_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define iResult a0
 
diff --git a/libc/arch-riscv64/string/strcpy_vext.S b/libc/arch-riscv64/string/strcpy_vext.S
index 9c11f7d..ab8da48 100644
--- a/libc/arch-riscv64/string/strcpy_vext.S
+++ b/libc/arch-riscv64/string/strcpy_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/strlen_vext.S b/libc/arch-riscv64/string/strlen_vext.S
index 393af58..694f95c 100644
--- a/libc/arch-riscv64/string/strlen_vext.S
+++ b/libc/arch-riscv64/string/strlen_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define iResult a0
 #define pStr a0
diff --git a/libc/arch-riscv64/string/strncat_vext.S b/libc/arch-riscv64/string/strncat_vext.S
index e9da434..9fcd37d 100644
--- a/libc/arch-riscv64/string/strncat_vext.S
+++ b/libc/arch-riscv64/string/strncat_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/strncmp_vext.S b/libc/arch-riscv64/string/strncmp_vext.S
index 88f0f3e..ec3ec50 100644
--- a/libc/arch-riscv64/string/strncmp_vext.S
+++ b/libc/arch-riscv64/string/strncmp_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define iResult a0
 
diff --git a/libc/arch-riscv64/string/strncpy_vext.S b/libc/arch-riscv64/string/strncpy_vext.S
index 1aedaf9..eff6293 100644
--- a/libc/arch-riscv64/string/strncpy_vext.S
+++ b/libc/arch-riscv64/string/strncpy_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pDst a0
 #define pSrc a1
diff --git a/libc/arch-riscv64/string/strnlen_vext.S b/libc/arch-riscv64/string/strnlen_vext.S
index f546689..ca07231 100644
--- a/libc/arch-riscv64/string/strnlen_vext.S
+++ b/libc/arch-riscv64/string/strnlen_vext.S
@@ -55,7 +55,7 @@
 
 #if defined(__riscv_v)
 
-#include "sys/asm.h"
+#include <private/bionic_asm.h>
 
 #define pStr a0
 #define pCopyStr a2
diff --git a/libc/arch-riscv64/string/sys/asm.h b/libc/arch-riscv64/string/sys/asm.h
deleted file mode 100644
index cc76dc5..0000000
--- a/libc/arch-riscv64/string/sys/asm.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * Copyright (c) 2023 SiFive, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the company may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY SIFIVE INC ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL SIFIVE INC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _SYS_ASM_H
-#define _SYS_ASM_H
-
-#undef LEAF
-#define LEAF(symbol)       \
-  .globl symbol;           \
-  .align 2;                \
-  .type symbol, @function; \
-  symbol:                  \
-  .cfi_startproc;
-
-#undef END
-#define END(function) \
-  .cfi_endproc;       \
-  .size function, .- function
-
-#define ENTRY(name) LEAF(name)
-
-#define L(label) .L##label
-
-#endif /* _SYS_ASM_H */
diff --git a/libc/arch-x86_64/bionic/__bionic_clone.S b/libc/arch-x86_64/bionic/__bionic_clone.S
index a4245b8..c293020 100644
--- a/libc/arch-x86_64/bionic/__bionic_clone.S
+++ b/libc/arch-x86_64/bionic/__bionic_clone.S
@@ -48,8 +48,8 @@
 
         # Check result.
         testq   %rax, %rax
-        jz      .L_bc_child
-        jg      .L_bc_parent
+        jz      L(bc_child)
+        jg      L(bc_parent)
 
         # An error occurred, set errno and return -1.
         negl    %eax
@@ -57,7 +57,7 @@
         call    __set_errno_internal
         ret
 
-.L_bc_child:
+L(bc_child):
         # We don't want anyone to unwind past this point.
         .cfi_undefined %rip
         .cfi_undefined %rbp
@@ -70,7 +70,7 @@
         call    __start_thread
         hlt
 
-.L_bc_parent:
+L(bc_parent):
         # We're the parent; nothing to do.
         ret
 END(__bionic_clone)
diff --git a/libc/arch-x86_64/string/avx2-memset-kbl.S b/libc/arch-x86_64/string/avx2-memset-kbl.S
index 09dd07d..ca62a9f 100644
--- a/libc/arch-x86_64/string/avx2-memset-kbl.S
+++ b/libc/arch-x86_64/string/avx2-memset-kbl.S
@@ -63,10 +63,9 @@
 	testb	$2, %dl
 	jnz	L(2_3bytes)
 	testb	$1, %dl
-	jz	L(return)
+	jz	1f
 	movb	%cl, (%rdi)
-L(return):
-	ret
+1:	ret
 
 L(8_15bytes):
 	movq	%rcx, (%rdi)
@@ -90,59 +89,54 @@
 	movdqu	%xmm0, (%rdi)
 	movdqu	%xmm0, -16(%rdi, %rdx)
 	cmpq	$32, %rdx
-	jbe	L(32bytesless)
+	jbe	L(done)
 	movdqu	%xmm0, 16(%rdi)
 	movdqu	%xmm0, -32(%rdi, %rdx)
 	cmpq	$64, %rdx
-	jbe	L(64bytesless)
+	jbe	L(done)
 	movdqu	%xmm0, 32(%rdi)
 	movdqu	%xmm0, 48(%rdi)
 	movdqu	%xmm0, -64(%rdi, %rdx)
 	movdqu	%xmm0, -48(%rdi, %rdx)
 	cmpq	$128, %rdx
-	jbe	L(128bytesless)
-        vpbroadcastb %xmm0, %ymm0
+	jbe	L(done)
+	vpbroadcastb %xmm0, %ymm0
 	vmovdqu	%ymm0, 64(%rdi)
 	vmovdqu	%ymm0, 96(%rdi)
 	vmovdqu	%ymm0, -128(%rdi, %rdx)
 	vmovdqu	%ymm0, -96(%rdi, %rdx)
 	cmpq	$256, %rdx
-        ja      L(256bytesmore)
-L(32bytesless):
-L(64bytesless):
-L(128bytesless):
-	ret
+	jbe	L(done)
 
 	ALIGN (4)
-L(256bytesmore):
 	leaq	128(%rdi), %rcx
 	andq	$-128, %rcx
 	movq	%rdx, %r8
 	addq	%rdi, %rdx
 	andq	$-128, %rdx
 	cmpq	%rcx, %rdx
-	je	L(return)
+	je	L(done)
 
 #ifdef SHARED_CACHE_SIZE
 	cmp	$SHARED_CACHE_SIZE, %r8
 #else
 	cmp	__x86_64_shared_cache_size(%rip), %r8
 #endif
-	ja	L(256bytesmore_nt)
+	ja	L(non_temporal_loop)
 
 	ALIGN (4)
-L(256bytesmore_normal):
+L(normal_loop):
 	vmovdqa	%ymm0, (%rcx)
 	vmovdqa	%ymm0, 32(%rcx)
 	vmovdqa	%ymm0, 64(%rcx)
 	vmovdqa	%ymm0, 96(%rcx)
 	addq	$128, %rcx
 	cmpq	%rcx, %rdx
-	jne	L(256bytesmore_normal)
-	ret
+	jne	L(normal_loop)
+	jmp	L(done)
 
 	ALIGN (4)
-L(256bytesmore_nt):
+L(non_temporal_loop):
 	movntdq	 %xmm0, (%rcx)
 	movntdq	 %xmm0, 16(%rcx)
 	movntdq	 %xmm0, 32(%rcx)
@@ -153,8 +147,14 @@
 	movntdq	 %xmm0, 112(%rcx)
 	leaq	128(%rcx), %rcx
 	cmpq	%rcx, %rdx
-	jne	L(256bytesmore_nt)
+	jne	L(non_temporal_loop)
+	# We used non-temporal stores, so we need a fence here.
 	sfence
+
+L(done):
+	# We used the ymm registers, and that can break SSE2 performance
+	# unless you do this.
+	vzeroupper
 	ret
 
 END(memset_avx2)
diff --git a/libc/bionic/bionic_call_ifunc_resolver.cpp b/libc/bionic/bionic_call_ifunc_resolver.cpp
index 437de78..410eb78 100644
--- a/libc/bionic/bionic_call_ifunc_resolver.cpp
+++ b/libc/bionic/bionic_call_ifunc_resolver.cpp
@@ -57,6 +57,13 @@
     hwcap = getauxval(AT_HWCAP);
   }
   return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(hwcap);
+#elif defined(__riscv)
+  // This argument and its value is just a placeholder for now,
+  // but it means that if we do pass something in future (such as
+  // getauxval() and/or hwprobe key/value pairs), callees will be able to
+  // recognize what they're being given.
+  typedef ElfW(Addr) (*ifunc_resolver_t)(void*);
+  return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(nullptr);
 #else
   typedef ElfW(Addr) (*ifunc_resolver_t)(void);
   return reinterpret_cast<ifunc_resolver_t>(resolver_addr)();
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index 4fa76ff..a7cd207 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -78,7 +78,7 @@
     length = 4;
   } else {
     errno = EILSEQ;
-    return __MB_ERR_ILLEGAL_SEQUENCE;
+    return BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE;
   }
 
   // Output the octets representing the character in chunks
diff --git a/libc/bionic/iconv.cpp b/libc/bionic/iconv.cpp
index 79a429c..5bff50a 100644
--- a/libc/bionic/iconv.cpp
+++ b/libc/bionic/iconv.cpp
@@ -160,9 +160,9 @@
 
       case UTF_8:
         src_bytes_used = mbrtoc32(&wc, *src_buf, *src_bytes_left, &ps);
-        if (src_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
+        if (src_bytes_used == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
           break;  // EILSEQ already set.
-        } else if (src_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
+        } else if (src_bytes_used == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
           errno = EINVAL;
           return false;
         }
@@ -235,9 +235,9 @@
 
       case UTF_8:
         dst_bytes_used = c32rtomb(buf, wc, &ps);
-        if (dst_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
+        if (dst_bytes_used == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
           break;  // EILSEQ already set.
-        } else if (dst_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
+        } else if (dst_bytes_used == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
           errno = EINVAL;
           return false;
         }
diff --git a/libc/bionic/malloc_limit.cpp b/libc/bionic/malloc_limit.cpp
index 1405a39..deb63f4 100644
--- a/libc/bionic/malloc_limit.cpp
+++ b/libc/bionic/malloc_limit.cpp
@@ -278,7 +278,7 @@
   // being called, allow a short period for the signal handler to complete
   // before failing.
   bool enabled = false;
-  size_t num_tries = 20;
+  size_t num_tries = 200;
   while (true) {
     if (!atomic_exchange(&gGlobalsMutating, true)) {
       __libc_globals.mutate([](libc_globals* globals) {
@@ -328,9 +328,16 @@
     current_allocated = Malloc(mallinfo)().uordblks;
   }
 #endif
+  // This has to be set before the enable occurs since "gAllocated" is used
+  // to compute the limit. If the enable fails, "gAllocated" is never used.
   atomic_store(&gAllocated, current_allocated);
 
-  return EnableLimitDispatchTable();
+  if (!EnableLimitDispatchTable()) {
+    // Failed to enable, reset so a future enable will pass.
+    atomic_store(&limit_enabled, false);
+    return false;
+  }
+  return true;
 }
 
 static size_t LimitUsableSize(const void* mem) {
diff --git a/libc/bionic/mbrtoc16.cpp b/libc/bionic/mbrtoc16.cpp
index 154b8a3..e87991a 100644
--- a/libc/bionic/mbrtoc16.cpp
+++ b/libc/bionic/mbrtoc16.cpp
@@ -47,15 +47,36 @@
   mbstate_set_byte(state, 3, nconv & 0xff);
 
   *pc16 = ((c32 & 0xffc00) >> 10) | 0xd800;
-  // Defined by POSIX as return value for first surrogate character.
-  return static_cast<size_t>(-3);
+  // https://issuetracker.google.com/289419882
+  //
+  // We misread the spec when implementing this. The first call should return
+  // the length of the decoded character, and the second call should return -3
+  // to indicate that the output is a continuation of the character decoded by
+  // the first call.
+  //
+  // C23 7.30.1.3.4:
+  //
+  //     between 1 and n inclusive if the next n or fewer bytes complete a valid
+  //     multibyte character (which is the value stored); the value returned is
+  //     the number of bytes that complete the multibyte character.
+  //
+  //     (size_t)(-3) if the next character resulting from a previous call has
+  //     been stored (no bytes from the input have been consumed by this call).
+  //
+  // The first call returns the number of bytes consumed, and the second call
+  // returns -3.
+  //
+  // All UTF-8 sequences that encode a surrogate pair are 4 bytes, but we may
+  // not have seen the full sequence yet.
+  return nconv;
 }
 
 static size_t finish_surrogate(char16_t* pc16, mbstate_t* state) {
   char16_t trail = mbstate_get_byte(state, 1) << 8 |
                    mbstate_get_byte(state, 0);
   *pc16 = trail;
-  return mbstate_reset_and_return(mbstate_get_byte(state, 3), state);
+  mbstate_reset(state);
+  return static_cast<size_t>(-3);
 }
 
 size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index d37ca66..74deb40 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -51,7 +51,21 @@
   }
 
   if (n == 0) {
-    return 0;
+    // C23 7.30.1 (for each `mbrtoc*` function) says:
+    //
+    // Returns:
+    //
+    //     0 if the next n or fewer bytes complete the multibyte character that
+    //     corresponds to the null wide character (which is the value stored).
+    //
+    //     (size_t)(-2) if the next n bytes contribute to an incomplete (but
+    //     potentially valid) multibyte character, and all n bytes have been
+    //     processed (no value is stored).
+    //
+    // Bionic historically interpreted the behavior when n is 0 to be the next 0
+    // bytes decoding to the null. That's a pretty bad interpretation, and both
+    // glibc and musl return -2 for that case.
+    return BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE;
   }
 
   uint8_t ch;
@@ -109,7 +123,7 @@
     mbstate_set_byte(state, bytes_so_far + i, *s++);
   }
   if (i < bytes_wanted) {
-    return __MB_ERR_INCOMPLETE_SEQUENCE;
+    return BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE;
   }
 
   // Decode the octet sequence representing the character in chunks
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 3290315..7d80b4c 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -50,14 +50,8 @@
 
 int ppoll(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset_t* ss) {
   // The underlying `__ppoll` system call only takes `sigset64_t`.
-  SigSetConverter set;
-  sigset64_t* ss_ptr = nullptr;
-  if (ss != nullptr) {
-    set = {};
-    set.sigset = *ss;
-    ss_ptr = &set.sigset64;
-  }
-  return ppoll64(fds, fd_count, ts, ss_ptr);
+  SigSetConverter set{ss};
+  return ppoll64(fds, fd_count, ts, set.ptr);
 }
 
 int ppoll64(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset64_t* ss) {
@@ -99,14 +93,8 @@
 int pselect(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds,
             const timespec* ts, const sigset_t* ss) {
   // The underlying `__pselect6` system call only takes `sigset64_t`.
-  SigSetConverter set;
-  sigset64_t* ss_ptr = nullptr;
-  if (ss != nullptr) {
-    set = {};
-    set.sigset = *ss;
-    ss_ptr = &set.sigset64;
-  }
-  return pselect64(fd_count, read_fds, write_fds, error_fds, ts, ss_ptr);
+  SigSetConverter set{ss};
+  return pselect64(fd_count, read_fds, write_fds, error_fds, ts, set.ptr);
 }
 
 int pselect64(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds,
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index b581b5a..2cf9940 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -76,13 +76,23 @@
   return SigAddSet(set, sig);
 }
 
-// This isn't in our header files, but is exposed on all architectures.
+union BsdSigSet {
+  int mask;
+  sigset64_t set;
+};
+
+// This isn't in our header files, but is exposed on all architectures except riscv64.
 extern "C" int sigblock(int mask) {
-  SigSetConverter in, out;
-  sigemptyset(&in.sigset);
-  in.bsd = mask;
-  if (sigprocmask(SIG_BLOCK, &in.sigset, &out.sigset) == -1) return -1;
-  return out.bsd;
+  BsdSigSet in{.mask = mask}, out;
+  if (sigprocmask64(SIG_BLOCK, &in.set, &out.set) == -1) return -1;
+  return out.mask;
+}
+
+// This isn't in our header files, but is exposed on all architectures except riscv64.
+extern "C" int sigsetmask(int mask) {
+  BsdSigSet in{.mask = mask}, out;
+  if (sigprocmask64(SIG_SETMASK, &in.set, &out.set) == -1) return -1;
+  return out.mask;
 }
 
 template <typename SigSetT>
@@ -198,10 +208,9 @@
 }
 
 int sigpending(sigset_t* bionic_set) {
-  SigSetConverter set = {};
-  set.sigset = *bionic_set;
-  if (__rt_sigpending(&set.sigset64, sizeof(set.sigset64)) == -1) return -1;
-  *bionic_set = set.sigset;
+  SigSetConverter set{bionic_set};
+  if (__rt_sigpending(set.ptr, sizeof(sigset64_t)) == -1) return -1;
+  set.copy_out();
   return 0;
 }
 
@@ -245,19 +254,9 @@
   return sigismember64(&old_mask, sig) ? SIG_HOLD : old_sa.sa_handler;
 }
 
-// This isn't in our header files, but is exposed on all architectures.
-extern "C" int sigsetmask(int mask) {
-  SigSetConverter in, out;
-  sigemptyset(&in.sigset);
-  in.bsd = mask;
-  if (sigprocmask(SIG_SETMASK, &in.sigset, &out.sigset) == -1) return -1;
-  return out.bsd;
-}
-
 int sigsuspend(const sigset_t* bionic_set) {
-  SigSetConverter set = {};
-  set.sigset = *bionic_set;
-  return sigsuspend64(&set.sigset64);
+  SigSetConverter set{bionic_set};
+  return sigsuspend64(set.ptr);
 }
 
 int sigsuspend64(const sigset64_t* set) {
@@ -271,9 +270,8 @@
 }
 
 int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) {
-  SigSetConverter set = {};
-  set.sigset = *bionic_set;
-  return sigtimedwait64(&set.sigset64, info, timeout);
+  SigSetConverter set{bionic_set};
+  return sigtimedwait64(set.ptr, info, timeout);
 }
 
 int sigtimedwait64(const sigset64_t* set, siginfo_t* info, const timespec* timeout) {
@@ -287,9 +285,8 @@
 }
 
 int sigwait(const sigset_t* bionic_set, int* sig) {
-  SigSetConverter set = {};
-  set.sigset = *bionic_set;
-  return sigwait64(&set.sigset64, sig);
+  SigSetConverter set{bionic_set};
+  return sigwait64(set.ptr, sig);
 }
 
 int sigwait64(const sigset64_t* set, int* sig) {
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
index 8781c9b..6d436a6 100644
--- a/libc/bionic/sigprocmask.cpp
+++ b/libc/bionic/sigprocmask.cpp
@@ -44,24 +44,13 @@
 int sigprocmask(int how,
                 const sigset_t* bionic_new_set,
                 sigset_t* bionic_old_set) __attribute__((__noinline__)) {
-  SigSetConverter new_set;
-  sigset64_t* new_set_ptr = nullptr;
-  if (bionic_new_set != nullptr) {
-    sigemptyset64(&new_set.sigset64);
-    new_set.sigset = *bionic_new_set;
-    new_set_ptr = &new_set.sigset64;
+  SigSetConverter new_set{bionic_new_set};
+  SigSetConverter old_set{bionic_old_set};
+  int rc = sigprocmask64(how, new_set.ptr, old_set.ptr);
+  if (rc == 0 && bionic_old_set != nullptr) {
+    old_set.copy_out();
   }
-
-  SigSetConverter old_set;
-  if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) {
-    return -1;
-  }
-
-  if (bionic_old_set != nullptr) {
-    *bionic_old_set = old_set.sigset;
-  }
-
-  return 0;
+  return rc;
 }
 
 int sigprocmask64(int how,
diff --git a/libc/bionic/spawn.cpp b/libc/bionic/spawn.cpp
index 5d76f77..38f99ad 100644
--- a/libc/bionic/spawn.cpp
+++ b/libc/bionic/spawn.cpp
@@ -41,7 +41,6 @@
 #include <android/fdsan.h>
 
 #include "private/ScopedSignalBlocker.h"
-#include "private/SigSetConverter.h"
 
 static int set_cloexec(int i) {
   int v = fcntl(i, F_GETFD);
@@ -131,8 +130,10 @@
   pid_t pgroup;
   sched_param schedparam;
   int schedpolicy;
-  SigSetConverter sigmask;
-  SigSetConverter sigdefault;
+  union {
+    sigset_t sigset;
+    sigset64_t sigset64;
+  } sigmask, sigdefault;
 };
 
 static void ApplyAttrs(short flags, const posix_spawnattr_t* attr) {
diff --git a/libc/bionic/sys_epoll.cpp b/libc/bionic/sys_epoll.cpp
index 22d0a98..cffa173 100644
--- a/libc/bionic/sys_epoll.cpp
+++ b/libc/bionic/sys_epoll.cpp
@@ -48,14 +48,8 @@
 }
 
 int epoll_pwait(int fd, epoll_event* events, int max_events, int timeout, const sigset_t* ss) {
-  SigSetConverter set;
-  sigset64_t* ss_ptr = nullptr;
-  if (ss != nullptr) {
-    set = {};
-    set.sigset = *ss;
-    ss_ptr = &set.sigset64;
-  }
-  return epoll_pwait64(fd, events, max_events, timeout, ss_ptr);
+  SigSetConverter set{ss};
+  return epoll_pwait64(fd, events, max_events, timeout, set.ptr);
 }
 
 int epoll_pwait64(int fd, epoll_event* events, int max_events, int timeout, const sigset64_t* ss) {
diff --git a/libc/bionic/sys_signalfd.cpp b/libc/bionic/sys_signalfd.cpp
index 53d1f25..1e62cf4 100644
--- a/libc/bionic/sys_signalfd.cpp
+++ b/libc/bionic/sys_signalfd.cpp
@@ -32,12 +32,12 @@
 
 extern "C" int __signalfd4(int, const sigset64_t*, size_t, int);
 
-int signalfd(int fd, const sigset_t* mask, int flags) {
-  SigSetConverter set = {};
-  set.sigset = *mask;
-  return signalfd64(fd, &set.sigset64, flags);
-}
-
 int signalfd64(int fd, const sigset64_t* mask, int flags) {
   return __signalfd4(fd, mask, sizeof(*mask), flags);
 }
+
+int signalfd(int fd, const sigset_t* mask, int flags) {
+  // The underlying `__signalfd4` system call only takes `sigset64_t`.
+  SigSetConverter set{mask};
+  return signalfd64(fd, set.ptr, flags);
+}
diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp
index dbca9c0..e834ec7 100644
--- a/libc/bionic/vdso.cpp
+++ b/libc/bionic/vdso.cpp
@@ -22,10 +22,16 @@
 #include <string.h>
 #include <sys/auxv.h>
 #include <sys/cdefs.h>
+#include <sys/hwprobe.h>
 #include <sys/time.h>
 #include <time.h>
 #include <unistd.h>
 
+extern "C" int __clock_gettime(int, struct timespec*);
+extern "C" int __clock_getres(int, struct timespec*);
+extern "C" int __gettimeofday(struct timeval*, struct timezone*);
+extern "C" int riscv_hwprobe(struct riscv_hwprobe*, size_t, size_t, unsigned long*, unsigned);
+
 static inline int vdso_return(int result) {
   if (__predict_true(result == 0)) return 0;
 
@@ -61,10 +67,13 @@
 }
 
 time_t time(time_t* t) {
+  // Only x86/x86-64 actually have time() in the vdso.
+#if defined(VDSO_TIME_SYMBOL)
   auto vdso_time = reinterpret_cast<decltype(&time)>(__libc_globals->vdso[VDSO_TIME].fn);
   if (__predict_true(vdso_time)) {
     return vdso_time(t);
   }
+#endif
 
   // We can't fallback to the time(2) system call because it doesn't exist for most architectures.
   timeval tv;
@@ -73,12 +82,29 @@
   return tv.tv_sec;
 }
 
+#if defined(__riscv)
+int __riscv_hwprobe(struct riscv_hwprobe* _Nonnull pairs, size_t pair_count, size_t cpu_count,
+                    unsigned long* _Nullable cpus, unsigned flags) {
+  auto vdso_riscv_hwprobe =
+      reinterpret_cast<decltype(&__riscv_hwprobe)>(__libc_globals->vdso[VDSO_RISCV_HWPROBE].fn);
+  if (__predict_true(vdso_riscv_hwprobe)) {
+    return vdso_return(vdso_riscv_hwprobe(pairs, pair_count, cpu_count, cpus, flags));
+  }
+  return riscv_hwprobe(pairs, pair_count, cpu_count, cpus, flags);
+}
+#endif
+
 void __libc_init_vdso(libc_globals* globals) {
   auto&& vdso = globals->vdso;
-  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, nullptr };
-  vdso[VDSO_CLOCK_GETRES] = { VDSO_CLOCK_GETRES_SYMBOL, nullptr };
-  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, nullptr };
-  vdso[VDSO_TIME] = { VDSO_TIME_SYMBOL, nullptr };
+  vdso[VDSO_CLOCK_GETTIME] = {VDSO_CLOCK_GETTIME_SYMBOL, nullptr};
+  vdso[VDSO_CLOCK_GETRES] = {VDSO_CLOCK_GETRES_SYMBOL, nullptr};
+  vdso[VDSO_GETTIMEOFDAY] = {VDSO_GETTIMEOFDAY_SYMBOL, nullptr};
+#if defined(VDSO_TIME_SYMBOL)
+  vdso[VDSO_TIME] = {VDSO_TIME_SYMBOL, nullptr};
+#endif
+#if defined(VDSO_RISCV_HWPROBE_SYMBOL)
+  vdso[VDSO_RISCV_HWPROBE] = {VDSO_RISCV_HWPROBE_SYMBOL, nullptr};
+#endif
 
   // Do we have a vdso?
   uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index bb97b3e..b8c4432 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -27,10 +27,10 @@
  */
 
 #include <errno.h>
-#include <sys/param.h>
 #include <string.h>
-#include <wchar.h>
+#include <sys/param.h>
 #include <uchar.h>
+#include <wchar.h>
 
 #include "private/bionic_mbstate.h"
 
@@ -88,10 +88,10 @@
         r = 1;
       } else {
         r = mbrtowc(nullptr, *src + i, nmc - i, state);
-        if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+        if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
           return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
-        if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
+        if (r == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
           return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == 0) {
@@ -114,11 +114,11 @@
       }
     } else {
       r = mbrtowc(dst + o, *src + i, nmc - i, state);
-      if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+      if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
         *src += i;
         return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
-      if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
+      if (r == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
         *src += nmc;
         return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
@@ -166,7 +166,7 @@
         r = 1;
       } else {
         r = wcrtomb(buf, wc, state);
-        if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+        if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
           return r;
         }
       }
@@ -187,14 +187,14 @@
     } else if (len - o >= sizeof(buf)) {
       // Enough space to translate in-place.
       r = wcrtomb(dst + o, wc, state);
-      if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+      if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
         *src += i;
         return r;
       }
     } else {
       // May not be enough space; use temp buffer.
       r = wcrtomb(buf, wc, state);
-      if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
+      if (r == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
         *src += i;
         return r;
       }
diff --git a/libc/include/bits/bionic_multibyte_result.h b/libc/include/bits/bionic_multibyte_result.h
new file mode 100644
index 0000000..0d5cf21
--- /dev/null
+++ b/libc/include/bits/bionic_multibyte_result.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+/**
+ * @file bits/bionic_multibyte_result.h
+ * @brief Named values for the magic number return values of multibyte
+ * conversion APIs defined by C.
+ */
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * @brief The error values defined by C for multibyte conversion APIs.
+ *
+ * Refer to C23 7.30.1 Restartable multibyte/wide character conversion functions
+ * for more details.
+ */
+enum : size_t {
+  /// @brief An encoding error occurred. The bytes read are not a valid unicode
+  /// character, nor are they a partially valid character.
+  BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE = -1UL,
+#define BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE
+
+  /// @brief The bytes read may produce a valid unicode character, but the
+  /// sequence is incomplete. Future calls may complete the character.
+  BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE = -2UL,
+#define BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE
+
+  /// @brief The output of the call was the result of a previous successful
+  /// decoding. No new bytes were consumed.
+  ///
+  /// The common case for this return value is when mbrtoc16 returns the low
+  /// surrogate of a pair.
+  BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED = -3UL,
+#define BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED BIONIC_MULTIBYTE_RESULT_NO_BYTES_CONSUMED
+};
+
+__END_DECLS
diff --git a/libc/include/sys/hwprobe.h b/libc/include/sys/hwprobe.h
new file mode 100644
index 0000000..f2fd98d
--- /dev/null
+++ b/libc/include/sys/hwprobe.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#if __riscv
+
+/**
+ * @file sys/hwprobe.h
+ * @brief RISC-V hardware probing.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/* Pull in struct riscv_hwprobe and corresponding constants. */
+#include <asm/hwprobe.h>
+
+__BEGIN_DECLS
+
+/**
+ * [__riscv_hwprobe(2)](https://docs.kernel.org/riscv/hwprobe.html)
+ * queries hardware characteristics.
+ *
+ * A `__cpu_count` of 0 and null `__cpus` means "all online cpus".
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
+int __riscv_hwprobe(struct riscv_hwprobe* _Nonnull __pairs, size_t __pair_count, size_t __cpu_count, unsigned long* _Nullable __cpus, unsigned __flags);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/uchar.h b/libc/include/uchar.h
index 0c7424d..626372a 100644
--- a/libc/include/uchar.h
+++ b/libc/include/uchar.h
@@ -35,6 +35,8 @@
 
 #include <stddef.h>
 #include <sys/cdefs.h>
+
+#include <bits/bionic_multibyte_result.h>
 #include <bits/mbstate_t.h>
 
 __BEGIN_DECLS
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index 2671580..c4e9679 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -37,6 +37,7 @@
 #include <time.h>
 #include <xlocale.h>
 
+#include <bits/bionic_multibyte_result.h>
 #include <bits/mbstate_t.h>
 #include <bits/wchar_limits.h>
 #include <bits/wctype.h>
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 41d18a6..e90618d 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -955,7 +955,7 @@
     sigaction;
     sigaddset; # introduced=21
     sigaltstack;
-    sigblock;
+    sigblock; # arm x86 arm64 x86_64
     sigdelset; # introduced=21
     sigemptyset; # introduced=21
     sigfillset; # introduced=21
@@ -968,7 +968,7 @@
     sigprocmask;
     sigqueue; # introduced=23
     sigsetjmp; # introduced-arm=9 introduced-arm64=21 introduced-x86=12 introduced-x86_64=21
-    sigsetmask;
+    sigsetmask; # arm x86 arm64 x86_64
     sigsuspend;
     sigtimedwait; # introduced=23
     sigwait;
@@ -1590,6 +1590,7 @@
     mbsrtowcs_l;
     mktime_z;
     __riscv_flush_icache; # riscv64
+    __riscv_hwprobe; # riscv64
     timespec_getres;
     tzalloc;
     tzfree;
diff --git a/libc/private/SigSetConverter.h b/libc/private/SigSetConverter.h
index 7d0b215..9e9df73 100644
--- a/libc/private/SigSetConverter.h
+++ b/libc/private/SigSetConverter.h
@@ -28,8 +28,45 @@
 
 #pragma once
 
-union SigSetConverter {
-  int bsd;
-  sigset_t sigset;
-  sigset64_t sigset64;
+// Android's 32-bit ABI shipped with a sigset_t too small to include any
+// of the realtime signals, so we have both sigset_t and sigset64_t. Many
+// new system calls only accept a sigset64_t, so this helps paper over
+// the difference at zero cost to LP64 in most cases after the optimizer
+// removes the unnecessary temporary `ptr`.
+struct SigSetConverter {
+ public:
+  SigSetConverter(const sigset_t* s) : SigSetConverter(const_cast<sigset_t*>(s)) {}
+
+  SigSetConverter(sigset_t* s) {
+#if defined(__LP64__)
+    // sigset_t == sigset64_t on LP64.
+    ptr = s;
+#else
+    sigset64 = {};
+    if (s != nullptr) {
+      original_ptr = s;
+      sigset = *s;
+      ptr = &sigset64;
+    } else {
+      ptr = nullptr;
+    }
+#endif
+  }
+
+  void copy_out() {
+#if defined(__LP64__)
+    // We used the original pointer directly, so no copy needed.
+#else
+    *original_ptr = sigset;
+#endif
+  }
+
+  sigset64_t* ptr;
+
+ private:
+  [[maybe_unused]] sigset_t* original_ptr;
+  union {
+    sigset_t sigset;
+    sigset64_t sigset64;
+  };
 };
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 78e5046..f9d85b2 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -90,3 +90,5 @@
 
 #define NOTE_GNU_PROPERTY() \
     __bionic_asm_custom_note_gnu_section()
+
+#define L(__label) .L##__label
diff --git a/libc/private/bionic_asm_offsets.h b/libc/private/bionic_asm_offsets.h
index c2f2b56..e72adda 100644
--- a/libc/private/bionic_asm_offsets.h
+++ b/libc/private/bionic_asm_offsets.h
@@ -28,6 +28,6 @@
 
 #pragma once
 
-#ifdef __aarch64__
-#define OFFSETOF_libc_globals_memtag_stack 80
+#if defined(__aarch64__)
+#define OFFSETOF_libc_globals_memtag_stack 64
 #endif
diff --git a/libc/private/bionic_inline_raise.h b/libc/private/bionic_inline_raise.h
index 8565c80..82a564d 100644
--- a/libc/private/bionic_inline_raise.h
+++ b/libc/private/bionic_inline_raise.h
@@ -60,6 +60,13 @@
   register long x3 __asm__("x3") = reinterpret_cast<long>(&info);
   register long x8 __asm__("x8") = __NR_rt_tgsigqueueinfo;
   __asm__("svc #0" : "=r"(x0) : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
+#elif defined(__riscv)
+  register long a0 __asm__("a0") = pid;
+  register long a1 __asm__("a1") = tid;
+  register long a2 __asm__("a2") = sig;
+  register long a3 __asm__("a3") = reinterpret_cast<long>(&info);
+  register long a7 __asm__("a7") = __NR_rt_tgsigqueueinfo;
+  __asm__("ecall" : "=r"(a0) : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a7) : "memory");
 #elif defined(__x86_64__)
   register long rax __asm__("rax") = __NR_rt_tgsigqueueinfo;
   register long rdi __asm__("rdi") = pid;
diff --git a/libc/private/bionic_mbstate.h b/libc/private/bionic_mbstate.h
index 243b220..0e5f861 100644
--- a/libc/private/bionic_mbstate.h
+++ b/libc/private/bionic_mbstate.h
@@ -34,15 +34,9 @@
 
 __BEGIN_DECLS
 
-/*
- * These return values are specified by POSIX for multibyte conversion
- * functions.
- */
-#define __MB_ERR_ILLEGAL_SEQUENCE static_cast<size_t>(-1)
-#define __MB_ERR_INCOMPLETE_SEQUENCE static_cast<size_t>(-2)
-
-#define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
-                         rv == __MB_ERR_INCOMPLETE_SEQUENCE)
+#define __MB_IS_ERR(rv)                              \
+  (rv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE || \
+   rv == BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE)
 
 static inline __wur bool mbstate_is_initial(const mbstate_t* ps) {
   return *(reinterpret_cast<const uint32_t*>(ps->__seq)) == 0;
@@ -63,14 +57,18 @@
   return ps->__seq[n];
 }
 
-static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
+static inline void mbstate_reset(mbstate_t* ps) {
   *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
 }
 
-static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
+  errno = _errno;
+  mbstate_reset(ps);
+  return BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE;
+}
+
+static inline __wur size_t mbstate_reset_and_return(size_t _return, mbstate_t* ps) {
+  mbstate_reset(ps);
   return _return;
 }
 
diff --git a/libc/private/bionic_vdso.h b/libc/private/bionic_vdso.h
index da19b29..406b064 100644
--- a/libc/private/bionic_vdso.h
+++ b/libc/private/bionic_vdso.h
@@ -26,26 +26,23 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _PRIVATE_BIONIC_VDSO_H
-#define _PRIVATE_BIONIC_VDSO_H
-
-#include <time.h>
+#pragma once
 
 #if defined(__aarch64__)
 #define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
-#define VDSO_CLOCK_GETRES_SYMBOL  "__kernel_clock_getres"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
-#define VDSO_TIME_SYMBOL          "__kernel_time"
+#define VDSO_CLOCK_GETRES_SYMBOL "__kernel_clock_getres"
+#define VDSO_GETTIMEOFDAY_SYMBOL "__kernel_gettimeofday"
 #else
 #define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
-#define VDSO_CLOCK_GETRES_SYMBOL  "__vdso_clock_getres"
-#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
-#define VDSO_TIME_SYMBOL          "__vdso_time"
+#define VDSO_CLOCK_GETRES_SYMBOL "__vdso_clock_getres"
+#define VDSO_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday"
 #endif
-
-extern "C" int __clock_gettime(int, timespec*);
-extern "C" int __clock_getres(int, timespec*);
-extern "C" int __gettimeofday(timeval*, struct timezone*);
+#if defined(__riscv)
+#define VDSO_RISCV_HWPROBE_SYMBOL "__vdso_riscv_hwprobe"
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+#define VDSO_TIME_SYMBOL "__vdso_time"
+#endif
 
 struct vdso_entry {
   const char* name;
@@ -56,8 +53,11 @@
   VDSO_CLOCK_GETTIME = 0,
   VDSO_CLOCK_GETRES,
   VDSO_GETTIMEOFDAY,
+#if defined(VDSO_TIME_SYMBOL)
   VDSO_TIME,
+#endif
+#if defined(VDSO_RISCV_HWPROBE_SYMBOL)
+  VDSO_RISCV_HWPROBE,
+#endif
   VDSO_END
 };
-
-#endif  // _PRIVATE_BIONIC_VDSO_H
diff --git a/libc/stdio/vfscanf.cpp b/libc/stdio/vfscanf.cpp
index 3133f1f..3607995 100644
--- a/libc/stdio/vfscanf.cpp
+++ b/libc/stdio/vfscanf.cpp
@@ -327,12 +327,12 @@
             fp->_r--;
             memset(&mbs, 0, sizeof(mbs));
             nconv = mbrtowc(wcp, buf, bytes, &mbs);
-            if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
+            if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
               fp->_flags |= __SERR;
               goto input_failure;
             }
             if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
-            if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
+            if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
               nread += bytes;
               width--;
               if (!(flags & SUPPRESS)) wcp++;
@@ -417,11 +417,11 @@
             wchar_t wc = L'\0';
             memset(&mbs, 0, sizeof(mbs));
             nconv = mbrtowc(&wc, buf, bytes, &mbs);
-            if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
+            if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
               fp->_flags |= __SERR;
               goto input_failure;
             }
-            if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
+            if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
               if ((c == CT_CCL && wctob(wc) != EOF && !ccltab[wctob(wc)]) || (c == CT_STRING && iswspace(wc))) {
                 while (bytes != 0) {
                   bytes--;
diff --git a/libc/upstream-freebsd/android/include/libc_private.h b/libc/upstream-freebsd/android/include/libc_private.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libc/upstream-freebsd/android/include/libc_private.h
diff --git a/libc/upstream-freebsd/lib/libc/gen/ldexp.c b/libc/upstream-freebsd/lib/libc/gen/ldexp.c
deleted file mode 100644
index 887f673..0000000
--- a/libc/upstream-freebsd/lib/libc/gen/ldexp.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* @(#)s_scalbn.c 5.1 93/09/24 */
-/* @(#)fdlibm.h 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$");
-
-#include <sys/types.h>
-#include <machine/endian.h>
-#include <math.h>
-
-/* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */
-
-#if BYTE_ORDER == BIG_ENDIAN
-
-typedef union
-{
-  double value;
-  struct
-  {
-    u_int32_t msw;
-    u_int32_t lsw;
-  } parts;
-} ieee_double_shape_type;
-
-#endif
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
-typedef union
-{
-  double value;
-  struct
-  {
-    u_int32_t lsw;
-    u_int32_t msw;
-  } parts;
-} ieee_double_shape_type;
-
-#endif
-
-/* Get two 32 bit ints from a double.  */
-
-#define EXTRACT_WORDS(ix0,ix1,d)				\
-do {								\
-  ieee_double_shape_type ew_u;					\
-  ew_u.value = (d);						\
-  (ix0) = ew_u.parts.msw;					\
-  (ix1) = ew_u.parts.lsw;					\
-} while (0)
-
-/* Get the more significant 32 bit int from a double.  */
-
-#define GET_HIGH_WORD(i,d)					\
-do {								\
-  ieee_double_shape_type gh_u;					\
-  gh_u.value = (d);						\
-  (i) = gh_u.parts.msw;						\
-} while (0)
-
-/* Set the more significant 32 bits of a double from an int.  */
-
-#define SET_HIGH_WORD(d,v)					\
-do {								\
-  ieee_double_shape_type sh_u;					\
-  sh_u.value = (d);						\
-  sh_u.parts.msw = (v);						\
-  (d) = sh_u.value;						\
-} while (0)
-
-
-static const double
-two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
-twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
-huge   = 1.0e+300,
-tiny   = 1.0e-300;
-
-static 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;
-}
-
-double
-ldexp(double x, int n)
-{
-	int32_t k,hx,lx;
-	EXTRACT_WORDS(hx,lx,x);
-        k = (hx&0x7ff00000)>>20;		/* extract exponent */
-        if (k==0) {				/* 0 or subnormal x */
-            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
-	    x *= two54;
-	    GET_HIGH_WORD(hx,x);
-	    k = ((hx&0x7ff00000)>>20) - 54;
-            if (n< -50000) return tiny*x; 	/*underflow*/
-	    }
-        if (k==0x7ff) return x+x;		/* NaN or Inf */
-        k = k+n;
-        if (k >  0x7fe) return huge*_copysign(huge,x); /* overflow  */
-        if (k > 0) 				/* normal result */
-	    {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
-        if (k <= -54) {
-            if (n > 50000) 	/* in case integer overflow in n+k */
-		return huge*_copysign(huge,x);	/*overflow*/
-	    else return tiny*_copysign(tiny,x); 	/*underflow*/
-	}
-        k += 54;				/* subnormal result */
-	SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
-        return x*twom54;
-}
diff --git a/libc/upstream-freebsd/lib/libc/locale/wcsftime.c b/libc/upstream-freebsd/lib/libc/locale/wcsftime.c
index aabb632..4fe6ad5 100644
--- a/libc/upstream-freebsd/lib/libc/locale/wcsftime.c
+++ b/libc/upstream-freebsd/lib/libc/locale/wcsftime.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2002 Tim J. Robbins
  * All rights reserved.
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/getopt_long.c b/libc/upstream-freebsd/lib/libc/stdlib/getopt_long.c
index 6a3067c..1f3548b 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/getopt_long.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/getopt_long.c
@@ -55,7 +55,7 @@
 #endif /* LIBC_SCCS and not lint */
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/getopt_long.c 342757 2019-01-04 03:13:24Z kevans $");
+__FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
@@ -88,7 +88,7 @@
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER 	(int)1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
 #ifdef GNU_COMPATIBLE
 #define NO_PREFIX	(-1)
@@ -194,7 +194,7 @@
 {
 	char *current_argv, *has_equal;
 #ifdef GNU_COMPATIBLE
-	char *current_dash;
+	const char *current_dash;
 #endif
 	size_t current_argv_len;
 	int i, match, exact_match, second_partial_match;
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/hcreate.c b/libc/upstream-freebsd/lib/libc/stdlib/hcreate.c
index b175d34..c9a0847 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/hcreate.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/hcreate.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2015 Nuxi, https://nuxi.nl/
  *
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/hcreate.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <search.h>
 #include <stdbool.h>
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/hcreate_r.c b/libc/upstream-freebsd/lib/libc/stdlib/hcreate_r.c
index 34db88e..83e322a 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/hcreate_r.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/hcreate_r.c
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/hcreate_r.c 292767 2015-12-27 07:50:11Z ed $");
+__FBSDID("$FreeBSD$");
 
 #include <search.h>
 #include <stdlib.h>
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/hdestroy_r.c b/libc/upstream-freebsd/lib/libc/stdlib/hdestroy_r.c
index 76d8a42..890bd08 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/hdestroy_r.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/hdestroy_r.c
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/hdestroy_r.c 292767 2015-12-27 07:50:11Z ed $");
+__FBSDID("$FreeBSD$");
 
 #include <search.h>
 #include <stdlib.h>
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/hsearch.h b/libc/upstream-freebsd/lib/libc/stdlib/hsearch.h
index a0542b5..649933d 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/hsearch.h
+++ b/libc/upstream-freebsd/lib/libc/stdlib/hsearch.h
@@ -22,7 +22,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libc/stdlib/hsearch.h 292767 2015-12-27 07:50:11Z ed $
+ * $FreeBSD$
  */
 
 #ifndef HSEARCH_H
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/hsearch_r.c b/libc/upstream-freebsd/lib/libc/stdlib/hsearch_r.c
index 9a859d3..2fb5991 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/hsearch_r.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/hsearch_r.c
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/hsearch_r.c 292767 2015-12-27 07:50:11Z ed $");
+__FBSDID("$FreeBSD$");
 
 #include <errno.h>
 #include <limits.h>
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/qsort.c b/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
index e0db4f3..0d65cd1 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
@@ -33,12 +33,20 @@
 static char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/stdlib/qsort.c 334928 2018-06-10 17:54:44Z kib $");
+__FBSDID("$FreeBSD$");
 
+#include <errno.h>
+#include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
+#include "libc_private.h"
 
-#ifdef I_AM_QSORT_R
+#if defined(I_AM_QSORT_R)
+typedef int		 cmp_t(const void *, const void *, void *);
+#elif defined(I_AM_QSORT_R_COMPAT)
 typedef int		 cmp_t(void *, const void *, const void *);
+#elif defined(I_AM_QSORT_S)
+typedef int		 cmp_t(const void *, const void *, void *);
 #else
 typedef int		 cmp_t(const void *, const void *);
 #endif
@@ -65,15 +73,19 @@
 #define	vecswap(a, b, n)				\
 	if ((n) > 0) swapfunc(a, b, n)
 
-#ifdef I_AM_QSORT_R
+#if defined(I_AM_QSORT_R)
+#define	CMP(t, x, y) (cmp((x), (y), (t)))
+#elif defined(I_AM_QSORT_R_COMPAT)
 #define	CMP(t, x, y) (cmp((t), (x), (y)))
+#elif defined(I_AM_QSORT_S)
+#define	CMP(t, x, y) (cmp((x), (y), (t)))
 #else
 #define	CMP(t, x, y) (cmp((x), (y)))
 #endif
 
 static inline char *
 med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
-#ifndef I_AM_QSORT_R
+#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) && !defined(I_AM_QSORT_S)
 __unused
 #endif
 )
@@ -83,20 +95,28 @@
 	      :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
 }
 
-#ifdef I_AM_QSORT_R
-void
-qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
-#else
-#define	thunk NULL
-void
-qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+/*
+ * The actual qsort() implementation is static to avoid preemptible calls when
+ * recursing. Also give them different names for improved debugging.
+ */
+#if defined(I_AM_QSORT_R)
+#define local_qsort local_qsort_r
+#elif defined(I_AM_QSORT_R_COMPAT)
+#define local_qsort local_qsort_r_compat
+#elif defined(I_AM_QSORT_S)
+#define local_qsort local_qsort_s
 #endif
+static void
+local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
 {
 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
 	size_t d1, d2;
 	int cmp_result;
 	int swap_cnt;
 
+	/* if there are less than 2 elements, then sorting is not needed */
+	if (__predict_false(n < 2))
+		return;
 loop:
 	swap_cnt = 0;
 	if (n < 7) {
@@ -160,7 +180,12 @@
 	pn = (char *)a + n * es;
 	d1 = MIN(pa - (char *)a, pb - pa);
 	vecswap(a, pb - d1, d1);
-	d1 = MIN(pd - pc, pn - pd - es);
+	/*
+	 * Cast es to preserve signedness of right-hand side of MIN()
+	 * expression, to avoid sign ambiguity in the implied comparison.  es
+	 * is safely within [0, SSIZE_MAX].
+	 */
+	d1 = MIN(pd - pc, pn - pd - (ssize_t)es);
 	vecswap(pb, pn - d1, d1);
 
 	d1 = pb - pa;
@@ -168,11 +193,7 @@
 	if (d1 <= d2) {
 		/* Recurse on left partition, then iterate on right partition */
 		if (d1 > es) {
-#ifdef I_AM_QSORT_R
-			qsort_r(a, d1 / es, es, thunk, cmp);
-#else
-			qsort(a, d1 / es, es, cmp);
-#endif
+			local_qsort(a, d1 / es, es, cmp, thunk);
 		}
 		if (d2 > es) {
 			/* Iterate rather than recurse to save stack space */
@@ -184,11 +205,7 @@
 	} else {
 		/* Recurse on right partition, then iterate on left partition */
 		if (d2 > es) {
-#ifdef I_AM_QSORT_R
-			qsort_r(pn - d2, d2 / es, es, thunk, cmp);
-#else
-			qsort(pn - d2, d2 / es, es, cmp);
-#endif
+			local_qsort(pn - d2, d2 / es, es, cmp, thunk);
 		}
 		if (d1 > es) {
 			/* Iterate rather than recurse to save stack space */
@@ -198,3 +215,53 @@
 		}
 	}
 }
+
+#if defined(I_AM_QSORT_R)
+void
+(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
+{
+	local_qsort_r(a, n, es, cmp, thunk);
+}
+#elif defined(I_AM_QSORT_R_COMPAT)
+void
+__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+{
+	local_qsort_r_compat(a, n, es, cmp, thunk);
+}
+#elif defined(I_AM_QSORT_S)
+errno_t
+qsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk)
+{
+	if (n > RSIZE_MAX) {
+		__throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL);
+		return (EINVAL);
+	} else if (es > RSIZE_MAX) {
+		__throw_constraint_handler_s("qsort_s : es > RSIZE_MAX",
+		    EINVAL);
+		return (EINVAL);
+	} else if (n != 0) {
+		if (a == NULL) {
+			__throw_constraint_handler_s("qsort_s : a == NULL",
+			    EINVAL);
+			return (EINVAL);
+		} else if (cmp == NULL) {
+			__throw_constraint_handler_s("qsort_s : cmp == NULL",
+			    EINVAL);
+			return (EINVAL);
+		} else if (es <= 0) {
+			__throw_constraint_handler_s("qsort_s : es <= 0",
+			    EINVAL);
+			return (EINVAL);
+		}
+	}
+
+	local_qsort_s(a, n, es, cmp, thunk);
+	return (0);
+}
+#else
+void
+qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+{
+	local_qsort(a, n, es, cmp, NULL);
+}
+#endif
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
index 9e4e79d..d486b1a 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Chisnall
  * All rights reserved.
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libc/stdlib/quick_exit.c 326193 2017-11-25 17:12:48Z pfg $
+ * $FreeBSD$
  */
 
 #include <sys/types.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wcpcpy.c b/libc/upstream-freebsd/lib/libc/string/wcpcpy.c
index e040dba..41b7c51 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcpcpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcpcpy.c
@@ -35,7 +35,7 @@
 static char sccsid[] = "@(#)strcpy.c	8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcpcpy.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcpncpy.c b/libc/upstream-freebsd/lib/libc/string/wcpncpy.c
index 8bf6e87..ccc64cd 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcpncpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcpncpy.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcpncpy.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcscasecmp.c b/libc/upstream-freebsd/lib/libc/string/wcscasecmp.c
index 5bd468d..03a61f8 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcscasecmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcscasecmp.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcscasecmp.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 #include <wctype.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wcscat.c b/libc/upstream-freebsd/lib/libc/string/wcscat.c
index 792f61e..777a576 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcscat.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcscat.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c)1999 Citrus Project,
  * All rights reserved.
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcscat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcscat.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcschr.c b/libc/upstream-freebsd/lib/libc/string/wcschr.c
index ca740c0..a7f1de0 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcschr.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcschr.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2002 Tim J. Robbins
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcschr.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcscmp.c b/libc/upstream-freebsd/lib/libc/string/wcscmp.c
index db01892..7205238 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcscmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcscmp.c
@@ -39,7 +39,7 @@
 __RCSID("$NetBSD: wcscmp.c,v 1.3 2001/01/05 12:13:12 itojun Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
-__FBSDID("$FreeBSD: head/lib/libc/string/wcscmp.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcscpy.c b/libc/upstream-freebsd/lib/libc/string/wcscpy.c
index a639e74..b400fae 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcscpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcscpy.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcscpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcscpy.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcscspn.c b/libc/upstream-freebsd/lib/libc/string/wcscspn.c
index 8a7682f..a0db715 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcscspn.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcscspn.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcscspn.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcscspn.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsdup.c b/libc/upstream-freebsd/lib/libc/string/wcsdup.c
index b97f766..327574b 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsdup.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsdup.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 Tim J. Robbins.
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsdup.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <stdlib.h>
 #include <wchar.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wcslcat.c b/libc/upstream-freebsd/lib/libc/string/wcslcat.c
index 9706fa6..f954b73 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcslcat.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcslcat.c
@@ -35,7 +35,7 @@
 __RCSID("$NetBSD: wcslcat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcslcat.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <wchar.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wcslen.c b/libc/upstream-freebsd/lib/libc/string/wcslen.c
index c596825..cfd3aa2 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcslen.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcslen.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcslen.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcslen.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsncasecmp.c b/libc/upstream-freebsd/lib/libc/string/wcsncasecmp.c
index a963444..39f58be 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsncasecmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsncasecmp.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsncasecmp.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 #include <wctype.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsncat.c b/libc/upstream-freebsd/lib/libc/string/wcsncat.c
index 0214af4..eb13fab 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsncat.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsncat.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcsncat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsncat.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsncmp.c b/libc/upstream-freebsd/lib/libc/string/wcsncmp.c
index 77b709c..55c88f6 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsncmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsncmp.c
@@ -36,7 +36,7 @@
 __RCSID("$NetBSD: wcsncmp.c,v 1.3 2001/01/05 12:13:13 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsncmp.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsncpy.c b/libc/upstream-freebsd/lib/libc/string/wcsncpy.c
index 4075ecc..f86e40f 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsncpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsncpy.c
@@ -38,7 +38,7 @@
 #endif /* LIBC_SCCS and not lint */
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsncpy.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsnlen.c b/libc/upstream-freebsd/lib/libc/string/wcsnlen.c
index 271d341..15fd520 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsnlen.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsnlen.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsnlen.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcspbrk.c b/libc/upstream-freebsd/lib/libc/string/wcspbrk.c
index 63efb01..0e9ccf6 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcspbrk.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcspbrk.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcspbrk.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcspbrk.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsrchr.c b/libc/upstream-freebsd/lib/libc/string/wcsrchr.c
index 97665ca..cc5e7f2 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsrchr.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsrchr.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2002 Tim J. Robbins
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsrchr.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsspn.c b/libc/upstream-freebsd/lib/libc/string/wcsspn.c
index b08a39e..2b08acb 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsspn.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsspn.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wcsspn.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsspn.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcsstr.c b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
index 4309025..74921fe 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcsstr.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
@@ -38,7 +38,7 @@
 #endif /* LIBC_SCCS and not lint */
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcsstr.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wcstok.c b/libc/upstream-freebsd/lib/libc/string/wcstok.c
index 8d62bf7..b4bdc86 100644
--- a/libc/upstream-freebsd/lib/libc/string/wcstok.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcstok.c
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/lib/libc/string/wcstok.c 326025 2017-11-20 19:49:47Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wmemchr.c b/libc/upstream-freebsd/lib/libc/string/wmemchr.c
index 412a276..42ae286 100644
--- a/libc/upstream-freebsd/lib/libc/string/wmemchr.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemchr.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wmemchr.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wmemchr.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wmemcmp.c b/libc/upstream-freebsd/lib/libc/string/wmemcmp.c
index c1e9f3c..f1b1b00 100644
--- a/libc/upstream-freebsd/lib/libc/string/wmemcmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemcmp.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wmemcmp.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wmemcmp.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-freebsd/lib/libc/string/wmemcpy.c b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
index e0d6c04..30956eb 100644
--- a/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wmemcpy.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wmemcpy.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <string.h>
 #include <wchar.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wmemmove.c b/libc/upstream-freebsd/lib/libc/string/wmemmove.c
index b84c2c0..5e8da9f 100644
--- a/libc/upstream-freebsd/lib/libc/string/wmemmove.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemmove.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wmemmove.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wmemmove.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <string.h>
 #include <wchar.h>
diff --git a/libc/upstream-freebsd/lib/libc/string/wmemset.c b/libc/upstream-freebsd/lib/libc/string/wmemset.c
index d4d6308..fcf40ef 100644
--- a/libc/upstream-freebsd/lib/libc/string/wmemset.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemset.c
@@ -34,7 +34,7 @@
 __RCSID("$NetBSD: wmemset.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
 #endif /* LIBC_SCCS and not lint */
 #endif
-__FBSDID("$FreeBSD: head/lib/libc/string/wmemset.c 326193 2017-11-25 17:12:48Z pfg $");
+__FBSDID("$FreeBSD$");
 
 #include <wchar.h>
 
diff --git a/libc/upstream-netbsd/lib/libc/regex/regcomp.c b/libc/upstream-netbsd/lib/libc/regex/regcomp.c
index 957f8ac..86321c1 100644
--- a/libc/upstream-netbsd/lib/libc/regex/regcomp.c
+++ b/libc/upstream-netbsd/lib/libc/regex/regcomp.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: regcomp.c,v 1.46 2021/03/11 15:00:29 christos Exp $	*/
+/*	$NetBSD: regcomp.c,v 1.47 2022/12/21 17:44:15 wiz Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
@@ -51,9 +51,7 @@
 static char sccsid[] = "@(#)regcomp.c	8.5 (Berkeley) 3/20/94";
 __FBSDID("$FreeBSD: head/lib/libc/regex/regcomp.c 368359 2020-12-05 03:18:48Z kevans $");
 #endif
-__RCSID("$NetBSD: regcomp.c,v 1.46 2021/03/11 15:00:29 christos Exp $");
-
-#define _OPENBSD_SOURCE
+__RCSID("$NetBSD: regcomp.c,v 1.47 2022/12/21 17:44:15 wiz Exp $");
 
 #ifndef LIBHACK
 #define REGEX_GNU_EXTENSIONS
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
index 6ee5a5c..af0169f 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: open_memstream.c,v 1.8 2019/05/02 08:30:10 yasuoka Exp $	*/
+/*	$OpenBSD: open_memstream.c,v 1.10 2023/07/11 12:14:16 claudio Exp $	*/
 
 /*
  * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
@@ -53,7 +53,6 @@
 		p = recallocarray(st->string, st->size, sz, 1);
 		if (!p)
 			return (-1);
-		bzero(p + st->size, sz - st->size);
 		*st->pbuf = st->string = p;
 		st->size = sz;
 	}
@@ -136,7 +135,6 @@
 		return (NULL);
 	}
 
-	*st->string = '\0';
 	st->pos = 0;
 	st->len = 0;
 	st->pbuf = pbuf;
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
index aceef35..fca0b71 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: open_wmemstream.c,v 1.8 2015/09/12 16:23:14 guenther Exp $	*/
+/*	$OpenBSD: open_wmemstream.c,v 1.10 2023/07/11 12:14:16 claudio Exp $	*/
 
 /*
  * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
@@ -52,10 +52,9 @@
 
 		if (sz < end + 1)
 			sz = end + 1;
-		p = reallocarray(st->string, sz, sizeof(wchar_t));
+		p = recallocarray(st->string, st->size, sz, sizeof(wchar_t));
 		if (!p)
 			return (-1);
-		bzero(p + st->size, (sz - st->size) * sizeof(wchar_t));
 		*st->pbuf = st->string = p;
 		st->size = sz;
 	}
@@ -146,7 +145,6 @@
 		return (NULL);
 	}
 
-	*st->string = L'\0';
 	st->pos = 0;
 	st->len = 0;
 	st->pbuf = pbuf;
diff --git a/libm/Android.bp b/libm/Android.bp
index 079fd9a..a89885f 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -466,8 +466,6 @@
     name: "libm",
     symbol_file: "libm.map.txt",
     first_version: "9",
-    // APIs implemented in asm don't have debug info: http://b/190554910.
-    allow_untyped_symbols: true,
 }
 
 genrule {
@@ -509,3 +507,8 @@
     tools: ["generate-version-script"],
     cmd: "$(location generate-version-script) x86_64 $(in) $(out)",
 }
+
+filegroup {
+    name: "libc_ldexp_srcs",
+    srcs: ["upstream-freebsd/lib/msun/src/s_scalbn.c"],
+}
diff --git a/libm/NOTICE b/libm/NOTICE
index 5e2f8ca..31337e7 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -1176,6 +1176,32 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 2017, 2023 Steven G. Kargl
+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 unmodified, this list of conditions, and the following
+   disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
 From: @(#)s_ilogb.c 5.1 93/09/24
 ====================================================
 Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/ld128/invtrig.c b/libm/upstream-freebsd/lib/msun/ld128/invtrig.c
index ab93732..3ba767b 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/invtrig.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/invtrig.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/ld128/invtrig.h b/libm/upstream-freebsd/lib/msun/ld128/invtrig.h
index 423b568..3f505c5 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/invtrig.h
+++ b/libm/upstream-freebsd/lib/msun/ld128/invtrig.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
index 159338f..3faf7a7 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
+++ b/libm/upstream-freebsd/lib/msun/ld128/k_expl.h
@@ -1,7 +1,7 @@
 /* from: FreeBSD: head/lib/msun/ld128/s_expl.c 251345 2013-06-03 20:09:22Z kargl */
 
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009-2013 Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/ld128/s_exp2l.c b/libm/upstream-freebsd/lib/msun/ld128/s_exp2l.c
index ee3d2c7..bcbdc5f 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/s_exp2l.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/s_exp2l.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/ld128/s_expl.c b/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
index 5b786af..0274a8f 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/s_expl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2009-2013 Steven G. Kargl
  * All rights reserved.
@@ -65,8 +65,6 @@
 	int k;
 	uint16_t hx, ix;
 
-	DOPRINT_START(&x);
-
 	/* Filter out exceptional cases. */
 	u.e = x;
 	hx = u.xbits.expsign;
@@ -74,15 +72,15 @@
 	if (ix >= BIAS + 13) {		/* |x| >= 8192 or x is NaN */
 		if (ix == BIAS + LDBL_MAX_EXP) {
 			if (hx & 0x8000)  /* x is -Inf or -NaN */
-				RETURNP(-1 / x);
-			RETURNP(x + x);	/* x is +Inf or +NaN */
+				RETURNF(-1 / x);
+			RETURNF(x + x);	/* x is +Inf or +NaN */
 		}
 		if (x > o_threshold)
-			RETURNP(huge * huge);
+			RETURNF(huge * huge);
 		if (x < u_threshold)
-			RETURNP(tiny * tiny);
+			RETURNF(tiny * tiny);
 	} else if (ix < BIAS - 114) {	/* |x| < 0x1p-114 */
-		RETURN2P(1, x);		/* 1 with inexact iff x != 0 */
+		RETURNF(1 + x);		/* 1 with inexact iff x != 0 */
 	}
 
 	ENTERI();
@@ -210,8 +208,6 @@
 	int k, n, n2;
 	uint16_t hx, ix;
 
-	DOPRINT_START(&x);
-
 	/* Filter out exceptional cases. */
 	u.e = x;
 	hx = u.xbits.expsign;
@@ -219,11 +215,11 @@
 	if (ix >= BIAS + 7) {		/* |x| >= 128 or x is NaN */
 		if (ix == BIAS + LDBL_MAX_EXP) {
 			if (hx & 0x8000)  /* x is -Inf or -NaN */
-				RETURNP(-1 / x - 1);
-			RETURNP(x + x);	/* x is +Inf or +NaN */
+				RETURNF(-1 / x - 1);
+			RETURNF(x + x);	/* x is +Inf or +NaN */
 		}
 		if (x > o_threshold)
-			RETURNP(huge * huge);
+			RETURNF(huge * huge);
 		/*
 		 * expm1l() never underflows, but it must avoid
 		 * unrepresentable large negative exponents.  We used a
@@ -232,7 +228,7 @@
 		 * in the same way as large ones here.
 		 */
 		if (hx & 0x8000)	/* x <= -128 */
-			RETURN2P(tiny, -1);	/* good for x < -114ln2 - eps */
+			RETURNF(tiny - 1);	/* good for x < -114ln2 - eps */
 	}
 
 	ENTERI();
@@ -244,7 +240,7 @@
 		if (x < T3) {
 			if (ix < BIAS - 113) {	/* |x| < 0x1p-113 */
 				/* x (rounded) with inexact if x != 0: */
-				RETURNPI(x == 0 ? x :
+				RETURNI(x == 0 ? x :
 				    (0x1p200 * x + fabsl(x)) * 0x1p-200);
 			}
 			q = x * x2 * C3 + x2 * x2 * (C4 + x * (C5 + x * (C6 +
@@ -265,9 +261,9 @@
 		hx2_hi = x_hi * x_hi / 2;
 		hx2_lo = x_lo * (x + x_hi) / 2;
 		if (ix >= BIAS - 7)
-			RETURN2PI(hx2_hi + x_hi, hx2_lo + x_lo + q);
+			RETURNI((hx2_hi + x_hi) + (hx2_lo + x_lo + q));
 		else
-			RETURN2PI(x, hx2_lo + q + hx2_hi);
+			RETURNI(x + (hx2_lo + q + hx2_hi));
 	}
 
 	/* Reduce x to (k*ln2 + endpoint[n2] + r1 + r2). */
diff --git a/libm/upstream-freebsd/lib/msun/ld128/s_logl.c b/libm/upstream-freebsd/lib/msun/ld128/s_logl.c
index 4774a27..bc53884 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/s_logl.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/s_logl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007-2013 Bruce D. Evans
  * All rights reserved.
@@ -573,24 +573,23 @@
 	int i, k;
 	int16_t ax, hx;
 
-	DOPRINT_START(&x);
 	EXTRACT_LDBL128_WORDS(hx, lx, llx, x);
 	if (hx < 0x3fff) {		/* x < 1, or x neg NaN */
 		ax = hx & 0x7fff;
 		if (ax >= 0x3fff) {	/* x <= -1, or x neg NaN */
 			if (ax == 0x3fff && (lx | llx) == 0)
-				RETURNP(-1 / zero);	/* log1p(-1) = -Inf */
+				RETURNF(-1 / zero);	/* log1p(-1) = -Inf */
 			/* log1p(x < 1, or x NaN) = qNaN: */
-			RETURNP((x - x) / (x - x));
+			RETURNF((x - x) / (x - x));
 		}
 		if (ax <= 0x3f8d) {	/* |x| < 2**-113 */
 			if ((int)x == 0)
-				RETURNP(x);	/* x with inexact if x != 0 */
+				RETURNF(x);	/* x with inexact if x != 0 */
 		}
 		f_hi = 1;
 		f_lo = x;
 	} else if (hx >= 0x7fff) {	/* x +Inf or non-neg NaN */
-		RETURNP(x + x);		/* log1p(Inf or NaN) = Inf or qNaN */
+		RETURNF(x + x);		/* log1p(Inf or NaN) = Inf or qNaN */
 	} else if (hx < 0x40e1) {	/* 1 <= x < 2**226 */
 		f_hi = x;
 		f_lo = 1;
@@ -669,7 +668,7 @@
 #endif
 
 	_3sumF(val_hi, val_lo, F_hi(i) + dk * ln2_hi);
-	RETURN2PI(val_hi, val_lo);
+	RETURNI(val_hi + val_lo);
 }
 
 #ifdef STRUCT_RETURN
@@ -680,7 +679,6 @@
 	struct ld r;
 
 	ENTERI();
-	DOPRINT_START(&x);
 	k_logl(x, &r);
 	RETURNSPI(&r);
 }
@@ -708,15 +706,13 @@
 	long double hi, lo;
 
 	ENTERI();
-	DOPRINT_START(&x);
 	k_logl(x, &r);
 	if (!r.lo_set)
-		RETURNPI(r.hi);
+		RETURNI(r.hi);
 	_2sumF(r.hi, r.lo);
 	hi = (float)r.hi;
 	lo = r.lo + (r.hi - hi);
-	RETURN2PI(invln10_hi * hi,
-	    invln10_lo_plus_hi * lo + invln10_lo * hi);
+	RETURNI(invln10_hi * hi + (invln10_lo_plus_hi * lo + invln10_lo * hi));
 }
 
 long double
@@ -726,15 +722,13 @@
 	long double hi, lo;
 
 	ENTERI();
-	DOPRINT_START(&x);
 	k_logl(x, &r);
 	if (!r.lo_set)
-		RETURNPI(r.hi);
+		RETURNI(r.hi);
 	_2sumF(r.hi, r.lo);
 	hi = (float)r.hi;
 	lo = r.lo + (r.hi - hi);
-	RETURN2PI(invln2_hi * hi,
-	    invln2_lo_plus_hi * lo + invln2_lo * hi);
+	RETURNI(invln2_hi * hi + (invln2_lo_plus_hi * lo + invln2_lo * hi));
 }
 
 #endif /* STRUCT_RETURN */
diff --git a/libm/upstream-freebsd/lib/msun/ld128/s_nanl.c b/libm/upstream-freebsd/lib/msun/ld128/s_nanl.c
index 45d10e5..cde3f18 100644
--- a/libm/upstream-freebsd/lib/msun/ld128/s_nanl.c
+++ b/libm/upstream-freebsd/lib/msun/ld128/s_nanl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 David Schultz
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/catrig.c b/libm/upstream-freebsd/lib/msun/src/catrig.c
index 431d8e6..82061b5 100644
--- a/libm/upstream-freebsd/lib/msun/src/catrig.c
+++ b/libm/upstream-freebsd/lib/msun/src/catrig.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/catrigf.c b/libm/upstream-freebsd/lib/msun/src/catrigf.c
index 62bcd39..fb4a6bf 100644
--- a/libm/upstream-freebsd/lib/msun/src/catrigf.c
+++ b/libm/upstream-freebsd/lib/msun/src/catrigf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/e_acos.c b/libm/upstream-freebsd/lib/msun/src/e_acos.c
index 1f6dca5..6623355 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_acos.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_acos.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_acos(x)
+/* acos(x)
  * Method :                  
  *	acos(x)  = pi/2 - asin(x)
  *	acos(-x) = pi/2 + asin(x)
@@ -62,7 +62,7 @@
 qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
 
 double
-__ieee754_acos(double x)
+acos(double x)
 {
 	double z,p,q,r,w,s,c,df;
 	int32_t hx,ix;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_acosf.c b/libm/upstream-freebsd/lib/msun/src/e_acosf.c
index c9f62cc..64f1c5a 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_acosf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_acosf.c
@@ -32,7 +32,7 @@
 qS1 = -7.0662963390e-01;
 
 float
-__ieee754_acosf(float x)
+acosf(float x)
 {
 	float z,p,q,r,w,s,c,df;
 	int32_t hx,ix;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_acosh.c b/libm/upstream-freebsd/lib/msun/src/e_acosh.c
index 358c8bd..7947995 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_acosh.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_acosh.c
@@ -15,7 +15,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_acosh(x)
+/* acosh(x)
  * Method :
  *	Based on 
  *		acosh(x) = log [ x + sqrt(x*x-1) ]
@@ -39,7 +39,7 @@
 ln2	= 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */
 
 double
-__ieee754_acosh(double x)
+acosh(double x)
 {
 	double t;
 	int32_t hx;
@@ -51,12 +51,12 @@
 	    if(hx >=0x7ff00000) {	/* x is inf of NaN */
 	        return x+x;
 	    } else 
-		return __ieee754_log(x)+ln2;	/* acosh(huge)=log(2x) */
+		return log(x)+ln2;	/* acosh(huge)=log(2x) */
 	} else if(((hx-0x3ff00000)|lx)==0) {
 	    return 0.0;			/* acosh(1) = 0 */
 	} else if (hx > 0x40000000) {	/* 2**28 > x > 2 */
 	    t=x*x;
-	    return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+	    return log(2.0*x-one/(x+sqrt(t-one)));
 	} else {			/* 1<x<2 */
 	    t = x-one;
 	    return log1p(t+sqrt(2.0*t+t*t));
diff --git a/libm/upstream-freebsd/lib/msun/src/e_acoshf.c b/libm/upstream-freebsd/lib/msun/src/e_acoshf.c
index f529b20..781ccf2 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_acoshf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_acoshf.c
@@ -24,7 +24,7 @@
 ln2	= 6.9314718246e-01;  /* 0x3f317218 */
 
 float
-__ieee754_acoshf(float x)
+acoshf(float x)
 {
 	float t;
 	int32_t hx;
@@ -35,14 +35,14 @@
 	    if(hx >=0x7f800000) {	/* x is inf of NaN */
 	        return x+x;
 	    } else
-		return __ieee754_logf(x)+ln2;	/* acosh(huge)=log(2x) */
+		return logf(x)+ln2;	/* acosh(huge)=log(2x) */
 	} else if (hx==0x3f800000) {
 	    return 0.0;			/* acosh(1) = 0 */
 	} else if (hx > 0x40000000) {	/* 2**28 > x > 2 */
 	    t=x*x;
-	    return __ieee754_logf((float)2.0*x-one/(x+__ieee754_sqrtf(t-one)));
+	    return logf((float)2.0*x-one/(x+sqrtf(t-one)));
 	} else {			/* 1<x<2 */
 	    t = x-one;
-	    return log1pf(t+__ieee754_sqrtf((float)2.0*t+t*t));
+	    return log1pf(t+sqrtf((float)2.0*t+t*t));
 	}
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_asin.c b/libm/upstream-freebsd/lib/msun/src/e_asin.c
index 931b270..fa180ab 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_asin.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_asin.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_asin(x)
+/* asin(x)
  * Method :                  
  *	Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
  *	we approximate asin(x) on [0,0.5] by
@@ -68,7 +68,7 @@
 qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
 
 double
-__ieee754_asin(double x)
+asin(double x)
 {
 	double t=0.0,w,p,q,c,r,s;
 	int32_t hx,ix;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_asinf.c b/libm/upstream-freebsd/lib/msun/src/e_asinf.c
index deaabb6..db4b9b6 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_asinf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_asinf.c
@@ -32,7 +32,7 @@
 pio2 =  1.570796326794896558e+00;
 
 float
-__ieee754_asinf(float x)
+asinf(float x)
 {
 	double s;
 	float t,w,p,q;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_atan2.c b/libm/upstream-freebsd/lib/msun/src/e_atan2.c
index 231a161..0b2e721 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_atan2.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_atan2.c
@@ -15,7 +15,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_atan2(y,x)
+/* atan2(y,x)
  * Method :
  *	1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
  *	2. Reduce x to positive by (if x and y are unexceptional): 
@@ -58,7 +58,7 @@
 pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
 
 double
-__ieee754_atan2(double y, double x)
+atan2(double y, double x)
 {
 	double z;
 	int32_t k,m,hx,hy,ix,iy;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_atan2f.c b/libm/upstream-freebsd/lib/msun/src/e_atan2f.c
index 346d767..4ea001d 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_atan2f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_atan2f.c
@@ -30,7 +30,7 @@
 pi_lo   = -8.7422776573e-08; /* 0xb3bbbd2e */
 
 float
-__ieee754_atan2f(float y, float x)
+atan2f(float y, float x)
 {
 	float z;
 	int32_t k,m,hx,hy,ix,iy;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_atanh.c b/libm/upstream-freebsd/lib/msun/src/e_atanh.c
index 422ff26..41f3bca 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_atanh.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_atanh.c
@@ -15,7 +15,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_atanh(x)
+/* atanh(x)
  * Method :
  *    1.Reduced x to positive by atanh(-x) = -atanh(x)
  *    2.For x>=0.5
@@ -42,7 +42,7 @@
 static const double zero = 0.0;
 
 double
-__ieee754_atanh(double x)
+atanh(double x)
 {
 	double t;
 	int32_t hx,ix;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_atanhf.c b/libm/upstream-freebsd/lib/msun/src/e_atanhf.c
index 4bd6a8f..46643be 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_atanhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_atanhf.c
@@ -24,7 +24,7 @@
 static const float zero = 0.0;
 
 float
-__ieee754_atanhf(float x)
+atanhf(float x)
 {
 	float t;
 	int32_t hx,ix;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_cosh.c b/libm/upstream-freebsd/lib/msun/src/e_cosh.c
index 246b5fb..071663e 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_cosh.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_cosh.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_cosh(x)
+/* cosh(x)
  * Method : 
  * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
  *	1. Replace x by |x| (cosh(x) = cosh(-x)). 
@@ -43,7 +43,7 @@
 static const double one = 1.0, half=0.5, huge = 1.0e300;
 
 double
-__ieee754_cosh(double x)
+cosh(double x)
 {
 	double t,w;
 	int32_t ix;
@@ -65,12 +65,12 @@
 
     /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
 	if (ix < 0x40360000) {
-		t = __ieee754_exp(fabs(x));
+		t = exp(fabs(x));
 		return half*t+half/t;
 	}
 
     /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
-	if (ix < 0x40862E42)  return half*__ieee754_exp(fabs(x));
+	if (ix < 0x40862E42)  return half*exp(fabs(x));
 
     /* |x| in [log(maxdouble), overflowthresold] */
 	if (ix<=0x408633CE)
diff --git a/libm/upstream-freebsd/lib/msun/src/e_coshf.c b/libm/upstream-freebsd/lib/msun/src/e_coshf.c
index 95a0d6e..1673315 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_coshf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_coshf.c
@@ -22,7 +22,7 @@
 static const float one = 1.0, half=0.5, huge = 1.0e30;
 
 float
-__ieee754_coshf(float x)
+coshf(float x)
 {
 	float t,w;
 	int32_t ix;
@@ -43,12 +43,12 @@
 
     /* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */
 	if (ix < 0x41100000) {
-		t = __ieee754_expf(fabsf(x));
+		t = expf(fabsf(x));
 		return half*t+half/t;
 	}
 
     /* |x| in [9, log(maxfloat)] return half*exp(|x|) */
-	if (ix < 0x42b17217)  return half*__ieee754_expf(fabsf(x));
+	if (ix < 0x42b17217)  return half*expf(fabsf(x));
 
     /* |x| in [log(maxfloat), overflowthresold] */
 	if (ix<=0x42b2d4fc)
diff --git a/libm/upstream-freebsd/lib/msun/src/e_exp.c b/libm/upstream-freebsd/lib/msun/src/e_exp.c
index dd04d8e..59da392 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_exp.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_exp.c
@@ -13,7 +13,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_exp(x)
+/* exp(x)
  * Returns the exponential of x.
  *
  * Method
@@ -102,7 +102,7 @@
 twom1000= 9.33263618503218878990e-302;     /* 2**-1000=0x01700000,0*/
 
 double
-__ieee754_exp(double x)	/* default IEEE double exp */
+exp(double x)	/* default IEEE double exp */
 {
 	double y,hi=0.0,lo=0.0,c,t,twopk;
 	int32_t k=0,xsb;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_expf.c b/libm/upstream-freebsd/lib/msun/src/e_expf.c
index 4903d55..620d341 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_expf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_expf.c
@@ -43,7 +43,7 @@
 twom100 = 7.8886090522e-31;      /* 2**-100=0x0d800000 */
 
 float
-__ieee754_expf(float x)
+expf(float x)
 {
 	float y,hi=0.0,lo=0.0,c,t,twopk;
 	int32_t k=0,xsb;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_fmod.c b/libm/upstream-freebsd/lib/msun/src/e_fmod.c
index 3a28dc4..6d5f533 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_fmod.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_fmod.c
@@ -15,7 +15,7 @@
 __FBSDID("$FreeBSD$");
 
 /* 
- * __ieee754_fmod(x,y)
+ * fmod(x,y)
  * Return x mod y in exact arithmetic
  * Method: shift and subtract
  */
@@ -28,7 +28,7 @@
 static const double one = 1.0, Zero[] = {0.0, -0.0,};
 
 double
-__ieee754_fmod(double x, double y)
+fmod(double x, double y)
 {
 	int32_t n,hx,hy,hz,ix,iy,sx,i;
 	u_int32_t lx,ly,lz;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_fmodf.c b/libm/upstream-freebsd/lib/msun/src/e_fmodf.c
index 1b6bf36..3cef921 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_fmodf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_fmodf.c
@@ -17,7 +17,7 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * __ieee754_fmodf(x,y)
+ * fmodf(x,y)
  * Return x mod y in exact arithmetic
  * Method: shift and subtract
  */
@@ -28,7 +28,7 @@
 static const float one = 1.0, Zero[] = {0.0, -0.0,};
 
 float
-__ieee754_fmodf(float x, float y)
+fmodf(float x, float y)
 {
 	int32_t n,hx,hy,hz,ix,iy,sx,i;
 
diff --git a/libm/upstream-freebsd/lib/msun/src/e_gamma.c b/libm/upstream-freebsd/lib/msun/src/e_gamma.c
index 28fb5cc..a13f3e2 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_gamma.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_gamma.c
@@ -15,10 +15,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_gamma(x)
+/* gamma(x)
  * Return the logarithm of the Gamma function of x.
  *
- * Method: call __ieee754_gamma_r
+ * Method: call gamma_r
  */
 
 #include "math.h"
@@ -27,7 +27,7 @@
 extern int signgam;
 
 double
-__ieee754_gamma(double x)
+gamma(double x)
 {
-	return __ieee754_gamma_r(x,&signgam);
+	return gamma_r(x,&signgam);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c b/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c
index 2c423dc..2d996ca 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_gamma_r.c
@@ -15,18 +15,18 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_gamma_r(x, signgamp)
+/* gamma_r(x, signgamp)
  * Reentrant version of the logarithm of the Gamma function 
  * with user provide pointer for the sign of Gamma(x). 
  *
- * Method: See __ieee754_lgamma_r
+ * Method: See lgamma_r
  */
 
 #include "math.h"
 #include "math_private.h"
 
 double
-__ieee754_gamma_r(double x, int *signgamp)
+gamma_r(double x, int *signgamp)
 {
-	return __ieee754_lgamma_r(x,signgamp);
+	return lgamma_r(x,signgamp);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_gammaf.c b/libm/upstream-freebsd/lib/msun/src/e_gammaf.c
index c1b1668..563c148 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_gammaf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_gammaf.c
@@ -16,10 +16,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_gammaf(x)
+/* gammaf(x)
  * Return the logarithm of the Gamma function of x.
  *
- * Method: call __ieee754_gammaf_r
+ * Method: call gammaf_r
  */
 
 #include "math.h"
@@ -28,7 +28,7 @@
 extern int signgam;
 
 float
-__ieee754_gammaf(float x)
+gammaf(float x)
 {
-	return __ieee754_gammaf_r(x,&signgam);
+	return gammaf_r(x,&signgam);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c b/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c
index 9d7831b..d7fc2db 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_gammaf_r.c
@@ -16,18 +16,18 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_gammaf_r(x, signgamp)
+/* gammaf_r(x, signgamp)
  * Reentrant version of the logarithm of the Gamma function
  * with user provide pointer for the sign of Gamma(x).
  *
- * Method: See __ieee754_lgammaf_r
+ * Method: See lgammaf_r
  */
 
 #include "math.h"
 #include "math_private.h"
 
 float
-__ieee754_gammaf_r(float x, int *signgamp)
+gammaf_r(float x, int *signgamp)
 {
-	return __ieee754_lgammaf_r(x,signgamp);
+	return lgammaf_r(x,signgamp);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_hypot.c b/libm/upstream-freebsd/lib/msun/src/e_hypot.c
index 7c455bb..8e3f931 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_hypot.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_hypot.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_hypot(x,y)
+/* hypot(x,y)
  *
  * Method :                  
  *	If (assume round-to-nearest) z=x*x+y*y 
@@ -52,7 +52,7 @@
 #include "math_private.h"
 
 double
-__ieee754_hypot(double x, double y)
+hypot(double x, double y)
 {
 	double a,b,t1,t2,y1,y2,w;
 	int32_t j,k,ha,hb;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_hypotf.c b/libm/upstream-freebsd/lib/msun/src/e_hypotf.c
index 0061026..a3b8c86 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_hypotf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_hypotf.c
@@ -20,7 +20,7 @@
 #include "math_private.h"
 
 float
-__ieee754_hypotf(float x, float y)
+hypotf(float x, float y)
 {
 	float a,b,t1,t2,y1,y2,w;
 	int32_t j,k,ha,hb;
@@ -67,14 +67,14 @@
 	if (w>b) {
 	    SET_FLOAT_WORD(t1,ha&0xfffff000);
 	    t2 = a-t1;
-	    w  = __ieee754_sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
+	    w  = sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
 	} else {
 	    a  = a+a;
 	    SET_FLOAT_WORD(y1,hb&0xfffff000);
 	    y2 = b - y1;
 	    SET_FLOAT_WORD(t1,(ha+0x00800000)&0xfffff000);
 	    t2 = a - t1;
-	    w  = __ieee754_sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+	    w  = sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
 	}
 	if(k!=0) {
 	    SET_FLOAT_WORD(t1,(127+k)<<23);
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0.c b/libm/upstream-freebsd/lib/msun/src/e_j0.c
index 5d862b6..c43ab69 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0.c
@@ -13,7 +13,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_j0(x), __ieee754_y0(x)
+/* j0(x), y0(x)
  * Bessel function of the first and second kinds of order zero.
  * Method -- j0(x):
  *	1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
@@ -83,7 +83,7 @@
 static const double zero = 0, qrtr = 0.25;
 
 double
-__ieee754_j0(double x)
+j0(double x)
 {
 	double z, s,c,ss,cc,r,u,v;
 	int32_t hx,ix;
@@ -143,7 +143,7 @@
 v04  =  4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
 
 double
-__ieee754_y0(double x)
+y0(double x)
 {
 	double z, s,c,ss,cc,u,v;
 	int32_t hx,ix,lx;
@@ -192,12 +192,12 @@
                 return z;
 	}
 	if(ix<=0x3e400000) {	/* x < 2**-27 */
-	    return(u00 + tpi*__ieee754_log(x));
+	    return(u00 + tpi*log(x));
 	}
 	z = x*x;
 	u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
 	v = one+z*(v01+z*(v02+z*(v03+z*v04)));
-	return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+	return(u/v + tpi*(j0(x)*log(x)));
 }
 
 /* The asymptotic expansions of pzero is
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j0f.c b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
index 1c5ef4d..290be04 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j0f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j0f.c
@@ -45,7 +45,7 @@
 static const float zero = 0, qrtr = 0.25;
 
 float
-__ieee754_j0f(float x)
+j0f(float x)
 {
 	float z, s,c,ss,cc,r,u,v;
 	int32_t hx,ix;
@@ -105,7 +105,7 @@
 v04  =  4.4111031494e-10; /* 0x2ff280c2 */
 
 float
-__ieee754_y0f(float x)
+y0f(float x)
 {
 	float z, s,c,ss,cc,u,v;
 	int32_t hx,ix;
@@ -147,12 +147,12 @@
                 return z;
 	}
 	if(ix<=0x39000000) {	/* x < 2**-13 */
-	    return(u00 + tpi*__ieee754_logf(x));
+	    return(u00 + tpi*logf(x));
 	}
 	z = x*x;
 	u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
 	v = one+z*(v01+z*(v02+z*(v03+z*v04)));
-	return(u/v + tpi*(__ieee754_j0f(x)*__ieee754_logf(x)));
+	return(u/v + tpi*(j0f(x)*logf(x)));
 }
 
 /* The asymptotic expansions of pzero is
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1.c b/libm/upstream-freebsd/lib/msun/src/e_j1.c
index fb44627..ee3f6fc 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j1.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j1.c
@@ -13,7 +13,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_j1(x), __ieee754_y1(x)
+/* j1(x), y1(x)
  * Bessel function of the first and second kinds of order zero.
  * Method -- j1(x):
  *	1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
@@ -84,7 +84,7 @@
 static const double zero    = 0.0;
 
 double
-__ieee754_j1(double x)
+j1(double x)
 {
 	double z, s,c,ss,cc,r,u,v,y;
 	int32_t hx,ix;
@@ -140,7 +140,7 @@
 };
 
 double
-__ieee754_y1(double x)
+y1(double x)
 {
 	double z, s,c,ss,cc,u,v;
 	int32_t hx,ix,lx;
@@ -190,7 +190,7 @@
         z = x*x;
         u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
         v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
-        return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+        return(x*(u/v) + tpi*(j1(x)*log(x)-one/x));
 }
 
 /* For x >= 8, the asymptotic expansions of pone is
diff --git a/libm/upstream-freebsd/lib/msun/src/e_j1f.c b/libm/upstream-freebsd/lib/msun/src/e_j1f.c
index c6c45c1..e1f4498 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_j1f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_j1f.c
@@ -46,7 +46,7 @@
 static const float zero    = 0.0;
 
 float
-__ieee754_j1f(float x)
+j1f(float x)
 {
 	float z, s,c,ss,cc,r,u,v,y;
 	int32_t hx,ix;
@@ -102,7 +102,7 @@
 };
 
 float
-__ieee754_y1f(float x)
+y1f(float x)
 {
 	float z, s,c,ss,cc,u,v;
 	int32_t hx,ix;
@@ -145,7 +145,7 @@
         z = x*x;
         u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
         v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
-        return(x*(u/v) + tpi*(__ieee754_j1f(x)*__ieee754_logf(x)-one/x));
+        return(x*(u/v) + tpi*(j1f(x)*logf(x)-one/x));
 }
 
 /* For x >= 8, the asymptotic expansions of pone is
diff --git a/libm/upstream-freebsd/lib/msun/src/e_jn.c b/libm/upstream-freebsd/lib/msun/src/e_jn.c
index c7ba7da..6b876ce 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_jn.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_jn.c
@@ -14,7 +14,7 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * jn(n, x), yn(n, x)
  * floating point Bessel's function of the 1st and 2nd kind
  * of order n
  *
@@ -22,15 +22,15 @@
  *	y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
  *	y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
  * Note 2. About jn(n,x), yn(n,x)
- *	For n=0, j0(x) is called,
- *	for n=1, j1(x) is called,
- *	for n<x, forward recursion us used starting
+ *	For n=0, j0(x) is called.
+ *	For n=1, j1(x) is called.
+ *	For n<x, forward recursion is used starting
  *	from values of j0(x) and j1(x).
- *	for n>x, a continued fraction approximation to
+ *	For n>x, a continued fraction approximation to
  *	j(n,x)/j(n-1,x) is evaluated and then backward
  *	recursion is used starting from a supposed value
- *	for j(n,x). The resulting value of j(0,x) is
- *	compared with the actual value to correct the
+ *	for j(n,x). The resulting values of j(0,x) or j(1,x) are
+ *	compared with the actual values to correct the
  *	supposed value of j(n,x).
  *
  *	yn(n,x) is similar in all respects, except
@@ -51,7 +51,7 @@
 static const double zero  =  0.00000000000000000000e+00;
 
 double
-__ieee754_jn(int n, double x)
+jn(int n, double x)
 {
 	int32_t i,hx,ix,lx, sgn;
 	double a, b, c, s, temp, di;
@@ -69,8 +69,8 @@
 		x = -x;
 		hx ^= 0x80000000;
 	}
-	if(n==0) return(__ieee754_j0(x));
-	if(n==1) return(__ieee754_j1(x));
+	if(n==0) return(j0(x));
+	if(n==1) return(j1(x));
 	sgn = (n&1)&(hx>>31);	/* even n -- 0, odd n -- sign(x) */
 	x = fabs(x);
 	if((ix|lx)==0||ix>=0x7ff00000) 	/* if x is 0 or inf */
@@ -100,8 +100,8 @@
 		}
 		b = invsqrtpi*temp/sqrt(x);
 	    } else {
-	        a = __ieee754_j0(x);
-	        b = __ieee754_j1(x);
+	        a = j0(x);
+	        b = j1(x);
 	        for(i=1;i<n;i++){
 		    temp = b;
 		    b = b*((double)(i+i)/x) - a; /* avoid underflow */
@@ -177,7 +177,7 @@
 		 */
 		tmp = n;
 		v = two/x;
-		tmp = tmp*__ieee754_log(fabs(v*tmp));
+		tmp = tmp*log(fabs(v*tmp));
 		if(tmp<7.09782712893383973096e+02) {
 	    	    for(i=n-1,di=(double)(i+i);i>0;i--){
 		        temp = b;
@@ -201,8 +201,8 @@
 			}
 	     	    }
 		}
-		z = __ieee754_j0(x);
-		w = __ieee754_j1(x);
+		z = j0(x);
+		w = j1(x);
 		if (fabs(z) >= fabs(w))
 		    b = (t*z/b);
 		else
@@ -213,7 +213,7 @@
 }
 
 double
-__ieee754_yn(int n, double x)
+yn(int n, double x)
 {
 	int32_t i,hx,ix,lx;
 	int32_t sign;
@@ -232,8 +232,8 @@
 		n = -n;
 		sign = 1 - ((n&1)<<1);
 	}
-	if(n==0) return(__ieee754_y0(x));
-	if(n==1) return(sign*__ieee754_y1(x));
+	if(n==0) return(y0(x));
+	if(n==1) return(sign*y1(x));
 	if(ix==0x7ff00000) return zero;
 	if(ix>=0x52D00000) { /* x > 2**302 */
     /* (x >> n**2)
@@ -259,8 +259,8 @@
 		b = invsqrtpi*temp/sqrt(x);
 	} else {
 	    u_int32_t high;
-	    a = __ieee754_y0(x);
-	    b = __ieee754_y1(x);
+	    a = y0(x);
+	    b = y1(x);
 	/* quit if b is -inf */
 	    GET_HIGH_WORD(high,b);
 	    for(i=1;i<n&&high!=0xfff00000;i++){
diff --git a/libm/upstream-freebsd/lib/msun/src/e_jnf.c b/libm/upstream-freebsd/lib/msun/src/e_jnf.c
index 965feeb..ba58622 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_jnf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_jnf.c
@@ -32,7 +32,7 @@
 static const float zero  =  0.0000000000e+00;
 
 float
-__ieee754_jnf(int n, float x)
+jnf(int n, float x)
 {
 	int32_t i,hx,ix, sgn;
 	float a, b, temp, di;
@@ -50,16 +50,16 @@
 		x = -x;
 		hx ^= 0x80000000;
 	}
-	if(n==0) return(__ieee754_j0f(x));
-	if(n==1) return(__ieee754_j1f(x));
+	if(n==0) return(j0f(x));
+	if(n==1) return(j1f(x));
 	sgn = (n&1)&(hx>>31);	/* even n -- 0, odd n -- sign(x) */
 	x = fabsf(x);
 	if(ix==0||ix>=0x7f800000) 	/* if x is 0 or inf */
 	    b = zero;
 	else if((float)n<=x) {
 		/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
-	    a = __ieee754_j0f(x);
-	    b = __ieee754_j1f(x);
+	    a = j0f(x);
+	    b = j1f(x);
 	    for(i=1;i<n;i++){
 		temp = b;
 		b = b*((float)(i+i)/x) - a; /* avoid underflow */
@@ -134,7 +134,7 @@
 		 */
 		tmp = n;
 		v = two/x;
-		tmp = tmp*__ieee754_logf(fabsf(v*tmp));
+		tmp = tmp*logf(fabsf(v*tmp));
 		if(tmp<(float)8.8721679688e+01) {
 	    	    for(i=n-1,di=(float)(i+i);i>0;i--){
 		        temp = b;
@@ -158,8 +158,8 @@
 			}
 	     	    }
 		}
-		z = __ieee754_j0f(x);
-		w = __ieee754_j1f(x);
+		z = j0f(x);
+		w = j1f(x);
 		if (fabsf(z) >= fabsf(w))
 		    b = (t*z/b);
 		else
@@ -170,7 +170,7 @@
 }
 
 float
-__ieee754_ynf(int n, float x)
+ynf(int n, float x)
 {
 	int32_t i,hx,ix,ib;
 	int32_t sign;
@@ -186,12 +186,12 @@
 		n = -n;
 		sign = 1 - ((n&1)<<1);
 	}
-	if(n==0) return(__ieee754_y0f(x));
-	if(n==1) return(sign*__ieee754_y1f(x));
+	if(n==0) return(y0f(x));
+	if(n==1) return(sign*y1f(x));
 	if(ix==0x7f800000) return zero;
 
-	a = __ieee754_y0f(x);
-	b = __ieee754_y1f(x);
+	a = y0f(x);
+	b = y1f(x);
 	/* quit if b is -inf */
 	GET_FLOAT_WORD(ib,b);
 	for(i=1;i<n&&ib!=0xff800000;i++){
diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgamma.c b/libm/upstream-freebsd/lib/msun/src/e_lgamma.c
index 43f5175..9c4a30e 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_lgamma.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_lgamma.c
@@ -15,10 +15,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_lgamma(x)
+/* lgamma(x)
  * Return the logarithm of the Gamma function of x.
  *
- * Method: call __ieee754_lgamma_r
+ * Method: call lgamma_r
  */
 
 #include <float.h>
@@ -29,9 +29,9 @@
 extern int signgam;
 
 double
-__ieee754_lgamma(double x)
+lgamma(double x)
 {
-	return __ieee754_lgamma_r(x,&signgam);
+	return lgamma_r(x,&signgam);
 }
 
 #if (LDBL_MANT_DIG == 53)
diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c b/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c
index be70767..c020b63 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_lgamma_r.c
@@ -13,7 +13,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_lgamma_r(x, signgamp)
+/* lgamma_r(x, signgamp)
  * Reentrant version of the logarithm of the Gamma function
  * with user provide pointer for the sign of Gamma(x).
  *
@@ -27,7 +27,7 @@
  *			    = log(6.3*5.3) + lgamma(5.3)
  *			    = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
  *   2. Polynomial approximation of lgamma around its
- *	minimun ymin=1.461632144968362245 to maintain monotonicity.
+ *	minimum ymin=1.461632144968362245 to maintain monotonicity.
  *	On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
  *		Let z = x-ymin;
  *		lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
@@ -199,7 +199,7 @@
 
 
 double
-__ieee754_lgamma_r(double x, int *signgamp)
+lgamma_r(double x, int *signgamp)
 {
 	double nadj,p,p1,p2,p3,q,r,t,w,y,z;
 	int32_t hx;
@@ -217,7 +217,7 @@
 	if(ix<0x3c700000) {	/* |x|<2**-56, return -log(|x|) */
 	    if((ix|lx)==0)
 	        return one/vzero;
-	    return -__ieee754_log(fabs(x));
+	    return -log(fabs(x));
 	}
 
     /* purge negative integers and start evaluation for other x < 0 */
@@ -227,7 +227,7 @@
 		return one/vzero;
 	    t = sin_pi(x);
 	    if(t==zero) return one/vzero; /* -integer */
-	    nadj = __ieee754_log(pi/fabs(t*x));
+	    nadj = log(pi/fabs(t*x));
 	    if(t<zero) *signgamp = -1;
 	    x = -x;
 	}
@@ -237,7 +237,7 @@
     /* for x < 2.0 */
 	else if(ix<0x40000000) {
 	    if(ix<=0x3feccccc) { 	/* lgamma(x) = lgamma(x+1)-log(x) */
-		r = -__ieee754_log(x);
+		r = -log(x);
 		if(ix>=0x3FE76944) {y = one-x; i= 0;}
 		else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
 	  	else {y = x; i=2;}
@@ -282,18 +282,18 @@
 	    case 5: z *= (y+4);		/* FALLTHRU */
 	    case 4: z *= (y+3);		/* FALLTHRU */
 	    case 3: z *= (y+2);		/* FALLTHRU */
-		    r += __ieee754_log(z); break;
+		    r += log(z); break;
 	    }
     /* 8.0 <= x < 2**56 */
 	} else if (ix < 0x43700000) {
-	    t = __ieee754_log(x);
+	    t = log(x);
 	    z = one/x;
 	    y = z*z;
 	    w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
 	    r = (x-half)*(t-one)+w;
 	} else
     /* 2**56 <= x <= inf */
-	    r =  x*(__ieee754_log(x)-one);
+	    r =  x*(log(x)-one);
 	if(hx<0) r = nadj - r;
 	return r;
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c b/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c
index 1e2c552..00a816c 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_lgammaf.c
@@ -16,10 +16,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_lgammaf(x)
+/* lgammaf(x)
  * Return the logarithm of the Gamma function of x.
  *
- * Method: call __ieee754_lgammaf_r
+ * Method: call lgammaf_r
  */
 
 #include "math.h"
@@ -28,7 +28,7 @@
 extern int signgam;
 
 float
-__ieee754_lgammaf(float x)
+lgammaf(float x)
 {
-	return __ieee754_lgammaf_r(x,&signgam);
+	return lgammaf_r(x,&signgam);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c b/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c
index 48346c3..fdd2321 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_lgammaf_r.c
@@ -120,7 +120,7 @@
 
 
 float
-__ieee754_lgammaf_r(float x, int *signgamp)
+lgammaf_r(float x, int *signgamp)
 {
 	float nadj,p,p1,p2,q,r,t,w,y,z;
 	int32_t hx;
@@ -138,7 +138,7 @@
 	if(ix<0x32000000) {		/* |x|<2**-27, return -log(|x|) */
 	    if(ix==0)
 	        return one/vzero;
-	    return -__ieee754_logf(fabsf(x));
+	    return -logf(fabsf(x));
 	}
 
     /* purge negative integers and start evaluation for other x < 0 */
@@ -148,7 +148,7 @@
 		return one/vzero;
 	    t = sin_pif(x);
 	    if(t==zero) return one/vzero; /* -integer */
-	    nadj = __ieee754_logf(pi/fabsf(t*x));
+	    nadj = logf(pi/fabsf(t*x));
 	    if(t<zero) *signgamp = -1;
 	    x = -x;
 	}
@@ -158,7 +158,7 @@
     /* for x < 2.0 */
 	else if(ix<0x40000000) {
 	    if(ix<=0x3f666666) { 	/* lgamma(x) = lgamma(x+1)-log(x) */
-		r = -__ieee754_logf(x);
+		r = -logf(x);
 		if(ix>=0x3f3b4a20) {y = one-x; i= 0;}
 		else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;}
 	  	else {y = x; i=2;}
@@ -198,18 +198,18 @@
 	    case 5: z *= (y+4);		/* FALLTHRU */
 	    case 4: z *= (y+3);		/* FALLTHRU */
 	    case 3: z *= (y+2);		/* FALLTHRU */
-		    r += __ieee754_logf(z); break;
+		    r += logf(z); break;
 	    }
     /* 8.0 <= x < 2**27 */
 	} else if (ix < 0x4d000000) {
-	    t = __ieee754_logf(x);
+	    t = logf(x);
 	    z = one/x;
 	    y = z*z;
 	    w = w0+z*(w1+y*w2);
 	    r = (x-half)*(t-one)+w;
 	} else
     /* 2**27 <= x <= inf */
-	    r =  x*(__ieee754_logf(x)-one);
+	    r =  x*(logf(x)-one);
 	if(hx<0) r = nadj - r;
 	return r;
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log.c b/libm/upstream-freebsd/lib/msun/src/e_log.c
index 68bc107..03ce820 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_log.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_log.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_log(x)
+/* log(x)
  * Return the logrithm of x
  *
  * Method :                  
@@ -86,7 +86,7 @@
 static volatile double vzero = 0.0;
 
 double
-__ieee754_log(double x)
+log(double x)
 {
 	double hfsq,f,s,z,R,w,t1,t2,dk;
 	int32_t k,hx,i,j;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log10.c b/libm/upstream-freebsd/lib/msun/src/e_log10.c
index 3c89ed2..595c238 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_log10.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_log10.c
@@ -39,7 +39,7 @@
 static volatile double vzero = 0.0;
 
 double
-__ieee754_log10(double x)
+log10(double x)
 {
 	double f,hfsq,hi,lo,r,val_hi,val_lo,w,y,y2;
 	int32_t i,k,hx;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log10f.c b/libm/upstream-freebsd/lib/msun/src/e_log10f.c
index 9856df2..d0c3a53 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_log10f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_log10f.c
@@ -31,7 +31,7 @@
 static volatile float vzero = 0.0;
 
 float
-__ieee754_log10f(float x)
+log10f(float x)
 {
 	float f,hfsq,hi,lo,r,y;
 	int32_t i,k,hx;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2.c b/libm/upstream-freebsd/lib/msun/src/e_log2.c
index 4766cdb..10b1c00 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_log2.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_log2.c
@@ -39,7 +39,7 @@
 static volatile double vzero = 0.0;
 
 double
-__ieee754_log2(double x)
+log2(double x)
 {
 	double f,hfsq,hi,lo,r,val_hi,val_lo,w,y;
 	int32_t i,k,hx;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_log2f.c b/libm/upstream-freebsd/lib/msun/src/e_log2f.c
index 1794484..956f33a 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_log2f.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_log2f.c
@@ -29,7 +29,7 @@
 static volatile float vzero = 0.0;
 
 float
-__ieee754_log2f(float x)
+log2f(float x)
 {
 	float f,hfsq,hi,lo,r,y;
 	int32_t i,k,hx;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_logf.c b/libm/upstream-freebsd/lib/msun/src/e_logf.c
index ec3985f..68a4d5d 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_logf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_logf.c
@@ -33,7 +33,7 @@
 static volatile float vzero = 0.0;
 
 float
-__ieee754_logf(float x)
+logf(float x)
 {
 	float hfsq,f,s,z,R,w,t1,t2,dk;
 	int32_t k,ix,i,j;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_pow.c b/libm/upstream-freebsd/lib/msun/src/e_pow.c
index 52b2f5c..adc64c9 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_pow.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_pow.c
@@ -12,7 +12,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_pow(x,y) return x**y
+/* pow(x,y) return x**y
  *
  *		      n
  * Method:  Let x =  2   * (1+f)
@@ -98,7 +98,7 @@
 ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
 
 double
-__ieee754_pow(double x, double y)
+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;
diff --git a/libm/upstream-freebsd/lib/msun/src/e_powf.c b/libm/upstream-freebsd/lib/msun/src/e_powf.c
index 122da45..f5a2c70 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_powf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_powf.c
@@ -56,7 +56,7 @@
 ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
 
 float
-__ieee754_powf(float x, float y)
+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;
@@ -108,7 +108,7 @@
 	if(hy==0x40000000) return x*x; /* y is  2 */
 	if(hy==0x3f000000) {	/* y is  0.5 */
 	    if(hx>=0)	/* x >= +0 */
-	    return __ieee754_sqrtf(x);
+	    return sqrtf(x);
 	}
 
 	ax   = fabsf(x);
diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainder.c b/libm/upstream-freebsd/lib/msun/src/e_remainder.c
index a4ae0b7..13156d8 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_remainder.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_remainder.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_remainder(x,p)
+/* remainder(x,p)
  * Return :                  
  * 	returns  x REM p  =  x - [x/p]*p as if in infinite 
  * 	precise arithmetic, where [x/p] is the (infinite bit) 
@@ -32,7 +32,7 @@
 
 
 double
-__ieee754_remainder(double x, double p)
+remainder(double x, double p)
 {
 	int32_t hx,hp;
 	u_int32_t sx,lx,lp;
@@ -52,7 +52,7 @@
 	    return nan_mix_op(x, p, *)/nan_mix_op(x, p, *);
 
 
-	if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p);	/* now x < 2p */
+	if (hp<=0x7fdfffff) x = fmod(x,p+p);	/* now x < 2p */
 	if (((hx-hp)|(lx-lp))==0) return zero*x;
 	x  = fabs(x);
 	p  = fabs(p);
diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainderf.c b/libm/upstream-freebsd/lib/msun/src/e_remainderf.c
index 8004493..e0dcfd1 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_remainderf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_remainderf.c
@@ -23,7 +23,7 @@
 
 
 float
-__ieee754_remainderf(float x, float p)
+remainderf(float x, float p)
 {
 	int32_t hx,hp;
 	u_int32_t sx;
@@ -42,7 +42,7 @@
 	    return nan_mix_op(x, p, *)/nan_mix_op(x, p, *);
 
 
-	if (hp<=0x7effffff) x = __ieee754_fmodf(x,p+p);	/* now x < 2p */
+	if (hp<=0x7effffff) x = fmodf(x,p+p);	/* now x < 2p */
 	if ((hx-hp)==0) return zero*x;
 	x  = fabsf(x);
 	p  = fabsf(p);
diff --git a/libm/upstream-freebsd/lib/msun/src/e_remainderl.c b/libm/upstream-freebsd/lib/msun/src/e_remainderl.c
index 4a67863..2295673 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_remainderl.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_remainderl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/e_scalb.c b/libm/upstream-freebsd/lib/msun/src/e_scalb.c
index c0a7b5b..84a6893 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_scalb.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_scalb.c
@@ -15,7 +15,7 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * __ieee754_scalb(x, fn) is provide for
+ * scalb(x, fn) is provide for
  * passing various standard test suite. One 
  * should use scalbn() instead.
  */
@@ -25,10 +25,10 @@
 
 #ifdef _SCALB_INT
 double
-__ieee754_scalb(double x, int fn)
+scalb(double x, int fn)
 #else
 double
-__ieee754_scalb(double x, double fn)
+scalb(double x, double fn)
 #endif
 {
 #ifdef _SCALB_INT
diff --git a/libm/upstream-freebsd/lib/msun/src/e_scalbf.c b/libm/upstream-freebsd/lib/msun/src/e_scalbf.c
index d49e904..28483a5 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_scalbf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_scalbf.c
@@ -21,10 +21,10 @@
 
 #ifdef _SCALB_INT
 float
-__ieee754_scalbf(float x, int fn)
+scalbf(float x, int fn)
 #else
 float
-__ieee754_scalbf(float x, float fn)
+scalbf(float x, float fn)
 #endif
 {
 #ifdef _SCALB_INT
diff --git a/libm/upstream-freebsd/lib/msun/src/e_sinh.c b/libm/upstream-freebsd/lib/msun/src/e_sinh.c
index 6c01f4a..9fe8999 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_sinh.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_sinh.c
@@ -14,7 +14,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* __ieee754_sinh(x)
+/* sinh(x)
  * Method : 
  * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
  *	1. Replace x by |x| (sinh(-x) = -sinh(x)). 
@@ -40,7 +40,7 @@
 static const double one = 1.0, shuge = 1.0e307;
 
 double
-__ieee754_sinh(double x)
+sinh(double x)
 {
 	double t,h;
 	int32_t ix,jx;
@@ -64,7 +64,7 @@
 	}
 
     /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
-	if (ix < 0x40862E42)  return h*__ieee754_exp(fabs(x));
+	if (ix < 0x40862E42)  return h*exp(fabs(x));
 
     /* |x| in [log(maxdouble), overflowthresold] */
 	if (ix<=0x408633CE)
diff --git a/libm/upstream-freebsd/lib/msun/src/e_sinhf.c b/libm/upstream-freebsd/lib/msun/src/e_sinhf.c
index 1be2dc3..082beb1 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_sinhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_sinhf.c
@@ -22,7 +22,7 @@
 static const float one = 1.0, shuge = 1.0e37;
 
 float
-__ieee754_sinhf(float x)
+sinhf(float x)
 {
 	float t,h;
 	int32_t ix,jx;
@@ -45,7 +45,7 @@
 	}
 
     /* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */
-	if (ix < 0x42b17217)  return h*__ieee754_expf(fabsf(x));
+	if (ix < 0x42b17217)  return h*expf(fabsf(x));
 
     /* |x| in [logf(maxfloat), overflowthresold] */
 	if (ix<=0x42b2d4fc)
diff --git a/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c b/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c
index 565d963..67c777f 100644
--- a/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c
+++ b/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/k_exp.c b/libm/upstream-freebsd/lib/msun/src/k_exp.c
index dd15ff4..1b86cd6 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_exp.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_exp.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/k_expf.c b/libm/upstream-freebsd/lib/msun/src/k_expf.c
index 80e629b..7071632 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_expf.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_expf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/k_tanf.c b/libm/upstream-freebsd/lib/msun/src/k_tanf.c
index 52f1aaa..5be1445 100644
--- a/libm/upstream-freebsd/lib/msun/src/k_tanf.c
+++ b/libm/upstream-freebsd/lib/msun/src/k_tanf.c
@@ -50,7 +50,7 @@
 	 * We add the small terms from lowest degree up for efficiency on
 	 * non-sequential machines (the lowest degree terms tend to be ready
 	 * earlier).  Apart from this, we don't care about order of
-	 * operations, and don't need to to care since we have precision to
+	 * operations, and don't need to care since we have precision to
 	 * spare.  However, the chosen splitting is good for accuracy too,
 	 * and would give results as accurate as Horner's method if the
 	 * small terms were added from highest degree down.
diff --git a/libm/upstream-freebsd/lib/msun/src/math_private.h b/libm/upstream-freebsd/lib/msun/src/math_private.h
index df526e7..a55d97a 100644
--- a/libm/upstream-freebsd/lib/msun/src/math_private.h
+++ b/libm/upstream-freebsd/lib/msun/src/math_private.h
@@ -624,7 +624,7 @@
  * The complications for extra precision are smaller for rnintl() since it
  * can safely assume that the rounding precision has been increased from
  * its default to FP_PE on x86.  We don't exploit that here to get small
- * optimizations from limiting the rangle to double.  We just need it for
+ * optimizations from limiting the range to double.  We just need it for
  * the magic number to work with long doubles.  ld128 callers should use
  * rnint() instead of this if possible.  ld80 callers should prefer
  * rnintl() since for amd64 this avoids swapping the register set, while
@@ -688,6 +688,59 @@
 }
 #endif
 
+/*
+ * The following are fast floor macros for 0 <= |x| < 0x1p(N-1), where
+ * N is the precision of the type of x. These macros are used in the
+ * half-cycle trignometric functions (e.g., sinpi(x)).
+ */
+#define	FFLOORF(x, j0, ix) do {			\
+	(j0) = (((ix) >> 23) & 0xff) - 0x7f;	\
+	(ix) &= ~(0x007fffff >> (j0));		\
+	SET_FLOAT_WORD((x), (ix));		\
+} while (0)
+
+#define	FFLOOR(x, j0, ix, lx) do {				\
+	(j0) = (((ix) >> 20) & 0x7ff) - 0x3ff;			\
+	if ((j0) < 20) {					\
+		(ix) &= ~(0x000fffff >> (j0));			\
+		(lx) = 0;					\
+	} else {						\
+		(lx) &= ~((uint32_t)0xffffffff >> ((j0) - 20));	\
+	}							\
+	INSERT_WORDS((x), (ix), (lx));				\
+} while (0)
+
+#define	FFLOORL80(x, j0, ix, lx) do {			\
+	j0 = ix - 0x3fff + 1;				\
+	if ((j0) < 32) {				\
+		(lx) = ((lx) >> 32) << 32;		\
+		(lx) &= ~((((lx) << 32)-1) >> (j0));	\
+	} else {					\
+		uint64_t _m;				\
+		_m = (uint64_t)-1 >> (j0);		\
+		if ((lx) & _m) (lx) &= ~_m;		\
+	}						\
+	INSERT_LDBL80_WORDS((x), (ix), (lx));		\
+} while (0)
+
+#define FFLOORL128(x, ai, ar) do {			\
+	union IEEEl2bits u;				\
+	uint64_t m;					\
+	int e;						\
+	u.e = (x);					\
+	e = u.bits.exp - 16383;				\
+	if (e < 48) {					\
+		m = ((1llu << 49) - 1) >> (e + 1);	\
+		u.bits.manh &= ~m;			\
+		u.bits.manl = 0;			\
+	} else {					\
+		m = (uint64_t)-1 >> (e - 48);		\
+		u.bits.manl &= ~m;			\
+	}						\
+	(ai) = u.e;					\
+	(ar) = (x) - (ai);				\
+} while (0)
+
 #ifdef DEBUG
 #if defined(__amd64__) || defined(__i386__)
 #define	breakpoint()	asm("int $3")
@@ -698,191 +751,25 @@
 #endif
 #endif
 
-/* Write a pari script to test things externally. */
-#ifdef DOPRINT
-#include <stdio.h>
-
-#ifndef DOPRINT_SWIZZLE
-#define	DOPRINT_SWIZZLE		0
-#endif
-
-#ifdef DOPRINT_LD80
-
-#define	DOPRINT_START(xp) do {						\
-	uint64_t __lx;							\
-	uint16_t __hx;							\
-									\
-	/* Hack to give more-problematic args. */			\
-	EXTRACT_LDBL80_WORDS(__hx, __lx, *xp);				\
-	__lx ^= DOPRINT_SWIZZLE;					\
-	INSERT_LDBL80_WORDS(*xp, __hx, __lx);				\
-	printf("x = %.21Lg; ", (long double)*xp);			\
-} while (0)
-#define	DOPRINT_END1(v)							\
-	printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v))
-#define	DOPRINT_END2(hi, lo)						\
-	printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n",		\
-	    (long double)(hi), (long double)(lo))
-
-#elif defined(DOPRINT_D64)
-
-#define	DOPRINT_START(xp) do {						\
-	uint32_t __hx, __lx;						\
-									\
-	EXTRACT_WORDS(__hx, __lx, *xp);					\
-	__lx ^= DOPRINT_SWIZZLE;					\
-	INSERT_WORDS(*xp, __hx, __lx);					\
-	printf("x = %.21Lg; ", (long double)*xp);			\
-} while (0)
-#define	DOPRINT_END1(v)							\
-	printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v))
-#define	DOPRINT_END2(hi, lo)						\
-	printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n",		\
-	    (long double)(hi), (long double)(lo))
-
-#elif defined(DOPRINT_F32)
-
-#define	DOPRINT_START(xp) do {						\
-	uint32_t __hx;							\
-									\
-	GET_FLOAT_WORD(__hx, *xp);					\
-	__hx ^= DOPRINT_SWIZZLE;					\
-	SET_FLOAT_WORD(*xp, __hx);					\
-	printf("x = %.21Lg; ", (long double)*xp);			\
-} while (0)
-#define	DOPRINT_END1(v)							\
-	printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v))
-#define	DOPRINT_END2(hi, lo)						\
-	printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n",		\
-	    (long double)(hi), (long double)(lo))
-
-#else /* !DOPRINT_LD80 && !DOPRINT_D64 (LD128 only) */
-
-#ifndef DOPRINT_SWIZZLE_HIGH
-#define	DOPRINT_SWIZZLE_HIGH	0
-#endif
-
-#define	DOPRINT_START(xp) do {						\
-	uint64_t __lx, __llx;						\
-	uint16_t __hx;							\
-									\
-	EXTRACT_LDBL128_WORDS(__hx, __lx, __llx, *xp);			\
-	__llx ^= DOPRINT_SWIZZLE;					\
-	__lx ^= DOPRINT_SWIZZLE_HIGH;					\
-	INSERT_LDBL128_WORDS(*xp, __hx, __lx, __llx);			\
-	printf("x = %.36Lg; ", (long double)*xp);					\
-} while (0)
-#define	DOPRINT_END1(v)							\
-	printf("y = %.36Lg; z = 0; show(x, y, z);\n", (long double)(v))
-#define	DOPRINT_END2(hi, lo)						\
-	printf("y = %.36Lg; z = %.36Lg; show(x, y, z);\n",		\
-	    (long double)(hi), (long double)(lo))
-
-#endif /* DOPRINT_LD80 */
-
-#else /* !DOPRINT */
-#define	DOPRINT_START(xp)
-#define	DOPRINT_END1(v)
-#define	DOPRINT_END2(hi, lo)
-#endif /* DOPRINT */
-
-#define	RETURNP(x) do {			\
-	DOPRINT_END1(x);		\
-	RETURNF(x);			\
-} while (0)
-#define	RETURNPI(x) do {		\
-	DOPRINT_END1(x);		\
-	RETURNI(x);			\
-} while (0)
-#define	RETURN2P(x, y) do {		\
-	DOPRINT_END2((x), (y));		\
-	RETURNF((x) + (y));		\
-} while (0)
-#define	RETURN2PI(x, y) do {		\
-	DOPRINT_END2((x), (y));		\
-	RETURNI((x) + (y));		\
-} while (0)
 #ifdef STRUCT_RETURN
 #define	RETURNSP(rp) do {		\
 	if (!(rp)->lo_set)		\
-		RETURNP((rp)->hi);	\
-	RETURN2P((rp)->hi, (rp)->lo);	\
+		RETURNF((rp)->hi);	\
+	RETURNF((rp)->hi + (rp)->lo);	\
 } while (0)
 #define	RETURNSPI(rp) do {		\
 	if (!(rp)->lo_set)		\
-		RETURNPI((rp)->hi);	\
-	RETURN2PI((rp)->hi, (rp)->lo);	\
+		RETURNI((rp)->hi);	\
+	RETURNI((rp)->hi + (rp)->lo);	\
 } while (0)
 #endif
+
 #define	SUM2P(x, y) ({			\
 	const __typeof (x) __x = (x);	\
 	const __typeof (y) __y = (y);	\
-					\
-	DOPRINT_END2(__x, __y);		\
 	__x + __y;			\
 })
 
-/*
- * ieee style elementary functions
- *
- * We rename functions here to improve other sources' diffability
- * against fdlibm.
- */
-#define	__ieee754_sqrt	sqrt
-#define	__ieee754_acos	acos
-#define	__ieee754_acosh	acosh
-#define	__ieee754_log	log
-#define	__ieee754_log2	log2
-#define	__ieee754_atanh	atanh
-#define	__ieee754_asin	asin
-#define	__ieee754_atan2	atan2
-#define	__ieee754_exp	exp
-#define	__ieee754_cosh	cosh
-#define	__ieee754_fmod	fmod
-#define	__ieee754_pow	pow
-#define	__ieee754_lgamma lgamma
-#define	__ieee754_gamma	gamma
-#define	__ieee754_lgamma_r lgamma_r
-#define	__ieee754_gamma_r gamma_r
-#define	__ieee754_log10	log10
-#define	__ieee754_sinh	sinh
-#define	__ieee754_hypot	hypot
-#define	__ieee754_j0	j0
-#define	__ieee754_j1	j1
-#define	__ieee754_y0	y0
-#define	__ieee754_y1	y1
-#define	__ieee754_jn	jn
-#define	__ieee754_yn	yn
-#define	__ieee754_remainder remainder
-#define	__ieee754_scalb	scalb
-#define	__ieee754_sqrtf	sqrtf
-#define	__ieee754_acosf	acosf
-#define	__ieee754_acoshf acoshf
-#define	__ieee754_logf	logf
-#define	__ieee754_atanhf atanhf
-#define	__ieee754_asinf	asinf
-#define	__ieee754_atan2f atan2f
-#define	__ieee754_expf	expf
-#define	__ieee754_coshf	coshf
-#define	__ieee754_fmodf	fmodf
-#define	__ieee754_powf	powf
-#define	__ieee754_lgammaf lgammaf
-#define	__ieee754_gammaf gammaf
-#define	__ieee754_lgammaf_r lgammaf_r
-#define	__ieee754_gammaf_r gammaf_r
-#define	__ieee754_log10f log10f
-#define	__ieee754_log2f log2f
-#define	__ieee754_sinhf	sinhf
-#define	__ieee754_hypotf hypotf
-#define	__ieee754_j0f	j0f
-#define	__ieee754_j1f	j1f
-#define	__ieee754_y0f	y0f
-#define	__ieee754_y1f	y1f
-#define	__ieee754_jnf	jnf
-#define	__ieee754_ynf	ynf
-#define	__ieee754_remainderf remainderf
-#define	__ieee754_scalbf scalbf
-
 /* fdlibm kernel function */
 int	__kernel_rem_pio2(double*,double*,int,int,int);
 
diff --git a/libm/upstream-freebsd/lib/msun/src/s_asinh.c b/libm/upstream-freebsd/lib/msun/src/s_asinh.c
index cbb3d46..a1b9169 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_asinh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_asinh.c
@@ -46,13 +46,13 @@
 	    if(huge+x>one) return x;	/* return x inexact except 0 */
 	}
 	if(ix>0x41b00000) {	/* |x| > 2**28 */
-	    w = __ieee754_log(fabs(x))+ln2;
+	    w = log(fabs(x))+ln2;
 	} else if (ix>0x40000000) {	/* 2**28 > |x| > 2.0 */
 	    t = fabs(x);
-	    w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t));
+	    w = log(2.0*t+one/(sqrt(x*x+one)+t));
 	} else {		/* 2.0 > |x| > 2**-28 */
 	    t = x*x;
-	    w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t)));
+	    w =log1p(fabs(x)+t/(one+sqrt(one+t)));
 	}
 	if(hx>0) return w; else return -w;
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_asinhf.c b/libm/upstream-freebsd/lib/msun/src/s_asinhf.c
index c1620dd..72bcefe 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_asinhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_asinhf.c
@@ -36,13 +36,13 @@
 	    if(huge+x>one) return x;	/* return x inexact except 0 */
 	}
 	if(ix>0x4d800000) {	/* |x| > 2**28 */
-	    w = __ieee754_logf(fabsf(x))+ln2;
+	    w = logf(fabsf(x))+ln2;
 	} else if (ix>0x40000000) {	/* 2**28 > |x| > 2.0 */
 	    t = fabsf(x);
-	    w = __ieee754_logf((float)2.0*t+one/(__ieee754_sqrtf(x*x+one)+t));
+	    w = logf((float)2.0*t+one/(sqrtf(x*x+one)+t));
 	} else {		/* 2.0 > |x| > 2**-28 */
 	    t = x*x;
-	    w =log1pf(fabsf(x)+t/(one+__ieee754_sqrtf(one+t)));
+	    w =log1pf(fabsf(x)+t/(one+sqrtf(one+t)));
 	}
 	if(hx>0) return w; else return -w;
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_carg.c b/libm/upstream-freebsd/lib/msun/src/s_carg.c
index 1611b9d..f203198 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_carg.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_carg.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cargf.c b/libm/upstream-freebsd/lib/msun/src/s_cargf.c
index 71c705d..6ea487c 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cargf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cargf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cargl.c b/libm/upstream-freebsd/lib/msun/src/s_cargl.c
index 96c3336..ba39438 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cargl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cargl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrt.c b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
index 0e609e1..4353d34 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cbrt.c
@@ -108,7 +108,7 @@
 	r=x/s;				/* error <= 0.5 ulps; |r| < |t| */
 	w=t+t;				/* t+t is exact */
 	r=(r-t)/(w+r);			/* r-t is exact; w+r ~= 3*t */
-	t=t+t*r;			/* error <= 0.5 + 0.5/3 + epsilon */
+	t=t+t*r;			/* error <= (0.5 + 0.5/3) * ulp */
 
 	return(t);
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c b/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c
index 2236c0f..b15c96e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c
@@ -136,7 +136,7 @@
 	r=x/s;				/* error <= 0.5 ulps; |r| < |t| */
 	w=t+t;				/* t+t is exact */
 	r=(r-t)/(w+r);			/* r-t is exact; w+r ~= 3*t */
-	t=t+t*r;			/* error <= 0.5 + 0.5/3 + epsilon */
+	t=t+t*r;			/* error <= (0.5 + 0.5/3) * ulp */
 
 	t *= v.e;
 	RETURNI(t);
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccosh.c b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
index 7652b3c..0fd9206 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ccosh.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
index 5d7a09b..2db8403 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ccoshf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexp.c b/libm/upstream-freebsd/lib/msun/src/s_cexp.c
index a1f853e..8db763d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cexp.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cexp.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cexpf.c b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
index d905b74..7247301 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cexpf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimag.c b/libm/upstream-freebsd/lib/msun/src/s_cimag.c
index 1f383cb..0b14fd7 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cimag.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cimag.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimagf.c b/libm/upstream-freebsd/lib/msun/src/s_cimagf.c
index 86a43c1..42a1efd 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cimagf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cimagf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cimagl.c b/libm/upstream-freebsd/lib/msun/src/s_cimagl.c
index 6d87950..9707bc3 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cimagl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cimagl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conj.c b/libm/upstream-freebsd/lib/msun/src/s_conj.c
index dc56f48..a83abd8 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conj.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conj.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjf.c b/libm/upstream-freebsd/lib/msun/src/s_conjf.c
index 3fd8b8f..f9eb146 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conjf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conjf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_conjl.c b/libm/upstream-freebsd/lib/msun/src/s_conjl.c
index d2f8d0f..4b86f2e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_conjl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_conjl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_copysignl.c b/libm/upstream-freebsd/lib/msun/src/s_copysignl.c
index bd67447..666a2ba 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_copysignl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_copysignl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cosl.c b/libm/upstream-freebsd/lib/msun/src/s_cosl.c
index 3d06648..6f0b36f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cosl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cosl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cospi.c b/libm/upstream-freebsd/lib/msun/src/s_cospi.c
index 860219e..f97570d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cospi.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cospi.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2017 Steven G. Kargl
+ * Copyright (c) 2017, 2023 Steven G. Kargl
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -104,20 +104,10 @@
 	}
 
 	if (ix < 0x43300000) {		/* 1 <= |x| < 0x1p52 */
-		/* Determine integer part of ax. */
-		j0 = ((ix >> 20) & 0x7ff) - 0x3ff;
-		if (j0 < 20) {
-			ix &= ~(0x000fffff >> j0);
-			lx = 0;
-		} else {
-			lx &= ~((uint32_t)0xffffffff >> (j0 - 20));
-		}
-		INSERT_WORDS(x, ix, lx);
-
+		FFLOOR(x, j0, ix, lx);	/* Integer part of ax. */
 		ax -= x;
 		EXTRACT_WORDS(ix, lx, ax);
 
-
 		if (ix < 0x3fe00000) {		/* |x| < 0.5 */
 			if (ix < 0x3fd00000)	/* |x| < 0.25 */
 				c = ix == 0 ? 1 : __kernel_cospi(ax);
@@ -138,13 +128,16 @@
 		return (j0 & 1 ? -c : c);
 	}
 
-	if (ix >= 0x7f800000)
+	/* x = +-inf or nan. */
+	if (ix >= 0x7ff00000)
 		return (vzero / vzero);
 
 	/*
-	 * |x| >= 0x1p52 is always an even integer, so return 1.
+	 * For 0x1p52 <= |x| < 0x1p53 need to determine if x is an even
+	 * or odd integer to return +1 or -1.
+	 * For |x| >= 0x1p53, it is always an even integer, so return 1.
 	 */
-	return (1);
+	return (ix < 0x43400000 ? ((lx & 1) ? -1 : 1) : 1);
 }
 
 #if LDBL_MANT_DIG == 53
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cproj.c b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
index 38e7747..5b0d4ed 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cproj.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cproj.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojf.c b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
index af4c3a8..0d76e75 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cprojf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_cprojl.c b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
index 16df514..7fc35d2 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_cprojl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_creal.c b/libm/upstream-freebsd/lib/msun/src/s_creal.c
index 69a10f2..5c8734e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_creal.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_creal.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_crealf.c b/libm/upstream-freebsd/lib/msun/src/s_crealf.c
index 83e4d46..a93421f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_crealf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_crealf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_creall.c b/libm/upstream-freebsd/lib/msun/src/s_creall.c
index 538b7d5..b4eb9ef 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_creall.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_creall.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 Stefan Farfeleder
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinh.c b/libm/upstream-freebsd/lib/msun/src/s_csinh.c
index 09b2dcb..b3928ce 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csinh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csinh.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csinhf.c b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
index ba1a794..a8d6f2d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csinhf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrt.c b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
index d172efc..d96c344 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrt.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
index 6836a39..e3ef4d0 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
index 40bc59d..d564133 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_csqrtl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007-2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanh.c b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
index e5840a1..aa4e10c 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ctanh.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
index c46f86d..e9ebe4f 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_ctanhf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2011 David Schultz
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_erf.c b/libm/upstream-freebsd/lib/msun/src/s_erf.c
index 5f22847..ab2dc19 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_erf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_erf.c
@@ -238,7 +238,7 @@
 	}
 	z  = x;
 	SET_LOW_WORD(z,0);
-	r  =  __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+	r  =  exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S);
 	if(hx>=0) return one-r/x; else return  r/x-one;
 }
 
@@ -297,7 +297,7 @@
 	    }
 	    z  = x;
 	    SET_LOW_WORD(z,0);
-	    r  =  __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+	    r  =  exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S);
 	    if(hx>0) return r/x; else return two-r/x;
 	} else {
 	    if(hx>0) return tiny*tiny; else return two-tiny;
diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2.c b/libm/upstream-freebsd/lib/msun/src/s_exp2.c
index bc36e55..1dd9673 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_exp2.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_exp2.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_exp2f.c b/libm/upstream-freebsd/lib/msun/src/s_exp2f.c
index c082924..c5b4c8e 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_exp2f.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_exp2f.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fdim.c b/libm/upstream-freebsd/lib/msun/src/s_fdim.c
index c40c3e9..b81dbac 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fdim.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fdim.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fma.c b/libm/upstream-freebsd/lib/msun/src/s_fma.c
index 95cffd0..2fd7075 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fma.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fma.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaf.c b/libm/upstream-freebsd/lib/msun/src/s_fmaf.c
index 4591cc2..ae979cb 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmaf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmaf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmal.c b/libm/upstream-freebsd/lib/msun/src/s_fmal.c
index a379346..a0622a2 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmal.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmal.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmax.c b/libm/upstream-freebsd/lib/msun/src/s_fmax.c
index b53b1e6..42bd11c 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmax.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmax.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c b/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c
index 8d3d14f..10667d3 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmaxf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c b/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c
index c0d7c88..bf42587 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fmin.c b/libm/upstream-freebsd/lib/msun/src/s_fmin.c
index 53f36c1..e79071d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fmin.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fmin.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fminf.c b/libm/upstream-freebsd/lib/msun/src/s_fminf.c
index 58b6a48..19ffd42 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fminf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fminf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_fminl.c b/libm/upstream-freebsd/lib/msun/src/s_fminl.c
index 97604b3..c906f1d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_fminl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_fminl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_frexpl.c b/libm/upstream-freebsd/lib/msun/src/s_frexpl.c
index 66e284f..7101615 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_frexpl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_frexpl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_lrint.c b/libm/upstream-freebsd/lib/msun/src/s_lrint.c
index ad9b978..be00cbb 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_lrint.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_lrint.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_lround.c b/libm/upstream-freebsd/lib/msun/src/s_lround.c
index 1dd8e69..00f4b95 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_lround.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_lround.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_modfl.c b/libm/upstream-freebsd/lib/msun/src/s_modfl.c
index 2d83bbe..8e5c4d3 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_modfl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_modfl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_nan.c b/libm/upstream-freebsd/lib/msun/src/s_nan.c
index 1769244..1345f22 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_nan.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_nan.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 David Schultz
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c b/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c
index 796dbaf..ae6ffde 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_nearbyint.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_rintl.c b/libm/upstream-freebsd/lib/msun/src/s_rintl.c
index 1e9824d..790edbc 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_rintl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_rintl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_round.c b/libm/upstream-freebsd/lib/msun/src/s_round.c
index ca25f8e..a112bc5 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_round.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_round.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2003, Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_roundf.c b/libm/upstream-freebsd/lib/msun/src/s_roundf.c
index 5bbf6b3..bb6f77c 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_roundf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_roundf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2003, Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_roundl.c b/libm/upstream-freebsd/lib/msun/src/s_roundl.c
index 8d1c02a..9e85423 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_roundl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_roundl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2003, Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_scalbln.c b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
index c27420c..e8c6377 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_scalbln.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_significand.c b/libm/upstream-freebsd/lib/msun/src/s_significand.c
index 356e300..eed80ec 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_significand.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_significand.c
@@ -25,5 +25,5 @@
 double
 significand(double x)
 {
-	return __ieee754_scalb(x,(double) -ilogb(x));
+	return scalb(x,(double) -ilogb(x));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_significandf.c b/libm/upstream-freebsd/lib/msun/src/s_significandf.c
index ad030e2..b33ab7b 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_significandf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_significandf.c
@@ -22,5 +22,5 @@
 float
 significandf(float x)
 {
-	return __ieee754_scalbf(x,(float) -ilogbf(x));
+	return scalbf(x,(float) -ilogbf(x));
 }
diff --git a/libm/upstream-freebsd/lib/msun/src/s_sinl.c b/libm/upstream-freebsd/lib/msun/src/s_sinl.c
index f1ef84c..c5ee106 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_sinl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_sinl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_sinpi.c b/libm/upstream-freebsd/lib/msun/src/s_sinpi.c
index 858459a..8b388de 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_sinpi.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_sinpi.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2017 Steven G. Kargl
+ * Copyright (c) 2017, 2023 Steven G. Kargl
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -118,16 +118,7 @@
 	}
 
 	if (ix < 0x43300000) {			/* 1 <= |x| < 0x1p52 */
-		/* Determine integer part of ax. */
-		j0 = ((ix >> 20) & 0x7ff) - 0x3ff;
-		if (j0 < 20) {
-			ix &= ~(0x000fffff >> j0);
-			lx = 0;
-		} else {
-			lx &= ~((uint32_t)0xffffffff >> (j0 - 20));
-		}
-		INSERT_WORDS(x, ix, lx);
-
+		FFLOOR(x, j0, ix, lx);	/* Integer part of ax. */
 		ax -= x;
 		EXTRACT_WORDS(ix, lx, ax);
 
@@ -155,7 +146,8 @@
 		return ((hx & 0x80000000) ? -s : s);
 	}
 
-	if (ix >= 0x7f800000)
+	/* x = +-inf or nan. */
+	if (ix >= 0x7ff00000)
 		return (vzero / vzero);
 
 	/*
diff --git a/libm/upstream-freebsd/lib/msun/src/s_tanl.c b/libm/upstream-freebsd/lib/msun/src/s_tanl.c
index 0c5228e..c21e38d 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_tanl.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_tanl.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2007 Steven G. Kargl
  * All rights reserved.
diff --git a/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c b/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c
index 1fd46e8..6cbd356 100644
--- a/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c
+++ b/libm/upstream-freebsd/lib/msun/src/s_tgammaf.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index a3f5246..fee19f4 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -97,7 +97,7 @@
                                     void* context) __LINKER_PUBLIC__;
 }
 
-static pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 static char* __bionic_set_dlerror(char* new_value) {
   char* old_value = __get_thread()->current_dlerror;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 5c26944..1553ba9 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -27,6 +27,7 @@
  */
 
 #include <android/api-level.h>
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 0998629..0cb7ca9 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -104,3 +104,4 @@
 };
 
 __LIBC_HIDDEN__ extern bool g_is_ldd;
+__LIBC_HIDDEN__ extern pthread_mutex_t g_dl_mutex;
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f7c8ea9..e92aada 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -43,10 +43,11 @@
 #include "linker_tls.h"
 #include "linker_utils.h"
 
+#include "private/KernelArgumentBlock.h"
+#include "private/ScopedPthreadMutexLocker.h"
 #include "private/bionic_call_ifunc_resolver.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
-#include "private/KernelArgumentBlock.h"
 
 #include "android-base/unique_fd.h"
 #include "android-base/strings.h"
@@ -498,6 +499,11 @@
 
   if (!get_cfi_shadow()->InitialLinkDone(solist)) __linker_cannot_link(g_argv[0]);
 
+  // A constructor could spawn a thread that calls into the loader, so as soon
+  // as we've called a constructor, we need to hold the lock while accessing
+  // global loader state.
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
   si->call_pre_init_constructors();
   si->call_constructors();
 
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index 456d254..7ce53b8 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -76,6 +76,10 @@
   return get_allocator().memalign(alignment, byte_count);
 }
 
+void* aligned_alloc(size_t alignment, size_t byte_count) {
+  return get_allocator().memalign(alignment, byte_count);
+}
+
 void* calloc(size_t item_count, size_t item_size) {
   return get_allocator().alloc(item_count*item_size);
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index 8dc8eaf..a4298ab 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -472,6 +472,7 @@
         "sys_auxv_test.cpp",
         "sys_cachectl_test.cpp",
         "sys_epoll_test.cpp",
+        "sys_hwprobe_test.cpp",
         "sys_mman_test.cpp",
         "sys_msg_test.cpp",
         "sys_param_test.cpp",
diff --git a/tests/execinfo_test.cpp b/tests/execinfo_test.cpp
index b8e1325..1a0c51b 100644
--- a/tests/execinfo_test.cpp
+++ b/tests/execinfo_test.cpp
@@ -79,9 +79,13 @@
 }
 
 static size_t FindFunction(std::vector<void*>& frames, uintptr_t func_addr) {
+  Dl_info func_info;
+  if (!dladdr(reinterpret_cast<void*>(func_addr), &func_info)) {
+    return 0;
+  }
   for (size_t i = 0; i < frames.size(); i++) {
-    uintptr_t frame_addr = reinterpret_cast<uintptr_t>(frames[i]);
-    if (frame_addr >= func_addr && frame_addr <= func_addr + 0x100) {
+    Dl_info frame_info;
+    if (dladdr(frames[i], &frame_info) && func_info.dli_saddr == frame_info.dli_saddr) {
       return i + 1;
     }
   }
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 862f498..c1c586c 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -360,6 +360,6 @@
 #endif
 }
 
-TEST(fcntl_DeathTest, fcntl_F_SETFD) {
+TEST_F(fcntl_DeathTest, fcntl_F_SETFD) {
   EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "non-FD_CLOEXEC");
 }
diff --git a/tests/gwp_asan_test.cpp b/tests/gwp_asan_test.cpp
index c31f48c..709a939 100644
--- a/tests/gwp_asan_test.cpp
+++ b/tests/gwp_asan_test.cpp
@@ -34,12 +34,15 @@
 #if defined(__BIONIC__)
 
 #include "android-base/file.h"
+#include "android-base/silent_death_test.h"
 #include "android-base/test_utils.h"
 #include "gwp_asan/options.h"
 #include "platform/bionic/malloc.h"
 #include "sys/system_properties.h"
 #include "utils.h"
 
+using gwp_asan_integration_DeathTest = SilentDeathTest;
+
 // basename is a mess, use gnu basename explicitly to avoid the need for string
 // mutation.
 extern "C" const char* __gnu_basename(const char* path);
@@ -133,7 +136,7 @@
   }
 };
 
-TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled) {
+TEST_F(gwp_asan_integration_DeathTest, DISABLED_assert_gwp_asan_enabled) {
   std::string maps;
   EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
   EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
@@ -173,7 +176,7 @@
   __system_property_set((std::string("libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
                         "40000");
 
-  RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+  RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
 }
 
 TEST(gwp_asan_integration, sysprops_persist_program_specific) {
@@ -191,7 +194,7 @@
   __system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
                         "40000");
 
-  RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+  RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
 }
 
 TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
@@ -235,7 +238,7 @@
   __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
   __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
 
-  RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+  RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
 }
 
 TEST(gwp_asan_integration, sysprops_can_disable) {
@@ -261,7 +264,7 @@
   __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
   __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
 
-  RunGwpAsanTest("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+  RunGwpAsanTest("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
 }
 
 #endif  // defined(__BIONIC__)
diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp
index 5d85e97..b88d64a 100644
--- a/tests/heap_tagging_level_test.cpp
+++ b/tests/heap_tagging_level_test.cpp
@@ -19,6 +19,8 @@
 #include <malloc.h>
 #include <sys/prctl.h>
 
+#include <android-base/silent_death_test.h>
+
 #if defined(__BIONIC__)
 #include "gtest_globals.h"
 #include "platform/bionic/mte.h"
@@ -44,7 +46,9 @@
 }
 #endif
 
-TEST(heap_tagging_level, tagged_pointer_dies) {
+using heap_tagging_level_DeathTest = SilentDeathTest;
+
+TEST_F(heap_tagging_level_DeathTest, tagged_pointer_dies) {
 #if defined(__BIONIC__)
   if (!KernelSupportsTaggedPointers()) {
     GTEST_SKIP() << "Kernel doesn't support tagged pointers.";
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 5df694c..776643d 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -1347,45 +1347,44 @@
 }
 
 #if defined(__BIONIC__)
-static void* SetAllocationLimit(void* data) {
-  std::atomic_bool* go = reinterpret_cast<std::atomic_bool*>(data);
-  while (!go->load()) {
-  }
-  size_t limit = 500 * 1024 * 1024;
-  if (android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &limit, sizeof(limit))) {
-    return reinterpret_cast<void*>(-1);
-  }
-  return nullptr;
-}
-
 static void SetAllocationLimitMultipleThreads() {
-  std::atomic_bool go;
-  go = false;
-
   static constexpr size_t kNumThreads = 4;
-  pthread_t threads[kNumThreads];
+  std::atomic_bool start_running = false;
+  std::atomic<size_t> num_running;
+  std::atomic<size_t> num_successful;
+  std::unique_ptr<std::thread> threads[kNumThreads];
   for (size_t i = 0; i < kNumThreads; i++) {
-    ASSERT_EQ(0, pthread_create(&threads[i], nullptr, SetAllocationLimit, &go));
+    threads[i].reset(new std::thread([&num_running, &start_running, &num_successful] {
+      ++num_running;
+      while (!start_running) {
+      }
+      size_t limit = 500 * 1024 * 1024;
+      if (android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &limit, sizeof(limit))) {
+        ++num_successful;
+      }
+    }));
   }
 
-  // Let them go all at once.
-  go = true;
+  // Wait until all of the threads have started.
+  while (num_running != kNumThreads)
+    ;
+
+  // Now start all of the threads setting the mallopt at once.
+  start_running = true;
+
   // Send hardcoded signal (BIONIC_SIGNAL_PROFILER with value 0) to trigger
-  // heapprofd handler.
-  union sigval signal_value;
-  signal_value.sival_int = 0;
+  // heapprofd handler. This will verify that changing the limit while
+  // the allocation handlers are being changed at the same time works,
+  // or that the limit handler is changed first and this also works properly.
+  union sigval signal_value {};
   ASSERT_EQ(0, sigqueue(getpid(), BIONIC_SIGNAL_PROFILER, signal_value));
 
-  size_t num_successful = 0;
+  // Wait for all of the threads to finish.
   for (size_t i = 0; i < kNumThreads; i++) {
-    void* result;
-    ASSERT_EQ(0, pthread_join(threads[i], &result));
-    if (result != nullptr) {
-      num_successful++;
-    }
+    threads[i]->join();
   }
-  ASSERT_EQ(1U, num_successful);
-  exit(0);
+  ASSERT_EQ(1U, num_successful) << "Only one thread should be able to set the limit.";
+  _exit(0);
 }
 #endif
 
diff --git a/tests/run-on-host.sh b/tests/run-on-host.sh
index fe2c25a..19bbacf 100755
--- a/tests/run-on-host.sh
+++ b/tests/run-on-host.sh
@@ -2,9 +2,14 @@
 
 . $(dirname $0)/../build/run-on-host.sh
 
-if [ "$1" = glibc ]; then
+if [ "$1" = glibc -o "$1" = musl ]; then
+  if [ "$1" = musl ]; then
+    BUILD_ARGS=USE_HOST_MUSL=true
+  else
+    BUILD_ARGS=
+  fi
   shift
-  m -j bionic-unit-tests-glibc
+  m -j $BUILD_ARGS bionic-unit-tests-glibc
   (
     cd ${ANDROID_BUILD_TOP}
     export ANDROID_DATA=${TARGET_OUT_DATA}
@@ -13,7 +18,7 @@
   )
   exit 0
 elif [ "$1" != 32 -a "$1" != 64 ]; then
-  echo "Usage: $0 [ 32 | 64 | glibc ] [gtest flags]"
+  echo "Usage: $0 [ 32 | 64 | glibc | musl ] [gtest flags]"
   exit 1
 fi
 
diff --git a/tests/scs_test.cpp b/tests/scs_test.cpp
index 0776a43..3d5ebc1 100644
--- a/tests/scs_test.cpp
+++ b/tests/scs_test.cpp
@@ -16,8 +16,12 @@
 
 #include <gtest/gtest.h>
 
+#include <android-base/silent_death_test.h>
+
 #include "private/bionic_constants.h"
 
+using scs_DeathTest = SilentDeathTest;
+
 int recurse2(int count);
 
 __attribute__((weak, noinline)) int recurse1(int count) {
@@ -30,7 +34,7 @@
   return 0;
 }
 
-TEST(scs_test, stack_overflow) {
+TEST_F(scs_DeathTest, stack_overflow) {
 #if defined(__aarch64__) || defined(__riscv)
   ASSERT_EXIT(recurse1(SCS_SIZE), testing::KilledBySignal(SIGSEGV), "");
 #else
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index fa648d2..2e6908c 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -530,14 +530,15 @@
 #endif
 }
 
-#if defined(__BIONIC__)
+#if defined(__BIONIC__) && !defined(__riscv)
 // Not exposed via headers, but the symbols are available if you declare them yourself.
 extern "C" int sigblock(int);
 extern "C" int sigsetmask(int);
+#define HAVE_SIGBLOCK_SIGSETMASK
 #endif
 
 TEST(signal, sigblock_filter) {
-#if defined(__BIONIC__)
+#if defined(HAVE_SIGBLOCK_SIGSETMASK)
   TestSignalMaskFunction([]() {
     sigblock(~0U);
   });
@@ -545,7 +546,7 @@
 }
 
 TEST(signal, sigsetmask_filter) {
-#if defined(__BIONIC__)
+#if defined(HAVE_SIGBLOCK_SIGSETMASK)
   TestSignalMaskFunction([]() {
     sigsetmask(~0U);
   });
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index b3a296d..b0f59bb 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -1049,11 +1049,13 @@
 }
 
 TEST(STDIO_TEST, popen_return_value_signal) {
-  FILE* fp = popen("kill -7 $$", "r");
+  // Use a realtime signal to avoid creating a tombstone when running.
+  std::string cmd = android::base::StringPrintf("kill -%d $$", SIGRTMIN);
+  FILE* fp = popen(cmd.c_str(), "r");
   ASSERT_TRUE(fp != nullptr);
   int status = pclose(fp);
   EXPECT_TRUE(WIFSIGNALED(status));
-  EXPECT_EQ(7, WTERMSIG(status));
+  EXPECT_EQ(SIGRTMIN, WTERMSIG(status));
 }
 
 TEST(STDIO_TEST, getc) {
@@ -3310,7 +3312,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, snprintf_invalid_w_width) {
+TEST_F(STDIO_DEATHTEST, snprintf_invalid_w_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat-invalid-specifier"
@@ -3323,7 +3325,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, swprintf_invalid_w_width) {
+TEST_F(STDIO_DEATHTEST, swprintf_invalid_w_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat-invalid-specifier"
@@ -3459,7 +3461,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, snprintf_invalid_wf_width) {
+TEST_F(STDIO_DEATHTEST, snprintf_invalid_wf_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat"
@@ -3473,7 +3475,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, swprintf_invalid_wf_width) {
+TEST_F(STDIO_DEATHTEST, swprintf_invalid_wf_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat"
@@ -3572,7 +3574,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, sscanf_invalid_w_or_wf_width) {
+TEST_F(STDIO_DEATHTEST, sscanf_invalid_w_or_wf_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat"
@@ -3672,7 +3674,7 @@
 #endif
 }
 
-TEST(STDIO_TEST, swscanf_invalid_w_or_wf_width) {
+TEST_F(STDIO_DEATHTEST, swscanf_invalid_w_or_wf_width) {
 #if defined(__BIONIC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wformat"
diff --git a/tests/sys_hwprobe_test.cpp b/tests/sys_hwprobe_test.cpp
new file mode 100644
index 0000000..15028ff
--- /dev/null
+++ b/tests/sys_hwprobe_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 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 __has_include(<sys/hwprobe.h>)
+#include <sys/hwprobe.h>
+#endif
+
+TEST(sys_hwprobe, __riscv_hwprobe) {
+#if defined(__riscv) && __has_include(<sys/cachectl.h>)
+  riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0},
+                            {.key = RISCV_HWPROBE_KEY_CPUPERF_0}};
+  ASSERT_EQ(0, __riscv_hwprobe(probes, 2, 0, nullptr, 0));
+  EXPECT_EQ(RISCV_HWPROBE_KEY_IMA_EXT_0, probes[0].key);
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_FD) != 0);
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_C) != 0);
+  // TODO: remove #define when our uapi headers are new enough.
+#define RISCV_HWPROBE_IMA_V (1 << 2)
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_IMA_V) != 0);
+  // TODO: remove #ifs when our kernel is new enough.
+#if defined(RISCV_HWPROBE_EXT_ZBA)
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBA) != 0);
+#endif
+#if defined(RISCV_HWPROBE_EXT_ZBB)
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBB) != 0);
+#endif
+#if defined(RISCV_HWPROBE_EXT_ZBS)
+  EXPECT_TRUE((probes[0].value & RISCV_HWPROBE_EXT_ZBS) != 0);
+#endif
+
+  EXPECT_EQ(RISCV_HWPROBE_KEY_CPUPERF_0, probes[1].key);
+  EXPECT_TRUE((probes[1].value & RISCV_HWPROBE_MISALIGNED_MASK) == RISCV_HWPROBE_MISALIGNED_FAST);
+#else
+  GTEST_SKIP() << "__riscv_hwprobe requires riscv64";
+#endif
+}
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index 1936a8d..512f098 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -33,11 +33,11 @@
 // excluded, so it has never supported them. Other implementations (at least
 // as of glibc 2.36), do support those sequences.
 #if defined(__ANDROID__) || defined(ANDROID_HOST_MUSL)
-constexpr bool kLibcSupportsLongUtf8Sequences = 0;
+constexpr bool kLibcRejectsOverLongUtf8Sequences = true;
 #elif defined(__GLIBC__)
-constexpr bool kLibcSupportsLongUtf8Sequences = 1;
+constexpr bool kLibcRejectsOverLongUtf8Sequences = false;
 #else
-#error kLibcSupportsLongUtf8Sequences must be configured for this platform
+#error kLibcRejectsOverLongUtf8Sequences must be configured for this platform
 #endif
 
 TEST(uchar, sizeof_uchar_t) {
@@ -46,16 +46,42 @@
 }
 
 TEST(uchar, start_state) {
+  // C23 does not appear to specify the behavior of the conversion functions if
+  // a state is reused before the character is completed. In the wchar.h section
+  // (7.31.6.3) it says:
+  //
+  //     If an mbstate_t object has been altered by any of the functions
+  //     described in this subclause, and is then used with a different
+  //     multibyte character sequence, or in the other conversion direction, or
+  //     with a different LC_CTYPE category setting than on earlier function
+  //     calls, the behavior is undefined.
+  //
+  // But "described in this subclause" refers to the wchar.h functions, not the
+  // uchar.h ones.
+  //
+  // Since C has no opinion, we need to make a choice. While no caller should
+  // ever do this (what does it mean to begin decoding a UTF-32 character while
+  // still in the middle of a UTF-8 sequence?), considering that a decoding
+  // error seems the least surprising. Bionic and glibc both have that behavior.
+  // musl ignores the state (it also doesn't make much sense to read the state
+  // when the entire conversion completes in a single call) and decodes the
+  // UTF-32 character.
+#if !defined(ANDROID_HOST_MUSL)
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   char out[MB_LEN_MAX];
   mbstate_t ps;
 
-  // Any non-initial state is invalid when calling c32rtomb.
   memset(&ps, 0, sizeof(ps));
   EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "\xc2", 1, &ps));
   errno = 0;
   EXPECT_EQ(static_cast<size_t>(-1), c32rtomb(out, 0x00a2, &ps));
   EXPECT_EQ(EILSEQ, errno);
 
+  // Similarly (but not in compliance with the standard afaict), musl seems to
+  // ignore the state entirely for the UTF-32 functions rather than reset it.
+
   // If the first argument to c32rtomb is nullptr or the second is L'\0' the shift
   // state should be reset.
   memset(&ps, 0, sizeof(ps));
@@ -67,14 +93,21 @@
   EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "\xf0\xa4", 1, &ps));
   EXPECT_EQ(1U, c32rtomb(out, L'\0', &ps));
   EXPECT_TRUE(mbsinit(&ps));
+#endif
 }
 
 TEST(uchar, c16rtomb_null_out) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   EXPECT_EQ(1U, c16rtomb(nullptr, L'\0', nullptr));
   EXPECT_EQ(1U, c16rtomb(nullptr, L'h', nullptr));
 }
 
 TEST(uchar, c16rtomb_null_char) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   char bytes[MB_LEN_MAX];
   EXPECT_EQ(1U, c16rtomb(bytes, L'\0', nullptr));
 }
@@ -115,6 +148,9 @@
 }
 
 TEST(uchar, c16rtomb_invalid) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   char bytes[MB_LEN_MAX];
 
   memset(bytes, 0, sizeof(bytes));
@@ -125,20 +161,26 @@
 }
 
 TEST(uchar, mbrtoc16_null) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   ASSERT_EQ(0U, mbrtoc16(nullptr, nullptr, 0, nullptr));
 }
 
 TEST(uchar, mbrtoc16_zero_len) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   char16_t out;
 
   out = L'x';
-  ASSERT_EQ(0U, mbrtoc16(&out, "hello", 0, nullptr));
-  ASSERT_EQ(L'x', out);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "hello", 0, nullptr));
+  EXPECT_EQ(L'x', out);
 
-  ASSERT_EQ(0U, mbrtoc16(&out, "hello", 0, nullptr));
-  ASSERT_EQ(0U, mbrtoc16(&out, "", 0, nullptr));
-  ASSERT_EQ(1U, mbrtoc16(&out, "hello", 1, nullptr));
-  ASSERT_EQ(L'h', out);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "", 0, nullptr));
+  EXPECT_EQ(1U, mbrtoc16(&out, "hello", 1, nullptr));
+  EXPECT_EQ(L'h', out);
 }
 
 TEST(uchar, mbrtoc16) {
@@ -157,10 +199,12 @@
   ASSERT_EQ(3U, mbrtoc16(&out, "\xe2\x82\xac" "def", 6, nullptr));
   ASSERT_EQ(static_cast<char16_t>(0x20ac), out);
   // 4-byte UTF-8 will be returned as a surrogate pair...
-  ASSERT_EQ(static_cast<size_t>(-3),
-            mbrtoc16(&out, "\xf4\x8a\xaf\x8d", 6, nullptr));
+  ASSERT_EQ(4U, mbrtoc16(&out, "\xf4\x8a\xaf\x8d", 6, nullptr));
   ASSERT_EQ(static_cast<char16_t>(0xdbea), out);
-  ASSERT_EQ(4U, mbrtoc16(&out, "\xf4\x8a\xaf\x8d" "ef", 6, nullptr));
+  ASSERT_EQ(static_cast<size_t>(-3), mbrtoc16(&out,
+                                              "\xf4\x8a\xaf\x8d"
+                                              "ef",
+                                              6, nullptr));
   ASSERT_EQ(static_cast<char16_t>(0xdfcd), out);
 }
 
@@ -171,27 +215,44 @@
   char16_t out = u'\0';
   errno = 0;
   auto result = mbrtoc16(&out, "\xf8\xa1\xa2\xa3\xa4", 5, nullptr);
-  if (kLibcSupportsLongUtf8Sequences) {
-    EXPECT_EQ(5U, result);
-    EXPECT_EQ(0, errno);
-    EXPECT_EQ(u'\uf94a', out);
-  } else {
+  if (kLibcRejectsOverLongUtf8Sequences) {
     EXPECT_EQ(static_cast<size_t>(-1), result);
     EXPECT_EQ(EILSEQ, errno);
     EXPECT_EQ(u'\0', out);
+  } else {
+    EXPECT_EQ(5U, result);
+    EXPECT_EQ(0, errno);
+    EXPECT_EQ(u'\uf94a', out);
   }
 }
 
 TEST(uchar, mbrtoc16_reserved_range) {
-  char16_t out;
-  ASSERT_EQ(static_cast<size_t>(-1),
-            mbrtoc16(&out, "\xf0\x80\xbf\xbf", 6, nullptr));
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
+  errno = 0;
+  char16_t out = u'\0';
+  EXPECT_EQ(static_cast<size_t>(-1), mbrtoc16(&out, "\xf0\x80\xbf\xbf", 6, nullptr));
+  EXPECT_EQ(u'\0', out);
+  EXPECT_EQ(EILSEQ, errno);
 }
 
 TEST(uchar, mbrtoc16_beyond_range) {
-  char16_t out;
-  ASSERT_EQ(static_cast<size_t>(-1),
-            mbrtoc16(&out, "\xf5\x80\x80\x80", 6, nullptr));
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
+  errno = 0;
+  char16_t out = u'\0';
+  auto result = mbrtoc16(&out, "\xf5\x80\x80\x80", 6, nullptr);
+  if (kLibcRejectsOverLongUtf8Sequences) {
+    EXPECT_EQ(static_cast<size_t>(-1), result);
+    EXPECT_EQ(u'\0', out);
+    EXPECT_EQ(EILSEQ, errno);
+  } else {
+    EXPECT_EQ(4U, result);
+    EXPECT_EQ(u'\xdcc0', out);
+    EXPECT_EQ(0, errno);
+  }
 }
 
 void test_mbrtoc16_incomplete(mbstate_t* ps) {
@@ -213,9 +274,15 @@
   // 4-byte UTF-8.
   ASSERT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "\xf4", 1, ps));
   ASSERT_EQ(static_cast<size_t>(-2), mbrtoc16(&out, "\x8a\xaf", 2, ps));
-  ASSERT_EQ(static_cast<size_t>(-3), mbrtoc16(&out, "\x8d" "ef", 3, ps));
+  ASSERT_EQ(1U, mbrtoc16(&out,
+                         "\x8d"
+                         "ef",
+                         3, ps));
   ASSERT_EQ(static_cast<char16_t>(0xdbea), out);
-  ASSERT_EQ(1U, mbrtoc16(&out, "\x80" "ef", 3, ps));
+  ASSERT_EQ(static_cast<size_t>(-3), mbrtoc16(&out,
+                                              "\x80"
+                                              "ef",
+                                              3, ps));
   ASSERT_EQ(static_cast<char16_t>(0xdfcd), out);
   ASSERT_TRUE(mbsinit(ps));
 
@@ -227,6 +294,9 @@
 }
 
 TEST(uchar, mbrtoc16_incomplete) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   mbstate_t ps;
   memset(&ps, 0, sizeof(ps));
 
@@ -295,55 +365,78 @@
   ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
   uselocale(LC_GLOBAL_LOCALE);
 
-  char32_t out[8] = {};
+  char32_t out = U'\0';
   errno = 0;
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf5\x80\x80\x80", 4, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  auto result = mbrtoc32(&out, "\xf5\x80\x80\x80", 4, nullptr);
+  if (kLibcRejectsOverLongUtf8Sequences) {
+    EXPECT_EQ(static_cast<size_t>(-1), result);
+    EXPECT_EQ(EILSEQ, errno);
+    EXPECT_EQ(U'\0', out);
+  } else {
+    EXPECT_EQ(4U, result);
+    EXPECT_EQ(0, errno);
+    EXPECT_EQ(U'\x140000', out);
+  }
 }
 
 TEST(uchar, mbrtoc32) {
   char32_t out[8];
 
   out[0] = L'x';
-  ASSERT_EQ(0U, mbrtoc32(out, "hello", 0, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(L'x'), out[0]);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(out, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(L'x'), out[0]);
 
-  ASSERT_EQ(0U, mbrtoc32(out, "hello", 0, nullptr));
-  ASSERT_EQ(0U, mbrtoc32(out, "", 0, nullptr));
-  ASSERT_EQ(1U, mbrtoc32(out, "hello", 1, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(L'h'), out[0]);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(out, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(out, "", 0, nullptr));
+  EXPECT_EQ(1U, mbrtoc32(out, "hello", 1, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(L'h'), out[0]);
 
-  ASSERT_EQ(0U, mbrtoc32(nullptr, "hello", 0, nullptr));
-  ASSERT_EQ(0U, mbrtoc32(nullptr, "", 0, nullptr));
-  ASSERT_EQ(1U, mbrtoc32(nullptr, "hello", 1, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtoc32(nullptr, "", 0, nullptr));
+  EXPECT_EQ(1U, mbrtoc32(nullptr, "hello", 1, nullptr));
 
-  ASSERT_EQ(0U, mbrtoc32(nullptr, nullptr, 0, nullptr));
+  EXPECT_EQ(0U, mbrtoc32(nullptr, nullptr, 0, nullptr));
 
   ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
   uselocale(LC_GLOBAL_LOCALE);
 
   // 1-byte UTF-8.
-  ASSERT_EQ(1U, mbrtoc32(out, "abcdef", 6, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(L'a'), out[0]);
+  EXPECT_EQ(1U, mbrtoc32(out, "abcdef", 6, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(L'a'), out[0]);
   // 2-byte UTF-8.
-  ASSERT_EQ(2U, mbrtoc32(out, "\xc2\xa2" "cdef", 6, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(0x00a2), out[0]);
+  EXPECT_EQ(2U, mbrtoc32(out,
+                         "\xc2\xa2"
+                         "cdef",
+                         6, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(0x00a2), out[0]);
   // 3-byte UTF-8.
-  ASSERT_EQ(3U, mbrtoc32(out, "\xe2\x82\xac" "def", 6, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(0x20ac), out[0]);
+  EXPECT_EQ(3U, mbrtoc32(out,
+                         "\xe2\x82\xac"
+                         "def",
+                         6, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(0x20ac), out[0]);
   // 4-byte UTF-8.
-  ASSERT_EQ(4U, mbrtoc32(out, "\xf0\xa4\xad\xa2" "ef", 6, nullptr));
-  ASSERT_EQ(static_cast<char32_t>(0x24b62), out[0]);
+  EXPECT_EQ(4U, mbrtoc32(out,
+                         "\xf0\xa4\xad\xa2"
+                         "ef",
+                         6, nullptr));
+  EXPECT_EQ(static_cast<char32_t>(0x24b62), out[0]);
 #if defined(__BIONIC__) // glibc allows this.
   // Illegal 5-byte UTF-8.
   errno = 0;
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  EXPECT_EQ(static_cast<size_t>(-1), mbrtoc32(out,
+                                              "\xf8\xa1\xa2\xa3\xa4"
+                                              "f",
+                                              6, nullptr));
+  EXPECT_EQ(EILSEQ, errno);
 #endif
   // Illegal over-long sequence.
   errno = 0;
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtoc32(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  EXPECT_EQ(static_cast<size_t>(-1), mbrtoc32(out,
+                                              "\xf0\x82\x82\xac"
+                                              "ef",
+                                              6, nullptr));
+  EXPECT_EQ(EILSEQ, errno);
 }
 
 void test_mbrtoc32_incomplete(mbstate_t* ps) {
@@ -377,6 +470,9 @@
 }
 
 TEST(uchar, mbrtoc32_incomplete) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   mbstate_t ps;
   memset(&ps, 0, sizeof(ps));
 
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 92ab145..948d0ec 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -28,6 +28,7 @@
 
 #include "utils.h"
 
+#include <syscall.h>
 #include <string>
 
 #include <android-base/properties.h>
@@ -63,3 +64,9 @@
          (android::base::GetBoolProperty("ro.debuggable", false) &&
           android::base::GetBoolProperty("debug.force_low_ram", false));
 }
+
+#if defined(__GLIBC__) && __GLIBC_MINOR__ < 30
+pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+#endif
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 8716810..28c1046 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -29,6 +29,37 @@
 
 #define NUM_WCHARS(num_bytes) ((num_bytes)/sizeof(wchar_t))
 
+#ifdef __GLIBC__
+// glibc immediately dereferences the locale passed to all wcsto*_l functions,
+// even if it won't be used, and even if it's LC_GLOBAL_LOCALE, which isn't a
+// pointer to valid memory.
+static locale_t SAFE_LC_GLOBAL_LOCALE = duplocale(LC_GLOBAL_LOCALE);
+#else
+static locale_t SAFE_LC_GLOBAL_LOCALE = LC_GLOBAL_LOCALE;
+#endif
+
+// Modern versions of UTF-8 (https://datatracker.ietf.org/doc/html/rfc3629 and
+// newer) explicitly disallow code points beyond U+10FFFF, which exclude all 5-
+// and 6-byte sequences. Earlier versions of UTF-8 allowed the wider range:
+// https://datatracker.ietf.org/doc/html/rfc2279.
+//
+// Bionic's unicode implementation was written after the high values were
+// excluded, so it has never supported them. Other implementations (at least
+// as of glibc 2.36), do support those sequences.
+#if defined(__ANDROID__) || defined(ANDROID_HOST_MUSL)
+constexpr bool kLibcRejectsOverLongUtf8Sequences = true;
+#elif defined(__GLIBC__)
+constexpr bool kLibcRejectsOverLongUtf8Sequences = false;
+#else
+#error kLibcRejectsOverLongUtf8Sequences must be configured for this platform
+#endif
+
+#if defined(__GLIBC__)
+constexpr bool kLibcSupportsParsingBinaryLiterals = __GLIBC_PREREQ(2, 38);
+#else
+constexpr bool kLibcSupportsParsingBinaryLiterals = true;
+#endif
+
 TEST(wchar, sizeof_wchar_t) {
   EXPECT_EQ(4U, sizeof(wchar_t));
   EXPECT_EQ(4U, sizeof(wint_t));
@@ -36,7 +67,7 @@
 
 TEST(wchar, mbrlen) {
   char bytes[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
-  EXPECT_EQ(0U, mbrlen(&bytes[0], 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrlen(&bytes[0], 0, nullptr));
   EXPECT_EQ(1U, mbrlen(&bytes[0], 1, nullptr));
 
   EXPECT_EQ(1U, mbrlen(&bytes[4], 1, nullptr));
@@ -95,6 +126,9 @@
 }
 
 TEST(wchar, wcrtomb_start_state) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   char out[MB_LEN_MAX];
   mbstate_t ps;
 
@@ -118,6 +152,9 @@
 }
 
 TEST(wchar, wcstombs_wcrtombs) {
+  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  uselocale(LC_GLOBAL_LOCALE);
+
   const wchar_t chars[] = { L'h', L'e', L'l', L'l', L'o', 0 };
   const wchar_t bad_chars[] = { L'h', L'i', static_cast<wchar_t>(0xffffffff), 0 };
   const wchar_t* src;
@@ -255,63 +292,97 @@
 TEST(wchar, mbtowc) {
   wchar_t out[8];
 
+  // mbtowc and all the mbrto* APIs behave slightly differently when n is 0:
+  //
+  // mbrtowc returns 0 "if the next n or fewer bytes complete the multibyte
+  // character that corresponds to the null wide character"
+  //
+  // mbrtoc says: "If s is not a null pointer, the mbtowc function either
+  // returns 0 (if s points to the null character)..."
+  //
+  // So mbrtowc will not provide the correct mbtowc return value for "" and
+  // n = 0.
+  //
+  // glibc gets this right, but all the BSDs (including macOS) and bionic (by
+  // way of openbsd) return -1 instead of 0.
+#ifdef __GLIBC__
+  int expected_result_for_zero_length_empty_string = 0;
+#else
+  int expected_result_for_zero_length_empty_string = -1;
+#endif
+
   out[0] = 'x';
-  ASSERT_EQ(0, mbtowc(out, "hello", 0));
-  ASSERT_EQ('x', out[0]);
+  EXPECT_EQ(-1, mbtowc(out, "hello", 0));
+  EXPECT_EQ('x', out[0]);
 
-  ASSERT_EQ(0, mbtowc(out, "hello", 0));
-  ASSERT_EQ(0, mbtowc(out, "", 0));
-  ASSERT_EQ(1, mbtowc(out, "hello", 1));
-  ASSERT_EQ(L'h', out[0]);
+  EXPECT_EQ(-1, mbtowc(out, "hello", 0));
+  EXPECT_EQ(expected_result_for_zero_length_empty_string, mbtowc(out, "", 0));
+  EXPECT_EQ(1, mbtowc(out, "hello", 1));
+  EXPECT_EQ(L'h', out[0]);
 
-  ASSERT_EQ(0, mbtowc(nullptr, "hello", 0));
-  ASSERT_EQ(0, mbtowc(nullptr, "", 0));
-  ASSERT_EQ(1, mbtowc(nullptr, "hello", 1));
+  EXPECT_EQ(-1, mbtowc(nullptr, "hello", 0));
+  EXPECT_EQ(expected_result_for_zero_length_empty_string, mbtowc(nullptr, "", 0));
+  EXPECT_EQ(1, mbtowc(nullptr, "hello", 1));
 
-  ASSERT_EQ(0, mbtowc(nullptr, nullptr, 0));
+  EXPECT_EQ(0, mbtowc(nullptr, nullptr, 0));
 }
 
 TEST(wchar, mbrtowc) {
   wchar_t out[8];
 
   out[0] = 'x';
-  ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
-  ASSERT_EQ('x', out[0]);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(out, "hello", 0, nullptr));
+  EXPECT_EQ('x', out[0]);
 
-  ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
-  ASSERT_EQ(0U, mbrtowc(out, "", 0, nullptr));
-  ASSERT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
-  ASSERT_EQ(L'h', out[0]);
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(out, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(out, "", 0, nullptr));
+  EXPECT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
+  EXPECT_EQ(L'h', out[0]);
 
-  ASSERT_EQ(0U, mbrtowc(nullptr, "hello", 0, nullptr));
-  ASSERT_EQ(0U, mbrtowc(nullptr, "", 0, nullptr));
-  ASSERT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(nullptr, "hello", 0, nullptr));
+  EXPECT_EQ(static_cast<size_t>(-2), mbrtowc(nullptr, "", 0, nullptr));
+  EXPECT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
 
-  ASSERT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
+  EXPECT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
 
-  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
+  EXPECT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
   uselocale(LC_GLOBAL_LOCALE);
 
   // 1-byte UTF-8.
-  ASSERT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
-  ASSERT_EQ(L'a', out[0]);
+  EXPECT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
+  EXPECT_EQ(L'a', out[0]);
   // 2-byte UTF-8.
-  ASSERT_EQ(2U, mbrtowc(out, "\xc2\xa2" "cdef", 6, nullptr));
-  ASSERT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
+  EXPECT_EQ(2U, mbrtowc(out,
+                        "\xc2\xa2"
+                        "cdef",
+                        6, nullptr));
+  EXPECT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
   // 3-byte UTF-8.
-  ASSERT_EQ(3U, mbrtowc(out, "\xe2\x82\xac" "def", 6, nullptr));
-  ASSERT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
+  EXPECT_EQ(3U, mbrtowc(out,
+                        "\xe2\x82\xac"
+                        "def",
+                        6, nullptr));
+  EXPECT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
   // 4-byte UTF-8.
-  ASSERT_EQ(4U, mbrtowc(out, "\xf0\xa4\xad\xa2" "ef", 6, nullptr));
-  ASSERT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
+  EXPECT_EQ(4U, mbrtowc(out,
+                        "\xf0\xa4\xad\xa2"
+                        "ef",
+                        6, nullptr));
+  EXPECT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
 #if defined(__BIONIC__) // glibc allows this.
   // Illegal 5-byte UTF-8.
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
+                                             "\xf8\xa1\xa2\xa3\xa4"
+                                             "f",
+                                             6, nullptr));
+  EXPECT_EQ(EILSEQ, errno);
 #endif
   // Illegal over-long sequence.
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
+                                             "\xf0\x82\x82\xac"
+                                             "ef",
+                                             6, nullptr));
+  EXPECT_EQ(EILSEQ, errno);
 }
 
 TEST(wchar, mbrtowc_valid_non_characters) {
@@ -332,8 +403,14 @@
 
   wchar_t out[8] = {};
   errno = 0;
-  ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf5\x80\x80\x80", 4, nullptr));
-  ASSERT_EQ(EILSEQ, errno);
+  auto result = mbrtowc(out, "\xf5\x80\x80\x80", 4, nullptr);
+  if (kLibcRejectsOverLongUtf8Sequences) {
+    ASSERT_EQ(static_cast<size_t>(-1), result);
+    ASSERT_EQ(EILSEQ, errno);
+  } else {
+    ASSERT_EQ(4U, result);
+    ASSERT_EQ(0, errno);
+  }
 }
 
 static void test_mbrtowc_incomplete(mbstate_t* ps) {
@@ -446,8 +523,8 @@
 void TestSingleWcsToInt(WcsToIntFn<T> fn, const wchar_t* str, int base,
                         T expected_value, ptrdiff_t expected_len) {
   wchar_t* p;
-  ASSERT_EQ(expected_value, fn(str, &p, base));
-  ASSERT_EQ(expected_len, p - str) << str;
+  EXPECT_EQ(expected_value, fn(str, &p, base)) << str << " " << base;
+  EXPECT_EQ(expected_len, p - str) << str << " " << base;
 }
 
 template <typename T>
@@ -460,7 +537,9 @@
   TestSingleWcsToInt(fn, L"   123 45", 0, static_cast<T>(123), 6);
   TestSingleWcsToInt(fn, L"  -123", 0, static_cast<T>(-123), 6);
   TestSingleWcsToInt(fn, L"0x10000", 0, static_cast<T>(65536), 7);
-  TestSingleWcsToInt(fn, L"0b1011", 0, static_cast<T>(0b1011), 6);
+  if (kLibcSupportsParsingBinaryLiterals) {
+    TestSingleWcsToInt(fn, L"0b1011", 0, static_cast<T>(0b1011), 6);
+  }
 }
 
 template <typename T>
@@ -584,7 +663,7 @@
 
   EXPECT_EQ(24U, wcsftime(buf, sizeof(buf), L"%c", &t));
   EXPECT_STREQ(L"Sun Mar 10 00:00:00 2100", buf);
-  EXPECT_EQ(24U, wcsftime_l(buf, sizeof(buf), L"%c", &t, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(24U, wcsftime_l(buf, sizeof(buf), L"%c", &t, SAFE_LC_GLOBAL_LOCALE));
   EXPECT_STREQ(L"Sun Mar 10 00:00:00 2100", buf);
 }
 
@@ -781,25 +860,25 @@
 
 TEST(wchar, wcstoll_l_EINVAL) {
   errno = 0;
-  wcstoll_l(L"123", nullptr, -1, LC_GLOBAL_LOCALE);
+  wcstoll_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
   errno = 0;
-  wcstoll_l(L"123", nullptr, 1, LC_GLOBAL_LOCALE);
+  wcstoll_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
   errno = 0;
-  wcstoll_l(L"123", nullptr, 37, LC_GLOBAL_LOCALE);
+  wcstoll_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
 }
 
 TEST(wchar, wcstoull_l_EINVAL) {
   errno = 0;
-  wcstoull_l(L"123", nullptr, -1, LC_GLOBAL_LOCALE);
+  wcstoull_l(L"123", nullptr, -1, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
   errno = 0;
-  wcstoull_l(L"123", nullptr, 1, LC_GLOBAL_LOCALE);
+  wcstoull_l(L"123", nullptr, 1, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
   errno = 0;
-  wcstoull_l(L"123", nullptr, 37, LC_GLOBAL_LOCALE);
+  wcstoull_l(L"123", nullptr, 37, SAFE_LC_GLOBAL_LOCALE);
   ASSERT_EQ(EINVAL, errno);
 }
 
@@ -922,7 +1001,7 @@
 
 TEST(wchar, wcstod_l) {
 #if !defined(ANDROID_HOST_MUSL)
-  EXPECT_EQ(1.23, wcstod_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(1.23, wcstod_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
 #else
   GTEST_SKIP() << "musl doesn't have wcstod_l";
 #endif
@@ -930,7 +1009,7 @@
 
 TEST(wchar, wcstof_l) {
 #if !defined(ANDROID_HOST_MUSL)
-  EXPECT_EQ(1.23f, wcstof_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(1.23f, wcstof_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
 #else
   GTEST_SKIP() << "musl doesn't have wcstof_l";
 #endif
@@ -938,30 +1017,30 @@
 
 TEST(wchar, wcstol_l) {
 #if !defined(ANDROID_HOST_MUSL)
-  EXPECT_EQ(123L, wcstol_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(123L, wcstol_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
 #else
   GTEST_SKIP() << "musl doesn't have wcstol_l";
 #endif
 }
 
 TEST(wchar, wcstold_l) {
-  EXPECT_EQ(1.23L, wcstold_l(L"1.23", nullptr, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(1.23L, wcstold_l(L"1.23", nullptr, SAFE_LC_GLOBAL_LOCALE));
 }
 
 TEST(wchar, wcstoll_l) {
-  EXPECT_EQ(123LL, wcstoll_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(123LL, wcstoll_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
 }
 
 TEST(wchar, wcstoul_l) {
 #if !defined(ANDROID_HOST_MUSL)
-  EXPECT_EQ(123UL, wcstoul_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(123UL, wcstoul_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
 #else
   GTEST_SKIP() << "musl doesn't have wcstoul_l";
 #endif
 }
 
 TEST(wchar, wcstoull_l) {
-  EXPECT_EQ(123ULL, wcstoull_l(L"123", nullptr, 10, LC_GLOBAL_LOCALE));
+  EXPECT_EQ(123ULL, wcstoull_l(L"123", nullptr, 10, SAFE_LC_GLOBAL_LOCALE));
 }
 
 static void AssertWcwidthRange(wchar_t begin, wchar_t end, int expected) {