about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/alloc/mod.rs33
-rw-r--r--library/std/src/sys/alloc/unix.rs10
-rw-r--r--library/std/src/sys/alloc/vexos.rs96
-rw-r--r--library/std/src/sys/alloc/wasm.rs17
-rw-r--r--library/std/src/sys/anonymous_pipe/mod.rs10
-rw-r--r--library/std/src/sys/args/mod.rs35
-rw-r--r--library/std/src/sys/args/wasip1.rs (renamed from library/std/src/sys/args/wasi.rs)0
-rw-r--r--library/std/src/sys/args/wasip2.rs6
-rw-r--r--library/std/src/sys/args/zkvm.rs103
-rw-r--r--library/std/src/sys/backtrace.rs2
-rw-r--r--library/std/src/sys/cmath.rs111
-rw-r--r--library/std/src/sys/env/mod.rs31
-rw-r--r--library/std/src/sys/env/wasi.rs7
-rw-r--r--library/std/src/sys/env_consts.rs13
-rw-r--r--library/std/src/sys/exit_guard.rs7
-rw-r--r--library/std/src/sys/fd/mod.rs14
-rw-r--r--library/std/src/sys/fd/unix.rs71
-rw-r--r--library/std/src/sys/fs/mod.rs50
-rw-r--r--library/std/src/sys/fs/unix.rs270
-rw-r--r--library/std/src/sys/fs/vexos.rs615
-rw-r--r--library/std/src/sys/fs/wasi.rs9
-rw-r--r--library/std/src/sys/fs/windows.rs30
-rw-r--r--library/std/src/sys/io/io_slice/uefi.rs74
-rw-r--r--library/std/src/sys/io/mod.rs30
-rw-r--r--library/std/src/sys/mod.rs4
-rw-r--r--library/std/src/sys/net/connection/mod.rs57
-rw-r--r--library/std/src/sys/net/connection/sgx.rs117
-rw-r--r--library/std/src/sys/net/connection/socket/hermit.rs3
-rw-r--r--library/std/src/sys/net/connection/socket/mod.rs (renamed from library/std/src/sys/net/connection/socket.rs)208
-rw-r--r--library/std/src/sys/net/connection/socket/tests.rs2
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs55
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs49
-rw-r--r--library/std/src/sys/net/connection/unsupported.rs32
-rw-r--r--library/std/src/sys/net/connection/wasip1.rs32
-rw-r--r--library/std/src/sys/net/connection/xous/dns.rs45
-rw-r--r--library/std/src/sys/net/connection/xous/mod.rs2
-rw-r--r--library/std/src/sys/net/connection/xous/tcplistener.rs26
-rw-r--r--library/std/src/sys/net/connection/xous/tcpstream.rs9
-rw-r--r--library/std/src/sys/net/connection/xous/udp.rs81
-rw-r--r--library/std/src/sys/net/mod.rs43
-rw-r--r--library/std/src/sys/os_str/mod.rs10
-rw-r--r--library/std/src/sys/os_str/wtf8.rs8
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs1
-rw-r--r--library/std/src/sys/pal/hermit/os.rs10
-rw-r--r--library/std/src/sys/pal/hermit/time.rs11
-rw-r--r--library/std/src/sys/pal/mod.rs62
-rw-r--r--library/std/src/sys/pal/sgx/abi/mod.rs2
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs4
-rw-r--r--library/std/src/sys/pal/sgx/os.rs10
-rw-r--r--library/std/src/sys/pal/solid/mod.rs4
-rw-r--r--library/std/src/sys/pal/solid/os.rs8
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs1
-rw-r--r--library/std/src/sys/pal/teeos/os.rs8
-rw-r--r--library/std/src/sys/pal/trusty/mod.rs2
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs4
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/os.rs3
-rw-r--r--library/std/src/sys/pal/uefi/tests.rs176
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs66
-rw-r--r--library/std/src/sys/pal/uefi/time.rs168
-rw-r--r--library/std/src/sys/pal/unix/futex.rs10
-rw-r--r--library/std/src/sys/pal/unix/mod.rs87
-rw-r--r--library/std/src/sys/pal/unix/os.rs65
-rw-r--r--library/std/src/sys/pal/unix/pipe.rs10
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs2
-rw-r--r--library/std/src/sys/pal/unix/time.rs27
-rw-r--r--library/std/src/sys/pal/unix/weak.rs130
-rw-r--r--library/std/src/sys/pal/unix/weak/tests.rs32
-rw-r--r--library/std/src/sys/pal/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/pal/unsupported/os.rs8
-rw-r--r--library/std/src/sys/pal/vexos/mod.rs80
-rw-r--r--library/std/src/sys/pal/vexos/time.rs28
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs212
-rw-r--r--library/std/src/sys/pal/wasip1/helpers.rs (renamed from library/std/src/sys/pal/wasi/helpers.rs)0
-rw-r--r--library/std/src/sys/pal/wasip1/mod.rs (renamed from library/std/src/sys/pal/wasi/mod.rs)1
-rw-r--r--library/std/src/sys/pal/wasip1/os.rs (renamed from library/std/src/sys/pal/wasi/os.rs)8
-rw-r--r--library/std/src/sys/pal/wasip1/time.rs (renamed from library/std/src/sys/pal/wasi/time.rs)0
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs7
-rw-r--r--library/std/src/sys/pal/wasip2/time.rs58
-rw-r--r--library/std/src/sys/pal/wasm/atomics/thread.rs75
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs14
-rw-r--r--library/std/src/sys/pal/windows/c.rs12
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt2
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs2
-rw-r--r--library/std/src/sys/pal/windows/handle.rs13
-rw-r--r--library/std/src/sys/pal/windows/mod.rs26
-rw-r--r--library/std/src/sys/pal/windows/os.rs8
-rw-r--r--library/std/src/sys/pal/windows/time.rs2
-rw-r--r--library/std/src/sys/pal/xous/mod.rs1
-rw-r--r--library/std/src/sys/pal/xous/os.rs8
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs2
-rw-r--r--library/std/src/sys/pal/zkvm/os.rs8
-rw-r--r--library/std/src/sys/path/mod.rs19
-rw-r--r--library/std/src/sys/personality/gcc.rs22
-rw-r--r--library/std/src/sys/personality/mod.rs15
-rw-r--r--library/std/src/sys/platform_version/darwin/core_foundation.rs180
-rw-r--r--library/std/src/sys/platform_version/darwin/mod.rs351
-rw-r--r--library/std/src/sys/platform_version/darwin/public_extern.rs156
-rw-r--r--library/std/src/sys/platform_version/darwin/tests.rs379
-rw-r--r--library/std/src/sys/platform_version/mod.rs13
-rw-r--r--library/std/src/sys/process/mod.rs15
-rw-r--r--library/std/src/sys/process/uefi.rs9
-rw-r--r--library/std/src/sys/process/unix/common.rs26
-rw-r--r--library/std/src/sys/process/unix/fuchsia.rs1
-rw-r--r--library/std/src/sys/process/unix/mod.rs15
-rw-r--r--library/std/src/sys/process/unix/unix.rs20
-rw-r--r--library/std/src/sys/process/unix/unix/tests.rs1
-rw-r--r--library/std/src/sys/process/unix/unsupported.rs1
-rw-r--r--library/std/src/sys/process/unix/vxworks.rs4
-rw-r--r--library/std/src/sys/process/unsupported.rs9
-rw-r--r--library/std/src/sys/process/windows.rs7
-rw-r--r--library/std/src/sys/process/windows/tests.rs24
-rw-r--r--library/std/src/sys/random/mod.rs79
-rw-r--r--library/std/src/sys/random/uefi.rs7
-rw-r--r--library/std/src/sys/random/wasip1.rs (renamed from library/std/src/sys/random/wasi.rs)0
-rw-r--r--library/std/src/sys/random/wasip2.rs9
-rw-r--r--library/std/src/sys/stdio/mod.rs49
-rw-r--r--library/std/src/sys/stdio/vexos.rs100
-rw-r--r--library/std/src/sys/stdio/wasip1.rs (renamed from library/std/src/sys/stdio/wasi.rs)0
-rw-r--r--library/std/src/sys/stdio/wasip2.rs120
-rw-r--r--library/std/src/sys/sync/condvar/mod.rs26
-rw-r--r--library/std/src/sys/sync/mutex/mod.rs29
-rw-r--r--library/std/src/sys/sync/once/mod.rs14
-rw-r--r--library/std/src/sys/sync/once/queue.rs4
-rw-r--r--library/std/src/sys/sync/rwlock/mod.rs20
-rw-r--r--library/std/src/sys/sync/thread_parking/mod.rs26
-rw-r--r--library/std/src/sys/thread/hermit.rs (renamed from library/std/src/sys/pal/hermit/thread.rs)66
-rw-r--r--library/std/src/sys/thread/mod.rs159
-rw-r--r--library/std/src/sys/thread/sgx.rs (renamed from library/std/src/sys/pal/sgx/thread.rs)49
-rw-r--r--library/std/src/sys/thread/solid.rs (renamed from library/std/src/sys/pal/itron/thread.rs)42
-rw-r--r--library/std/src/sys/thread/teeos.rs (renamed from library/std/src/sys/pal/teeos/thread.rs)71
-rw-r--r--library/std/src/sys/thread/uefi.rs25
-rw-r--r--library/std/src/sys/thread/unix.rs (renamed from library/std/src/sys/pal/unix/thread.rs)708
-rw-r--r--library/std/src/sys/thread/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/thread.rs)39
-rw-r--r--library/std/src/sys/thread/vexos.rs17
-rw-r--r--library/std/src/sys/thread/wasip1.rs185
-rw-r--r--library/std/src/sys/thread/wasip2.rs32
-rw-r--r--library/std/src/sys/thread/wasm.rs23
-rw-r--r--library/std/src/sys/thread/windows.rs (renamed from library/std/src/sys/pal/windows/thread.rs)112
-rw-r--r--library/std/src/sys/thread/xous.rs (renamed from library/std/src/sys/pal/xous/thread.rs)54
-rw-r--r--library/std/src/sys/thread_local/mod.rs62
141 files changed, 5063 insertions, 2238 deletions
diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs
index f3af1f7f599..2045b2fecc6 100644
--- a/library/std/src/sys/alloc/mod.rs
+++ b/library/std/src/sys/alloc/mod.rs
@@ -68,29 +68,40 @@ unsafe fn realloc_fallback(
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_family = "unix",
         target_os = "wasi",
         target_os = "teeos",
         target_os = "trusty",
-    ))] {
+    ) => {
         mod unix;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
-    } else if #[cfg(target_family = "wasm")] {
+    }
+    target_os = "vexos" => {
+        mod vexos;
+    }
+    target_family = "wasm" => {
         mod wasm;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
     }
 }
diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs
index a7ac4117ec9..3d369b08abc 100644
--- a/library/std/src/sys/alloc/unix.rs
+++ b/library/std/src/sys/alloc/unix.rs
@@ -58,18 +58,16 @@ unsafe impl GlobalAlloc for System {
     }
 }
 
-cfg_if::cfg_if! {
+cfg_select! {
     // We use posix_memalign wherever possible, but some targets have very incomplete POSIX coverage
     // so we need a fallback for those.
-    if #[cfg(any(
-        target_os = "horizon",
-        target_os = "vita",
-    ))] {
+    any(target_os = "horizon", target_os = "vita") => {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
             unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
         }
-    } else {
+    }
+    _ => {
         #[inline]
         #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
diff --git a/library/std/src/sys/alloc/vexos.rs b/library/std/src/sys/alloc/vexos.rs
new file mode 100644
index 00000000000..c1fb6896a89
--- /dev/null
+++ b/library/std/src/sys/alloc/vexos.rs
@@ -0,0 +1,96 @@
+// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+#![allow(static_mut_refs)]
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sync::atomic::{AtomicBool, Ordering};
+
+// Symbols for heap section boundaries defined in the target's linkerscript
+unsafe extern "C" {
+    static mut __heap_start: u8;
+    static mut __heap_end: u8;
+}
+
+static mut DLMALLOC: dlmalloc::Dlmalloc<Vexos> = dlmalloc::Dlmalloc::new_with_allocator(Vexos);
+
+struct Vexos;
+
+unsafe impl dlmalloc::Allocator for Vexos {
+    /// Allocs system resources
+    fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
+        static INIT: AtomicBool = AtomicBool::new(false);
+
+        if !INIT.swap(true, Ordering::Relaxed) {
+            // This target has no growable heap, as user memory has a fixed
+            // size/location and VEXos does not manage allocation for us.
+            unsafe {
+                (
+                    (&raw mut __heap_start).cast::<u8>(),
+                    (&raw const __heap_end).offset_from_unsigned(&raw const __heap_start),
+                    0,
+                )
+            }
+        } else {
+            (ptr::null_mut(), 0, 0)
+        }
+    }
+
+    fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
+        ptr::null_mut()
+    }
+
+    fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
+        false
+    }
+
+    fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
+        return false;
+    }
+
+    fn can_release_part(&self, _flags: u32) -> bool {
+        false
+    }
+
+    fn allocates_zeros(&self) -> bool {
+        false
+    }
+
+    fn page_size(&self) -> usize {
+        0x1000
+    }
+}
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling free() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
+    }
+}
diff --git a/library/std/src/sys/alloc/wasm.rs b/library/std/src/sys/alloc/wasm.rs
index c8fab992a88..48e2fdd4ecc 100644
--- a/library/std/src/sys/alloc/wasm.rs
+++ b/library/std/src/sys/alloc/wasm.rs
@@ -16,12 +16,15 @@
 //! The crate itself provides a global allocator which on wasm has no
 //! synchronization as there are no threads!
 
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
+use core::cell::SyncUnsafeCell;
 
 use crate::alloc::{GlobalAlloc, Layout, System};
 
-static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
+struct SyncDlmalloc(dlmalloc::Dlmalloc);
+unsafe impl Sync for SyncDlmalloc {}
+
+static DLMALLOC: SyncUnsafeCell<SyncDlmalloc> =
+    SyncUnsafeCell::new(SyncDlmalloc(dlmalloc::Dlmalloc::new()));
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
@@ -30,7 +33,7 @@ unsafe impl GlobalAlloc for System {
         // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
-        unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
+        unsafe { (*DLMALLOC.get()).0.malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
@@ -38,7 +41,7 @@ unsafe impl GlobalAlloc for System {
         // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
-        unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
+        unsafe { (*DLMALLOC.get()).0.calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
@@ -46,7 +49,7 @@ unsafe impl GlobalAlloc for System {
         // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling free() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
-        unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
+        unsafe { (*DLMALLOC.get()).0.free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
@@ -54,7 +57,7 @@ unsafe impl GlobalAlloc for System {
         // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
-        unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
+        unsafe { (*DLMALLOC.get()).0.realloc(ptr, layout.size(), layout.align(), new_size) }
     }
 }
 
diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs
index aa14c8b650d..b6f464161ee 100644
--- a/library/std/src/sys/anonymous_pipe/mod.rs
+++ b/library/std/src/sys/anonymous_pipe/mod.rs
@@ -1,13 +1,15 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(unix)] {
+cfg_select! {
+    unix => {
         mod unix;
         pub use unix::{AnonPipe, pipe};
-    } else if #[cfg(windows)] {
+    }
+    windows => {
         mod windows;
         pub use windows::{AnonPipe, pipe};
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::{AnonPipe, pipe};
     }
diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs
index 0011f55dc14..e11e8e5430f 100644
--- a/library/std/src/sys/args/mod.rs
+++ b/library/std/src/sys/args/mod.rs
@@ -12,32 +12,43 @@
 ))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_family = "windows")] {
+    }
+    target_family = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::*;
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::*;
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasip1.rs
index 72063a87dc9..72063a87dc9 100644
--- a/library/std/src/sys/args/wasi.rs
+++ b/library/std/src/sys/args/wasip1.rs
diff --git a/library/std/src/sys/args/wasip2.rs b/library/std/src/sys/args/wasip2.rs
new file mode 100644
index 00000000000..a57e4b97786
--- /dev/null
+++ b/library/std/src/sys/args/wasip2.rs
@@ -0,0 +1,6 @@
+pub use super::common::Args;
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    Args::new(wasip2::cli::environment::get_arguments().into_iter().map(|arg| arg.into()).collect())
+}
diff --git a/library/std/src/sys/args/zkvm.rs b/library/std/src/sys/args/zkvm.rs
index 194ba7159d4..d26bf1eaff9 100644
--- a/library/std/src/sys/args/zkvm.rs
+++ b/library/std/src/sys/args/zkvm.rs
@@ -1,25 +1,20 @@
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::sys::os_str;
+use crate::ffi::{OsStr, OsString};
+use crate::num::NonZero;
+use crate::sync::OnceLock;
 use crate::sys::pal::{WORD_SIZE, abi};
-use crate::sys_common::FromInner;
-
-pub struct Args {
-    i_forward: usize,
-    i_back: usize,
-    count: usize,
-}
+use crate::{fmt, ptr, slice};
 
 pub fn args() -> Args {
-    let count = unsafe { abi::sys_argc() };
-    Args { i_forward: 0, i_back: 0, count }
+    Args { iter: ARGS.get_or_init(|| get_args()).iter() }
 }
 
-impl Args {
-    /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc
-    /// and will not return if the index is out of bounds.
-    fn argv(i: usize) -> OsString {
-        let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) };
+fn get_args() -> Vec<&'static OsStr> {
+    let argc = unsafe { abi::sys_argc() };
+    let mut args = Vec::with_capacity(argc);
+
+    for i in 0..argc {
+        // Get the size of the argument then the data.
+        let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) };
 
         let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
         let words = unsafe { abi::sys_alloc_words(arg_len_words) };
@@ -27,20 +22,24 @@ impl Args {
         let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
         debug_assert_eq!(arg_len, arg_len2);
 
-        // Convert to OsString.
-        //
-        // FIXME: We can probably get rid of the extra copy here if we
-        // reimplement "os_str" instead of just using the generic unix
-        // "os_str".
-        let arg_bytes: &[u8] =
-            unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) };
-        OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() })
+        let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) };
+        args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) });
     }
+    args
 }
 
+static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new();
+
+pub struct Args {
+    iter: slice::Iter<'static, &'static OsStr>,
+}
+
+impl !Send for Args {}
+impl !Sync for Args {}
+
 impl fmt::Debug for Args {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().finish()
+        self.iter.as_slice().fmt(f)
     }
 }
 
@@ -48,34 +47,48 @@ impl Iterator for Args {
     type Item = OsString;
 
     fn next(&mut self) -> Option<OsString> {
-        if self.i_forward >= self.count - self.i_back {
-            None
-        } else {
-            let arg = Self::argv(self.i_forward);
-            self.i_forward += 1;
-            Some(arg)
-        }
+        self.iter.next().map(|arg| arg.to_os_string())
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.count, Some(self.count))
+        self.iter.size_hint()
     }
-}
 
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize {
-        self.count
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.len()
+    }
+
+    fn last(self) -> Option<OsString> {
+        self.iter.last().map(|arg| arg.to_os_string())
+    }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.iter.advance_by(n)
     }
 }
 
 impl DoubleEndedIterator for Args {
     fn next_back(&mut self) -> Option<OsString> {
-        if self.i_back >= self.count - self.i_forward {
-            None
-        } else {
-            let arg = Self::argv(self.count - 1 - self.i_back);
-            self.i_back += 1;
-            Some(arg)
-        }
+        self.iter.next_back().map(|arg| arg.to_os_string())
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.iter.advance_back_by(n)
+    }
+}
+
+impl ExactSizeIterator for Args {
+    #[inline]
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
     }
 }
diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs
index 272d0fa4d1a..57682207e07 100644
--- a/library/std/src/sys/backtrace.rs
+++ b/library/std/src/sys/backtrace.rs
@@ -113,7 +113,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                         res = bt_fmt.frame().symbol(frame, symbol);
                     }
                 });
-                #[cfg(target_os = "nto")]
+                #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))]
                 if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
                     if !hit && print {
                         use crate::backtrace_rs::SymbolName;
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
index 299ce1a6ff0..1592218ead8 100644
--- a/library/std/src/sys/cmath.rs
+++ b/library/std/src/sys/cmath.rs
@@ -45,69 +45,70 @@ unsafe extern "C" {
     pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
     pub safe fn erff128(n: f128) -> f128;
     pub safe fn erfcf128(n: f128) -> f128;
-
-    cfg_if::cfg_if! {
-    if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
-        pub safe fn acosf(n: f32) -> f32;
-        pub safe fn asinf(n: f32) -> f32;
-        pub safe fn atan2f(a: f32, b: f32) -> f32;
-        pub safe fn atanf(n: f32) -> f32;
-        pub safe fn coshf(n: f32) -> f32;
-        pub safe fn sinhf(n: f32) -> f32;
-        pub safe fn tanf(n: f32) -> f32;
-        pub safe fn tanhf(n: f32) -> f32;
-    }}
 }
 
-// On AIX, we don't have lgammaf_r only the f64 version, so we can
-// use the f64 version lgamma_r
-#[cfg(target_os = "aix")]
-pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
-    lgamma_r(n.into(), s) as f32
-}
+cfg_select! {
+    all(target_os = "windows", target_env = "msvc", target_arch = "x86") => {
+        // On 32-bit x86 MSVC these functions aren't defined, so we just define shims
+        // which promote everything to f64, perform the calculation, and then demote
+        // back to f32. While not precisely correct should be "correct enough" for now.
+        #[inline]
+        pub fn acosf(n: f32) -> f32 {
+            f64::acos(n as f64) as f32
+        }
 
-// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
-// which promote everything to f64, perform the calculation, and then demote
-// back to f32. While not precisely correct should be "correct enough" for now.
-cfg_if::cfg_if! {
-if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
-    #[inline]
-    pub fn acosf(n: f32) -> f32 {
-        f64::acos(n as f64) as f32
-    }
+        #[inline]
+        pub fn asinf(n: f32) -> f32 {
+            f64::asin(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn asinf(n: f32) -> f32 {
-        f64::asin(n as f64) as f32
-    }
+        #[inline]
+        pub fn atan2f(n: f32, b: f32) -> f32 {
+            f64::atan2(n as f64, b as f64) as f32
+        }
 
-    #[inline]
-    pub fn atan2f(n: f32, b: f32) -> f32 {
-        f64::atan2(n as f64, b as f64) as f32
-    }
+        #[inline]
+        pub fn atanf(n: f32) -> f32 {
+            f64::atan(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn atanf(n: f32) -> f32 {
-        f64::atan(n as f64) as f32
-    }
+        #[inline]
+        pub fn coshf(n: f32) -> f32 {
+            f64::cosh(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn coshf(n: f32) -> f32 {
-        f64::cosh(n as f64) as f32
-    }
+        #[inline]
+        pub fn sinhf(n: f32) -> f32 {
+            f64::sinh(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn sinhf(n: f32) -> f32 {
-        f64::sinh(n as f64) as f32
-    }
+        #[inline]
+        pub fn tanf(n: f32) -> f32 {
+            f64::tan(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn tanf(n: f32) -> f32 {
-        f64::tan(n as f64) as f32
+        #[inline]
+        pub fn tanhf(n: f32) -> f32 {
+            f64::tanh(n as f64) as f32
+        }
     }
-
-    #[inline]
-    pub fn tanhf(n: f32) -> f32 {
-        f64::tanh(n as f64) as f32
+    _ => {
+        unsafe extern "C" {
+            pub safe fn acosf(n: f32) -> f32;
+            pub safe fn asinf(n: f32) -> f32;
+            pub safe fn atan2f(a: f32, b: f32) -> f32;
+            pub safe fn atanf(n: f32) -> f32;
+            pub safe fn coshf(n: f32) -> f32;
+            pub safe fn sinhf(n: f32) -> f32;
+            pub safe fn tanf(n: f32) -> f32;
+            pub safe fn tanhf(n: f32) -> f32;
+        }
     }
-}}
+}
+
+// On AIX, we don't have lgammaf_r only the f64 version, so we can
+// use the f64 version lgamma_r
+#[cfg(target_os = "aix")]
+pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
+    lgamma_r(n.into(), s) as f32
+}
diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs
index d81ff875c83..f211a9fc86b 100644
--- a/library/std/src/sys/env/mod.rs
+++ b/library/std/src/sys/env/mod.rs
@@ -13,35 +13,44 @@
 ))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_family = "windows")] {
+    }
+    target_family = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs
index 3719f9db51e..1327cbc3263 100644
--- a/library/std/src/sys/env/wasi.rs
+++ b/library/std/src/sys/env/wasi.rs
@@ -7,8 +7,8 @@ use crate::os::wasi::prelude::*;
 use crate::sys::common::small_c_string::run_with_cstr;
 use crate::sys::pal::os::{cvt, libc};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
+cfg_select! {
+    target_feature = "atomics" => {
         // Access to the environment must be protected by a lock in multi-threaded scenarios.
         use crate::sync::{PoisonError, RwLock};
         static ENV_LOCK: RwLock<()> = RwLock::new(());
@@ -18,7 +18,8 @@ cfg_if::cfg_if! {
         pub fn env_write_lock() -> impl Drop {
             ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner)
         }
-    } else {
+    }
+    _ => {
         // No need for a lock if we are single-threaded.
         pub fn env_read_lock() -> impl Drop {
             Box::new(())
diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs
index 9683fd47cf9..573f540483b 100644
--- a/library/std/src/sys/env_consts.rs
+++ b/library/std/src/sys/env_consts.rs
@@ -2,7 +2,7 @@
 
 // Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates.
 // This ensures that they must be mutually exclusive and do not have precedence
-// like cfg_if!.
+// like cfg_select!.
 macro cfg_unordered(
     $(#[cfg($cfg:meta)] $os:item)*
     #[else] $fallback:item
@@ -323,6 +323,17 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "efi";
 }
 
+#[cfg(target_os = "vexos")]
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "vexos";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = ".bin";
+    pub const EXE_EXTENSION: &str = "bin";
+}
+
 #[cfg(target_os = "visionos")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs
index bd70d178244..00b91842e9d 100644
--- a/library/std/src/sys/exit_guard.rs
+++ b/library/std/src/sys/exit_guard.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "linux")] {
+cfg_select! {
+    target_os = "linux" => {
         /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
         ///
         /// On glibc, `libc::exit` has been observed to not always be thread-safe.
@@ -56,7 +56,8 @@ cfg_if::cfg_if! {
                 }
             }
         }
-    } else {
+    }
+    _ => {
         /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
         ///
         /// Mitigation is ***NOT*** implemented on this platform, either because this platform
diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs
index e0f5eab6951..7cb9dd1cba9 100644
--- a/library/std/src/sys/fd/mod.rs
+++ b/library/std/src/sys/fd/mod.rs
@@ -2,18 +2,22 @@
 
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
     }
+    _ => {}
 }
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index cdca73cdca1..2b2dfe48e89 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -18,6 +18,21 @@ use libc::off_t as off64_t;
 ))]
 use libc::off64_t;
 
+cfg_select! {
+    any(
+        all(target_os = "linux", not(target_env = "musl")),
+        target_os = "android",
+        target_os = "hurd",
+    ) => {
+        // Prefer explicit pread64 for 64-bit offset independently of libc
+        // #[cfg(gnu_file_offset_bits64)].
+        use libc::pread64;
+    }
+    _ => {
+        use libc::pread as pread64;
+    }
+}
+
 use crate::cmp;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
@@ -37,10 +52,10 @@ pub struct FileDesc(OwnedFd);
 //
 // On Apple targets however, apparently the 64-bit libc is either buggy or
 // intentionally showing odd behavior by rejecting any read with a size
-// larger than or equal to INT_MAX. To handle both of these the read
-// size is capped on both platforms.
+// larger than INT_MAX. To handle both of these the read size is capped on
+// both platforms.
 const READ_LIMIT: usize = if cfg!(target_vendor = "apple") {
-    libc::c_int::MAX as usize - 1
+    libc::c_int::MAX as usize
 } else {
     libc::ssize_t::MAX as usize
 };
@@ -146,42 +161,47 @@ impl FileDesc {
         (&mut me).read_to_end(buf)
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        #[cfg(not(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        )))]
-        use libc::pread as pread64;
-        #[cfg(any(
-            all(target_os = "linux", not(target_env = "musl")),
-            target_os = "android",
-            target_os = "hurd"
-        ))]
-        use libc::pread64;
-
-        unsafe {
-            cvt(pread64(
+        cvt(unsafe {
+            pread64(
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut libc::c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as off64_t,
-            ))
-            .map(|n| n as usize)
-        }
+                offset as off64_t, // EINVAL if offset + count overflows
+            )
+        })
+        .map(|n| n as usize)
     }
 
     pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
         let ret = cvt(unsafe {
             libc::read(
                 self.as_raw_fd(),
-                cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
+                cmp::min(cursor.capacity(), READ_LIMIT),
+            )
+        })?;
+
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let ret = cvt(unsafe {
+            pread64(
+                self.as_raw_fd(),
+                cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
                 cmp::min(cursor.capacity(), READ_LIMIT),
+                offset as off64_t, // EINVAL if offset + count overflows
             )
         })?;
 
-        // Safety: `ret` bytes were written to the initialized portion of the buffer
+        // SAFETY: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
             cursor.advance_unchecked(ret as usize);
         }
@@ -369,7 +389,6 @@ impl FileDesc {
         )))
     }
 
-    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         #[cfg(not(any(
             all(target_os = "linux", not(target_env = "musl")),
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index d55e28074fe..64f5a6b36d3 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -5,8 +5,8 @@ use crate::path::{Path, PathBuf};
 
 pub mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         use unix as imp;
         pub use unix::{chown, fchown, lchown, mkfifo};
@@ -16,24 +16,34 @@ cfg_if::cfg_if! {
         #[cfg(any(target_os = "linux", target_os = "android"))]
         pub(crate) use unix::CachedFileMetadata;
         use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         use windows as imp;
         pub use windows::{symlink_inner, junction_point};
         use crate::sys::path::with_native_path;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         use hermit as imp;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         use solid as imp;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         use uefi as imp;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "vexos" => {
+        mod vexos;
+        use vexos as imp;
+    }
+    target_os = "wasi" => {
         mod wasi;
         use wasi as imp;
-    } else {
+    }
+    _ => {
         mod unsupported;
         use unsupported as imp;
     }
@@ -108,6 +118,30 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
     with_native_path(path, &|path| imp::set_perm(path, perm.clone()))
 }
 
+#[cfg(unix)]
+pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> {
+    use crate::fs::OpenOptions;
+
+    let mut options = OpenOptions::new();
+
+    // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it.
+    // Their filesystems do not have symbolic links, so no special handling is required.
+    #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
+    {
+        use crate::os::unix::fs::OpenOptionsExt;
+        options.custom_flags(libc::O_NOFOLLOW);
+    }
+
+    options.open(path)?.set_permissions(perm)
+}
+
+#[cfg(not(unix))]
+pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> {
+    crate::unimplemented!(
+        "`set_permissions_nofollow` is currently only implemented on Unix platforms"
+    )
+}
+
 pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
     with_native_path(path, &imp::canonicalize)
 }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index b310db2dac4..33a1e7ff5e4 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -21,29 +21,31 @@ use libc::fstatat as fstatat64;
 #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
 use libc::fstatat64;
 #[cfg(any(
+    target_os = "aix",
     target_os = "android",
-    target_os = "solaris",
+    target_os = "freebsd",
     target_os = "fuchsia",
-    target_os = "redox",
     target_os = "illumos",
-    target_os = "aix",
     target_os = "nto",
+    target_os = "redox",
+    target_os = "solaris",
     target_os = "vita",
     all(target_os = "linux", target_env = "musl"),
 ))]
 use libc::readdir as readdir64;
 #[cfg(not(any(
+    target_os = "aix",
     target_os = "android",
-    target_os = "linux",
-    target_os = "solaris",
+    target_os = "freebsd",
+    target_os = "fuchsia",
+    target_os = "hurd",
     target_os = "illumos",
     target_os = "l4re",
-    target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "aix",
+    target_os = "linux",
     target_os = "nto",
+    target_os = "redox",
+    target_os = "solaris",
     target_os = "vita",
-    target_os = "hurd",
 )))]
 use libc::readdir_r as readdir64_r;
 #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
@@ -101,10 +103,11 @@ pub struct File(FileDesc);
 // https://github.com/rust-lang/rust/pull/67774
 macro_rules! cfg_has_statx {
     ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
-        cfg_if::cfg_if! {
-            if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
+        cfg_select! {
+            all(target_os = "linux", target_env = "gnu") => {
                 $($then_tt)*
-            } else {
+            }
+            _ => {
                 $($else_tt)*
             }
         }
@@ -270,16 +273,17 @@ unsafe impl Send for Dir {}
 unsafe impl Sync for Dir {}
 
 #[cfg(any(
+    target_os = "aix",
     target_os = "android",
-    target_os = "linux",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "freebsd",
     target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "aix",
+    target_os = "hurd",
+    target_os = "illumos",
+    target_os = "linux",
     target_os = "nto",
+    target_os = "redox",
+    target_os = "solaris",
     target_os = "vita",
-    target_os = "hurd",
 ))]
 pub struct DirEntry {
     dir: Arc<InnerReadDir>,
@@ -294,16 +298,17 @@ pub struct DirEntry {
 // we're not using the immediate `d_name` on these targets. Keeping this as an
 // `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere.
 #[cfg(any(
+    target_os = "aix",
     target_os = "android",
-    target_os = "linux",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "freebsd",
     target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "aix",
+    target_os = "hurd",
+    target_os = "illumos",
+    target_os = "linux",
     target_os = "nto",
+    target_os = "redox",
+    target_os = "solaris",
     target_os = "vita",
-    target_os = "hurd",
 ))]
 struct dirent64_min {
     d_ino: u64,
@@ -318,16 +323,17 @@ struct dirent64_min {
 }
 
 #[cfg(not(any(
+    target_os = "aix",
     target_os = "android",
-    target_os = "linux",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "freebsd",
     target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "aix",
+    target_os = "hurd",
+    target_os = "illumos",
+    target_os = "linux",
     target_os = "nto",
+    target_os = "redox",
+    target_os = "solaris",
     target_os = "vita",
-    target_os = "hurd",
 )))]
 pub struct DirEntry {
     dir: Arc<InnerReadDir>,
@@ -697,16 +703,17 @@ impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
     #[cfg(any(
+        target_os = "aix",
         target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
+        target_os = "freebsd",
         target_os = "fuchsia",
-        target_os = "redox",
+        target_os = "hurd",
         target_os = "illumos",
-        target_os = "aix",
+        target_os = "linux",
         target_os = "nto",
+        target_os = "redox",
+        target_os = "solaris",
         target_os = "vita",
-        target_os = "hurd",
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         use crate::sys::os::{errno, set_errno};
@@ -767,6 +774,9 @@ impl Iterator for ReadDir {
                 // only access those bytes.
                 #[cfg(not(target_os = "vita"))]
                 let entry = dirent64_min {
+                    #[cfg(target_os = "freebsd")]
+                    d_ino: (*entry_ptr).d_fileno,
+                    #[cfg(not(target_os = "freebsd"))]
                     d_ino: (*entry_ptr).d_ino as u64,
                     #[cfg(not(any(
                         target_os = "solaris",
@@ -790,16 +800,17 @@ impl Iterator for ReadDir {
     }
 
     #[cfg(not(any(
+        target_os = "aix",
         target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
+        target_os = "freebsd",
         target_os = "fuchsia",
-        target_os = "redox",
+        target_os = "hurd",
         target_os = "illumos",
-        target_os = "aix",
+        target_os = "linux",
         target_os = "nto",
+        target_os = "redox",
+        target_os = "solaris",
         target_os = "vita",
-        target_os = "hurd",
     )))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         if self.end_of_stream {
@@ -969,36 +980,32 @@ impl DirEntry {
     }
 
     #[cfg(any(
-        target_os = "linux",
+        target_os = "aix",
+        target_os = "android",
         target_os = "cygwin",
         target_os = "emscripten",
-        target_os = "android",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "haiku",
-        target_os = "l4re",
-        target_os = "fuchsia",
-        target_os = "redox",
-        target_os = "vxworks",
         target_os = "espidf",
+        target_os = "freebsd",
+        target_os = "fuchsia",
+        target_os = "haiku",
         target_os = "horizon",
-        target_os = "vita",
-        target_os = "aix",
-        target_os = "nto",
         target_os = "hurd",
+        target_os = "illumos",
+        target_os = "l4re",
+        target_os = "linux",
+        target_os = "nto",
+        target_os = "redox",
         target_os = "rtems",
+        target_os = "solaris",
+        target_os = "vita",
+        target_os = "vxworks",
         target_vendor = "apple",
     ))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
     }
 
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "openbsd",
-        target_os = "netbsd",
-        target_os = "dragonfly"
-    ))]
+    #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly"))]
     pub fn ino(&self) -> u64 {
         self.entry.d_fileno as u64
     }
@@ -1013,7 +1020,6 @@ impl DirEntry {
     #[cfg(any(
         target_os = "netbsd",
         target_os = "openbsd",
-        target_os = "freebsd",
         target_os = "dragonfly",
         target_vendor = "apple",
     ))]
@@ -1029,7 +1035,6 @@ impl DirEntry {
     #[cfg(not(any(
         target_os = "netbsd",
         target_os = "openbsd",
-        target_os = "freebsd",
         target_os = "dragonfly",
         target_vendor = "apple",
     )))]
@@ -1039,6 +1044,7 @@ impl DirEntry {
 
     #[cfg(not(any(
         target_os = "android",
+        target_os = "freebsd",
         target_os = "linux",
         target_os = "solaris",
         target_os = "illumos",
@@ -1054,6 +1060,7 @@ impl DirEntry {
     }
     #[cfg(any(
         target_os = "android",
+        target_os = "freebsd",
         target_os = "linux",
         target_os = "solaris",
         target_os = "illumos",
@@ -1122,7 +1129,21 @@ impl OpenOptions {
             (true, true, false) => Ok(libc::O_RDWR),
             (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
             (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
-            (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
+            (false, false, false) => {
+                // If no access mode is set, check if any creation flags are set
+                // to provide a more descriptive error message
+                if self.create || self.create_new || self.truncate {
+                    Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ))
+                } else {
+                    Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "must specify at least one of read, write, or append access",
+                    ))
+                }
+            }
         }
     }
 
@@ -1131,12 +1152,18 @@ impl OpenOptions {
             (true, false) => {}
             (false, false) => {
                 if self.truncate || self.create || self.create_new {
-                    return Err(Error::from_raw_os_error(libc::EINVAL));
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ));
                 }
             }
             (_, true) => {
                 if self.truncate && !self.create_new {
-                    return Err(Error::from_raw_os_error(libc::EINVAL));
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ));
                 }
             }
         }
@@ -1263,6 +1290,8 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
         target_vendor = "apple",
     ))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1270,11 +1299,23 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn lock(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_WRLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1286,6 +1327,8 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
         target_vendor = "apple",
     ))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1293,11 +1336,23 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn lock_shared(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_RDLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1309,6 +1364,8 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
         target_vendor = "apple",
     ))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1324,11 +1381,31 @@ impl File {
         }
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn try_lock(&self) -> Result<(), TryLockError> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_WRLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
+        if let Err(err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                Err(TryLockError::WouldBlock)
+            } else {
+                Err(TryLockError::Error(err))
+            }
+        } else {
+            Ok(())
+        }
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1343,6 +1420,8 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
         target_vendor = "apple",
     ))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1358,11 +1437,31 @@ impl File {
         }
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_RDLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
+        if let Err(err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                Err(TryLockError::WouldBlock)
+            } else {
+                Err(TryLockError::Error(err))
+            }
+        } else {
+            Ok(())
+        }
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1377,6 +1476,8 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
         target_vendor = "apple",
     ))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1384,11 +1485,23 @@ impl File {
         return Ok(());
     }
 
+    #[cfg(target_os = "solaris")]
+    pub fn unlock(&self) -> io::Result<()> {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_UNLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
+        Ok(())
+    }
+
     #[cfg(not(any(
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "cygwin",
+        target_os = "solaris",
         target_vendor = "apple",
     )))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1422,6 +1535,10 @@ impl File {
         self.0.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.0.read_buf_at(cursor, offset)
+    }
+
     pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.0.read_vectored_at(bufs, offset)
     }
@@ -1505,8 +1622,8 @@ impl File {
             )),
             None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
         };
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx"))] {
+        cfg_select! {
+            any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => {
                 // Redox doesn't appear to support `UTIME_OMIT`.
                 // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
                 // the same as for Redox.
@@ -1515,7 +1632,8 @@ impl File {
                     io::ErrorKind::Unsupported,
                     "setting file times not supported",
                 ))
-            } else if #[cfg(target_vendor = "apple")] {
+            }
+            target_vendor = "apple" => {
                 let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3];
                 let mut num_times = 0;
                 let mut attrlist: libc::attrlist = unsafe { mem::zeroed() };
@@ -1543,7 +1661,8 @@ impl File {
                     0
                 ) })?;
                 Ok(())
-            } else if #[cfg(target_os = "android")] {
+            }
+            target_os = "android" => {
                 let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
                 // futimens requires Android API level 19
                 cvt(unsafe {
@@ -1559,7 +1678,8 @@ impl File {
                     }
                 })?;
                 Ok(())
-            } else {
+            }
+            _ => {
                 #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
                 {
                     use crate::sys::{time::__timespec64, weak::weak};
@@ -1677,13 +1797,14 @@ impl fmt::Debug for File {
             let mut buf = vec![0; libc::PATH_MAX as usize];
             let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
             if n == -1 {
-                cfg_if::cfg_if! {
-                    if #[cfg(target_os = "netbsd")] {
+                cfg_select! {
+                    target_os = "netbsd" => {
                         // fallback to procfs as last resort
                         let mut p = PathBuf::from("/proc/self/fd");
                         p.push(&fd.to_string());
                         return run_path_with_cstr(&p, &readlink).ok()
-                    } else {
+                    }
+                    _ => {
                         return None;
                     }
                 }
@@ -1884,15 +2005,16 @@ pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> {
 }
 
 pub fn link(original: &CStr, link: &CStr) -> io::Result<()> {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] {
+    cfg_select! {
+        any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70") => {
             // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
             // it implementation-defined whether `link` follows symlinks, so rely on the
             // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
             // Android has `linkat` on newer versions, but we happen to know `link`
             // always has the correct behavior, so it's here as well.
             cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?;
-        } else {
+        }
+        _ => {
             // Where we can, use `linkat` instead of `link`; see the comment above
             // this one for details on why.
             cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?;
diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs
new file mode 100644
index 00000000000..f642e7cb074
--- /dev/null
+++ b/library/std/src/sys/fs/vexos.rs
@@ -0,0 +1,615 @@
+use crate::ffi::{OsString, c_char};
+use crate::fmt;
+use crate::fs::TryLockError;
+use crate::hash::Hash;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::common::small_c_string::run_path_with_cstr;
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, unsupported_err};
+
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_fs;
+pub use unsupported_fs::{
+    DirBuilder, FileTimes, canonicalize, link, readlink, remove_dir_all, rename, rmdir, symlink,
+    unlink,
+};
+
+/// VEXos file descriptor.
+///
+/// This stores an opaque pointer to a [FatFs file object structure] managed by VEXos
+/// representing an open file on disk.
+///
+/// [FatFs file object structure]: https://github.com/Xilinx/embeddedsw/blob/master/lib/sw_services/xilffs/src/include/ff.h?rgh-link-date=2025-09-23T20%3A03%3A43Z#L215
+///
+/// # Safety
+///
+/// Since this platform uses a pointer to to an internal filesystem structure with a lifetime
+/// associated with it (rather than a UNIX-style file descriptor table), care must be taken to
+/// ensure that the pointer held by `FileDesc` is valid for as long as it exists.
+#[derive(Debug)]
+struct FileDesc(*mut vex_sdk::FIL);
+
+// SAFETY: VEXos's FDs can be used on a thread other than the one they were created on.
+unsafe impl Send for FileDesc {}
+// SAFETY: We assume an environment without threads (i.e. no RTOS).
+// (If there were threads, it is possible that a mutex would be required.)
+unsafe impl Sync for FileDesc {}
+
+pub struct File {
+    fd: FileDesc,
+}
+
+#[derive(Clone)]
+pub enum FileAttr {
+    Dir,
+    File { size: u64 },
+}
+
+pub struct ReadDir(!);
+
+pub struct DirEntry {
+    path: PathBuf,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions {}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct FileType {
+    is_dir: bool,
+}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self {
+            Self::File { size } => *size,
+            Self::Dir => 0,
+        }
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType { is_dir: matches!(self, FileAttr::Dir) }
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        false
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        panic!("Perimissions do not exist")
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        self.is_dir
+    }
+
+    pub fn is_file(&self) -> bool {
+        !self.is_dir
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        // No symlinks in VEXos - entries are either files or directories.
+        false
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        self.0
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        self.path.clone()
+    }
+
+    pub fn file_name(&self) -> OsString {
+        self.path.file_name().unwrap_or_default().into()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        stat(&self.path)
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        Ok(self.metadata()?.file_type())
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+        }
+    }
+
+    pub fn read(&mut self, read: bool) {
+        self.read = read;
+    }
+    pub fn write(&mut self, write: bool) {
+        self.write = write;
+    }
+    pub fn append(&mut self, append: bool) {
+        self.append = append;
+    }
+    pub fn truncate(&mut self, truncate: bool) {
+        self.truncate = truncate;
+    }
+    pub fn create(&mut self, create: bool) {
+        self.create = create;
+    }
+    pub fn create_new(&mut self, create_new: bool) {
+        self.create_new = create_new;
+    }
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        run_path_with_cstr(path, &|path| {
+            // Enforce the invariants of `create_new`/`create`.
+            //
+            // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce
+            // the requirements that `create_new` can't have an existing file and `!create`
+            // doesn't create a file ourselves.
+            if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) {
+                let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) };
+
+                if opts.create_new && status != 0 {
+                    return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",));
+                } else if !opts.create && status == 0 {
+                    return Err(io::const_error!(
+                        io::ErrorKind::NotFound,
+                        "no such file or directory",
+                    ));
+                }
+            }
+
+            let file = match opts {
+                // read + write - unsupported
+                OpenOptions { read: true, write: true, .. } => {
+                    return Err(io::const_error!(
+                        io::ErrorKind::InvalidInput,
+                        "opening files with read and write access is unsupported on this target",
+                    ));
+                }
+
+                // read
+                OpenOptions {
+                    read: true,
+                    write: false,
+                    append: _,
+                    truncate: false,
+                    create: false,
+                    create_new: false,
+                } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) },
+
+                // append
+                OpenOptions {
+                    read: false,
+                    write: _,
+                    append: true,
+                    truncate: false,
+                    create: _,
+                    create_new: _,
+                } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) },
+
+                // write
+                OpenOptions {
+                    read: false,
+                    write: true,
+                    append: false,
+                    truncate,
+                    create: _,
+                    create_new: _,
+                } => unsafe {
+                    if *truncate {
+                        vex_sdk::vexFileOpenCreate(path.as_ptr())
+                    } else {
+                        // Open in append, but jump to the start of the file.
+                        let fd = vex_sdk::vexFileOpenWrite(path.as_ptr());
+                        vex_sdk::vexFileSeek(fd, 0, 0);
+                        fd
+                    }
+                },
+
+                _ => {
+                    return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument"));
+                }
+            };
+
+            if file.is_null() {
+                Err(io::const_error!(io::ErrorKind::NotFound, "could not open file"))
+            } else {
+                Ok(Self { fd: FileDesc(file) })
+            }
+        })
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        // `vexFileSize` returns -1 upon error, so u64::try_from will fail on error.
+        if let Ok(size) = u64::try_from(unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileSize(self.fd.0)
+        }) {
+            Ok(FileAttr::File { size })
+        } else {
+            Err(io::const_error!(io::ErrorKind::InvalidData, "failed to get file size"))
+        }
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> Result<(), TryLockError> {
+        Err(TryLockError::Error(unsupported_err()))
+    }
+
+    pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
+        Err(TryLockError::Error(unsupported_err()))
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let len = buf.len() as u32;
+        let buf_ptr = buf.as_mut_ptr();
+        let read = unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileRead(buf_ptr.cast::<c_char>(), 1, len, self.fd.0)
+        };
+
+        if read < 0 {
+            Err(io::const_error!(io::ErrorKind::Other, "could not read from file"))
+        } else {
+            Ok(read as usize)
+        }
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|b| self.read(b), cursor)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = buf.len() as u32;
+        let buf_ptr = buf.as_ptr();
+        let written = unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast::<c_char>(), 1, len, self.fd.0)
+        };
+
+        if written < 0 {
+            Err(io::const_error!(io::ErrorKind::Other, "could not write to file"))
+        } else {
+            Ok(written as usize)
+        }
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileSync(self.fd.0);
+        }
+        Ok(())
+    }
+
+    pub fn tell(&self) -> io::Result<u64> {
+        // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+        let position = unsafe { vex_sdk::vexFileTell(self.fd.0) };
+
+        position.try_into().map_err(|_| {
+            io::const_error!(io::ErrorKind::InvalidData, "failed to get current location in file")
+        })
+    }
+
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        const SEEK_SET: i32 = 0;
+        const SEEK_CUR: i32 = 1;
+        const SEEK_END: i32 = 2;
+
+        fn try_convert_offset<T: TryInto<u32>>(offset: T) -> io::Result<u32> {
+            offset.try_into().map_err(|_| {
+                io::const_error!(
+                    io::ErrorKind::InvalidInput,
+                    "cannot seek to an offset too large to fit in a 32 bit integer",
+                )
+            })
+        }
+
+        // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+        match pos {
+            SeekFrom::Start(offset) => unsafe {
+                map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))?
+            },
+            SeekFrom::End(offset) => unsafe {
+                if offset >= 0 {
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset(offset)?,
+                        SEEK_END,
+                    ))?
+                } else {
+                    // `vexFileSeek` does not support seeking with negative offset, meaning
+                    // we have to calculate the offset from the end of the file ourselves.
+
+                    // Seek to the end of the file to get the end position in the open buffer.
+                    map_fresult(vex_sdk::vexFileSeek(self.fd.0, 0, SEEK_END))?;
+                    let end_position = self.tell()?;
+
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        // NOTE: Files internally use a 32-bit representation for stream
+                        // position, so `end_position as i64` should never overflow.
+                        try_convert_offset(end_position as i64 + offset)?,
+                        SEEK_SET,
+                    ))?
+                }
+            },
+            SeekFrom::Current(offset) => unsafe {
+                if offset >= 0 {
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset(offset)?,
+                        SEEK_CUR,
+                    ))?
+                } else {
+                    // `vexFileSeek` does not support seeking with negative offset, meaning
+                    // we have to calculate the offset from the stream position ourselves.
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset((self.tell()? as i64) + offset)?,
+                        SEEK_SET,
+                    ))?
+                }
+            },
+        }
+
+        Ok(self.tell()?)
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("File").field("fd", &self.fd.0).finish()
+    }
+}
+impl Drop for File {
+    fn drop(&mut self) {
+        unsafe { vex_sdk::vexFileClose(self.fd.0) };
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    // While there *is* a userspace function for reading file directories,
+    // the necessary implementation cannot currently be done cleanly, as
+    // VEXos does not expose directory length to user programs.
+    //
+    // This means that we would need to create a large fixed-length buffer
+    // and hope that the folder's contents didn't exceed that buffer's length,
+    // which obviously isn't behavior we want to rely on in the standard library.
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn exists(path: &Path) -> io::Result<bool> {
+    run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0))
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+    // `vexFileStatus` returns 3 if the given path is a directory, 1 if the path is a
+    // file, or 0 if no such path exists.
+    const FILE_STATUS_DIR: u32 = 3;
+
+    run_path_with_cstr(p, &|c_path| {
+        let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) };
+
+        // We can't get the size if its a directory because we cant open it as a file
+        if file_type == FILE_STATUS_DIR {
+            Ok(FileAttr::Dir)
+        } else {
+            let mut opts = OpenOptions::new();
+            opts.read(true);
+            let file = File::open(p, &opts)?;
+            file.file_attr()
+        }
+    })
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    // Symlinks aren't supported in this filesystem
+    stat(p)
+}
+
+// Cannot use `copy` from `common` here, since `File::set_permissions` is unsupported on this target.
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use crate::fs::File;
+
+    // NOTE: If `from` is a directory, this call should fail due to vexFileOpen* returning null.
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+
+    io::copy(&mut reader, &mut writer)
+}
+
+fn map_fresult(fresult: vex_sdk::FRESULT) -> io::Result<()> {
+    // VEX uses a derivative of FatFs (Xilinx's xilffs library) for filesystem operations.
+    match fresult {
+        vex_sdk::FRESULT::FR_OK => Ok(()),
+        vex_sdk::FRESULT::FR_DISK_ERR => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "internal function reported an unrecoverable hard error",
+        )),
+        vex_sdk::FRESULT::FR_INT_ERR => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "internal error in filesystem runtime",
+        )),
+        vex_sdk::FRESULT::FR_NOT_READY => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "the storage device could not be prepared to work",
+        )),
+        vex_sdk::FRESULT::FR_NO_FILE => Err(io::const_error!(
+            io::ErrorKind::NotFound,
+            "could not find the file in the directory"
+        )),
+        vex_sdk::FRESULT::FR_NO_PATH => Err(io::const_error!(
+            io::ErrorKind::NotFound,
+            "a directory in the path name could not be found",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_NAME => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "the given string is invalid as a path name",
+        )),
+        vex_sdk::FRESULT::FR_DENIED => Err(io::const_error!(
+            io::ErrorKind::PermissionDenied,
+            "the required access for this operation was denied",
+        )),
+        vex_sdk::FRESULT::FR_EXIST => Err(io::const_error!(
+            io::ErrorKind::AlreadyExists,
+            "an object with the same name already exists in the directory",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_OBJECT => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "invalid or null file/directory object",
+        )),
+        vex_sdk::FRESULT::FR_WRITE_PROTECTED => Err(io::const_error!(
+            io::ErrorKind::PermissionDenied,
+            "a write operation was performed on write-protected media",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_DRIVE => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "an invalid drive number was specified in the path name",
+        )),
+        vex_sdk::FRESULT::FR_NOT_ENABLED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "work area for the logical drive has not been registered",
+        )),
+        vex_sdk::FRESULT::FR_NO_FILESYSTEM => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "valid FAT volume could not be found on the drive",
+        )),
+        vex_sdk::FRESULT::FR_MKFS_ABORTED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "failed to create filesystem volume"
+        )),
+        vex_sdk::FRESULT::FR_TIMEOUT => Err(io::const_error!(
+            io::ErrorKind::TimedOut,
+            "the function was canceled due to a timeout of thread-safe control",
+        )),
+        vex_sdk::FRESULT::FR_LOCKED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "the operation to the object was rejected by file sharing control",
+        )),
+        vex_sdk::FRESULT::FR_NOT_ENOUGH_CORE => {
+            Err(io::const_error!(io::ErrorKind::OutOfMemory, "not enough memory for the operation"))
+        }
+        vex_sdk::FRESULT::FR_TOO_MANY_OPEN_FILES => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "maximum number of open files has been reached",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_PARAMETER => {
+            Err(io::const_error!(io::ErrorKind::InvalidInput, "a given parameter was invalid"))
+        }
+        _ => unreachable!(), // C-style enum
+    }
+}
diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs
index b65d86de12a..0b65b9cb389 100644
--- a/library/std/src/sys/fs/wasi.rs
+++ b/library/std/src/sys/fs/wasi.rs
@@ -848,7 +848,14 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
 
     // Iterate over all the entries in this directory, and travel recursively if
     // necessary
-    for entry in ReadDir::new(fd, dummy_root) {
+    //
+    // Note that all directory entries for this directory are read first before
+    // any removal is done. This works around the fact that the WASIp1 API for
+    // reading directories is not well-designed for handling mutations between
+    // invocations of reading a directory. By reading all the entries at once
+    // this ensures that, at least without concurrent modifications, it should
+    // be possible to delete everything.
+    for entry in ReadDir::new(fd, dummy_root).collect::<Vec<_>>() {
         let entry = entry?;
         let path = crate::str::from_utf8(&entry.name).map_err(|_| {
             io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index 09feddd0be9..ccfe410627f 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -258,7 +258,19 @@ impl OpenOptions {
                 Ok(c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA))
             }
             (false, false, false, None) => {
-                Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32))
+                // If no access mode is set, check if any creation flags are set
+                // to provide a more descriptive error message
+                if self.create || self.create_new || self.truncate {
+                    Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ))
+                } else {
+                    Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "must specify at least one of read, write, or append access",
+                    ))
+                }
             }
         }
     }
@@ -268,12 +280,18 @@ impl OpenOptions {
             (true, false) => {}
             (false, false) => {
                 if self.truncate || self.create || self.create_new {
-                    return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32));
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ));
                 }
             }
             (_, true) => {
                 if self.truncate && !self.create_new {
-                    return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32));
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "creating or truncating a file requires write or append access",
+                    ));
                 }
             }
         }
@@ -587,6 +605,10 @@ impl File {
         self.handle.read_buf(cursor)
     }
 
+    pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        self.handle.read_buf_at(cursor, offset)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
@@ -1606,7 +1628,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
     };
     unsafe {
         let ptr = header.PathBuffer.as_mut_ptr();
-        ptr.copy_from(abs_path.as_ptr().cast::<MaybeUninit<u16>>(), abs_path.len());
+        ptr.copy_from(abs_path.as_ptr().cast_uninit(), abs_path.len());
 
         let mut ret = 0;
         cvt(c::DeviceIoControl(
diff --git a/library/std/src/sys/io/io_slice/uefi.rs b/library/std/src/sys/io/io_slice/uefi.rs
new file mode 100644
index 00000000000..909cfbea0b7
--- /dev/null
+++ b/library/std/src/sys/io/io_slice/uefi.rs
@@ -0,0 +1,74 @@
+//! A buffer type used with `Write::write_vectored` for UEFI Networking APIs. Vectored writing to
+//! File is not supported as of UEFI Spec 2.11.
+
+use crate::marker::PhantomData;
+use crate::slice;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct IoSlice<'a> {
+    len: u32,
+    data: *const u8,
+    _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        let len = buf.len().try_into().unwrap();
+        Self { len, data: buf.as_ptr(), _p: PhantomData }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.len = u32::try_from(n)
+            .ok()
+            .and_then(|n| self.len.checked_sub(n))
+            .expect("advancing IoSlice beyond its length");
+        unsafe { self.data = self.data.add(n) };
+    }
+
+    #[inline]
+    pub const fn as_slice(&self) -> &'a [u8] {
+        unsafe { slice::from_raw_parts(self.data, self.len as usize) }
+    }
+}
+
+#[repr(C)]
+pub struct IoSliceMut<'a> {
+    len: u32,
+    data: *mut u8,
+    _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        let len = buf.len().try_into().unwrap();
+        Self { len, data: buf.as_mut_ptr(), _p: PhantomData }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.len = u32::try_from(n)
+            .ok()
+            .and_then(|n| self.len.checked_sub(n))
+            .expect("advancing IoSlice beyond its length");
+        unsafe { self.data = self.data.add(n) };
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.data, self.len as usize) }
+    }
+
+    #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
+    }
+}
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index 4d0365d42fd..fe8ec1dbb73 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -1,17 +1,24 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
 mod io_slice {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty"))] {
+    cfg_select! {
+        any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty") => {
             mod iovec;
             pub use iovec::*;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub use windows::*;
-        } else if #[cfg(target_os = "wasi")] {
+        }
+        target_os = "wasi" => {
             mod wasi;
             pub use wasi::*;
-        } else {
+        }
+        target_os = "uefi" => {
+            mod uefi;
+            pub use uefi::*;
+        }
+        _ => {
             mod unsupported;
             pub use unsupported::*;
         }
@@ -19,17 +26,20 @@ mod io_slice {
 }
 
 mod is_terminal {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_family = "unix", target_os = "wasi"))] {
+    cfg_select! {
+        any(target_family = "unix", target_os = "wasi") => {
             mod isatty;
             pub use isatty::*;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub use windows::*;
-        } else if #[cfg(target_os = "hermit")] {
+        }
+        target_os = "hermit" => {
             mod hermit;
             pub use hermit::*;
-        } else {
+        }
+        _ => {
             mod unsupported;
             pub use unsupported::*;
         }
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 8ec0a0e3302..2dbdc8a4e02 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -1,7 +1,7 @@
 #![allow(unsafe_op_in_unsafe_fn)]
 
 /// The configure builtins provides runtime support compiler-builtin features
-/// which require dynamic intialization to work as expected, e.g. aarch64
+/// which require dynamic initialization to work as expected, e.g. aarch64
 /// outline-atomics.
 mod configure_builtins;
 
@@ -26,10 +26,12 @@ pub mod io;
 pub mod net;
 pub mod os_str;
 pub mod path;
+pub mod platform_version;
 pub mod process;
 pub mod random;
 pub mod stdio;
 pub mod sync;
+pub mod thread;
 pub mod thread_local;
 
 // FIXME(117276): remove this, move feature implementations into individual
diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs
new file mode 100644
index 00000000000..7f9636a8ccf
--- /dev/null
+++ b/library/std/src/sys/net/connection/mod.rs
@@ -0,0 +1,57 @@
+cfg_select! {
+    any(
+        all(target_family = "unix", not(target_os = "l4re")),
+        target_os = "windows",
+        target_os = "hermit",
+        all(target_os = "wasi", target_env = "p2"),
+        target_os = "solid_asp3",
+    ) => {
+        mod socket;
+        pub use socket::*;
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
+        mod sgx;
+        pub use sgx::*;
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::*;
+    }
+    target_os = "xous" => {
+        mod xous;
+        pub use xous::*;
+    }
+    target_os = "uefi" => {
+        mod uefi;
+        pub use uefi::*;
+    }
+    _ => {
+        mod unsupported;
+        pub use unsupported::*;
+    }
+}
+
+#[cfg_attr(
+    // Make sure that this is used on some platforms at least.
+    not(any(target_os = "linux", target_os = "windows")),
+    allow(dead_code)
+)]
+fn each_addr<A: crate::net::ToSocketAddrs, F, T>(addr: A, mut f: F) -> crate::io::Result<T>
+where
+    F: FnMut(&crate::net::SocketAddr) -> crate::io::Result<T>,
+{
+    use crate::io::Error;
+
+    let mut last_err = None;
+    for addr in addr.to_socket_addrs()? {
+        match f(&addr) {
+            Ok(l) => return Ok(l),
+            Err(e) => last_err = Some(e),
+        }
+    }
+
+    match last_err {
+        Some(err) => Err(err),
+        None => Err(Error::NO_ADDRESSES),
+    }
+}
diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs
index 242df10bc32..8c9c17d3f17 100644
--- a/library/std/src/sys/net/connection/sgx.rs
+++ b/library/std/src/sys/net/connection/sgx.rs
@@ -1,3 +1,5 @@
+use crate::error;
+use crate::fmt::{self, Write};
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sync::Arc;
@@ -5,7 +7,6 @@ use crate::sys::abi::usercalls;
 use crate::sys::fd::FileDesc;
 use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported};
 use crate::time::Duration;
-use crate::{error, fmt};
 
 const DEFAULT_FAKE_TTL: u32 = 64;
 
@@ -63,18 +64,52 @@ impl fmt::Debug for TcpStream {
     }
 }
 
-fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
-    match result {
-        Ok(saddr) => Ok(saddr.to_string()),
-        // need to downcast twice because io::Error::into_inner doesn't return the original
-        // value if the conversion fails
-        Err(e) => {
-            if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
-                Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
-            } else {
-                Err(e)
+/// Converts each address in `addr` into a hostname.
+///
+/// SGX doesn't support DNS resolution but rather accepts hostnames in
+/// the same place as socket addresses. So, to make e.g.
+/// ```rust
+/// TcpStream::connect("example.com:80")`
+/// ```
+/// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead,
+/// which contains the hostname being looked up. When `.to_socket_addrs()`
+/// fails, we inspect the error and try recover the hostname from it. If that
+/// succeeds, we thus continue with the hostname.
+///
+/// This is a terrible hack and leads to buggy code. For instance, when users
+/// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs`
+/// implementation to select from a list of possible URLs, the only URL used
+/// will be that of the last item tried.
+// FIXME: This is a terrible, terrible hack. Fixing this requires Fortanix to
+// add a method for resolving addresses.
+fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
+where
+    F: FnMut(&str) -> io::Result<T>,
+{
+    match addr.to_socket_addrs() {
+        Ok(addrs) => {
+            let mut last_err = None;
+            let mut encoded = String::new();
+            for addr in addrs {
+                // Format the IP address as a string, reusing the buffer.
+                encoded.clear();
+                write!(encoded, "{}", &addr).unwrap();
+
+                match f(&encoded) {
+                    Ok(val) => return Ok(val),
+                    Err(err) => last_err = Some(err),
+                }
+            }
+
+            match last_err {
+                Some(err) => Err(err),
+                None => Err(io::Error::NO_ADDRESSES),
             }
         }
+        Err(err) => match err.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()) {
+            Some(NonIpSockAddr { host }) => f(host),
+            None => Err(err),
+        },
     }
 }
 
@@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
 }
 
 impl TcpStream {
-    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        let addr = io_err_to_addr(addr)?;
-        let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
-        Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
+    pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+        each_addr(addr, |addr| {
+            let (fd, local_addr, peer_addr) = usercalls::connect_stream(addr)?;
+            Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
+        })
     }
 
     pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
         if dur == Duration::default() {
             return Err(io::Error::ZERO_TIMEOUT);
         }
-        Self::connect(Ok(addr)) // FIXME: ignoring timeout
+        Self::connect(addr) // FIXME: ignoring timeout
     }
 
     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
@@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        let addr = io_err_to_addr(addr)?;
-        let (fd, local_addr) = usercalls::bind_stream(&addr)?;
-        Ok(TcpListener { inner: Socket::new(fd, local_addr) })
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+        each_addr(addr, |addr| {
+            let (fd, local_addr) = usercalls::bind_stream(addr)?;
+            Ok(TcpListener { inner: Socket::new(fd, local_addr) })
+        })
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
@@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener {
 pub struct UdpSocket(!);
 
 impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -436,7 +473,7 @@ impl UdpSocket {
         self.0
     }
 
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+    pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
         self.0
     }
 }
@@ -452,12 +489,7 @@ pub struct NonIpSockAddr {
     host: String,
 }
 
-impl error::Error for NonIpSockAddr {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "Failed to convert address to SocketAddr"
-    }
-}
+impl error::Error for NonIpSockAddr {}
 
 impl fmt::Display for NonIpSockAddr {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -467,16 +499,6 @@ impl fmt::Display for NonIpSockAddr {
 
 pub struct LookupHost(!);
 
-impl LookupHost {
-    fn new(host: String) -> io::Result<LookupHost> {
-        Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host }))
-    }
-
-    pub fn port(&self) -> u16 {
-        self.0
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -484,18 +506,9 @@ impl Iterator for LookupHost {
     }
 }
 
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(v: &str) -> io::Result<LookupHost> {
-        LookupHost::new(v.to_owned())
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
-        LookupHost::new(format!("{host}:{port}"))
-    }
+pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
+    Err(io::Error::new(
+        io::ErrorKind::Uncategorized,
+        NonIpSockAddr { host: format!("{host}:{port}") },
+    ))
 }
diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs
index f49821657d9..5200eaa5786 100644
--- a/library/std/src/sys/net/connection/socket/hermit.rs
+++ b/library/std/src/sys/net/connection/socket/hermit.rs
@@ -304,7 +304,8 @@ impl Socket {
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        unimplemented!()
+        let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
     }
 
     // This is used by sys_common code to abstract over Windows and Unix.
diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket/mod.rs
index 7301bde6881..1dd06e97bba 100644
--- a/library/std/src/sys/net/connection/socket.rs
+++ b/library/std/src/sys/net/connection/socket/mod.rs
@@ -3,35 +3,43 @@ mod tests;
 
 use crate::ffi::{c_int, c_void};
 use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6};
+use crate::net::{
+    Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
+};
 use crate::sys::common::small_c_string::run_with_cstr;
+use crate::sys::net::connection::each_addr;
 use crate::sys_common::{AsInner, FromInner};
 use crate::time::Duration;
 use crate::{cmp, fmt, mem, ptr};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "hermit")] {
+cfg_select! {
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_family = "unix")] {
+    }
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
+    }
+    all(target_os = "wasi", target_env = "p2") => {
         mod wasip2;
         pub use wasip2::*;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::*;
     }
+    _ => {}
 }
 
 use netc as c;
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "dragonfly",
         target_os = "freebsd",
         target_os = "openbsd",
@@ -43,39 +51,44 @@ cfg_if::cfg_if! {
         target_os = "nto",
         target_os = "nuttx",
         target_vendor = "apple",
-    ))] {
+    ) => {
         use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
         use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
-    } else {
+    }
+    _ => {
         use c::IPV6_ADD_MEMBERSHIP;
         use c::IPV6_DROP_MEMBERSHIP;
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "linux", target_os = "android",
         target_os = "hurd",
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos",
         target_os = "haiku", target_os = "nto",
-        target_os = "cygwin"))] {
+        target_os = "cygwin",
+    ) => {
         use libc::MSG_NOSIGNAL;
-    } else {
+    }
+    _ => {
         const MSG_NOSIGNAL: c_int = 0x0;
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos",
-        target_os = "nto"))] {
+        target_os = "nto",
+    ) => {
         use crate::ffi::c_uchar;
         type IpV4MultiCastType = c_uchar;
-    } else {
+    }
+    _ => {
         type IpV4MultiCastType = c_int;
     }
 }
@@ -245,7 +258,7 @@ fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// get_host_addresses
+// lookup_host
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct LookupHost {
@@ -254,12 +267,6 @@ pub struct LookupHost {
     port: u16,
 }
 
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.port
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -268,7 +275,10 @@ impl Iterator for LookupHost {
                 let cur = self.cur.as_ref()?;
                 self.cur = cur.ai_next;
                 match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) {
-                    Ok(addr) => return Some(addr),
+                    Ok(mut addr) => {
+                        addr.set_port(self.port);
+                        return Some(addr);
+                    }
                     Err(_) => continue,
                 }
             }
@@ -285,42 +295,17 @@ impl Drop for LookupHost {
     }
 }
 
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(s: &str) -> io::Result<LookupHost> {
-        macro_rules! try_opt {
-            ($e:expr, $msg:expr) => {
-                match $e {
-                    Some(r) => r,
-                    None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)),
-                }
-            };
+pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
+    init();
+    run_with_cstr(host.as_bytes(), &|c_host| {
+        let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+        hints.ai_socktype = c::SOCK_STREAM;
+        let mut res = ptr::null_mut();
+        unsafe {
+            cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res))
+                .map(|_| LookupHost { original: res, cur: res, port })
         }
-
-        // split the string by ':' and convert the second part to u16
-        let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
-        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
-        (host, port).try_into()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
-        init();
-
-        run_with_cstr(host.as_bytes(), &|c_host| {
-            let mut hints: c::addrinfo = unsafe { mem::zeroed() };
-            hints.ai_socktype = c::SOCK_STREAM;
-            let mut res = ptr::null_mut();
-            unsafe {
-                cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res))
-                    .map(|_| LookupHost { original: res, cur: res, port })
-            }
-        })
-    }
+    })
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -332,14 +317,15 @@ pub struct TcpStream {
 }
 
 impl TcpStream {
-    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        let addr = addr?;
-
+    pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
         init();
+        return each_addr(addr, inner);
 
-        let sock = Socket::new(addr, c::SOCK_STREAM)?;
-        sock.connect(addr)?;
-        Ok(TcpStream { inner: sock })
+        fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
+            let sock = Socket::new(addr, c::SOCK_STREAM)?;
+            sock.connect(addr)?;
+            Ok(TcpStream { inner: sock })
+        }
     }
 
     pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
@@ -502,46 +488,45 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        let addr = addr?;
-
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
         init();
-
-        let sock = Socket::new(addr, c::SOCK_STREAM)?;
-
-        // On platforms with Berkeley-derived sockets, this allows to quickly
-        // rebind a socket, without needing to wait for the OS to clean up the
-        // previous one.
-        //
-        // On Windows, this allows rebinding sockets which are actively in use,
-        // which allows “socket hijacking”, so we explicitly don't set it here.
-        // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
-        #[cfg(not(windows))]
-        setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
-
-        // Bind our new socket
-        let (addr, len) = socket_addr_to_c(addr);
-        cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
-
-        cfg_if::cfg_if! {
-            if #[cfg(target_os = "horizon")] {
+        return each_addr(addr, inner);
+
+        fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
+            let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+            // On platforms with Berkeley-derived sockets, this allows to quickly
+            // rebind a socket, without needing to wait for the OS to clean up the
+            // previous one.
+            //
+            // On Windows, this allows rebinding sockets which are actively in use,
+            // which allows “socket hijacking”, so we explicitly don't set it here.
+            // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
+            #[cfg(not(windows))]
+            setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
+
+            // Bind our new socket
+            let (addr, len) = socket_addr_to_c(addr);
+            cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
+
+            let backlog = if cfg!(target_os = "horizon") {
                 // The 3DS doesn't support a big connection backlog. Sometimes
                 // it allows up to about 37, but other times it doesn't even
                 // accept 32. There may be a global limitation causing this.
-                let backlog = 20;
-            } else if #[cfg(target_os = "haiku")] {
+                20
+            } else if cfg!(target_os = "haiku") {
                 // Haiku does not support a queue length > 32
                 // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81
-                let backlog = 32;
+                32
             } else {
                 // The default for all other platforms
-                let backlog = 128;
-            }
-        }
+                128
+            };
 
-        // Start listening
-        cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
-        Ok(TcpListener { inner: sock })
+            // Start listening
+            cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
+            Ok(TcpListener { inner: sock })
+        }
     }
 
     #[inline]
@@ -627,15 +612,16 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-        let addr = addr?;
-
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
         init();
+        return each_addr(addr, inner);
 
-        let sock = Socket::new(addr, c::SOCK_DGRAM)?;
-        let (addr, len) = socket_addr_to_c(addr);
-        cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
-        Ok(UdpSocket { inner: sock })
+        fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> {
+            let sock = Socket::new(addr, c::SOCK_DGRAM)?;
+            let (addr, len) = socket_addr_to_c(addr);
+            cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
+            Ok(UdpSocket { inner: sock })
+        }
     }
 
     #[inline]
@@ -810,9 +796,13 @@ impl UdpSocket {
         Ok(ret as usize)
     }
 
-    pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
-        let (addr, len) = socket_addr_to_c(addr?);
-        cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
+    pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+        return each_addr(addr, |addr| inner(self, addr));
+
+        fn inner(this: &UdpSocket, addr: &SocketAddr) -> io::Result<()> {
+            let (addr, len) = socket_addr_to_c(addr);
+            cvt_r(|| unsafe { c::connect(this.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
+        }
     }
 }
 
diff --git a/library/std/src/sys/net/connection/socket/tests.rs b/library/std/src/sys/net/connection/socket/tests.rs
index fc236b8027b..049355afca7 100644
--- a/library/std/src/sys/net/connection/socket/tests.rs
+++ b/library/std/src/sys/net/connection/socket/tests.rs
@@ -4,7 +4,7 @@ use crate::collections::HashMap;
 #[test]
 fn no_lookup_host_duplicates() {
     let mut addrs = HashMap::new();
-    let lh = match LookupHost::try_from(("localhost", 0)) {
+    let lh = match lookup_host("localhost", 0) {
         Ok(lh) => lh,
         Err(e) => panic!("couldn't resolve `localhost`: {e}"),
     };
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index cc111f3521b..a191576d93b 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -12,10 +12,11 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::{Duration, Instant};
 use crate::{cmp, mem};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "apple")] {
+cfg_select! {
+    target_vendor = "apple" => {
         use libc::SO_LINGER_SEC as SO_LINGER;
-    } else {
+    }
+    _ => {
         use libc::SO_LINGER;
     }
 }
@@ -72,8 +73,8 @@ impl Socket {
 
     pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
         unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(
+            cfg_select! {
+                any(
                     target_os = "android",
                     target_os = "dragonfly",
                     target_os = "freebsd",
@@ -85,7 +86,7 @@ impl Socket {
                     target_os = "cygwin",
                     target_os = "nto",
                     target_os = "solaris",
-                ))] {
+                ) => {
                     // On platforms that support it we pass the SOCK_CLOEXEC
                     // flag to atomically create the socket and set it as
                     // CLOEXEC. On Linux this was added in 2.6.27.
@@ -98,7 +99,8 @@ impl Socket {
                     setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
 
                     Ok(socket)
-                } else {
+                }
+                _ => {
                     let fd = cvt(libc::socket(fam, ty, 0))?;
                     let fd = FileDesc::from_raw_fd(fd);
                     fd.set_cloexec()?;
@@ -120,8 +122,8 @@ impl Socket {
         unsafe {
             let mut fds = [0, 0];
 
-            cfg_if::cfg_if! {
-                if #[cfg(any(
+            cfg_select! {
+                any(
                     target_os = "android",
                     target_os = "dragonfly",
                     target_os = "freebsd",
@@ -132,11 +134,12 @@ impl Socket {
                     target_os = "openbsd",
                     target_os = "cygwin",
                     target_os = "nto",
-                ))] {
+                ) => {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
                     Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1]))))
-                } else {
+                }
+                _ => {
                     cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
                     let a = FileDesc::from_raw_fd(fds[0]);
                     let b = FileDesc::from_raw_fd(fds[1]);
@@ -250,8 +253,8 @@ impl Socket {
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
         // platforms that support it. On Linux, this was added in 2.6.28,
         // glibc 2.10 and musl 0.9.5.
-        cfg_if::cfg_if! {
-            if #[cfg(any(
+        cfg_select! {
+            any(
                 target_os = "android",
                 target_os = "dragonfly",
                 target_os = "freebsd",
@@ -261,12 +264,13 @@ impl Socket {
                 target_os = "netbsd",
                 target_os = "openbsd",
                 target_os = "cygwin",
-            ))] {
+            ) => {
                 unsafe {
                     let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
                     Ok(Socket(FileDesc::from_raw_fd(fd)))
                 }
-            } else {
+            }
+            _ => {
                 unsafe {
                     let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?;
                     let fd = FileDesc::from_raw_fd(fd);
@@ -357,7 +361,7 @@ impl Socket {
         self.recv_from_with_flags(buf, 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
         let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?;
         Ok(n as usize)
@@ -380,7 +384,7 @@ impl Socket {
         self.0.is_write_vectored()
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
         let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?;
         Ok(n as usize)
@@ -468,12 +472,12 @@ impl Socket {
         Ok(raw != 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
         setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn quickack(&self) -> io::Result<bool> {
         let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?;
         Ok(raw != 0)
@@ -481,14 +485,15 @@ impl Socket {
 
     // bionic libc makes no use of this flag
     #[cfg(target_os = "linux")]
-    pub fn set_deferaccept(&self, accept: u32) -> io::Result<()> {
-        setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, accept as c_int)
+    pub fn set_deferaccept(&self, accept: Duration) -> io::Result<()> {
+        let val = cmp::min(accept.as_secs(), c_int::MAX as u64) as c_int;
+        setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val)
     }
 
     #[cfg(target_os = "linux")]
-    pub fn deferaccept(&self) -> io::Result<u32> {
+    pub fn deferaccept(&self) -> io::Result<Duration> {
         let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?;
-        Ok(raw as u32)
+        Ok(Duration::from_secs(raw as _))
     }
 
     #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
@@ -537,12 +542,12 @@ impl Socket {
         Ok(raw != 0)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux",))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
     pub fn passcred(&self) -> io::Result<bool> {
         let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?;
         Ok(passcred != 0)
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index 16e3487a174..004f6d413a1 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -1,6 +1,7 @@
+use super::each_addr;
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sync::{Arc, Mutex};
 use crate::sys::unsupported;
 use crate::time::Duration;
@@ -15,13 +16,17 @@ pub struct TcpStream {
 }
 
 impl TcpStream {
-    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        let inner = tcp::Tcp::connect(addr?, None)?;
-        Ok(Self {
-            inner,
-            read_timeout: Arc::new(Mutex::new(None)),
-            write_timeout: Arc::new(Mutex::new(None)),
-        })
+    pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+        return each_addr(addr, inner);
+
+        fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
+            let inner = tcp::Tcp::connect(addr, None)?;
+            Ok(TcpStream {
+                inner,
+                read_timeout: Arc::new(Mutex::new(None)),
+                write_timeout: Arc::new(Mutex::new(None)),
+            })
+        }
     }
 
     pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
@@ -145,7 +150,7 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
         unsupported()
     }
 
@@ -195,7 +200,7 @@ impl fmt::Debug for TcpListener {
 pub struct UdpSocket(!);
 
 impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -315,7 +320,7 @@ impl UdpSocket {
         self.0
     }
 
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+    pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
         self.0
     }
 }
@@ -328,12 +333,6 @@ impl fmt::Debug for UdpSocket {
 
 pub struct LookupHost(!);
 
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.0
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -341,18 +340,6 @@ impl Iterator for LookupHost {
     }
 }
 
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &str) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
-    }
+pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
+    unsupported()
 }
diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs
index da217439626..fb18e8dec55 100644
--- a/library/std/src/sys/net/connection/unsupported.rs
+++ b/library/std/src/sys/net/connection/unsupported.rs
@@ -1,13 +1,13 @@
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sys::unsupported;
 use crate::time::Duration;
 
 pub struct TcpStream(!);
 
 impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+    pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> {
         unsupported()
     }
 
@@ -121,7 +121,7 @@ impl fmt::Debug for TcpStream {
 pub struct TcpListener(!);
 
 impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
         unsupported()
     }
 
@@ -171,7 +171,7 @@ impl fmt::Debug for TcpListener {
 pub struct UdpSocket(!);
 
 impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -291,7 +291,7 @@ impl UdpSocket {
         self.0
     }
 
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+    pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
         self.0
     }
 }
@@ -304,12 +304,6 @@ impl fmt::Debug for UdpSocket {
 
 pub struct LookupHost(!);
 
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.0
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -317,18 +311,6 @@ impl Iterator for LookupHost {
     }
 }
 
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &str) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
-    }
+pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
+    unsupported()
 }
diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs
index 951dc65e5b4..048dafdcd7f 100644
--- a/library/std/src/sys/net/connection/wasip1.rs
+++ b/library/std/src/sys/net/connection/wasip1.rs
@@ -2,7 +2,7 @@
 
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::WasiFd;
 use crate::sys::{err2io, unsupported};
@@ -60,7 +60,7 @@ impl FromRawFd for Socket {
 }
 
 impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+    pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> {
         unsupported()
     }
 
@@ -212,7 +212,7 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
         unsupported()
     }
 
@@ -316,7 +316,7 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+    pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -436,7 +436,7 @@ impl UdpSocket {
         unsupported()
     }
 
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+    pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
         unsupported()
     }
 
@@ -477,12 +477,6 @@ impl fmt::Debug for UdpSocket {
 
 pub struct LookupHost(!);
 
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.0
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -490,18 +484,6 @@ impl Iterator for LookupHost {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
-    }
+pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
+    unsupported()
 }
diff --git a/library/std/src/sys/net/connection/xous/dns.rs b/library/std/src/sys/net/connection/xous/dns.rs
index bb29d211fad..b139376f597 100644
--- a/library/std/src/sys/net/connection/xous/dns.rs
+++ b/library/std/src/sys/net/connection/xous/dns.rs
@@ -1,15 +1,8 @@
-use core::convert::{TryFrom, TryInto};
-
 use crate::io;
 use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 use crate::os::xous::ffi::lend_mut;
 use crate::os::xous::services::{DnsLendMut, dns_server};
 
-pub struct DnsError {
-    #[allow(dead_code)]
-    pub code: u8,
-}
-
 #[repr(C, align(4096))]
 struct LookupHostQuery([u8; 4096]);
 
@@ -20,12 +13,6 @@ pub struct LookupHost {
     count: usize,
 }
 
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.port
-    }
-}
-
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -72,7 +59,7 @@ impl Iterator for LookupHost {
     }
 }
 
-pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
+pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> {
     let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port };
 
     // Copy the query into the message that gets sent to the DNS server
@@ -89,7 +76,7 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
     )
     .unwrap();
     if result.data.0[0] != 0 {
-        return Err(DnsError { code: result.data.0[1] });
+        return Err(io::const_error!(io::ErrorKind::InvalidInput, "DNS failure"));
     }
     assert_eq!(result.offset, 0);
     result.count = result.data.0[1] as usize;
@@ -98,31 +85,3 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
     result.offset = 2;
     Ok(result)
 }
-
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(s: &str) -> io::Result<LookupHost> {
-        macro_rules! try_opt {
-            ($e:expr, $msg:expr) => {
-                match $e {
-                    Some(r) => r,
-                    None => return Err(io::const_error!(io::ErrorKind::InvalidInput, &$msg)),
-                }
-            };
-        }
-
-        // split the string by ':' and convert the second part to u16
-        let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
-        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
-        (host, port).try_into()
-    }
-}
-
-impl TryFrom<(&str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(v: (&str, u16)) -> io::Result<LookupHost> {
-        lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, "DNS failure"))
-    }
-}
diff --git a/library/std/src/sys/net/connection/xous/mod.rs b/library/std/src/sys/net/connection/xous/mod.rs
index e44a375b9e3..0f77be5c3fa 100644
--- a/library/std/src/sys/net/connection/xous/mod.rs
+++ b/library/std/src/sys/net/connection/xous/mod.rs
@@ -45,4 +45,4 @@ pub struct GetAddress {
     raw: [u8; 4096],
 }
 
-pub use dns::LookupHost;
+pub use dns::lookup_host;
diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs
index bdf1fcd9302..8818ef2ca9a 100644
--- a/library/std/src/sys/net/connection/xous/tcplistener.rs
+++ b/library/std/src/sys/net/connection/xous/tcplistener.rs
@@ -2,9 +2,10 @@ use core::convert::TryInto;
 use core::sync::atomic::{Atomic, AtomicBool, AtomicU16, AtomicUsize, Ordering};
 
 use super::*;
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
 use crate::os::xous::services;
 use crate::sync::Arc;
+use crate::sys::net::connection::each_addr;
 use crate::{fmt, io};
 
 macro_rules! unimpl {
@@ -25,16 +26,19 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        let mut addr = *socketaddr?;
-
-        let fd = TcpListener::bind_inner(&mut addr)?;
-        return Ok(TcpListener {
-            fd: Arc::new(AtomicU16::new(fd)),
-            local: addr,
-            handle_count: Arc::new(AtomicUsize::new(1)),
-            nonblocking: Arc::new(AtomicBool::new(false)),
-        });
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+        return each_addr(addr, inner);
+
+        fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
+            let mut addr = *addr;
+            let fd = TcpListener::bind_inner(&mut addr)?;
+            Ok(TcpListener {
+                fd: Arc::new(AtomicU16::new(fd)),
+                local: addr,
+                handle_count: Arc::new(AtomicUsize::new(1)),
+                nonblocking: Arc::new(AtomicBool::new(false)),
+            })
+        }
     }
 
     /// This returns the raw fd of a Listener, so that it can also be used by the
diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs
index 54524767452..4df75453d1f 100644
--- a/library/std/src/sys/net/connection/xous/tcpstream.rs
+++ b/library/std/src/sys/net/connection/xous/tcpstream.rs
@@ -3,9 +3,12 @@ use core::sync::atomic::{Atomic, AtomicBool, AtomicU32, AtomicUsize, Ordering};
 use super::*;
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6};
+use crate::net::{
+    IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
+};
 use crate::os::xous::services;
 use crate::sync::Arc;
+use crate::sys::net::connection::each_addr;
 use crate::time::Duration;
 
 macro_rules! unimpl {
@@ -79,8 +82,8 @@ impl TcpStream {
         }
     }
 
-    pub fn connect(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        Self::connect_timeout(socketaddr?, Duration::ZERO)
+    pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+        each_addr(addr, |addr| Self::connect_timeout(addr, Duration::ZERO))
     }
 
     pub fn connect_timeout(addr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {
diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs
index 2127d3267ed..ce54ea3b79e 100644
--- a/library/std/src/sys/net/connection/xous/udp.rs
+++ b/library/std/src/sys/net/connection/xous/udp.rs
@@ -3,9 +3,10 @@ use core::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 use super::*;
 use crate::cell::Cell;
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
 use crate::os::xous::services;
 use crate::sync::Arc;
+use crate::sys::net::connection::each_addr;
 use crate::time::Duration;
 use crate::{fmt, io};
 
@@ -32,40 +33,45 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-        let addr = socketaddr?;
-        // Construct the request
-        let mut connect_request = ConnectRequest { raw: [0u8; 4096] };
-
-        // Serialize the StdUdpBind structure. This is done "manually" because we don't want to
-        // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous.
-        let port_bytes = addr.port().to_le_bytes();
-        connect_request.raw[0] = port_bytes[0];
-        connect_request.raw[1] = port_bytes[1];
-        match addr.ip() {
-            IpAddr::V4(addr) => {
-                connect_request.raw[2] = 4;
-                for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
-                    *dest = src;
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
+        return each_addr(addr, inner);
+
+        fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> {
+            // Construct the request
+            let mut connect_request = ConnectRequest { raw: [0u8; 4096] };
+
+            // Serialize the StdUdpBind structure. This is done "manually" because we don't want to
+            // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous.
+            let port_bytes = addr.port().to_le_bytes();
+            connect_request.raw[0] = port_bytes[0];
+            connect_request.raw[1] = port_bytes[1];
+            match addr.ip() {
+                IpAddr::V4(addr) => {
+                    connect_request.raw[2] = 4;
+                    for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
+                        *dest = src;
+                    }
                 }
-            }
-            IpAddr::V6(addr) => {
-                connect_request.raw[2] = 6;
-                for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
-                    *dest = src;
+                IpAddr::V6(addr) => {
+                    connect_request.raw[2] = 6;
+                    for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
+                        *dest = src;
+                    }
                 }
             }
-        }
 
-        let response = crate::os::xous::ffi::lend_mut(
-            services::net_server(),
-            services::NetLendMut::StdUdpBind.into(),
-            &mut connect_request.raw,
-            0,
-            4096,
-        );
+            let response = crate::os::xous::ffi::lend_mut(
+                services::net_server(),
+                services::NetLendMut::StdUdpBind.into(),
+                &mut connect_request.raw,
+                0,
+                4096,
+            );
+
+            let Ok((_, valid)) = response else {
+                return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response"));
+            };
 
-        if let Ok((_, valid)) = response {
             // The first four bytes should be zero upon success, and will be nonzero
             // for an error.
             let response = connect_request.raw;
@@ -87,8 +93,9 @@ impl UdpSocket {
                     ));
                 }
             }
+
             let fd = response[1] as u16;
-            return Ok(UdpSocket {
+            Ok(UdpSocket {
                 fd,
                 local: *addr,
                 remote: Cell::new(None),
@@ -96,9 +103,8 @@ impl UdpSocket {
                 write_timeout: Cell::new(0),
                 handle_count: Arc::new(AtomicUsize::new(1)),
                 nonblocking: Cell::new(false),
-            });
+            })
         }
-        Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response"))
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
@@ -198,10 +204,11 @@ impl UdpSocket {
         self.peek_from(buf).map(|(len, _addr)| len)
     }
 
-    pub fn connect(&self, maybe_addr: io::Result<&SocketAddr>) -> io::Result<()> {
-        let addr = maybe_addr?;
-        self.remote.set(Some(*addr));
-        Ok(())
+    pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+        each_addr(addr, |addr| {
+            self.remote.set(Some(*addr));
+            Ok(())
+        })
     }
 
     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs
index 646679a1cc8..dffc4ea7f81 100644
--- a/library/std/src/sys/net/mod.rs
+++ b/library/std/src/sys/net/mod.rs
@@ -1,41 +1,4 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        all(target_family = "unix", not(target_os = "l4re")),
-        target_os = "windows",
-        target_os = "hermit",
-        all(target_os = "wasi", target_env = "p2"),
-        target_os = "solid_asp3",
-    ))] {
-        mod connection {
-            mod socket;
-            pub use socket::*;
-        }
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
-        mod connection {
-            mod sgx;
-            pub use sgx::*;
-        }
-    } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] {
-        mod connection {
-            mod wasip1;
-            pub use wasip1::*;
-        }
-    } else if #[cfg(target_os = "xous")] {
-        mod connection {
-            mod xous;
-            pub use xous::*;
-        }
-    } else if #[cfg(target_os = "uefi")] {
-        mod connection {
-            mod uefi;
-            pub use uefi::*;
-        }
-    } else {
-        mod connection {
-            mod unsupported;
-            pub use unsupported::*;
-        }
-    }
-}
-
+/// This module contains the implementations of `TcpStream`, `TcpListener` and
+/// `UdpSocket` as well as related functionality like DNS resolving.
+mod connection;
 pub use connection::*;
diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs
index 345e661586d..65c90d88049 100644
--- a/library/std/src/sys/os_str/mod.rs
+++ b/library/std/src/sys/os_str/mod.rs
@@ -1,13 +1,11 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_os = "windows",
-        target_os = "uefi",
-    ))] {
+cfg_select! {
+    any(target_os = "windows", target_os = "uefi") => {
         mod wtf8;
         pub use wtf8::{Buf, Slice};
-    } else {
+    }
+    _ => {
         mod bytes;
         pub use bytes::{Buf, Slice};
     }
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index bbc704ebf86..96da891874e 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -1,12 +1,12 @@
 //! The underlying OsString/OsStr implementation on Windows is a
 //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
+use alloc::wtf8::{Wtf8, Wtf8Buf};
 use core::clone::CloneToUninit;
 
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::wtf8::{Wtf8, Wtf8Buf, check_utf8_boundary};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::{fmt, mem};
 
@@ -220,7 +220,9 @@ impl Buf {
     /// trailing surrogate half.
     #[inline]
     pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
-        self.inner.extend_from_slice(other);
+        unsafe {
+            self.inner.extend_from_slice_unchecked(other);
+        }
     }
 }
 
@@ -238,7 +240,7 @@ impl Slice {
     #[track_caller]
     #[inline]
     pub fn check_public_boundary(&self, index: usize) {
-        check_utf8_boundary(&self.inner, index);
+        self.inner.check_utf8_boundary(index);
     }
 
     #[inline]
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index fb8d69b7375..3ddf6e5acb0 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -25,7 +25,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 pub fn unsupported<T>() -> crate::io::Result<T> {
diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs
index a998c3165e5..9681964ed9b 100644
--- a/library/std/src/sys/pal/hermit/os.rs
+++ b/library/std/src/sys/pal/hermit/os.rs
@@ -1,10 +1,9 @@
 use super::hermit_abi;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::path::{self, PathBuf};
 use crate::sys::unsupported;
-use crate::{fmt, io, str};
+use crate::{fmt, io};
 
 pub fn errno() -> i32 {
     unsafe { hermit_abi::get_errno() }
@@ -52,12 +51,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on hermit yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index f76a5f96c87..bd6fd5a3de4 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -26,15 +26,22 @@ impl Timespec {
     }
 
     fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
+            debug_assert!(a >= b);
+            a.wrapping_sub(b).cast_unsigned()
+        }
+
         if self >= other {
+            // Logic here is identical to Unix version of `Timestamp::sub_timespec`,
+            // check comments there why operations do not overflow.
             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                 Duration::new(
-                    (self.t.tv_sec - other.t.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec),
                     (self.t.tv_nsec - other.t.tv_nsec) as u32,
                 )
             } else {
                 Duration::new(
-                    (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec),
                     (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32,
                 )
             })
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index fbefc62ac88..dd5e83ee570 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -24,60 +24,74 @@
 
 pub mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(unix)] {
+cfg_select! {
+    unix => {
         mod unix;
         pub use self::unix::*;
-    } else if #[cfg(windows)] {
+    }
+    windows => {
         mod windows;
         pub use self::windows::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use self::solid::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use self::hermit::*;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use self::trusty::*;
-    } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
+    }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use self::vexos::*;
+    }
+    all(target_os = "wasi", target_env = "p2") => {
         mod wasip2;
         pub use self::wasip2::*;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use self::wasi::*;
-    } else if #[cfg(target_family = "wasm")] {
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use self::wasip1::*;
+    }
+    target_family = "wasm" => {
         mod wasm;
         pub use self::wasm::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use self::xous::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use self::uefi::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use self::sgx::*;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use self::teeos::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use self::zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use self::unsupported::*;
     }
 }
 
-cfg_if::cfg_if! {
+pub const FULL_BACKTRACE_DEFAULT: bool = cfg_select! {
     // Fuchsia components default to full backtrace.
-    if #[cfg(target_os = "fuchsia")] {
-        pub const FULL_BACKTRACE_DEFAULT: bool = true;
-    } else {
-        pub const FULL_BACKTRACE_DEFAULT: bool = false;
-    }
-}
+    target_os = "fuchsia" => true,
+    _ => false,
+};
 
 #[cfg(not(target_os = "uefi"))]
 pub type RawOsError = i32;
diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs
index 57247cffad3..b8c4d7740c4 100644
--- a/library/std/src/sys/pal/sgx/abi/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/mod.rs
@@ -67,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
     let tls_guard = unsafe { tls.activate() };
 
     if secondary {
-        let join_notifier = super::thread::Thread::entry();
+        let join_notifier = crate::sys::thread::Thread::entry();
         drop(tls_guard);
         drop(join_notifier);
 
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 6e43a79ddec..9a33873af58 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -13,7 +13,6 @@ mod libunwind_integration;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod thread_parking;
 pub mod time;
 pub mod waitqueue;
@@ -59,8 +58,7 @@ pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
 
 #[inline]
 pub fn is_interrupted(code: i32) -> bool {
-    use fortanix_sgx_abi::Error;
-    code == Error::Interrupted as _
+    code == fortanix_sgx_abi::Error::Interrupted as _
 }
 
 pub fn decode_error_kind(code: i32) -> ErrorKind {
diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs
index 70f838679c9..28d79963ac8 100644
--- a/library/std/src/sys/pal/sgx/os.rs
+++ b/library/std/src/sys/pal/sgx/os.rs
@@ -1,11 +1,10 @@
 use fortanix_sgx_abi::{Error, RESULT_SUCCESS};
 
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::path::{self, PathBuf};
 use crate::sys::{decode_error_kind, sgx_ineffective, unsupported};
-use crate::{fmt, io, str};
+use crate::{fmt, io};
 
 pub fn errno() -> i32 {
     RESULT_SUCCESS
@@ -59,12 +58,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported in SGX yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 0011cf256df..9ca6dc58118 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -10,10 +10,8 @@ pub mod itron {
     pub mod error;
     pub mod spin;
     pub mod task;
-    pub mod thread;
     pub mod thread_parking;
     pub mod time;
-    use super::unsupported;
 }
 
 // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
@@ -22,7 +20,7 @@ pub(crate) mod error;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub use self::itron::{thread, thread_parking};
+pub use self::itron::thread_parking;
 pub mod time;
 
 // SAFETY: must be called only once during runtime initialization.
diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs
index 8f5976b0592..cb6e2cbceae 100644
--- a/library/std/src/sys/pal/solid/os.rs
+++ b/library/std/src/sys/pal/solid/os.rs
@@ -1,5 +1,4 @@
 use super::{error, itron, unsupported};
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::path::{self, PathBuf};
 use crate::{fmt, io};
@@ -58,12 +57,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index c7b17777258..dd0155265da 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -9,7 +9,6 @@
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 #[allow(non_upper_case_globals)]
 #[path = "../unix/time.rs"]
 pub mod time;
diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs
index 03f3c72b022..512b3e2885b 100644
--- a/library/std/src/sys/pal/teeos/os.rs
+++ b/library/std/src/sys/pal/teeos/os.rs
@@ -3,7 +3,6 @@
 use core::marker::PhantomData;
 
 use super::unsupported;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::path::PathBuf;
 use crate::{fmt, io, path};
@@ -62,12 +61,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs
index 275f6062463..cf0c098f8a2 100644
--- a/library/std/src/sys/pal/trusty/mod.rs
+++ b/library/std/src/sys/pal/trusty/mod.rs
@@ -7,8 +7,6 @@ mod common;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/thread.rs"]
-pub mod thread;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index b50574de937..c0d69c3e002 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -92,6 +92,9 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
 ///
 /// Queries a handle to determine if it supports a specified protocol. If the protocol is
 /// supported by the handle, it opens the protocol on behalf of the calling agent.
+///
+/// The protocol is opened with the attribute GET_PROTOCOL, which means the caller is not required
+/// to close the protocol interface with `EFI_BOOT_SERVICES.CloseProtocol()`
 pub(crate) fn open_protocol<T>(
     handle: NonNull<crate::ffi::c_void>,
     mut protocol_guid: Guid,
@@ -473,6 +476,7 @@ impl<'a> crate::fmt::Debug for DevicePathNode<'a> {
     }
 }
 
+/// Protocols installed by Rust side on a handle.
 pub(crate) struct OwnedProtocol<T> {
     guid: r_efi::efi::Guid,
     handle: NonNull<crate::ffi::c_void>,
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 8911a2ee519..ebd311db1e1 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -17,7 +17,6 @@ pub mod helpers;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[cfg(test)]
diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs
index bfd4dc81cb4..aae6cb9e064 100644
--- a/library/std/src/sys/pal/uefi/os.rs
+++ b/library/std/src/sys/pal/uefi/os.rs
@@ -2,7 +2,6 @@ use r_efi::efi::Status;
 use r_efi::efi::protocols::{device_path, loaded_image_device_path};
 
 use super::{RawOsError, helpers, unsupported_err};
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::os::uefi;
@@ -122,7 +121,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     let protocol = helpers::image_handle_protocol::<device_path::Protocol>(
diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs
index 38658cc4e9a..56ca999cc7e 100644
--- a/library/std/src/sys/pal/uefi/tests.rs
+++ b/library/std/src/sys/pal/uefi/tests.rs
@@ -1,7 +1,13 @@
+//! These tests are not run automatically right now. Please run these tests manually by copying them
+//! to a separate project when modifying any related code.
+
 use super::alloc::*;
-use super::time::*;
+use super::time::system_time_internal::{from_uefi, to_uefi};
+use crate::io::{IoSlice, IoSliceMut};
 use crate::time::Duration;
 
+const SECS_IN_MINUTE: u64 = 60;
+
 #[test]
 fn align() {
     // UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
@@ -23,19 +29,177 @@ fn align() {
 }
 
 #[test]
-fn epoch() {
-    let t = r_efi::system::Time {
-        year: 1970,
+fn systemtime_start() {
+    let t = r_efi::efi::Time {
+        year: 1900,
         month: 1,
         day: 1,
         hour: 0,
         minute: 0,
         second: 0,
         nanosecond: 0,
-        timezone: r_efi::efi::UNSPECIFIED_TIMEZONE,
+        timezone: -1440,
         daylight: 0,
+        pad2: 0,
+    };
+    assert_eq!(from_uefi(&t), Duration::new(0, 0));
+    assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
+    assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
+}
+
+#[test]
+fn systemtime_utc_start() {
+    let t = r_efi::efi::Time {
+        year: 1900,
+        month: 1,
+        day: 1,
+        hour: 0,
+        minute: 0,
+        second: 0,
         pad1: 0,
+        nanosecond: 0,
+        timezone: 0,
+        daylight: 0,
         pad2: 0,
     };
-    assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
+    assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
+    assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
+    assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
+}
+
+#[test]
+fn systemtime_end() {
+    let t = r_efi::efi::Time {
+        year: 9999,
+        month: 12,
+        day: 31,
+        hour: 23,
+        minute: 59,
+        second: 59,
+        pad1: 0,
+        nanosecond: 0,
+        timezone: 1440,
+        daylight: 0,
+        pad2: 0,
+    };
+    assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
+    assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
+}
+
+// UEFI IoSlice and IoSliceMut Tests
+//
+// Strictly speaking, vectored read/write types for UDP4, UDP6, TCP4, TCP6 are defined
+// separately in the UEFI Spec. However, they have the same signature. These tests just ensure
+// that `IoSlice` and `IoSliceMut` are compatible with the vectored types for all the
+// networking protocols.
+
+unsafe fn to_slice<T>(val: &T) -> &[u8] {
+    let len = size_of_val(val);
+    unsafe { crate::slice::from_raw_parts(crate::ptr::from_ref(val).cast(), len) }
+}
+
+#[test]
+fn io_slice_single() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp4_frag = r_efi::protocols::udp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp6_frag = r_efi::protocols::udp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let io_slice = IoSlice::new(&data);
+
+    unsafe {
+        assert_eq!(to_slice(&io_slice), to_slice(&tcp4_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&tcp6_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&udp4_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&udp6_frag));
+    }
+}
+
+#[test]
+fn io_slice_mut_single() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp4_frag = r_efi::protocols::udp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp6_frag = r_efi::protocols::udp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let io_slice_mut = IoSliceMut::new(&mut data);
+
+    unsafe {
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp4_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp6_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&udp4_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&udp6_frag));
+    }
+}
+
+#[test]
+fn io_slice_multi() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let rhs =
+        [tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag];
+    let lhs = [
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+    ];
+
+    unsafe {
+        assert_eq!(to_slice(&lhs), to_slice(&rhs));
+    }
+}
+
+#[test]
+fn io_slice_basic() {
+    let data = [0, 1, 2, 3, 4];
+    let mut io_slice = IoSlice::new(&data);
+
+    assert_eq!(data, io_slice.as_slice());
+    io_slice.advance(2);
+    assert_eq!(&data[2..], io_slice.as_slice());
+}
+
+#[test]
+fn io_slice_mut_basic() {
+    let data = [0, 1, 2, 3, 4];
+    let mut data_clone = [0, 1, 2, 3, 4];
+    let mut io_slice_mut = IoSliceMut::new(&mut data_clone);
+
+    assert_eq!(data, io_slice_mut.as_slice());
+    assert_eq!(data, io_slice_mut.as_mut_slice());
+
+    io_slice_mut.advance(2);
+    assert_eq!(&data[2..], io_slice_mut.into_slice());
 }
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
deleted file mode 100644
index 47a48008c76..00000000000
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use super::unsupported;
-use crate::ffi::CStr;
-use crate::io;
-use crate::num::NonZero;
-use crate::ptr::NonNull;
-use crate::time::{Duration, Instant};
-
-pub struct Thread(!);
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(
-        _stack: usize,
-        _name: Option<&str>,
-        _p: Box<dyn FnOnce()>,
-    ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {
-        // do nothing
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        let boot_services: NonNull<r_efi::efi::BootServices> =
-            crate::os::uefi::env::boot_services().expect("can't sleep").cast();
-        let mut dur_ms = dur.as_micros();
-        // ceil up to the nearest microsecond
-        if dur.subsec_nanos() % 1000 > 0 {
-            dur_ms += 1;
-        }
-
-        while dur_ms > 0 {
-            let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
-            let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
-            dur_ms -= ms;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {
-        self.0
-    }
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    // UEFI is single threaded
-    Ok(NonZero::new(1).unwrap())
-}
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index eeb2c35ffbb..c6636626fd5 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -1,16 +1,42 @@
 use crate::time::Duration;
 
-const SECS_IN_MINUTE: u64 = 60;
-const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
-const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
-
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(Duration);
 
+/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then
+/// the timezone is assumed to be in UTC.
+///
+/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct SystemTime(Duration);
 
-pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
+    year: 1970,
+    month: 1,
+    day: 1,
+    hour: 0,
+    minute: 0,
+    second: 0,
+    nanosecond: 0,
+    timezone: 0,
+    daylight: 0,
+    pad1: 0,
+    pad2: 0,
+});
+
+const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
+    year: 9999,
+    month: 12,
+    day: 31,
+    hour: 23,
+    minute: 59,
+    second: 59,
+    nanosecond: 999_999_999,
+    timezone: 1440,
+    daylight: 0,
+    pad1: 0,
+    pad2: 0,
+});
 
 impl Instant {
     pub fn now() -> Instant {
@@ -40,6 +66,15 @@ impl Instant {
 }
 
 impl SystemTime {
+    pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self {
+        Self(system_time_internal::from_uefi(&t))
+    }
+
+    #[expect(dead_code)]
+    pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
+        system_time_internal::to_uefi(&self.0, timezone, daylight)
+    }
+
     pub fn now() -> SystemTime {
         system_time_internal::now()
             .unwrap_or_else(|| panic!("time not implemented on this platform"))
@@ -50,11 +85,14 @@ impl SystemTime {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(*other)?))
+        let temp = Self(self.0.checked_add(*other)?);
+
+        // Check if can be represented in UEFI
+        if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(*other)?))
+        self.0.checked_sub(*other).map(Self)
     }
 }
 
@@ -66,51 +104,132 @@ pub(crate) mod system_time_internal {
     use crate::mem::MaybeUninit;
     use crate::ptr::NonNull;
 
+    const SECS_IN_MINUTE: u64 = 60;
+    const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
+    const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
+    const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE;
+
     pub fn now() -> Option<SystemTime> {
         let runtime_services: NonNull<RuntimeServices> = helpers::runtime_services()?;
         let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
         let r = unsafe {
             ((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut())
         };
-
         if r.is_error() {
             return None;
         }
 
         let t = unsafe { t.assume_init() };
 
-        Some(SystemTime(uefi_time_to_duration(t)))
+        Some(SystemTime::from_uefi(t))
     }
 
-    // This algorithm is based on the one described in the post
-    // https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
-    pub(crate) const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration {
-        assert!(t.month <= 12);
-        assert!(t.month != 0);
+    /// This algorithm is a modified form of the one described in the post
+    /// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
+    ///
+    /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
+    /// epoch used in the original algorithm.
+    pub(crate) const fn from_uefi(t: &Time) -> Duration {
+        assert!(t.month <= 12 && t.month != 0);
+        assert!(t.year >= 1900 && t.year <= 9999);
+        assert!(t.day <= 31 && t.day != 0);
+
+        assert!(t.second < 60);
+        assert!(t.minute < 60);
+        assert!(t.hour < 24);
+        assert!(t.nanosecond < 1_000_000_000);
+
+        assert!(
+            (t.timezone <= 1440 && t.timezone >= -1440)
+                || t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
+        );
 
         const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
 
-        // Calculate the number of days since 1/1/1970
+        // Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
+        // time.
         // Use 1 March as the start
         let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
         let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
         let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
         let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
         let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
-        let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2472632;
+        let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
 
         let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
             + (t.second as u64)
             + (t.minute as u64) * SECS_IN_MINUTE
             + (t.hour as u64) * SECS_IN_HOUR;
 
-        let utc_epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
-            localtime_epoch
+        // Calculate the offset from 1/1/1900 at timezone -1440 min
+        let adjusted_localtime_epoc: u64 = localtime_epoch + TIMEZONE_DELTA;
+
+        let epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
+            adjusted_localtime_epoc
         } else {
-            (localtime_epoch as i64 + (t.timezone as i64) * SECS_IN_MINUTE as i64) as u64
+            adjusted_localtime_epoc
+                .checked_add_signed((t.timezone as i64) * SECS_IN_MINUTE as i64)
+                .unwrap()
         };
 
-        Duration::new(utc_epoch, t.nanosecond)
+        Duration::new(epoch, t.nanosecond)
+    }
+
+    /// This algorithm is a modified version of the one described in the post:
+    /// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
+    ///
+    /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
+    /// epoch used in the original algorithm.
+    pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
+        // Check timzone validity
+        assert!(timezone <= 1440 && timezone >= -1440);
+
+        // FIXME(#126043): use checked_sub_signed once stabilized
+        let secs =
+            dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
+
+        // Convert to seconds since 1900-01-01-00:00:00 in timezone.
+        let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else { return None };
+
+        let days = secs / SECS_IN_DAY;
+        let remaining_secs = secs % SECS_IN_DAY;
+
+        let z = days + 693901;
+        let era = z / 146097;
+        let doe = z - (era * 146097);
+        let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
+        let mut y = yoe + era * 400;
+        let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
+        let mp = (5 * doy + 2) / 153;
+        let d = doy - (153 * mp + 2) / 5 + 1;
+        let m = if mp < 10 { mp + 3 } else { mp - 9 };
+
+        if m <= 2 {
+            y += 1;
+        }
+
+        let hour = (remaining_secs / SECS_IN_HOUR) as u8;
+        let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
+        let second = (remaining_secs % SECS_IN_MINUTE) as u8;
+
+        // Check Bounds
+        if y >= 1900 && y <= 9999 {
+            Some(Time {
+                year: y as u16,
+                month: m as u8,
+                day: d as u8,
+                hour,
+                minute,
+                second,
+                nanosecond: dur.subsec_nanos(),
+                timezone,
+                daylight,
+                pad1: 0,
+                pad2: 0,
+            })
+        } else {
+            None
+        }
     }
 }
 
@@ -164,12 +283,9 @@ pub(crate) mod instant_internal {
     }
 
     pub fn platform_specific() -> Option<Instant> {
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
-                timestamp_rdtsc().map(Instant)
-            } else {
-                None
-            }
+        cfg_select! {
+            any(target_arch = "x86_64", target_arch = "x86") => timestamp_rdtsc().map(Instant),
+            _ => None,
         }
     }
 
diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs
index c23278bdf5e..265067d84d5 100644
--- a/library/std/src/sys/pal/unix/futex.rs
+++ b/library/std/src/sys/pal/unix/futex.rs
@@ -46,8 +46,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
         }
 
         let r = unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(target_os = "freebsd")] {
+            cfg_select! {
+                target_os = "freebsd" => {
                     // FreeBSD doesn't have futex(), but it has
                     // _umtx_op(UMTX_OP_WAIT_UINT_PRIVATE), which is nearly
                     // identical. It supports absolute timeouts through a flag
@@ -66,7 +66,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
                         crate::ptr::without_provenance_mut(umtx_timeout_size),
                         umtx_timeout_ptr as *mut _,
                     )
-                } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
+                }
+                any(target_os = "linux", target_os = "android") => {
                     // Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT to be able to give an
                     // absolute time rather than a relative time.
                     libc::syscall(
@@ -78,7 +79,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
                         null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
                         !0u32,         // A full bitmask, to make it behave like a regular FUTEX_WAIT.
                     )
-                } else {
+                }
+                _ => {
                     compile_error!("unknown target_os");
                 }
             }
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index ba9e14b8009..dd1059fe04a 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -17,7 +17,6 @@ pub mod os;
 pub mod pipe;
 pub mod stack_overflow;
 pub mod sync;
-pub mod thread;
 pub mod thread_parking;
 pub mod time;
 
@@ -55,10 +54,34 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     // thread-id for the main thread and so renaming the main thread will rename the
     // process and we only want to enable this on platforms we've tested.
     if cfg!(target_vendor = "apple") {
-        thread::Thread::set_name(&c"main");
+        crate::sys::thread::set_name(c"main");
     }
 
     unsafe fn sanitize_standard_fds() {
+        #[allow(dead_code, unused_variables, unused_mut)]
+        let mut opened_devnull = -1;
+        #[allow(dead_code, unused_variables, unused_mut)]
+        let mut open_devnull = || {
+            #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
+            use libc::open;
+            #[cfg(all(target_os = "linux", target_env = "gnu"))]
+            use libc::open64 as open;
+
+            if opened_devnull != -1 {
+                if libc::dup(opened_devnull) != -1 {
+                    return;
+                }
+            }
+            opened_devnull = open(c"/dev/null".as_ptr(), libc::O_RDWR, 0);
+            if opened_devnull == -1 {
+                // If the stream is closed but we failed to reopen it, abort the
+                // process. Otherwise we wouldn't preserve the safety of
+                // operations on the corresponding Rust object Stdin, Stdout, or
+                // Stderr.
+                libc::abort();
+            }
+        };
+
         // fast path with a single syscall for systems with poll()
         #[cfg(not(any(
             miri,
@@ -74,11 +97,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             target_vendor = "apple",
         )))]
         'poll: {
-            #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-            use libc::open as open64;
-            #[cfg(all(target_os = "linux", target_env = "gnu"))]
-            use libc::open64;
-
             use crate::sys::os::errno;
             let pfds: &mut [_] = &mut [
                 libc::pollfd { fd: 0, events: 0, revents: 0 },
@@ -106,13 +124,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
                 if pfd.revents & libc::POLLNVAL == 0 {
                     continue;
                 }
-                if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 {
-                    // If the stream is closed but we failed to reopen it, abort the
-                    // process. Otherwise we wouldn't preserve the safety of
-                    // operations on the corresponding Rust object Stdin, Stdout, or
-                    // Stderr.
-                    libc::abort();
-                }
+                open_devnull();
             }
             return;
         }
@@ -129,21 +141,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             target_os = "vita",
         )))]
         {
-            #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-            use libc::open as open64;
-            #[cfg(all(target_os = "linux", target_env = "gnu"))]
-            use libc::open64;
-
             use crate::sys::os::errno;
             for fd in 0..3 {
                 if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
-                    if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 {
-                        // If the stream is closed but we failed to reopen it, abort the
-                        // process. Otherwise we wouldn't preserve the safety of
-                        // operations on the corresponding Rust object Stdin, Stdout, or
-                        // Stderr.
-                        libc::abort();
-                    }
+                    open_devnull();
                 }
             }
         }
@@ -362,35 +363,42 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
 // multithreaded C program.  It is much less severe for Rust, because Rust
 // stdlib doesn't use libc stdio buffering.  In a typical Rust program, which
 // does not use C stdio, even a buggy libc::abort() is, in fact, safe.
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "android")] {
+cfg_select! {
+    target_os = "android" => {
         #[link(name = "dl", kind = "static", modifiers = "-bundle",
             cfg(target_feature = "crt-static"))]
         #[link(name = "dl", cfg(not(target_feature = "crt-static")))]
         #[link(name = "log", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "freebsd")] {
+    }
+    target_os = "freebsd" => {
         #[link(name = "execinfo")]
         #[link(name = "pthread")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "netbsd")] {
+    }
+    target_os = "netbsd" => {
+        #[link(name = "execinfo")]
         #[link(name = "pthread")]
         #[link(name = "rt")]
         unsafe extern "C" {}
-    } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin"))] {
+    }
+    any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin") => {
         #[link(name = "pthread")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "solaris")] {
+    }
+    target_os = "solaris" => {
         #[link(name = "socket")]
         #[link(name = "posix4")]
         #[link(name = "pthread")]
         #[link(name = "resolv")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "illumos")] {
+    }
+    target_os = "illumos" => {
         #[link(name = "socket")]
         #[link(name = "posix4")]
         #[link(name = "pthread")]
@@ -399,24 +407,29 @@ cfg_if::cfg_if! {
         // Use libumem for the (malloc-compatible) allocator
         #[link(name = "umem")]
         unsafe extern "C" {}
-    } else if #[cfg(target_vendor = "apple")] {
+    }
+    target_vendor = "apple" => {
         // Link to `libSystem.dylib`.
         //
         // Don't get confused by the presence of `System.framework`,
         // it is a deprecated wrapper over the dynamic library.
         #[link(name = "System")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         #[link(name = "zircon")]
         #[link(name = "fdio")]
         unsafe extern "C" {}
-    } else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] {
+    }
+    all(target_os = "linux", target_env = "uclibc") => {
         #[link(name = "dl")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "vita")] {
+    }
+    target_os = "vita" => {
         #[link(name = "pthread", kind = "static", modifiers = "-bundle")]
         unsafe extern "C" {}
     }
+    _ => {}
 }
 
 #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 0e68313cc3e..7c9f3b7992f 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -7,7 +7,6 @@ mod tests;
 
 use libc::{c_char, c_int, c_void};
 
-use crate::error::Error as StdError;
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::os::unix::prelude::*;
 use crate::path::{self, PathBuf};
@@ -17,13 +16,7 @@ use crate::{fmt, io, iter, mem, ptr, slice, str};
 
 const TMPBUF_SZ: usize = 128;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "redox")] {
-        const PATH_SEPARATOR: u8 = b';';
-    } else {
-        const PATH_SEPARATOR: u8 = b':';
-    }
-}
+const PATH_SEPARATOR: u8 = b':';
 
 unsafe extern "C" {
     #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
@@ -193,33 +186,24 @@ pub fn chdir(p: &path::Path) -> io::Result<()> {
     if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
 }
 
-pub struct SplitPaths<'a> {
-    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
-}
+// This can't just be `impl Iterator` because that requires `'a` to be live on
+// drop (see #146045).
+pub type SplitPaths<'a> = iter::Map<
+    slice::Split<'a, u8, impl FnMut(&u8) -> bool + 'static>,
+    impl FnMut(&[u8]) -> PathBuf + 'static,
+>;
 
+#[define_opaque(SplitPaths)]
 pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
-    fn bytes_to_path(b: &[u8]) -> PathBuf {
-        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+    fn is_separator(&b: &u8) -> bool {
+        b == PATH_SEPARATOR
     }
-    fn is_separator(b: &u8) -> bool {
-        *b == PATH_SEPARATOR
-    }
-    let unparsed = unparsed.as_bytes();
-    SplitPaths {
-        iter: unparsed
-            .split(is_separator as fn(&u8) -> bool)
-            .map(bytes_to_path as fn(&[u8]) -> PathBuf),
-    }
-}
 
-impl<'a> Iterator for SplitPaths<'a> {
-    type Item = PathBuf;
-    fn next(&mut self) -> Option<PathBuf> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
+    fn into_pathbuf(part: &[u8]) -> PathBuf {
+        PathBuf::from(OsStr::from_bytes(part))
     }
+
+    unparsed.as_bytes().split(is_separator).map(into_pathbuf)
 }
 
 #[derive(Debug)]
@@ -251,12 +235,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "failed to join paths"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 #[cfg(target_os = "aix")]
 pub fn current_exe() -> io::Result<PathBuf> {
@@ -478,7 +457,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     unsafe {
         let result = libc::find_path(
             crate::ptr::null_mut(),
-            libc::path_base_directory::B_FIND_PATH_IMAGE_PATH,
+            libc::B_FIND_PATH_IMAGE_PATH,
             crate::ptr::null_mut(),
             name.as_mut_ptr(),
             name.len(),
@@ -620,14 +599,10 @@ fn darwin_temp_dir() -> PathBuf {
 
 pub fn temp_dir() -> PathBuf {
     crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
-        cfg_if::cfg_if! {
-            if #[cfg(all(target_vendor = "apple", not(miri)))] {
-                darwin_temp_dir()
-            } else if #[cfg(target_os = "android")] {
-                PathBuf::from("/data/local/tmp")
-            } else {
-                PathBuf::from("/tmp")
-            }
+        cfg_select! {
+            all(target_vendor = "apple", not(miri)) => darwin_temp_dir(),
+            target_os = "android" => PathBuf::from("/data/local/tmp"),
+            _ => PathBuf::from("/tmp"),
         }
     })
 }
diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs
index 55510153dc8..4798acf9dad 100644
--- a/library/std/src/sys/pal/unix/pipe.rs
+++ b/library/std/src/sys/pal/unix/pipe.rs
@@ -18,8 +18,9 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
     // The only known way right now to create atomically set the CLOEXEC flag is
     // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
     // and musl 0.9.3, and some other targets also have it.
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
+            target_os = "android",
             target_os = "dragonfly",
             target_os = "freebsd",
             target_os = "hurd",
@@ -29,12 +30,13 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
             target_os = "openbsd",
             target_os = "cygwin",
             target_os = "redox"
-        ))] {
+        ) => {
             unsafe {
                 cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
                 Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1]))))
             }
-        } else {
+        }
+        _ => {
             unsafe {
                 cvt(libc::pipe(fds.as_mut_ptr()))?;
 
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 0d2100d66bc..51463eef5b7 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -72,7 +72,7 @@ mod imp {
     use crate::sync::OnceLock;
     use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sys::pal::unix::os;
-    use crate::{io, mem, panic, ptr};
+    use crate::{io, mem, ptr};
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
     // (unmapped pages) at the end of every thread's stack, so if a thread ends
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index bd7f74fea6a..c207f41cad4 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -134,28 +134,25 @@ impl Timespec {
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        // When a >= b, the difference fits in u64.
+        fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
+            debug_assert!(a >= b);
+            a.wrapping_sub(b).cast_unsigned()
+        }
+
         if self >= other {
-            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
-            // to optimize it into a branchless form (see also #75545):
-            //
-            // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
-            //    in both branches, i.e. the `else` must have its `- 1`
-            //    subtraction after the common one, not interleaved with it
-            //    (it used to be `self.tv_sec - 1 - other.tv_sec`)
-            //
-            // 2. the `Duration::new` call (or any other additional complexity)
-            //    is outside of the `if`-`else`, not duplicated in both branches
-            //
-            // Ideally this code could be rearranged such that it more
-            // directly expresses the lower-cost behavior we want from it.
             let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() {
                 (
-                    (self.tv_sec - other.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.tv_sec, other.tv_sec),
                     self.tv_nsec.as_inner() - other.tv_nsec.as_inner(),
                 )
             } else {
+                // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow.
+                debug_assert!(self.tv_nsec < other.tv_nsec);
+                debug_assert!(self.tv_sec > other.tv_sec);
+                debug_assert!(self.tv_sec > i64::MIN);
                 (
-                    (self.tv_sec - other.tv_sec - 1) as u64,
+                    sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec),
                     self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(),
                 )
             };
diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs
index c8cf75b876c..a3b980a3f3d 100644
--- a/library/std/src/sys/pal/unix/weak.rs
+++ b/library/std/src/sys/pal/unix/weak.rs
@@ -22,11 +22,24 @@
 #![allow(dead_code, unused_macros)]
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use crate::ffi::CStr;
-use crate::marker::PhantomData;
-use crate::sync::atomic::{self, Atomic, AtomicPtr, Ordering};
+use crate::ffi::{CStr, c_char, c_void};
+use crate::marker::{FnPtr, PhantomData};
+use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 use crate::{mem, ptr};
 
+// We currently only test `dlsym!`, but that doesn't work on all platforms, so
+// we gate the tests to only the platforms where it is actually used.
+//
+// FIXME(joboet): add more tests, reorganise the whole module and get rid of
+//                `#[allow(dead_code, unused_macros)]`.
+#[cfg(any(
+    target_vendor = "apple",
+    all(target_os = "linux", target_env = "gnu"),
+    target_os = "freebsd",
+))]
+#[cfg(test)]
+mod tests;
+
 // We can use true weak linkage on ELF targets.
 #[cfg(all(unix, not(target_vendor = "apple")))]
 pub(crate) macro weak {
@@ -64,7 +77,7 @@ impl<F: Copy> ExternWeak<F> {
 
 pub(crate) macro dlsym {
     (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
-         dlsym!(
+        dlsym!(
             #[link_name = stringify!($name)]
             fn $name($($param : $t),*) -> $ret;
         );
@@ -73,21 +86,39 @@ pub(crate) macro dlsym {
         #[link_name = $sym:expr]
         fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
     ) => (
-        static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
-            DlsymWeak::new(concat!($sym, '\0'));
+        static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+            let Ok(name) = CStr::from_bytes_with_nul(concat!($sym, '\0').as_bytes()) else {
+                panic!("symbol name may not contain NUL")
+            };
+
+            // SAFETY: Whoever calls the function pointer returned by `get()`
+            // is responsible for ensuring that the signature is correct. Just
+            // like with extern blocks, this is syntactically enforced by making
+            // the function pointer be unsafe.
+            unsafe { DlsymWeak::new(name) }
+        };
+
         let $name = &DLSYM;
     )
 }
+
 pub(crate) struct DlsymWeak<F> {
-    name: &'static str,
+    /// A pointer to the nul-terminated name of the symbol.
+    // Use a pointer instead of `&'static CStr` to save space.
+    name: *const c_char,
     func: Atomic<*mut libc::c_void>,
     _marker: PhantomData<F>,
 }
 
-impl<F> DlsymWeak<F> {
-    pub(crate) const fn new(name: &'static str) -> Self {
+impl<F: FnPtr> DlsymWeak<F> {
+    /// # Safety
+    ///
+    /// If the signature of `F` does not match the signature of the symbol (if
+    /// it exists), calling the function pointer returned by `get()` is
+    /// undefined behaviour.
+    pub(crate) const unsafe fn new(name: &'static CStr) -> Self {
         DlsymWeak {
-            name,
+            name: name.as_ptr(),
             func: AtomicPtr::new(ptr::without_provenance_mut(1)),
             _marker: PhantomData,
         }
@@ -95,62 +126,59 @@ impl<F> DlsymWeak<F> {
 
     #[inline]
     pub(crate) fn get(&self) -> Option<F> {
-        unsafe {
-            // Relaxed is fine here because we fence before reading through the
-            // pointer (see the comment below).
-            match self.func.load(Ordering::Relaxed) {
-                func if func.addr() == 1 => self.initialize(),
-                func if func.is_null() => None,
-                func => {
-                    let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
-                    // The caller is presumably going to read through this value
-                    // (by calling the function we've dlsymed). This means we'd
-                    // need to have loaded it with at least C11's consume
-                    // ordering in order to be guaranteed that the data we read
-                    // from the pointer isn't from before the pointer was
-                    // stored. Rust has no equivalent to memory_order_consume,
-                    // so we use an acquire fence (sorry, ARM).
-                    //
-                    // Now, in practice this likely isn't needed even on CPUs
-                    // where relaxed and consume mean different things. The
-                    // symbols we're loading are probably present (or not) at
-                    // init, and even if they aren't the runtime dynamic loader
-                    // is extremely likely have sufficient barriers internally
-                    // (possibly implicitly, for example the ones provided by
-                    // invoking `mprotect`).
-                    //
-                    // That said, none of that's *guaranteed*, and so we fence.
-                    atomic::fence(Ordering::Acquire);
-                    Some(func)
-                }
-            }
+        // The caller is presumably going to read through this value
+        // (by calling the function we've dlsymed). This means we'd
+        // need to have loaded it with at least C11's consume
+        // ordering in order to be guaranteed that the data we read
+        // from the pointer isn't from before the pointer was
+        // stored. Rust has no equivalent to memory_order_consume,
+        // so we use an acquire load (sorry, ARM).
+        //
+        // Now, in practice this likely isn't needed even on CPUs
+        // where relaxed and consume mean different things. The
+        // symbols we're loading are probably present (or not) at
+        // init, and even if they aren't the runtime dynamic loader
+        // is extremely likely have sufficient barriers internally
+        // (possibly implicitly, for example the ones provided by
+        // invoking `mprotect`).
+        //
+        // That said, none of that's *guaranteed*, so we use acquire.
+        match self.func.load(Ordering::Acquire) {
+            func if func.addr() == 1 => self.initialize(),
+            func if func.is_null() => None,
+            // SAFETY:
+            // `func` is not null and `F` implements `FnPtr`, thus this
+            // transmutation is well-defined. It is the responsibility of the
+            // creator of this `DlsymWeak` to ensure that calling the resulting
+            // function pointer does not result in undefined behaviour (though
+            // the `dlsym!` macro delegates this responsibility to the caller
+            // of the function by using `unsafe` function pointers).
+            // FIXME: use `transmute` once it stops complaining about generics.
+            func => Some(unsafe { mem::transmute_copy::<*mut c_void, F>(&func) }),
         }
     }
 
     // Cold because it should only happen during first-time initialization.
     #[cold]
-    unsafe fn initialize(&self) -> Option<F> {
-        assert_eq!(size_of::<F>(), size_of::<*mut libc::c_void>());
-
-        let val = unsafe { fetch(self.name) };
-        // This synchronizes with the acquire fence in `get`.
+    fn initialize(&self) -> Option<F> {
+        // SAFETY: `self.name` was created from a `&'static CStr` and is
+        // therefore a valid C string pointer.
+        let val = unsafe { libc::dlsym(libc::RTLD_DEFAULT, self.name) };
+        // This synchronizes with the acquire load in `get`.
         self.func.store(val, Ordering::Release);
 
         if val.is_null() {
             None
         } else {
+            // SAFETY: see the comment in `get`.
+            // FIXME: use `transmute` once it stops complaining about generics.
             Some(unsafe { mem::transmute_copy::<*mut libc::c_void, F>(&val) })
         }
     }
 }
 
-unsafe fn fetch(name: &str) -> *mut libc::c_void {
-    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
-        Ok(cstr) => cstr,
-        Err(..) => return ptr::null_mut(),
-    };
-    unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) }
-}
+unsafe impl<F> Send for DlsymWeak<F> {}
+unsafe impl<F> Sync for DlsymWeak<F> {}
 
 #[cfg(not(any(target_os = "linux", target_os = "android")))]
 pub(crate) macro syscall {
diff --git a/library/std/src/sys/pal/unix/weak/tests.rs b/library/std/src/sys/pal/unix/weak/tests.rs
new file mode 100644
index 00000000000..d807ba64e35
--- /dev/null
+++ b/library/std/src/sys/pal/unix/weak/tests.rs
@@ -0,0 +1,32 @@
+use super::*;
+
+#[test]
+fn dlsym_existing() {
+    const TEST_STRING: &'static CStr = c"Ferris!";
+
+    // Try to find a symbol that definitely exists.
+    dlsym! {
+        fn strlen(cs: *const c_char) -> usize;
+    }
+
+    dlsym! {
+        #[link_name = "strlen"]
+        fn custom_name(cs: *const c_char) -> usize;
+    }
+
+    let strlen = strlen.get().unwrap();
+    assert_eq!(unsafe { strlen(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
+
+    let custom_name = custom_name.get().unwrap();
+    assert_eq!(unsafe { custom_name(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
+}
+
+#[test]
+fn dlsym_missing() {
+    // Try to find a symbol that definitely does not exist.
+    dlsym! {
+        fn test_symbol_that_does_not_exist() -> i32;
+    }
+
+    assert!(test_symbol_that_does_not_exist.get().is_none());
+}
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index 5e3295b1331..e64bbc7c616 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -2,7 +2,6 @@
 
 pub mod os;
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 mod common;
diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs
index a8ef97ecf67..13d2a2044f4 100644
--- a/library/std/src/sys/pal/unsupported/os.rs
+++ b/library/std/src/sys/pal/unsupported/os.rs
@@ -1,5 +1,4 @@
 use super::unsupported;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::path::{self, PathBuf};
@@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs
new file mode 100644
index 00000000000..61a34b0f68a
--- /dev/null
+++ b/library/std/src/sys/pal/vexos/mod.rs
@@ -0,0 +1,80 @@
+#[path = "../unsupported/os.rs"]
+pub mod os;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+pub mod time;
+
+#[expect(dead_code)]
+#[path = "../unsupported/common.rs"]
+mod unsupported_common;
+
+pub use unsupported_common::{
+    decode_error_kind, init, is_interrupted, unsupported, unsupported_err,
+};
+
+use crate::arch::global_asm;
+use crate::ptr;
+use crate::sys::stdio;
+use crate::time::{Duration, Instant};
+
+global_asm!(
+    r#"
+    .section .boot, "ax"
+    .global _boot
+
+    _boot:
+        ldr sp, =__stack_top @ Set up the user stack.
+        b _start             @ Jump to the Rust entrypoint.
+    "#
+);
+
+#[cfg(not(test))]
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn _start() -> ! {
+    unsafe extern "C" {
+        static mut __bss_start: u8;
+        static mut __bss_end: u8;
+
+        fn main() -> i32;
+    }
+
+    // Clear the .bss (uninitialized statics) section by filling it with zeroes.
+    // This is required, since the compiler assumes it will be zeroed on first access.
+    ptr::write_bytes(
+        &raw mut __bss_start,
+        0,
+        (&raw mut __bss_end).offset_from_unsigned(&raw mut __bss_start),
+    );
+
+    main();
+
+    cleanup();
+    abort_internal()
+}
+
+// SAFETY: must be called only once during runtime cleanup.
+// NOTE: this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {
+    let exit_time = Instant::now();
+    const FLUSH_TIMEOUT: Duration = Duration::from_millis(15);
+
+    // Force the serial buffer to flush
+    while exit_time.elapsed() < FLUSH_TIMEOUT {
+        vex_sdk::vexTasksRun();
+
+        // If the buffer has been fully flushed, exit the loop
+        if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) {
+            break;
+        }
+    }
+}
+
+pub fn abort_internal() -> ! {
+    unsafe {
+        vex_sdk::vexSystemExitRequest();
+
+        loop {
+            vex_sdk::vexTasksRun();
+        }
+    }
+}
diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs
new file mode 100644
index 00000000000..f95d96cd27a
--- /dev/null
+++ b/library/std/src/sys/pal/vexos/time.rs
@@ -0,0 +1,28 @@
+use crate::time::Duration;
+
+#[expect(dead_code)]
+#[path = "../unsupported/time.rs"]
+mod unsupported_time;
+pub use unsupported_time::{SystemTime, UNIX_EPOCH};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+impl Instant {
+    pub fn now() -> Instant {
+        let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() };
+        Self(Duration::from_micros(micros))
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.0.checked_sub(other.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_sub(*other)?))
+    }
+}
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
deleted file mode 100644
index 4755e2ef5da..00000000000
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::CStr;
-use crate::num::NonZero;
-use crate::time::{Duration, Instant};
-use crate::{io, mem};
-
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
-        use crate::cmp;
-        use crate::ptr;
-        use crate::sys::os;
-        // Add a few symbols not in upstream `libc` just yet.
-        mod libc {
-            pub use crate::ffi;
-            pub use libc::*;
-
-            // defined in wasi-libc
-            // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
-            #[repr(C)]
-            union pthread_attr_union {
-                __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
-            }
-
-            #[repr(C)]
-            pub struct pthread_attr_t {
-                __u: pthread_attr_union,
-            }
-
-            #[allow(non_camel_case_types)]
-            pub type pthread_t = *mut ffi::c_void;
-
-            pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
-
-            unsafe extern "C" {
-                pub fn pthread_create(
-                    native: *mut pthread_t,
-                    attr: *const pthread_attr_t,
-                    f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
-                    value: *mut ffi::c_void,
-                ) -> ffi::c_int;
-                pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
-                pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
-                pub fn pthread_attr_setstacksize(
-                    attr: *mut pthread_attr_t,
-                    stack_size: libc::size_t,
-                ) -> ffi::c_int;
-                pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
-                pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
-            }
-        }
-
-        pub struct Thread {
-            id: libc::pthread_t,
-        }
-
-        impl Drop for Thread {
-            fn drop(&mut self) {
-                let ret = unsafe { libc::pthread_detach(self.id) };
-                debug_assert_eq!(ret, 0);
-            }
-        }
-    } else {
-        pub struct Thread(!);
-    }
-}
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    cfg_if::cfg_if! {
-        if #[cfg(target_feature = "atomics")] {
-            pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-                let p = Box::into_raw(Box::new(p));
-                let mut native: libc::pthread_t = unsafe { mem::zeroed() };
-                let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
-                assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
-
-                let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
-
-                match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
-                    0 => {}
-                    n => {
-                        assert_eq!(n, libc::EINVAL);
-                        // EINVAL means |stack_size| is either too small or not a
-                        // multiple of the system page size. Because it's definitely
-                        // >= PTHREAD_STACK_MIN, it must be an alignment issue.
-                        // Round up to the nearest page and try again.
-                        let page_size = os::page_size();
-                        let stack_size =
-                            (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
-                        assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
-                    }
-                };
-
-                let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
-                // Note: if the thread creation fails and this assert fails, then p will
-                // be leaked. However, an alternative design could cause double-free
-                // which is clearly worse.
-                assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0);
-
-                return if ret != 0 {
-                    // The thread failed to start and as a result p was not consumed. Therefore, it is
-                    // safe to reconstruct the box so that it gets deallocated.
-                    unsafe { drop(Box::from_raw(p)); }
-                    Err(io::Error::from_raw_os_error(ret))
-                } else {
-                    Ok(Thread { id: native })
-                };
-
-                extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
-                    unsafe {
-                        // Finally, let's run some code.
-                        Box::from_raw(main as *mut Box<dyn FnOnce()>)();
-                    }
-                    ptr::null_mut()
-                }
-            }
-        } else {
-            pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-                crate::sys::unsupported()
-            }
-        }
-    }
-
-    pub fn yield_now() {
-        let ret = unsafe { wasi::sched_yield() };
-        debug_assert_eq!(ret, Ok(()));
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        let mut nanos = dur.as_nanos();
-        while nanos > 0 {
-            const USERDATA: wasi::Userdata = 0x0123_45678;
-
-            let clock = wasi::SubscriptionClock {
-                id: wasi::CLOCKID_MONOTONIC,
-                timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
-                precision: 0,
-                flags: 0,
-            };
-            nanos -= u128::from(clock.timeout);
-
-            let in_ = wasi::Subscription {
-                userdata: USERDATA,
-                u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
-            };
-            unsafe {
-                let mut event: wasi::Event = mem::zeroed();
-                let res = wasi::poll_oneoff(&in_, &mut event, 1);
-                match (res, event) {
-                    (
-                        Ok(1),
-                        wasi::Event {
-                            userdata: USERDATA,
-                            error: wasi::ERRNO_SUCCESS,
-                            type_: wasi::EVENTTYPE_CLOCK,
-                            ..
-                        },
-                    ) => {}
-                    _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
-                }
-            }
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {
-        cfg_if::cfg_if! {
-            if #[cfg(target_feature = "atomics")] {
-                let id = mem::ManuallyDrop::new(self).id;
-                let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
-                if ret != 0 {
-                    rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
-                }
-            } else {
-                self.0
-            }
-        }
-    }
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    cfg_if::cfg_if! {
-        if #[cfg(target_feature = "atomics")] {
-            match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-                -1 => Err(io::Error::last_os_error()),
-                cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
-            }
-        } else {
-            crate::sys::unsupported()
-        }
-    }
-}
diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasip1/helpers.rs
index 404747f0dc7..404747f0dc7 100644
--- a/library/std/src/sys/pal/wasi/helpers.rs
+++ b/library/std/src/sys/pal/wasip1/helpers.rs
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs
index 61dd1c3f98b..ae5da3c1f77 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasip1/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasip1/os.rs
index 672cf70d1a5..151ba254ec4 100644
--- a/library/std/src/sys/pal/wasi/os.rs
+++ b/library/std/src/sys/pal/wasip1/os.rs
@@ -1,6 +1,5 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use crate::error::Error as StdError;
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::os::wasi::prelude::*;
@@ -105,12 +104,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on wasm yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasip1/time.rs
index 0d8d0b59ac1..0d8d0b59ac1 100644
--- a/library/std/src/sys/pal/wasi/time.rs
+++ b/library/std/src/sys/pal/wasip1/time.rs
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 47fe3221c90..c1d89da2677 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -10,13 +10,10 @@
 #[path = "../wasm/atomics/futex.rs"]
 pub mod futex;
 
-#[path = "../wasi/os.rs"]
+#[path = "../wasip1/os.rs"]
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../wasi/thread.rs"]
-pub mod thread;
-#[path = "../wasi/time.rs"]
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
@@ -26,7 +23,7 @@ mod common;
 
 pub use common::*;
 
-#[path = "../wasi/helpers.rs"]
+#[path = "../wasip1/helpers.rs"]
 mod helpers;
 
 // The following exports are listed individually to work around Rust's glob
diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs
new file mode 100644
index 00000000000..43489183994
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/time.rs
@@ -0,0 +1,58 @@
+use crate::time::Duration;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+    pub fn now() -> Instant {
+        Instant(Duration::from_nanos(wasip2::clocks::monotonic_clock::now()))
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.0.checked_sub(other.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_sub(*other)?))
+    }
+
+    pub(crate) fn as_duration(&self) -> &Duration {
+        &self.0
+    }
+}
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        let now = wasip2::clocks::wall_clock::now();
+        SystemTime(Duration::new(now.seconds, now.nanoseconds))
+    }
+
+    pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
+        SystemTime(Duration::from_nanos(ts))
+    }
+
+    pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
+        self.0.as_nanos().try_into().ok()
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_sub(*other)?))
+    }
+}
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
deleted file mode 100644
index 42a7dbdf8b8..00000000000
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use crate::ffi::CStr;
-use crate::io;
-use crate::num::NonZero;
-use crate::sys::unsupported;
-use crate::time::{Duration, Instant};
-
-pub struct Thread(!);
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(
-        _stack: usize,
-        _name: Option<&str>,
-        _p: Box<dyn FnOnce()>,
-    ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {}
-
-    pub fn set_name(_name: &CStr) {}
-
-    pub fn sleep(dur: Duration) {
-        #[cfg(target_arch = "wasm32")]
-        use core::arch::wasm32 as wasm;
-        #[cfg(target_arch = "wasm64")]
-        use core::arch::wasm64 as wasm;
-
-        use crate::cmp;
-
-        // Use an atomic wait to block the current thread artificially with a
-        // timeout listed. Note that we should never be notified (return value
-        // of 0) or our comparison should never fail (return value of 1) so we
-        // should always only resume execution through a timeout (return value
-        // 2).
-        let mut nanos = dur.as_nanos();
-        while nanos > 0 {
-            let amt = cmp::min(i64::MAX as u128, nanos);
-            let mut x = 0;
-            let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
-            debug_assert_eq!(val, 2);
-            nanos -= amt;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {}
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
-}
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 37cb46a8f6b..a20cd0e9ac7 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -23,17 +23,9 @@ pub mod pipe;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
-        #[path = "atomics/futex.rs"]
-        pub mod futex;
-        #[path = "atomics/thread.rs"]
-        pub mod thread;
-    } else {
-        #[path = "../unsupported/thread.rs"]
-        pub mod thread;
-    }
-}
+#[cfg(target_feature = "atomics")]
+#[path = "atomics/futex.rs"]
+pub mod futex;
 
 #[path = "../unsupported/common.rs"]
 #[deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index edac5262a4e..25c1a82cc42 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -95,11 +95,8 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
 }
 
 // Desktop specific functions & types
-cfg_if::cfg_if! {
-if #[cfg(not(target_vendor = "uwp"))] {
-    pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
-}
-}
+#[cfg(not(target_vendor = "uwp"))]
+pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
 
 // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
 #[cfg(not(target_vendor = "win7"))]
@@ -230,12 +227,13 @@ compat_fn_with_fallback! {
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "uwp")] {
+cfg_select! {
+    target_vendor = "uwp" => {
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
     }
+    _ => {}
 }
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index c8e4dca4781..abc1c19827f 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2158,6 +2158,7 @@ GetCurrentDirectoryW
 GetCurrentProcess
 GetCurrentProcessId
 GetCurrentThread
+GetCurrentThreadId
 GetEnvironmentStringsW
 GetEnvironmentVariableW
 GetExitCodeProcess
@@ -2185,7 +2186,6 @@ GetSystemInfo
 GetSystemTimeAsFileTime
 GetSystemTimePreciseAsFileTime
 GetTempPathW
-GetThreadId
 GetUserProfileDirectoryW
 GetWindowsDirectoryW
 HANDLE
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 45a273d241a..989a1246650 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -38,6 +38,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferle
 windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
 windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
 windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn GetCurrentThreadId() -> u32);
 windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR);
 windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL);
@@ -61,7 +62,6 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
-windows_targets::link!("kernel32.dll" "system" fn GetThreadId(thread : HANDLE) -> u32);
 windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index 82a880faf5f..76c8aa939d3 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -136,6 +136,19 @@ impl Handle {
         }
     }
 
+    pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
+        // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
+        let read = unsafe {
+            self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset))
+        }?;
+
+        // SAFETY: `read` bytes were written to the initialized portion of the buffer
+        unsafe {
+            cursor.advance_unchecked(read);
+        }
+        Ok(())
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let mut me = self;
 
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 8f54e2376eb..3357946b8f7 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -20,12 +20,12 @@ pub mod futex;
 pub mod handle;
 pub mod os;
 pub mod pipe;
-pub mod thread;
 pub mod time;
-cfg_if::cfg_if! {
-    if #[cfg(not(target_vendor = "uwp"))] {
+cfg_select! {
+    not(target_vendor = "uwp") => {
         pub mod stack_overflow;
-    } else {
+    }
+    _ => {
         pub mod stack_overflow_uwp;
         pub use self::stack_overflow_uwp as stack_overflow;
     }
@@ -47,9 +47,9 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
     unsafe {
         stack_overflow::init();
 
-        // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+        // Normally, `thread::spawn` will call `set_name` but since this thread already
         // exists, we have to call it ourselves.
-        thread::Thread::set_name_wide(wide_str!("main"));
+        crate::sys::thread::set_name_wide(wide_str!("main"));
     }
 }
 
@@ -337,14 +337,17 @@ pub fn dur2timeout(dur: Duration) -> u32 {
 #[cfg(not(miri))] // inline assembly does not work in Miri
 pub fn abort_internal() -> ! {
     unsafe {
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+        cfg_select! {
+            any(target_arch = "x86", target_arch = "x86_64") => {
                 core::arch::asm!("int $$0x29", in("ecx") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
+            }
+            all(target_arch = "arm", target_feature = "thumb-mode") => {
                 core::arch::asm!(".inst 0xDEFB", in("r0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] {
+            }
+            any(target_arch = "aarch64", target_arch = "arm64ec") => {
                 core::arch::asm!("brk 0xF003", in("x0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else {
+            }
+            _ => {
                 core::intrinsics::abort();
             }
         }
@@ -352,6 +355,7 @@ pub fn abort_internal() -> ! {
 }
 
 #[cfg(miri)]
+#[track_caller] // even without panics, this helps for Miri backtraces
 pub fn abort_internal() -> ! {
     crate::intrinsics::abort();
 }
diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs
index f331282d2d7..1b3c80c079b 100644
--- a/library/std/src/sys/pal/windows/os.rs
+++ b/library/std/src/sys/pal/windows/os.rs
@@ -8,7 +8,6 @@ mod tests;
 use super::api;
 #[cfg(not(target_vendor = "uwp"))]
 use super::api::WinError;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::os::windows::ffi::EncodeWide;
 use crate::os::windows::prelude::*;
@@ -162,12 +161,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "failed to join paths"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     super::fill_utf16_buf(
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index 68126bd8d2f..0d31b80e56a 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -224,7 +224,7 @@ mod perf_counter {
 }
 
 /// A timer you can wait on.
-pub(super) struct WaitableTimer {
+pub(crate) struct WaitableTimer {
     handle: c::HANDLE,
 }
 impl WaitableTimer {
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 042c4ff862f..e673157e0eb 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -5,7 +5,6 @@ use crate::os::xous::ffi::exit;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs
index d612a27d2bd..d9b8418e6c3 100644
--- a/library/std/src/sys/pal/xous/os.rs
+++ b/library/std/src/sys/pal/xous/os.rs
@@ -1,5 +1,4 @@
 use super::unsupported;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::os::xous::ffi::Error as XousError;
@@ -110,12 +109,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index e1efa240685..9069c8d12fa 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -14,8 +14,6 @@ pub mod abi;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/thread.rs"]
-pub mod thread;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs
index a8ef97ecf67..13d2a2044f4 100644
--- a/library/std/src/sys/pal/zkvm/os.rs
+++ b/library/std/src/sys/pal/zkvm/os.rs
@@ -1,5 +1,4 @@
 use super::unsupported;
-use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::path::{self, PathBuf};
@@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl crate::error::Error for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs
index a4ff4338cf5..254683bc83f 100644
--- a/library/std/src/sys/path/mod.rs
+++ b/library/std/src/sys/path/mod.rs
@@ -1,22 +1,27 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "windows")] {
+cfg_select! {
+    target_os = "windows" => {
         mod windows;
         mod windows_prefix;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod unsupported_backslash;
         pub use unsupported_backslash::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "cygwin")] {
+    }
+    target_os = "cygwin" => {
         mod cygwin;
         mod windows_prefix;
         pub use cygwin::*;
-    } else {
+    }
+    _ => {
         mod unix;
         pub use unix::*;
     }
diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs
index 75e793f18b8..019d5629d6d 100644
--- a/library/std/src/sys/personality/gcc.rs
+++ b/library/std/src/sys/personality/gcc.rs
@@ -93,12 +93,12 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
 // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
 
-cfg_if::cfg_if! {
-    if #[cfg(all(
+cfg_select! {
+    all(
         target_arch = "arm",
         not(target_vendor = "apple"),
         not(target_os = "netbsd"),
-    ))] {
+    ) => {
         /// personality fn called by [ARM EHABI][armeabi-eh]
         ///
         /// 32-bit ARM on iOS/tvOS/watchOS does not use ARM EHABI, it uses
@@ -202,7 +202,8 @@ cfg_if::cfg_if! {
                 }
             }
         }
-    } else {
+    }
+    _ => {
         /// Default personality routine, which is used directly on most targets
         /// and indirectly on Windows x86_64 and AArch64 via SEH.
         unsafe extern "C" fn rust_eh_personality_impl(
@@ -247,11 +248,11 @@ cfg_if::cfg_if! {
             }
         }
 
-        cfg_if::cfg_if! {
-            if #[cfg(any(
-                    all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
-                    target_os = "cygwin",
-                ))] {
+        cfg_select! {
+            any(
+                all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
+                target_os = "cygwin",
+            ) => {
                 /// personality fn called by [Windows Structured Exception Handling][windows-eh]
                 ///
                 /// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH,
@@ -279,7 +280,8 @@ cfg_if::cfg_if! {
                         )
                     }
                 }
-            } else {
+            }
+            _ => {
                 /// personality fn called by [Itanium C++ ABI Exception Handling][itanium-eh]
                 ///
                 /// The personality routine for most non-Windows targets. This will be called by
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 2e1d2e53a29..158e44e1764 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -13,10 +13,11 @@
 mod dwarf;
 
 #[cfg(not(any(test, doctest)))]
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "emscripten")] {
+cfg_select! {
+    target_os = "emscripten" => {
         mod emcc;
-    } else if #[cfg(any(target_env = "msvc", target_family = "wasm"))] {
+    }
+    any(target_env = "msvc", target_family = "wasm") => {
         // This is required by the compiler to exist (e.g., it's a lang item),
         // but it's never actually called by the compiler because
         // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the
@@ -26,16 +27,18 @@ cfg_if::cfg_if! {
         fn rust_eh_personality() {
             core::intrinsics::abort()
         }
-    } else if #[cfg(any(
+    }
+    any(
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
         target_os = "xous",
         target_os = "solid_asp3",
         all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")),
         all(target_vendor = "fortanix", target_env = "sgx"),
-    ))] {
+    ) => {
         mod gcc;
-    } else {
+    }
+    _ => {
         // Targets that don't support unwinding.
         // - os=none ("bare metal" targets)
         // - os=uefi
diff --git a/library/std/src/sys/platform_version/darwin/core_foundation.rs b/library/std/src/sys/platform_version/darwin/core_foundation.rs
new file mode 100644
index 00000000000..1e0d15fcf66
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/core_foundation.rs
@@ -0,0 +1,180 @@
+//! Minimal utilities for interfacing with a dynamically loaded CoreFoundation.
+#![allow(non_snake_case, non_upper_case_globals)]
+use super::root_relative;
+use crate::ffi::{CStr, c_char, c_void};
+use crate::ptr::null_mut;
+use crate::sys::common::small_c_string::run_path_with_cstr;
+
+// MacTypes.h
+pub(super) type Boolean = u8;
+// CoreFoundation/CFBase.h
+pub(super) type CFTypeID = usize;
+pub(super) type CFOptionFlags = usize;
+pub(super) type CFIndex = isize;
+pub(super) type CFTypeRef = *mut c_void;
+pub(super) type CFAllocatorRef = CFTypeRef;
+pub(super) const kCFAllocatorDefault: CFAllocatorRef = null_mut();
+// CoreFoundation/CFError.h
+pub(super) type CFErrorRef = CFTypeRef;
+// CoreFoundation/CFData.h
+pub(super) type CFDataRef = CFTypeRef;
+// CoreFoundation/CFPropertyList.h
+pub(super) const kCFPropertyListImmutable: CFOptionFlags = 0;
+pub(super) type CFPropertyListFormat = CFIndex;
+pub(super) type CFPropertyListRef = CFTypeRef;
+// CoreFoundation/CFString.h
+pub(super) type CFStringRef = CFTypeRef;
+pub(super) type CFStringEncoding = u32;
+pub(super) const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100;
+// CoreFoundation/CFDictionary.h
+pub(super) type CFDictionaryRef = CFTypeRef;
+
+/// An open handle to the dynamically loaded CoreFoundation framework.
+///
+/// This is `dlopen`ed, and later `dlclose`d. This is done to try to avoid
+/// "leaking" the CoreFoundation symbols to the rest of the user's binary if
+/// they decided to not link CoreFoundation themselves.
+///
+/// It is also faster to look up symbols directly via this handle than with
+/// `RTLD_DEFAULT`.
+pub(super) struct CFHandle(*mut c_void);
+
+macro_rules! dlsym_fn {
+    (
+        unsafe fn $name:ident($($param:ident: $param_ty:ty),* $(,)?) $(-> $ret:ty)?;
+    ) => {
+        pub(super) unsafe fn $name(&self, $($param: $param_ty),*) $(-> $ret)? {
+            let ptr = unsafe {
+                libc::dlsym(
+                    self.0,
+                    concat!(stringify!($name), '\0').as_bytes().as_ptr().cast(),
+                )
+            };
+            if ptr.is_null() {
+                let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+                panic!("could not find function {}: {err:?}", stringify!($name));
+            }
+
+            // SAFETY: Just checked that the symbol isn't NULL, and macro invoker verifies that
+            // the signature is correct.
+            let fnptr = unsafe {
+                crate::mem::transmute::<
+                    *mut c_void,
+                    unsafe extern "C" fn($($param_ty),*) $(-> $ret)?,
+                >(ptr)
+            };
+
+            // SAFETY: Upheld by caller.
+            unsafe { fnptr($($param),*) }
+        }
+    };
+}
+
+impl CFHandle {
+    /// Link to the CoreFoundation dylib, and look up symbols from that.
+    pub(super) fn new() -> Self {
+        // We explicitly use non-versioned path here, to allow this to work on older iOS devices.
+        let cf_path =
+            root_relative("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");
+
+        let handle = run_path_with_cstr(&cf_path, &|path| unsafe {
+            Ok(libc::dlopen(path.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL))
+        })
+        .expect("failed allocating string");
+
+        if handle.is_null() {
+            let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+            panic!("could not open CoreFoundation.framework: {err:?}");
+        }
+
+        Self(handle)
+    }
+
+    pub(super) fn kCFAllocatorNull(&self) -> CFAllocatorRef {
+        // Available: in all CF versions.
+        let static_ptr = unsafe { libc::dlsym(self.0, c"kCFAllocatorNull".as_ptr()) };
+        if static_ptr.is_null() {
+            let err = unsafe { CStr::from_ptr(libc::dlerror()) };
+            panic!("could not find kCFAllocatorNull: {err:?}");
+        }
+        unsafe { *static_ptr.cast() }
+    }
+
+    // CoreFoundation/CFBase.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFRelease(cf: CFTypeRef);
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
+    );
+
+    // CoreFoundation/CFData.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDataCreateWithBytesNoCopy(
+            allocator: CFAllocatorRef,
+            bytes: *const u8,
+            length: CFIndex,
+            bytes_deallocator: CFAllocatorRef,
+        ) -> CFDataRef;
+    );
+
+    // CoreFoundation/CFPropertyList.h
+    dlsym_fn!(
+        // Available: since macOS 10.6.
+        unsafe fn CFPropertyListCreateWithData(
+            allocator: CFAllocatorRef,
+            data: CFDataRef,
+            options: CFOptionFlags,
+            format: *mut CFPropertyListFormat,
+            error: *mut CFErrorRef,
+        ) -> CFPropertyListRef;
+    );
+
+    // CoreFoundation/CFString.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringGetTypeID() -> CFTypeID;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringCreateWithCStringNoCopy(
+            alloc: CFAllocatorRef,
+            c_str: *const c_char,
+            encoding: CFStringEncoding,
+            contents_deallocator: CFAllocatorRef,
+        ) -> CFStringRef;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFStringGetCString(
+            the_string: CFStringRef,
+            buffer: *mut c_char,
+            buffer_size: CFIndex,
+            encoding: CFStringEncoding,
+        ) -> Boolean;
+    );
+
+    // CoreFoundation/CFDictionary.h
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDictionaryGetTypeID() -> CFTypeID;
+    );
+    dlsym_fn!(
+        // Available: in all CF versions.
+        unsafe fn CFDictionaryGetValue(
+            the_dict: CFDictionaryRef,
+            key: *const c_void,
+        ) -> *const c_void;
+    );
+}
+
+impl Drop for CFHandle {
+    fn drop(&mut self) {
+        // Ignore errors when closing. This is also what `libloading` does:
+        // https://docs.rs/libloading/0.8.6/src/libloading/os/unix/mod.rs.html#374
+        let _ = unsafe { libc::dlclose(self.0) };
+    }
+}
diff --git a/library/std/src/sys/platform_version/darwin/mod.rs b/library/std/src/sys/platform_version/darwin/mod.rs
new file mode 100644
index 00000000000..06b97fcdef4
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/mod.rs
@@ -0,0 +1,351 @@
+use self::core_foundation::{
+    CFDictionaryRef, CFHandle, CFIndex, CFStringRef, CFTypeRef, kCFAllocatorDefault,
+    kCFPropertyListImmutable, kCFStringEncodingUTF8,
+};
+use crate::borrow::Cow;
+use crate::bstr::ByteStr;
+use crate::ffi::{CStr, c_char};
+use crate::num::{NonZero, ParseIntError};
+use crate::path::{Path, PathBuf};
+use crate::ptr::null_mut;
+use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::{env, fs};
+
+mod core_foundation;
+mod public_extern;
+#[cfg(test)]
+mod tests;
+
+/// The version of the operating system.
+///
+/// We use a packed u32 here to allow for fast comparisons and to match Mach-O's `LC_BUILD_VERSION`.
+type OSVersion = u32;
+
+/// Combine parts of a version into an [`OSVersion`].
+///
+/// The size of the parts are inherently limited by Mach-O's `LC_BUILD_VERSION`.
+#[inline]
+const fn pack_os_version(major: u16, minor: u8, patch: u8) -> OSVersion {
+    let (major, minor, patch) = (major as u32, minor as u32, patch as u32);
+    (major << 16) | (minor << 8) | patch
+}
+
+/// [`pack_os_version`], but takes `i32` and saturates.
+///
+/// Instead of using e.g. `major as u16`, which truncates.
+#[inline]
+fn pack_i32_os_version(major: i32, minor: i32, patch: i32) -> OSVersion {
+    let major: u16 = major.try_into().unwrap_or(u16::MAX);
+    let minor: u8 = minor.try_into().unwrap_or(u8::MAX);
+    let patch: u8 = patch.try_into().unwrap_or(u8::MAX);
+    pack_os_version(major, minor, patch)
+}
+
+/// Get the current OS version, packed according to [`pack_os_version`].
+///
+/// # Semantics
+///
+/// The reported version on macOS might be 10.16 if the SDK version of the binary is less than 11.0.
+/// This is a workaround that Apple implemented to handle applications that assumed that macOS
+/// versions would always start with "10", see:
+/// <https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/libsyscall/wrappers/system-version-compat.c>
+///
+/// It _is_ possible to get the real version regardless of the SDK version of the binary, this is
+/// what Zig does:
+/// <https://github.com/ziglang/zig/blob/0.13.0/lib/std/zig/system/darwin/macos.zig>
+///
+/// We choose to not do that, and instead follow Apple's behaviour here, and return 10.16 when
+/// compiled with an older SDK; the user should instead upgrade their tooling.
+///
+/// NOTE: `rustc` currently doesn't set the right SDK version when linking with ld64, so this will
+/// have the wrong behaviour with `-Clinker=ld` on x86_64. But that's a `rustc` bug:
+/// <https://github.com/rust-lang/rust/issues/129432>
+#[inline]
+fn current_version() -> OSVersion {
+    // Cache the lookup for performance.
+    //
+    // 0.0.0 is never going to be a valid version ("vtool" reports "n/a" on 0 versions), so we use
+    // that as our sentinel value.
+    static CURRENT_VERSION: AtomicU32 = AtomicU32::new(0);
+
+    // We use relaxed atomics instead of e.g. a `Once`, it doesn't matter if multiple threads end up
+    // racing to read or write the version, `lookup_version` should be idempotent and always return
+    // the same value.
+    //
+    // `compiler-rt` uses `dispatch_once`, but that's overkill for the reasons above.
+    let version = CURRENT_VERSION.load(Ordering::Relaxed);
+    if version == 0 {
+        let version = lookup_version().get();
+        CURRENT_VERSION.store(version, Ordering::Relaxed);
+        version
+    } else {
+        version
+    }
+}
+
+/// Look up the os version.
+///
+/// # Aborts
+///
+/// Aborts if reading or parsing the version fails (or if the system was out of memory).
+///
+/// We deliberately choose to abort, as having this silently return an invalid OS version would be
+/// impossible for a user to debug.
+// The lookup is costly and should be on the cold path because of the cache in `current_version`.
+#[cold]
+// Micro-optimization: We use `extern "C"` to abort on panic, allowing `current_version` (inlined)
+// to be free of unwind handling. Aborting is required for `__isPlatformVersionAtLeast` anyhow.
+extern "C" fn lookup_version() -> NonZero<OSVersion> {
+    // Try to read from `sysctl` first (faster), but if that fails, fall back to reading the
+    // property list (this is roughly what `_availability_version_check` does internally).
+    let version = version_from_sysctl().unwrap_or_else(version_from_plist);
+
+    // Use `NonZero` to try to make it clearer to the optimizer that this will never return 0.
+    NonZero::new(version).expect("version cannot be 0.0.0")
+}
+
+/// Read the version from `kern.osproductversion` or `kern.iossupportversion`.
+///
+/// This is faster than `version_from_plist`, since it doesn't need to invoke `dlsym`.
+fn version_from_sysctl() -> Option<OSVersion> {
+    // This won't work in the simulator, as `kern.osproductversion` returns the host macOS version,
+    // and `kern.iossupportversion` returns the host macOS' iOSSupportVersion (while you can run
+    // simulators with many different iOS versions).
+    if cfg!(target_abi = "sim") {
+        // Fall back to `version_from_plist` on these targets.
+        return None;
+    }
+
+    let sysctl_version = |name: &CStr| {
+        let mut buf: [u8; 32] = [0; 32];
+        let mut size = buf.len();
+        let ptr = buf.as_mut_ptr().cast();
+        let ret = unsafe { libc::sysctlbyname(name.as_ptr(), ptr, &mut size, null_mut(), 0) };
+        if ret != 0 {
+            // This sysctl is not available.
+            return None;
+        }
+        let buf = &buf[..(size - 1)];
+
+        if buf.is_empty() {
+            // The buffer may be empty when using `kern.iossupportversion` on an actual iOS device,
+            // or on visionOS when running under "Designed for iPad".
+            //
+            // In that case, fall back to `kern.osproductversion`.
+            return None;
+        }
+
+        Some(parse_os_version(buf).unwrap_or_else(|err| {
+            panic!("failed parsing version from sysctl ({}): {err}", ByteStr::new(buf))
+        }))
+    };
+
+    // When `target_os = "ios"`, we may be in many different states:
+    // - Native iOS device.
+    // - iOS Simulator.
+    // - Mac Catalyst.
+    // - Mac + "Designed for iPad".
+    // - Native visionOS device + "Designed for iPad".
+    // - visionOS simulator + "Designed for iPad".
+    //
+    // Of these, only native, Mac Catalyst and simulators can be differentiated at compile-time
+    // (with `target_abi = ""`, `target_abi = "macabi"` and `target_abi = "sim"` respectively).
+    //
+    // That is, "Designed for iPad" will act as iOS at compile-time, but the `ProductVersion` will
+    // still be the host macOS or visionOS version.
+    //
+    // Furthermore, we can't even reliably differentiate between these at runtime, since
+    // `dyld_get_active_platform` isn't publicly available.
+    //
+    // Fortunately, we won't need to know any of that; we can simply attempt to get the
+    // `iOSSupportVersion` (which may be set on native iOS too, but then it will be set to the host
+    // iOS version), and if that fails, fall back to the `ProductVersion`.
+    if cfg!(target_os = "ios") {
+        // https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/bsd/kern/kern_sysctl.c#L2077-L2100
+        if let Some(ios_support_version) = sysctl_version(c"kern.iossupportversion") {
+            return Some(ios_support_version);
+        }
+
+        // On Mac Catalyst, if we failed looking up `iOSSupportVersion`, we don't want to
+        // accidentally fall back to `ProductVersion`.
+        if cfg!(target_abi = "macabi") {
+            return None;
+        }
+    }
+
+    // Introduced in macOS 10.13.4.
+    // https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.81.4/bsd/kern/kern_sysctl.c#L2015-L2051
+    sysctl_version(c"kern.osproductversion")
+}
+
+/// Look up the current OS version(s) from `/System/Library/CoreServices/SystemVersion.plist`.
+///
+/// More specifically, from the `ProductVersion` and `iOSSupportVersion` keys, and from
+/// `$IPHONE_SIMULATOR_ROOT/System/Library/CoreServices/SystemVersion.plist` on the simulator.
+///
+/// This file was introduced in macOS 10.3, which is well below the minimum supported version by
+/// `rustc`, which is (at the time of writing) macOS 10.12.
+///
+/// # Implementation
+///
+/// We do roughly the same thing in here as `compiler-rt`, and dynamically look up CoreFoundation
+/// utilities for parsing PLists (to avoid having to re-implement that in here, as pulling in a full
+/// PList parser into `std` seems costly).
+///
+/// If this is found to be undesirable, we _could_ possibly hack it by parsing the PList manually
+/// (it seems to use the plain-text "xml1" encoding/format in all versions), but that seems brittle.
+fn version_from_plist() -> OSVersion {
+    // Read `SystemVersion.plist`. Always present on Apple platforms, reading it cannot fail.
+    let path = root_relative("/System/Library/CoreServices/SystemVersion.plist");
+    let plist_buffer = fs::read(&path).unwrap_or_else(|e| panic!("failed reading {path:?}: {e}"));
+    let cf_handle = CFHandle::new();
+    parse_version_from_plist(&cf_handle, &plist_buffer)
+}
+
+/// Parse OS version from the given PList.
+///
+/// Split out from [`version_from_plist`] to allow for testing.
+fn parse_version_from_plist(cf_handle: &CFHandle, plist_buffer: &[u8]) -> OSVersion {
+    let plist_data = unsafe {
+        cf_handle.CFDataCreateWithBytesNoCopy(
+            kCFAllocatorDefault,
+            plist_buffer.as_ptr(),
+            plist_buffer.len() as CFIndex,
+            cf_handle.kCFAllocatorNull(),
+        )
+    };
+    assert!(!plist_data.is_null(), "failed creating CFData");
+    let _plist_data_release = Deferred(|| unsafe { cf_handle.CFRelease(plist_data) });
+
+    let plist = unsafe {
+        cf_handle.CFPropertyListCreateWithData(
+            kCFAllocatorDefault,
+            plist_data,
+            kCFPropertyListImmutable,
+            null_mut(), // Don't care about the format of the PList.
+            null_mut(), // Don't care about the error data.
+        )
+    };
+    assert!(!plist.is_null(), "failed reading PList in SystemVersion.plist");
+    let _plist_release = Deferred(|| unsafe { cf_handle.CFRelease(plist) });
+
+    assert_eq!(
+        unsafe { cf_handle.CFGetTypeID(plist) },
+        unsafe { cf_handle.CFDictionaryGetTypeID() },
+        "SystemVersion.plist did not contain a dictionary at the top level"
+    );
+    let plist: CFDictionaryRef = plist.cast();
+
+    // Same logic as in `version_from_sysctl`.
+    if cfg!(target_os = "ios") {
+        if let Some(ios_support_version) =
+            unsafe { string_version_key(cf_handle, plist, c"iOSSupportVersion") }
+        {
+            return ios_support_version;
+        }
+
+        // Force Mac Catalyst to use iOSSupportVersion (do not fall back to ProductVersion).
+        if cfg!(target_abi = "macabi") {
+            panic!("expected iOSSupportVersion in SystemVersion.plist");
+        }
+    }
+
+    // On all other platforms, we can find the OS version by simply looking at `ProductVersion`.
+    unsafe { string_version_key(cf_handle, plist, c"ProductVersion") }
+        .expect("expected ProductVersion in SystemVersion.plist")
+}
+
+/// Look up a string key in a CFDictionary, and convert it to an [`OSVersion`].
+unsafe fn string_version_key(
+    cf_handle: &CFHandle,
+    plist: CFDictionaryRef,
+    lookup_key: &CStr,
+) -> Option<OSVersion> {
+    let cf_lookup_key = unsafe {
+        cf_handle.CFStringCreateWithCStringNoCopy(
+            kCFAllocatorDefault,
+            lookup_key.as_ptr(),
+            kCFStringEncodingUTF8,
+            cf_handle.kCFAllocatorNull(),
+        )
+    };
+    assert!(!cf_lookup_key.is_null(), "failed creating CFString");
+    let _lookup_key_release = Deferred(|| unsafe { cf_handle.CFRelease(cf_lookup_key) });
+
+    let value: CFTypeRef =
+        unsafe { cf_handle.CFDictionaryGetValue(plist, cf_lookup_key) }.cast_mut();
+    // `CFDictionaryGetValue` is a "getter", so we should not release,
+    // the value is held alive internally by the CFDictionary, see:
+    // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW12
+    if value.is_null() {
+        return None;
+    }
+
+    assert_eq!(
+        unsafe { cf_handle.CFGetTypeID(value) },
+        unsafe { cf_handle.CFStringGetTypeID() },
+        "key in SystemVersion.plist must be a string"
+    );
+    let value: CFStringRef = value.cast();
+
+    let mut version_str = [0u8; 32];
+    let ret = unsafe {
+        cf_handle.CFStringGetCString(
+            value,
+            version_str.as_mut_ptr().cast::<c_char>(),
+            version_str.len() as CFIndex,
+            kCFStringEncodingUTF8,
+        )
+    };
+    assert_ne!(ret, 0, "failed getting string from CFString");
+
+    let version_str =
+        CStr::from_bytes_until_nul(&version_str).expect("failed converting CFString to CStr");
+
+    Some(parse_os_version(version_str.to_bytes()).unwrap_or_else(|err| {
+        panic!(
+            "failed parsing version from PList ({}): {err}",
+            ByteStr::new(version_str.to_bytes())
+        )
+    }))
+}
+
+/// Parse an OS version from a bytestring like b"10.1" or b"14.3.7".
+fn parse_os_version(version: &[u8]) -> Result<OSVersion, ParseIntError> {
+    if let Some((major, minor)) = version.split_once(|&b| b == b'.') {
+        let major = u16::from_ascii(major)?;
+        if let Some((minor, patch)) = minor.split_once(|&b| b == b'.') {
+            let minor = u8::from_ascii(minor)?;
+            let patch = u8::from_ascii(patch)?;
+            Ok(pack_os_version(major, minor, patch))
+        } else {
+            let minor = u8::from_ascii(minor)?;
+            Ok(pack_os_version(major, minor, 0))
+        }
+    } else {
+        let major = u16::from_ascii(version)?;
+        Ok(pack_os_version(major, 0, 0))
+    }
+}
+
+/// Get a path relative to the root directory in which all files for the current env are located.
+fn root_relative(path: &str) -> Cow<'_, Path> {
+    if cfg!(target_abi = "sim") {
+        let mut root = PathBuf::from(env::var_os("IPHONE_SIMULATOR_ROOT").expect(
+            "environment variable `IPHONE_SIMULATOR_ROOT` must be set when executing under simulator",
+        ));
+        // Convert absolute path to relative path, to make the `.push` work as expected.
+        root.push(Path::new(path).strip_prefix("/").unwrap());
+        root.into()
+    } else {
+        Path::new(path).into()
+    }
+}
+
+struct Deferred<F: FnMut()>(F);
+
+impl<F: FnMut()> Drop for Deferred<F> {
+    fn drop(&mut self) {
+        (self.0)();
+    }
+}
diff --git a/library/std/src/sys/platform_version/darwin/public_extern.rs b/library/std/src/sys/platform_version/darwin/public_extern.rs
new file mode 100644
index 00000000000..c0848d94798
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/public_extern.rs
@@ -0,0 +1,156 @@
+//! # Runtime version checking ABI for other compilers.
+//!
+//! The symbols in this file are useful for us to expose to allow linking code written in the
+//! following languages when using their version checking functionality:
+//! - Clang's `__builtin_available` macro.
+//! - Objective-C's `@available`.
+//! - Swift's `#available`,
+//!
+//! Without Rust exposing these symbols, the user would encounter a linker error when linking to
+//! C/Objective-C/Swift libraries using these features.
+//!
+//! The presence of these symbols is mostly considered a quality-of-implementation detail, and
+//! should not be relied upon to be available. The intended effect is that linking with code built
+//! with Clang's `__builtin_available` (or similar) will continue to work. For example, we may
+//! decide to remove `__isOSVersionAtLeast` if support for Clang 11 (Xcode 11) is dropped.
+//!
+//! ## Background
+//!
+//! The original discussion of this feature can be found at:
+//! - <https://lists.llvm.org/pipermail/cfe-dev/2016-July/049851.html>
+//! - <https://reviews.llvm.org/D27827>
+//! - <https://reviews.llvm.org/D30136>
+//!
+//! And the upstream implementation of these can be found in `compiler-rt`:
+//! <https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/compiler-rt/lib/builtins/os_version_check.c>
+//!
+//! Ideally, these symbols should probably have been a part of Apple's `libSystem.dylib`, both
+//! because their implementation is quite complex, using allocation, environment variables, file
+//! access and dynamic library loading (and emitting all of this into every binary).
+//!
+//! The reason why Apple chose to not do that originally is lost to the sands of time, but a good
+//! reason would be that implementing it as part of `compiler-rt` allowed them to back-deploy this
+//! to older OSes immediately.
+//!
+//! In Rust's case, while we may provide a feature similar to `@available` in the future, we will
+//! probably do so as a macro exposed by `std` (and not as a compiler builtin). So implementing this
+//! in `std` makes sense, since then we can implement it using `std` utilities, and we can avoid
+//! having `compiler-builtins` depend on `libSystem.dylib`.
+//!
+//! This does mean that users that attempt to link C/Objective-C/Swift code _and_ use `#![no_std]`
+//! in all their crates may get a linker error because these symbols are missing. Using `no_std` is
+//! quite uncommon on Apple systems though, so it's probably fine to not support this use-case.
+//!
+//! The workaround would be to link `libclang_rt.osx.a` or otherwise use Clang's `compiler-rt`.
+//!
+//! See also discussion in <https://github.com/rust-lang/compiler-builtins/pull/794>.
+//!
+//! ## Implementation details
+//!
+//! NOTE: Since macOS 10.15, `libSystem.dylib` _has_ actually provided the undocumented
+//! `_availability_version_check` via `libxpc` for doing the version lookup (zippered, which is why
+//! it requires a platform parameter to differentiate between macOS and Mac Catalyst), though its
+//! usage may be a bit dangerous, see:
+//! - <https://reviews.llvm.org/D150397>
+//! - <https://github.com/llvm/llvm-project/issues/64227>
+//!
+//! Besides, we'd need to implement the version lookup via PList to support older versions anyhow,
+//! so we might as well use that everywhere (since it can also be optimized more after inlining).
+
+#![allow(non_snake_case)]
+
+use super::{current_version, pack_i32_os_version};
+
+/// Whether the current platform's OS version is higher than or equal to the given version.
+///
+/// The first argument is the _base_ Mach-O platform (i.e. `PLATFORM_MACOS`, `PLATFORM_IOS`, etc.,
+/// but not `PLATFORM_IOSSIMULATOR` or `PLATFORM_MACCATALYST`) of the invoking binary.
+///
+/// Arguments are specified statically by Clang. Inlining with LTO should allow the versions to be
+/// combined into a single `u32`, which should make comparisons faster, and should make the
+/// `BASE_TARGET_PLATFORM` check a no-op.
+//
+// SAFETY: The signature is the same as what Clang expects, and we export weakly to allow linking
+// both this and `libclang_rt.*.a`, similar to how `compiler-builtins` does it:
+// https://github.com/rust-lang/compiler-builtins/blob/0.1.113/src/macros.rs#L494
+//
+// NOTE: This symbol has a workaround in the compiler's symbol mangling to avoid mangling it, while
+// still not exposing it from non-cdylib (like `#[no_mangle]` would).
+#[rustc_std_internal_symbol]
+// NOTE: Making this a weak symbol might not be entirely the right solution for this, `compiler_rt`
+// doesn't do that, it instead makes the symbol have "hidden" visibility. But since this is placed
+// in `libstd`, which might be used as a dylib, we cannot do the same here.
+#[linkage = "weak"]
+// extern "C" is correct, Clang assumes the function cannot unwind:
+// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/clang/lib/CodeGen/CGObjC.cpp#L3980
+//
+// If an error happens in this, we instead abort the process.
+pub(super) extern "C" fn __isPlatformVersionAtLeast(
+    platform: i32,
+    major: i32,
+    minor: i32,
+    subminor: i32,
+) -> i32 {
+    let version = pack_i32_os_version(major, minor, subminor);
+
+    // Mac Catalyst is a technology that allows macOS to run in a different "mode" that closely
+    // resembles iOS (and has iOS libraries like UIKit available).
+    //
+    // (Apple has added a "Designed for iPad" mode later on that allows running iOS apps
+    // natively, but we don't need to think too much about those, since they link to
+    // iOS-specific system binaries as well).
+    //
+    // To support Mac Catalyst, Apple added the concept of a "zippered" binary, which is a single
+    // binary that can be run on both macOS and Mac Catalyst (has two `LC_BUILD_VERSION` Mach-O
+    // commands, one set to `PLATFORM_MACOS` and one to `PLATFORM_MACCATALYST`).
+    //
+    // Most system libraries are zippered, which allows re-use across macOS and Mac Catalyst.
+    // This includes the `libclang_rt.osx.a` shipped with Xcode! This means that `compiler-rt`
+    // can't statically know whether it's compiled for macOS or Mac Catalyst, and thus this new
+    // API (which replaces `__isOSVersionAtLeast`) is needed.
+    //
+    // In short:
+    //      normal  binary calls  normal  compiler-rt --> `__isOSVersionAtLeast` was enough
+    //      normal  binary calls zippered compiler-rt --> `__isPlatformVersionAtLeast` required
+    //     zippered binary calls zippered compiler-rt --> `__isPlatformOrVariantPlatformVersionAtLeast` called
+
+    // FIXME(madsmtm): `rustc` doesn't support zippered binaries yet, see rust-lang/rust#131216.
+    // But once it does, we need the pre-compiled `std` shipped with rustup to be zippered, and thus
+    // we also need to handle the `platform` difference here:
+    //
+    // if cfg!(target_os = "macos") && platform == 2 /* PLATFORM_IOS */ && cfg!(zippered) {
+    //     return (version.to_u32() <= current_ios_version()) as i32;
+    // }
+    //
+    // `__isPlatformOrVariantPlatformVersionAtLeast` would also need to be implemented.
+
+    // The base Mach-O platform for the current target.
+    const BASE_TARGET_PLATFORM: i32 = if cfg!(target_os = "macos") {
+        1 // PLATFORM_MACOS
+    } else if cfg!(target_os = "ios") {
+        2 // PLATFORM_IOS
+    } else if cfg!(target_os = "tvos") {
+        3 // PLATFORM_TVOS
+    } else if cfg!(target_os = "watchos") {
+        4 // PLATFORM_WATCHOS
+    } else if cfg!(target_os = "visionos") {
+        11 // PLATFORM_VISIONOS
+    } else {
+        0 // PLATFORM_UNKNOWN
+    };
+    debug_assert_eq!(
+        platform, BASE_TARGET_PLATFORM,
+        "invalid platform provided to __isPlatformVersionAtLeast",
+    );
+
+    (version <= current_version()) as i32
+}
+
+/// Old entry point for availability. Used when compiling with older Clang versions.
+// SAFETY: Same as for `__isPlatformVersionAtLeast`.
+#[rustc_std_internal_symbol]
+#[linkage = "weak"]
+pub(super) extern "C" fn __isOSVersionAtLeast(major: i32, minor: i32, subminor: i32) -> i32 {
+    let version = pack_i32_os_version(major, minor, subminor);
+    (version <= current_version()) as i32
+}
diff --git a/library/std/src/sys/platform_version/darwin/tests.rs b/library/std/src/sys/platform_version/darwin/tests.rs
new file mode 100644
index 00000000000..17b2cc18ec0
--- /dev/null
+++ b/library/std/src/sys/platform_version/darwin/tests.rs
@@ -0,0 +1,379 @@
+use super::public_extern::*;
+use super::*;
+use crate::process::Command;
+
+#[test]
+fn test_general_available() {
+    // Lowest version always available.
+    assert_eq!(__isOSVersionAtLeast(0, 0, 0), 1);
+    // This high version never available.
+    assert_eq!(__isOSVersionAtLeast(9999, 99, 99), 0);
+}
+
+#[test]
+fn test_saturating() {
+    // Higher version than supported by OSVersion -> make sure we saturate.
+    assert_eq!(__isOSVersionAtLeast(0x10000, 0, 0), 0);
+}
+
+#[test]
+#[cfg_attr(not(target_os = "macos"), ignore = "`sw_vers` is only available on host macOS")]
+fn compare_against_sw_vers() {
+    let sw_vers = Command::new("sw_vers").arg("-productVersion").output().unwrap().stdout;
+    let sw_vers = String::from_utf8(sw_vers).unwrap();
+    let mut sw_vers = sw_vers.trim().split('.');
+
+    let major: i32 = sw_vers.next().unwrap().parse().unwrap();
+    let minor: i32 = sw_vers.next().unwrap_or("0").parse().unwrap();
+    let subminor: i32 = sw_vers.next().unwrap_or("0").parse().unwrap();
+    assert_eq!(sw_vers.count(), 0);
+
+    // Test directly against the lookup
+    assert_eq!(lookup_version().get(), pack_os_version(major as _, minor as _, subminor as _));
+
+    // Current version is available
+    assert_eq!(__isOSVersionAtLeast(major, minor, subminor), 1);
+
+    // One lower is available
+    assert_eq!(__isOSVersionAtLeast(major, minor, (subminor as u32).saturating_sub(1) as i32), 1);
+    assert_eq!(__isOSVersionAtLeast(major, (minor as u32).saturating_sub(1) as i32, subminor), 1);
+    assert_eq!(__isOSVersionAtLeast((major as u32).saturating_sub(1) as i32, minor, subminor), 1);
+
+    // One higher isn't available
+    assert_eq!(__isOSVersionAtLeast(major, minor, subminor + 1), 0);
+    assert_eq!(__isOSVersionAtLeast(major, minor + 1, subminor), 0);
+    assert_eq!(__isOSVersionAtLeast(major + 1, minor, subminor), 0);
+}
+
+#[test]
+fn sysctl_same_as_in_plist() {
+    if let Some(version) = version_from_sysctl() {
+        assert_eq!(version, version_from_plist());
+    }
+}
+
+#[test]
+fn lookup_idempotent() {
+    let version = lookup_version();
+    for _ in 0..10 {
+        assert_eq!(version, lookup_version());
+    }
+}
+
+/// Test parsing a bunch of different PLists found in the wild, to ensure that
+/// if we decide to parse it without CoreFoundation in the future, that it
+/// would continue to work, even on older platforms.
+#[test]
+fn parse_plist() {
+    #[track_caller]
+    fn check(
+        (major, minor, patch): (u16, u8, u8),
+        ios_version: Option<(u16, u8, u8)>,
+        plist: &str,
+    ) {
+        let expected = if cfg!(target_os = "ios") {
+            if let Some((ios_major, ios_minor, ios_patch)) = ios_version {
+                pack_os_version(ios_major, ios_minor, ios_patch)
+            } else if cfg!(target_abi = "macabi") {
+                // Skip checking iOS version on Mac Catalyst.
+                return;
+            } else {
+                // iOS version will be parsed from ProductVersion
+                pack_os_version(major, minor, patch)
+            }
+        } else {
+            pack_os_version(major, minor, patch)
+        };
+        let cf_handle = CFHandle::new();
+        assert_eq!(expected, parse_version_from_plist(&cf_handle, plist.as_bytes()));
+    }
+
+    // macOS 10.3.0
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>7B85</string>
+            <key>ProductCopyright</key>
+            <string>Apple Computer, Inc. 1983-2003</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.3</string>
+            <key>ProductVersion</key>
+            <string>10.3</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 3, 0), None, plist);
+
+    // macOS 10.7.5
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>11G63</string>
+            <key>ProductCopyright</key>
+            <string>1983-2012 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.7.5</string>
+            <key>ProductVersion</key>
+            <string>10.7.5</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 7, 5), None, plist);
+
+    // macOS 14.7.4
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>6A558D8A-E2EA-11EF-A1D3-6222CAA672A8</string>
+            <key>ProductBuildVersion</key>
+            <string>23H420</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>macOS</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>14.7.4</string>
+            <key>ProductVersion</key>
+            <string>14.7.4</string>
+            <key>iOSSupportVersion</key>
+            <string>17.7</string>
+        </dict>
+        </plist>
+    "#;
+    check((14, 7, 4), Some((17, 7, 0)), plist);
+
+    // SystemVersionCompat.plist on macOS 14.7.4
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>6A558D8A-E2EA-11EF-A1D3-6222CAA672A8</string>
+            <key>ProductBuildVersion</key>
+            <string>23H420</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Mac OS X</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>10.16</string>
+            <key>ProductVersion</key>
+            <string>10.16</string>
+            <key>iOSSupportVersion</key>
+            <string>17.7</string>
+        </dict>
+        </plist>
+    "#;
+    check((10, 16, 0), Some((17, 7, 0)), plist);
+
+    // macOS 15.4 Beta 24E5238a
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>67A50F62-00DA-11F0-BDB6-F99BB8310D2A</string>
+            <key>ProductBuildVersion</key>
+            <string>24E5238a</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>macOS</string>
+            <key>ProductUserVisibleVersion</key>
+            <string>15.4</string>
+            <key>ProductVersion</key>
+            <string>15.4</string>
+            <key>iOSSupportVersion</key>
+            <string>18.4</string>
+        </dict>
+        </plist>
+    "#;
+    check((15, 4, 0), Some((18, 4, 0)), plist);
+
+    // iOS Simulator 17.5
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>210B8A2C-09C3-11EF-9DB8-273A64AEFA1C</string>
+            <key>ProductBuildVersion</key>
+            <string>21F79</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>iPhone OS</string>
+            <key>ProductVersion</key>
+            <string>17.5</string>
+        </dict>
+        </plist>
+    "#;
+    check((17, 5, 0), None, plist);
+
+    // visionOS Simulator 2.3
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>57CEFDE6-D079-11EF-837C-8B8C7961D0AC</string>
+            <key>ProductBuildVersion</key>
+            <string>22N895</string>
+            <key>ProductCopyright</key>
+            <string>1983-2025 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>xrOS</string>
+            <key>ProductVersion</key>
+            <string>2.3</string>
+            <key>SystemImageID</key>
+            <string>D332C7F1-08DF-4DD9-8122-94EF39A1FB92</string>
+            <key>iOSSupportVersion</key>
+            <string>18.3</string>
+        </dict>
+        </plist>
+    "#;
+    check((2, 3, 0), Some((18, 3, 0)), plist);
+
+    // tvOS Simulator 18.2
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>617587B0-B059-11EF-BE70-4380EDE44645</string>
+            <key>ProductBuildVersion</key>
+            <string>22K154</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Apple TVOS</string>
+            <key>ProductVersion</key>
+            <string>18.2</string>
+            <key>SystemImageID</key>
+            <string>8BB5A425-33F0-4821-9F93-40E7ED92F4E0</string>
+        </dict>
+        </plist>
+    "#;
+    check((18, 2, 0), None, plist);
+
+    // watchOS Simulator 11.2
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>BuildID</key>
+            <string>BAAE2D54-B122-11EF-BF78-C6C6836B724A</string>
+            <key>ProductBuildVersion</key>
+            <string>22S99</string>
+            <key>ProductCopyright</key>
+            <string>1983-2024 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>Watch OS</string>
+            <key>ProductVersion</key>
+            <string>11.2</string>
+            <key>SystemImageID</key>
+            <string>79F773E2-2041-43B4-98EE-FAE52402AE95</string>
+        </dict>
+        </plist>
+    "#;
+    check((11, 2, 0), None, plist);
+
+    // iOS 9.3.6
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+            <key>ProductBuildVersion</key>
+            <string>13G37</string>
+            <key>ProductCopyright</key>
+            <string>1983-2019 Apple Inc.</string>
+            <key>ProductName</key>
+            <string>iPhone OS</string>
+            <key>ProductVersion</key>
+            <string>9.3.6</string>
+        </dict>
+        </plist>
+    "#;
+    check((9, 3, 6), None, plist);
+}
+
+#[test]
+#[should_panic = "SystemVersion.plist did not contain a dictionary at the top level"]
+fn invalid_plist() {
+    let cf_handle = CFHandle::new();
+    let _ = parse_version_from_plist(&cf_handle, b"INVALID");
+}
+
+#[test]
+#[cfg_attr(
+    target_abi = "macabi",
+    should_panic = "expected iOSSupportVersion in SystemVersion.plist"
+)]
+#[cfg_attr(
+    not(target_abi = "macabi"),
+    should_panic = "expected ProductVersion in SystemVersion.plist"
+)]
+fn empty_plist() {
+    let plist = r#"<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+        <dict>
+        </dict>
+        </plist>
+    "#;
+    let cf_handle = CFHandle::new();
+    let _ = parse_version_from_plist(&cf_handle, plist.as_bytes());
+}
+
+#[test]
+fn parse_version() {
+    #[track_caller]
+    fn check(major: u16, minor: u8, patch: u8, version: &str) {
+        assert_eq!(
+            pack_os_version(major, minor, patch),
+            parse_os_version(version.as_bytes()).unwrap()
+        )
+    }
+
+    check(0, 0, 0, "0");
+    check(0, 0, 0, "0.0.0");
+    check(1, 0, 0, "1");
+    check(1, 2, 0, "1.2");
+    check(1, 2, 3, "1.2.3");
+    check(9999, 99, 99, "9999.99.99");
+
+    // Check leading zeroes
+    check(10, 0, 0, "010");
+    check(10, 20, 0, "010.020");
+    check(10, 20, 30, "010.020.030");
+    check(10000, 100, 100, "000010000.00100.00100");
+
+    // Too many parts
+    assert!(parse_os_version(b"1.2.3.4").is_err());
+
+    // Empty
+    assert!(parse_os_version(b"").is_err());
+
+    // Invalid digit
+    assert!(parse_os_version(b"A.B").is_err());
+
+    // Missing digits
+    assert!(parse_os_version(b".").is_err());
+    assert!(parse_os_version(b".1").is_err());
+    assert!(parse_os_version(b"1.").is_err());
+
+    // Too large
+    assert!(parse_os_version(b"100000").is_err());
+    assert!(parse_os_version(b"1.1000").is_err());
+    assert!(parse_os_version(b"1.1.1000").is_err());
+}
diff --git a/library/std/src/sys/platform_version/mod.rs b/library/std/src/sys/platform_version/mod.rs
new file mode 100644
index 00000000000..88896c97ea3
--- /dev/null
+++ b/library/std/src/sys/platform_version/mod.rs
@@ -0,0 +1,13 @@
+//! Runtime lookup of operating system / platform version.
+//!
+//! Related to [RFC 3750](https://github.com/rust-lang/rfcs/pull/3750), which
+//! does version detection at compile-time.
+//!
+//! See also the `os_info` crate.
+
+#[cfg(target_vendor = "apple")]
+mod darwin;
+
+// In the future, we could expand this module with:
+// - `RtlGetVersion` on Windows.
+// - `__system_property_get` on Android.
diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs
index 91c7005a328..a1ed0cd2cdd 100644
--- a/library/std/src/sys/process/mod.rs
+++ b/library/std/src/sys/process/mod.rs
@@ -1,14 +1,17 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         use unix as imp;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         use windows as imp;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         use uefi as imp;
-    } else {
+    }
+    _ => {
         mod unsupported;
         use unsupported as imp;
     }
@@ -21,7 +24,7 @@ mod env;
 
 pub use env::CommandEnvs;
 pub use imp::{
-    Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes,
+    Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio,
 };
 
 #[cfg(any(
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index 4864c586988..11c8b682bb9 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -6,6 +6,7 @@ pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
 use crate::num::{NonZero, NonZeroI32};
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fs::File;
 use crate::sys::pal::helpers;
 use crate::sys::pal::os::error_string;
@@ -27,14 +28,6 @@ pub struct Command {
     env: CommandEnv,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Stdio {
     Inherit,
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index 6219be60caf..1d5909e99ba 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -9,6 +9,7 @@ use crate::collections::BTreeMap;
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::os::unix::prelude::*;
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 #[cfg(not(target_os = "fuchsia"))]
@@ -20,12 +21,14 @@ use crate::{fmt, io};
 
 mod cstring_array;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
+cfg_select! {
+    target_os = "fuchsia" => {
         // fuchsia doesn't have /dev/null
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         const DEV_NULL: &CStr = c"/null";
-    } else {
+    }
+    _ => {
         const DEV_NULL: &CStr = c"/dev/null";
     }
 }
@@ -35,8 +38,8 @@ cfg_if::cfg_if! {
 // to support older Android version (independent of libc version).
 // The following implementations are based on
 // https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "android")] {
+cfg_select! {
+    target_os = "android" => {
         #[allow(dead_code)]
         pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
             set.write_bytes(0u8, 1);
@@ -69,7 +72,8 @@ cfg_if::cfg_if! {
             raw[bit / LONG_BIT] |= 1 << (bit % LONG_BIT);
             return 0;
         }
-    } else {
+    }
+    _ => {
         #[allow(unused_imports)]
         pub use libc::{sigemptyset, sigaddset};
     }
@@ -101,14 +105,6 @@ pub struct Command {
     setsid: bool,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 // passed to do_exec() with configuration of what the child stdio should look
 // like
 #[cfg_attr(target_os = "vita", allow(dead_code))]
diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs
index d71be510b6a..3fae5ec1468 100644
--- a/library/std/src/sys/process/unix/fuchsia.rs
+++ b/library/std/src/sys/process/unix/fuchsia.rs
@@ -2,6 +2,7 @@ use libc::{c_int, size_t};
 
 use super::common::*;
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::pal::fuchsia::*;
 use crate::{fmt, io, mem, ptr};
 
diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs
index ee8fd8b2ca3..cda1bf74f1c 100644
--- a/library/std/src/sys/process/unix/mod.rs
+++ b/library/std/src/sys/process/unix/mod.rs
@@ -1,18 +1,21 @@
 #[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
+cfg_select! {
+    target_os = "fuchsia" => {
         mod fuchsia;
         use fuchsia as imp;
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         mod vxworks;
         use vxworks as imp;
-    } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
+    }
+    any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx") => {
         mod unsupported;
         use unsupported as imp;
         pub use unsupported::output;
-    } else {
+    }
+    _ => {
         mod unix;
         use unix as imp;
     }
@@ -20,5 +23,5 @@ cfg_if::cfg_if! {
 
 pub use imp::{ExitStatus, ExitStatusError, Process};
 
-pub use self::common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
+pub use self::common::{Command, CommandArgs, ExitCode, Stdio};
 pub use crate::ffi::OsString as EnvKey;
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 5d13d6da185..7d944f2f7ee 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -13,13 +13,14 @@ use libc::{gid_t, uid_t};
 use super::common::*;
 use crate::io::{self, Error, ErrorKind};
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::cvt;
 #[cfg(target_os = "linux")]
 use crate::sys::pal::linux::pidfd::PidFd;
 use crate::{fmt, mem, sys};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "nto")] {
+cfg_select! {
+    target_os = "nto" => {
         use crate::thread;
         use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
         use crate::time::Duration;
@@ -43,6 +44,7 @@ cfg_if::cfg_if! {
         // Maximum duration of sleeping before giving up and returning an error
         const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000);
     }
+    _ => {}
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -465,8 +467,8 @@ impl Command {
             return Ok(None);
         }
 
-        cfg_if::cfg_if! {
-            if #[cfg(target_os = "linux")] {
+        cfg_select! {
+            target_os = "linux" => {
                 use crate::sys::weak::weak;
 
                 weak!(
@@ -526,7 +528,8 @@ impl Command {
                     }
                     core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
                 }
-            } else {
+            }
+            _ => {
                 if self.get_create_pidfd() {
                     unreachable!("only implemented on linux")
                 }
@@ -746,10 +749,11 @@ impl Command {
             }
 
             if self.get_setsid() {
-                cfg_if::cfg_if! {
-                    if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
+                cfg_select! {
+                    all(target_os = "linux", target_env = "gnu") => {
                         flags |= libc::POSIX_SPAWN_SETSID;
-                    } else {
+                    }
+                    _ => {
                         return Ok(None);
                     }
                 }
diff --git a/library/std/src/sys/process/unix/unix/tests.rs b/library/std/src/sys/process/unix/unix/tests.rs
index f4d6ac6b4e3..663ba61f966 100644
--- a/library/std/src/sys/process/unix/unix/tests.rs
+++ b/library/std/src/sys/process/unix/unix/tests.rs
@@ -51,6 +51,7 @@ fn exitstatus_display_tests() {
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "tvos", target_os = "watchos"), ignore = "fork is prohibited")]
 fn test_command_fork_no_unwind() {
     let got = catch_unwind(|| {
         let mut c = Command::new("echo");
diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs
index 87403cd50f8..9bda394f246 100644
--- a/library/std/src/sys/process/unix/unsupported.rs
+++ b/library/std/src/sys/process/unix/unsupported.rs
@@ -3,6 +3,7 @@ use libc::{c_int, pid_t};
 use super::common::*;
 use crate::io;
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::pal::unsupported::*;
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index 2275cbb946a..346ca6d74c9 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -4,8 +4,8 @@ use libc::{self, RTP_ID, c_char, c_int};
 use super::common::*;
 use crate::io::{self, ErrorKind};
 use crate::num::NonZero;
-use crate::sys::cvt;
-use crate::sys::pal::thread;
+use crate::process::StdioPipes;
+use crate::sys::{cvt, thread};
 use crate::{fmt, sys};
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs
index 469922c78ac..636465b68e5 100644
--- a/library/std/src/sys/process/unsupported.rs
+++ b/library/std/src/sys/process/unsupported.rs
@@ -3,6 +3,7 @@ pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
 use crate::num::NonZero;
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::unsupported;
@@ -23,14 +24,6 @@ pub struct Command {
     stderr: Option<Stdio>,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 #[derive(Debug)]
 pub enum Stdio {
     Inherit,
diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs
index f9e15b82475..1f2001bdc20 100644
--- a/library/std/src/sys/process/windows.rs
+++ b/library/std/src/sys/process/windows.rs
@@ -15,6 +15,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
 use crate::os::windows::process::ProcThreadAttributeList;
 use crate::path::{Path, PathBuf};
+use crate::process::StdioPipes;
 use crate::sync::Mutex;
 use crate::sys::args::{self, Arg};
 use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS};
@@ -169,12 +170,6 @@ pub enum Stdio {
     Handle(Handle),
 }
 
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 impl Command {
     pub fn new(program: &OsStr) -> Command {
         Command {
diff --git a/library/std/src/sys/process/windows/tests.rs b/library/std/src/sys/process/windows/tests.rs
index 1377e12162f..a21afe3363c 100644
--- a/library/std/src/sys/process/windows/tests.rs
+++ b/library/std/src/sys/process/windows/tests.rs
@@ -1,7 +1,8 @@
 use super::{Arg, make_command_line};
 use crate::env;
 use crate::ffi::{OsStr, OsString};
-use crate::process::Command;
+use crate::os::windows::io::AsHandle;
+use crate::process::{Command, Stdio};
 
 #[test]
 fn test_raw_args() {
@@ -29,19 +30,30 @@ fn test_thread_handle() {
     use crate::os::windows::process::{ChildExt, CommandExt};
     const CREATE_SUSPENDED: u32 = 0x00000004;
 
-    let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
+    let p = Command::new("whoami").stdout(Stdio::null()).creation_flags(CREATE_SUSPENDED).spawn();
     assert!(p.is_ok());
-    let mut p = p.unwrap();
+
+    // Ensure the process is killed in the event something goes wrong.
+    struct DropGuard(crate::process::Child);
+    impl Drop for DropGuard {
+        fn drop(&mut self) {
+            let _ = self.0.kill();
+        }
+    }
+    let mut p = DropGuard(p.unwrap());
+    let p = &mut p.0;
 
     unsafe extern "system" {
-        fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
+        unsafe fn ResumeThread(hHandle: BorrowedHandle<'_>) -> u32;
+        unsafe fn WaitForSingleObject(hHandle: BorrowedHandle<'_>, dwMilliseconds: u32) -> u32;
     }
     unsafe {
         ResumeThread(p.main_thread_handle());
+        // Wait until the process exits or 1 minute passes.
+        // We don't bother checking the result here as that's done below using `try_wait`.
+        WaitForSingleObject(p.as_handle(), 1000 * 60);
     }
 
-    crate::thread::sleep(crate::time::Duration::from_millis(100));
-
     let res = p.try_wait();
     assert!(res.is_ok());
     assert!(res.unwrap().is_some());
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index fc85797dcc2..3c5a4c82a9f 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -1,16 +1,19 @@
-cfg_if::cfg_if! {
+cfg_select! {
     // Tier 1
-    if #[cfg(any(target_os = "linux", target_os = "android"))] {
+    any(target_os = "linux", target_os = "android") => {
         mod linux;
         pub use linux::{fill_bytes, hashmap_random_keys};
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::fill_bytes;
-    } else if #[cfg(target_vendor = "apple")] {
+    }
+    target_vendor = "apple" => {
         mod apple;
         pub use apple::fill_bytes;
     // Others, in alphabetical ordering.
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "dragonfly",
         target_os = "freebsd",
         target_os = "haiku",
@@ -21,76 +24,100 @@ cfg_if::cfg_if! {
         target_os = "solaris",
         target_os = "vita",
         target_os = "nuttx",
-    ))] {
+    ) => {
         mod arc4random;
         pub use arc4random::fill_bytes;
-    } else if #[cfg(target_os = "emscripten")] {
+    }
+    target_os = "emscripten" => {
         mod getentropy;
         pub use getentropy::fill_bytes;
-    } else if #[cfg(target_os = "espidf")] {
+    }
+    target_os = "espidf" => {
         mod espidf;
         pub use espidf::fill_bytes;
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         mod fuchsia;
         pub use fuchsia::fill_bytes;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::fill_bytes;
-    } else if #[cfg(any(target_os = "horizon", target_os = "cygwin"))] {
+    }
+    any(target_os = "horizon", target_os = "cygwin") => {
         // FIXME(horizon): add arc4random_buf to shim-3ds
         mod getrandom;
         pub use getrandom::fill_bytes;
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "aix",
         target_os = "hurd",
         target_os = "l4re",
         target_os = "nto",
-    ))] {
+    ) => {
         mod unix_legacy;
         pub use unix_legacy::fill_bytes;
-    } else if #[cfg(target_os = "redox")] {
+    }
+    target_os = "redox" => {
         mod redox;
         pub use redox::fill_bytes;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::fill_bytes;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::fill_bytes;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::fill_bytes;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use trusty::fill_bytes;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::fill_bytes;
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         mod vxworks;
         pub use vxworks::fill_bytes;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use wasi::fill_bytes;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::fill_bytes;
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::{fill_bytes, hashmap_random_keys};
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::fill_bytes;
-    } else if #[cfg(any(
+    }
+    any(
         all(target_family = "wasm", target_os = "unknown"),
         target_os = "xous",
-    ))] {
+        target_os = "vexos",
+    ) => {
         // FIXME: finally remove std support for wasm32-unknown-unknown
         // FIXME: add random data generation to xous
         mod unsupported;
         pub use unsupported::{fill_bytes, hashmap_random_keys};
     }
+    _ => {}
 }
 
 #[cfg(not(any(
     target_os = "linux",
     target_os = "android",
     all(target_family = "wasm", target_os = "unknown"),
+    all(target_os = "wasi", target_env = "p2"),
     target_os = "xous",
+    target_os = "vexos",
 )))]
 pub fn hashmap_random_keys() -> (u64, u64) {
     let mut buf = [0; 16];
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
index 4a71d32fffe..697933f197b 100644
--- a/library/std/src/sys/random/uefi.rs
+++ b/library/std/src/sys/random/uefi.rs
@@ -55,12 +55,13 @@ mod rng_protocol {
 /// Port from [getrandom](https://github.com/rust-random/getrandom/blob/master/src/backends/rdrand.rs)
 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
 mod rdrand {
-    cfg_if::cfg_if! {
-        if #[cfg(target_arch = "x86_64")] {
+    cfg_select! {
+        target_arch = "x86_64" => {
             use crate::arch::x86_64 as arch;
             use arch::_rdrand64_step as rdrand_step;
             type Word = u64;
-        } else if #[cfg(target_arch = "x86")] {
+        }
+        target_arch = "x86" => {
             use crate::arch::x86 as arch;
             use arch::_rdrand32_step as rdrand_step;
             type Word = u32;
diff --git a/library/std/src/sys/random/wasi.rs b/library/std/src/sys/random/wasip1.rs
index d41da3751fc..d41da3751fc 100644
--- a/library/std/src/sys/random/wasi.rs
+++ b/library/std/src/sys/random/wasip1.rs
diff --git a/library/std/src/sys/random/wasip2.rs b/library/std/src/sys/random/wasip2.rs
new file mode 100644
index 00000000000..a67c8a6428d
--- /dev/null
+++ b/library/std/src/sys/random/wasip2.rs
@@ -0,0 +1,9 @@
+pub fn fill_bytes(bytes: &mut [u8]) {
+    bytes.copy_from_slice(&wasip2::random::random::get_random_bytes(
+        u64::try_from(bytes.len()).unwrap(),
+    ));
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    wasip2::random::insecure_seed::insecure_seed()
+}
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
index 336d4c8527d..404ac877926 100644
--- a/library/std/src/sys/stdio/mod.rs
+++ b/library/std/src/sys/stdio/mod.rs
@@ -1,40 +1,55 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_family = "unix",
-        target_os = "hermit"
-    ))] {
+cfg_select! {
+    any(target_family = "unix", target_os = "hermit") => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::*;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use trusty::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use vexos::*;
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::*;
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::*;
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs
new file mode 100644
index 00000000000..9a391feb7a8
--- /dev/null
+++ b/library/std/src/sys/stdio/vexos.rs
@@ -0,0 +1,100 @@
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout;
+pub type Stderr = Stdout;
+
+pub const STDIO_CHANNEL: u32 = 1;
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut count = 0;
+
+        for out_byte in buf.iter_mut() {
+            let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) };
+            if byte < 0 {
+                break;
+            }
+
+            *out_byte = byte as u8;
+            count += 1;
+        }
+
+        Ok(count)
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let mut written = 0;
+
+        // HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1
+        // roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we
+        // must block until that buffer is flushed to USB1 before writing the rest of `buf`.
+        //
+        // This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed
+        // recursive panic when using macros such as `print!` to write large amounts of data
+        // (buf.len() > 2048) to stdout at once.
+        for chunk in buf.chunks(STDOUT_BUF_SIZE) {
+            if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() {
+                self.flush().unwrap();
+            }
+
+            let count: usize = unsafe {
+                vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32)
+            }
+            .try_into()
+            .map_err(|_| {
+                io::const_error!(io::ErrorKind::Uncategorized, "internal write error occurred")
+            })?;
+
+            written += count;
+
+            // This is a sanity check to ensure that we don't end up with non-contiguous
+            // buffer writes. e.g. a chunk gets only partially written, but we continue
+            // attempting to write the remaining chunks.
+            //
+            // In practice, this should never really occur since the previous flush ensures
+            // enough space in FIFO to write the entire chunk to vexSerialWriteBuffer.
+            if count != chunk.len() {
+                break;
+            }
+        }
+
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // This may block for up to a millisecond.
+        unsafe {
+            while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE {
+                vex_sdk::vexTasksRun();
+            }
+        }
+
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 4096;
+pub const STDOUT_BUF_SIZE: usize = 2048;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    false
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stdout::new())
+}
diff --git a/library/std/src/sys/stdio/wasi.rs b/library/std/src/sys/stdio/wasip1.rs
index b70efd026f9..b70efd026f9 100644
--- a/library/std/src/sys/stdio/wasi.rs
+++ b/library/std/src/sys/stdio/wasip1.rs
diff --git a/library/std/src/sys/stdio/wasip2.rs b/library/std/src/sys/stdio/wasip2.rs
new file mode 100644
index 00000000000..1fcb49a083d
--- /dev/null
+++ b/library/std/src/sys/stdio/wasip2.rs
@@ -0,0 +1,120 @@
+use wasip2::cli;
+use wasip2::io::streams::{Error, InputStream, OutputStream, StreamError};
+
+use crate::io::{self, BorrowedBuf, BorrowedCursor};
+
+pub struct Stdin(Option<InputStream>);
+pub struct Stdout(Option<OutputStream>);
+pub struct Stderr(Option<OutputStream>);
+
+fn error_to_io(err: Error) -> io::Error {
+    // There exists a function in `wasi:filesystem` to optionally acquire an
+    // error code from an error, but the streams in use in this module are
+    // exclusively used with stdio meaning that a filesystem error is not
+    // possible here.
+    //
+    // In lieu of an error code, which WASIp2 does not specify, this instead
+    // carries along the `to_debug_string` implementation that the host
+    // supplies. If this becomes too expensive in the future this could also
+    // become `io::Error::from_raw_os_error(libc::EIO)` or similar.
+    io::Error::new(io::ErrorKind::Other, err.to_debug_string())
+}
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin(None)
+    }
+
+    fn stream(&mut self) -> &InputStream {
+        self.0.get_or_insert_with(cli::stdin::get_stdin)
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(data);
+        self.read_buf(buf.unfilled())?;
+        Ok(buf.len())
+    }
+
+    fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        match self.stream().blocking_read(u64::try_from(buf.capacity()).unwrap()) {
+            Ok(result) => {
+                buf.append(&result);
+                Ok(())
+            }
+            Err(StreamError::Closed) => Ok(()),
+            Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)),
+        }
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout(None)
+    }
+
+    fn stream(&mut self) -> &OutputStream {
+        self.0.get_or_insert_with(cli::stdout::get_stdout)
+    }
+}
+
+fn write(stream: &OutputStream, buf: &[u8]) -> io::Result<usize> {
+    // WASIp2's `blocking_write_and_flush` function is defined as accepting no
+    // more than 4096 bytes. Larger writes can be issued by manually using
+    // `check_write`, `write`, and `blocking_flush`, but for now just go ahead
+    // and use `blocking_write_and_flush` and report a short write and let a
+    // higher level loop over the result.
+    const MAX: usize = 4096;
+    let buf = &buf[..buf.len().min(MAX)];
+    match stream.blocking_write_and_flush(buf) {
+        Ok(()) => Ok(buf.len()),
+        Err(StreamError::Closed) => Ok(0),
+        Err(StreamError::LastOperationFailed(e)) => Err(error_to_io(e)),
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        write(self.stream(), data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // Note that `OutputStream` has a `flush` function but for stdio all
+        // writes are accompanied with a flush which means that this flush
+        // doesn't need to do anything.
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub const fn new() -> Stderr {
+        Stderr(None)
+    }
+
+    fn stream(&mut self) -> &OutputStream {
+        self.0.get_or_insert_with(cli::stderr::get_stderr)
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        write(self.stream(), data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // See `Stdout::flush` for why this is a noop.
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    // WASIp2 stdio streams are always available so ebadf never shows up.
+    false
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stderr::new())
+}
diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs
index d0c998a5597..cb67d273759 100644
--- a/library/std/src/sys/sync/condvar/mod.rs
+++ b/library/std/src/sys/sync/condvar/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor="win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,28 +9,34 @@ cfg_if::cfg_if! {
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Condvar;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         target_os = "teeos",
-    ))] {
+    ) => {
         mod pthread;
         pub use pthread::Condvar;
-    } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
+    }
+    all(target_os = "windows", target_vendor = "win7") => {
         mod windows7;
         pub use windows7::Condvar;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::Condvar;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod itron;
         pub use itron::Condvar;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Condvar;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::Condvar;
     }
diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs
index 360df3fc4b5..c885b0eabae 100644
--- a/library/std/src/sys/sync/mutex/mod.rs
+++ b/library/std/src/sys/sync/mutex/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -8,31 +8,38 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Mutex;
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         mod fuchsia;
         pub use fuchsia::Mutex;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         target_os = "teeos",
-    ))] {
+    ) => {
         mod pthread;
         pub use pthread::Mutex;
-    } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
+    }
+    all(target_os = "windows", target_vendor = "win7") => {
         mod windows7;
         pub use windows7::{Mutex, raw};
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::Mutex;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod itron;
         pub use itron::Mutex;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Mutex;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::Mutex;
     }
diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs
index 0e38937b121..8adeb1f259d 100644
--- a/library/std/src/sys/sync/once/mod.rs
+++ b/library/std/src/sys/sync/once/mod.rs
@@ -7,8 +7,8 @@
 // This also gives us the opportunity to optimize the implementation a bit which
 // should help the fast path on call sites.
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor="win7")),
         target_os = "linux",
         target_os = "android",
@@ -18,19 +18,21 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         target_os = "fuchsia",
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::{Once, OnceState};
-    } else if #[cfg(any(
+    }
+    any(
         windows,
         target_family = "unix",
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "solid_asp3",
         target_os = "xous",
-    ))] {
+    ) => {
         mod queue;
         pub use queue::{Once, OnceState};
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::{Once, OnceState};
     }
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 49e15d65f25..17d99cdb385 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -276,7 +276,9 @@ fn wait(
             // If the managing thread happens to signal and unpark us before we
             // can park ourselves, the result could be this thread never gets
             // unparked. Luckily `park` comes with the guarantee that if it got
-            // an `unpark` just before on an unparked thread it does not park.
+            // an `unpark` just before on an unparked thread it does not park. Crucially, we know
+            // the `unpark` must have happened between the `compare_exchange_weak` above and here,
+            // and there's no other `park` in that code that could steal our token.
             // SAFETY: we retrieved this handle on the current thread above.
             unsafe { node.thread.park() }
         }
diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs
index 70ba6bf38ef..82f1dd18dee 100644
--- a/library/std/src/sys/sync/rwlock/mod.rs
+++ b/library/std/src/sys/sync/rwlock/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,24 +9,28 @@ cfg_if::cfg_if! {
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::RwLock;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         all(target_os = "windows", target_vendor = "win7"),
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "xous",
-    ))] {
+    ) => {
         mod queue;
         pub use queue::RwLock;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::RwLock;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::RwLock;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::RwLock;
     }
diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs
index f4d8fa0a58c..b9fb27b4eef 100644
--- a/library/std/src/sys/sync/thread_parking/mod.rs
+++ b/library/std/src/sys/sync/thread_parking/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,30 +9,36 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         target_os = "fuchsia",
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Parker;
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "netbsd",
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "solid_asp3",
-    ))] {
+    ) => {
         mod id;
         pub use id::Parker;
-    } else if #[cfg(target_vendor = "win7")] {
+    }
+    target_vendor = "win7" => {
         mod windows7;
         pub use windows7::Parker;
-    } else if #[cfg(all(target_vendor = "apple", not(miri)))] {
+    }
+    all(target_vendor = "apple", not(miri)) => {
         // Doesn't work in Miri, see <https://github.com/rust-lang/miri/issues/2589>.
         mod darwin;
         pub use darwin::Parker;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Parker;
-    } else if #[cfg(target_family = "unix")] {
+    }
+    target_family = "unix" => {
         mod pthread;
         pub use pthread::Parker;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::Parker;
     }
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/thread/hermit.rs
index cc4734b6819..4d9f3b114c2 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/thread/hermit.rs
@@ -1,10 +1,5 @@
-#![allow(dead_code)]
-
-use super::hermit_abi;
-use crate::ffi::CStr;
-use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{io, ptr};
 
 pub type Tid = hermit_abi::Tid;
@@ -68,57 +63,30 @@ impl Thread {
         }
     }
 
-    #[inline]
-    pub fn yield_now() {
-        unsafe {
-            hermit_abi::yield_now();
-        }
-    }
-
-    #[inline]
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    #[inline]
-    pub fn sleep(dur: Duration) {
-        let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
-        let micros = u64::try_from(micros).unwrap_or(u64::MAX);
-
-        unsafe {
-            hermit_abi::usleep(micros);
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         unsafe {
             let _ = hermit_abi::join(self.tid);
         }
     }
+}
 
-    #[inline]
-    pub fn id(&self) -> Tid {
-        self.tid
-    }
-
-    #[inline]
-    pub fn into_id(self) -> Tid {
-        ManuallyDrop::new(self).tid
-    }
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
+#[inline]
+pub fn sleep(dur: Duration) {
+    let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
+    let micros = u64::try_from(micros).unwrap_or(u64::MAX);
+
+    unsafe {
+        hermit_abi::usleep(micros);
+    }
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
+#[inline]
+pub fn yield_now() {
+    unsafe {
+        hermit_abi::yield_now();
+    }
 }
diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs
new file mode 100644
index 00000000000..3bd83dd760a
--- /dev/null
+++ b/library/std/src/sys/thread/mod.rs
@@ -0,0 +1,159 @@
+cfg_select! {
+    target_os = "hermit" => {
+        mod hermit;
+        pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
+        mod sgx;
+        pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+
+        // SGX should protect in-enclave data from outside attackers, so there
+        // must not be any data leakage to the OS, particularly no 1-1 mapping
+        // between SGX thread names and OS thread names. Hence `set_name` is
+        // intentionally a no-op.
+        //
+        // Note that the internally visible SGX thread name is already provided
+        // by the platform-agnostic Rust thread code. This can be observed in
+        // the [`std::thread::tests::test_named_thread`] test, which succeeds
+        // as-is with the SGX target.
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, set_name};
+    }
+    target_os = "solid_asp3" => {
+        mod solid;
+        pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, current_os_id, set_name};
+    }
+    target_os = "teeos" => {
+        mod teeos;
+        pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, current_os_id, set_name};
+    }
+    target_os = "uefi" => {
+        mod uefi;
+        pub use uefi::{available_parallelism, sleep};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_family = "unix" => {
+        mod unix;
+        pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[cfg(not(any(
+            target_env = "newlib",
+            target_os = "l4re",
+            target_os = "emscripten",
+            target_os = "redox",
+            target_os = "hurd",
+            target_os = "aix",
+        )))]
+        pub use unix::set_name;
+        #[cfg(any(
+            target_os = "freebsd",
+            target_os = "netbsd",
+            target_os = "linux",
+            target_os = "android",
+            target_os = "solaris",
+            target_os = "illumos",
+            target_os = "dragonfly",
+            target_os = "hurd",
+            target_os = "fuchsia",
+            target_os = "vxworks",
+        ))]
+        pub use unix::sleep_until;
+        #[expect(dead_code)]
+        mod unsupported;
+        #[cfg(any(
+            target_env = "newlib",
+            target_os = "l4re",
+            target_os = "emscripten",
+            target_os = "redox",
+            target_os = "hurd",
+            target_os = "aix",
+        ))]
+        pub use unsupported::set_name;
+    }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use vexos::{sleep, yield_now};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE};
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now};
+        #[cfg(target_feature = "atomics")]
+        pub use wasip1::{Thread, available_parallelism};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+        #[cfg(not(target_feature = "atomics"))]
+        pub use unsupported::{Thread, available_parallelism};
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::{sleep, sleep_until};
+        #[expect(dead_code)]
+        mod unsupported;
+        // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
+        // there is no support for threads, not even experimentally, not even in
+        // wasi-libc. Thus this is unconditionally unsupported.
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    all(target_family = "wasm", target_feature = "atomics") => {
+        mod wasm;
+        pub use wasm::sleep;
+
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_os = "windows" => {
+        mod windows;
+        pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_os = "xous" => {
+        mod xous;
+        pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+    }
+    _ => {
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+}
+
+#[cfg(not(any(
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "dragonfly",
+    target_os = "hurd",
+    target_os = "fuchsia",
+    target_os = "vxworks",
+    all(target_os = "wasi", target_env = "p2"),
+)))]
+pub fn sleep_until(deadline: crate::time::Instant) {
+    use crate::time::Instant;
+
+    let now = Instant::now();
+
+    if let Some(delay) = deadline.checked_duration_since(now) {
+        sleep(delay);
+    }
+}
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/thread/sgx.rs
index 1f613badcd7..f20ef7d86b9 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/thread/sgx.rs
@@ -1,11 +1,8 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
 
-use super::abi::{thread, usercalls};
-use super::unsupported;
-use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::sys::pal::abi::{thread, usercalls};
+use crate::time::Duration;
 
 pub struct Thread(task_queue::JoinHandle);
 
@@ -108,51 +105,27 @@ impl Thread {
         Ok(Thread(handle))
     }
 
-    pub(super) fn entry() -> JoinNotifier {
+    pub(crate) fn entry() -> JoinNotifier {
         let mut pending_tasks = task_queue::lock();
         let task = rtunwrap!(Some, pending_tasks.pop());
         drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
         task.run()
     }
 
-    pub fn yield_now() {
-        let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
-        rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
-    }
-
-    /// SGX should protect in-enclave data from the outside (attacker),
-    /// so there should be no data leakage to the OS,
-    /// and therefore also no 1-1 mapping between SGX thread names and OS thread names.
-    ///
-    /// This is why the method is intentionally No-Op.
-    pub fn set_name(_name: &CStr) {
-        // Note that the internally visible SGX thread name is already provided
-        // by the platform-agnostic (target-agnostic) Rust thread code.
-        // This can be observed in the [`std::thread::tests::test_named_thread`] test,
-        // which succeeds as-is with the SGX target.
-    }
-
-    pub fn sleep(dur: Duration) {
-        usercalls::wait_timeout(0, dur, || true);
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         self.0.wait();
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
+pub fn current_os_id() -> Option<u64> {
     Some(thread::current().addr().get() as u64)
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
+pub fn sleep(dur: Duration) {
+    usercalls::wait_timeout(0, dur, || true);
+}
+
+pub fn yield_now() {
+    let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
+    rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
 }
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/thread/solid.rs
index 4e14cb3cbca..46a84faa802 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/thread/solid.rs
@@ -1,16 +1,14 @@
 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
 //! `exd_tsk` are available.
 
-use super::error::{ItronError, expect_success, expect_success_aborting};
-use super::time::dur2reltims;
-use super::{abi, task};
 use crate::cell::UnsafeCell;
-use crate::ffi::CStr;
 use crate::mem::ManuallyDrop;
-use crate::num::NonZero;
 use crate::ptr::NonNull;
 use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
-use crate::time::{Duration, Instant};
+use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting};
+use crate::sys::pal::itron::time::dur2reltims;
+use crate::sys::pal::itron::{abi, task};
+use crate::time::Duration;
 use crate::{hint, io};
 
 pub struct Thread {
@@ -195,28 +193,6 @@ impl Thread {
         Ok(Self { p_inner, task: new_task })
     }
 
-    pub fn yield_now() {
-        expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        for timeout in dur2reltims(dur) {
-            expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         // Safety: `ThreadInner` is alive at this point
         let inner = unsafe { self.p_inner.as_ref() };
@@ -361,10 +337,12 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
+pub fn yield_now() {
+    expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    super::unsupported()
+pub fn sleep(dur: Duration) {
+    for timeout in dur2reltims(dur) {
+        expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
+    }
 }
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/thread/teeos.rs
index 1812d11e692..cad100395c9 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/thread/teeos.rs
@@ -1,12 +1,18 @@
-use crate::ffi::CStr;
 use crate::mem::{self, ManuallyDrop};
-use crate::num::NonZero;
 use crate::sys::os;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{cmp, io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
 
+unsafe extern "C" {
+    safe fn TEE_Wait(timeout: u32) -> u32;
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+}
+
 pub struct Thread {
     id: libc::pthread_t,
 }
@@ -16,10 +22,6 @@ pub struct Thread {
 unsafe impl Send for Thread {}
 unsafe impl Sync for Thread {}
 
-unsafe extern "C" {
-    pub fn TEE_Wait(timeout: u32) -> u32;
-}
-
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(
@@ -74,7 +76,7 @@ impl Thread {
         } else {
             // The new thread will start running earliest after the next yield.
             // We add a yield here, so that the user does not have to.
-            Thread::yield_now();
+            yield_now();
             Ok(Thread { id: native })
         };
 
@@ -91,36 +93,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        let ret = unsafe { libc::sched_yield() };
-        debug_assert_eq!(ret, 0);
-    }
-
-    /// This does not do anything on teeos
-    pub fn set_name(_name: &CStr) {
-        // Both pthread_setname_np and prctl are not available to the TA,
-        // so we can't implement this currently. If the need arises please
-        // contact the teeos rustzone team.
-    }
-
-    /// only main thread could wait for sometime in teeos
-    pub fn sleep(dur: Duration) {
-        let sleep_millis = dur.as_millis();
-        let final_sleep: u32 =
-            if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
-        unsafe {
-            let _ = TEE_Wait(final_sleep);
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     /// must join, because no pthread_detach supported
     pub fn join(self) {
         let id = self.into_id();
@@ -128,10 +100,6 @@ impl Thread {
         assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
     }
 
-    pub fn id(&self) -> libc::pthread_t {
-        self.id
-    }
-
     pub fn into_id(self) -> libc::pthread_t {
         ManuallyDrop::new(self).id
     }
@@ -144,16 +112,15 @@ impl Drop for Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
-// teeos, so this function always returns an Error!
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    Err(io::Error::UNKNOWN_THREAD_COUNT)
+pub fn yield_now() {
+    let ret = unsafe { libc::sched_yield() };
+    debug_assert_eq!(ret, 0);
 }
 
-fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
-    libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+/// only main thread could wait for sometime in teeos
+pub fn sleep(dur: Duration) {
+    let sleep_millis = dur.as_millis();
+    let final_sleep: u32 =
+        if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
+    TEE_Wait(final_sleep);
 }
diff --git a/library/std/src/sys/thread/uefi.rs b/library/std/src/sys/thread/uefi.rs
new file mode 100644
index 00000000000..94f67d7ace2
--- /dev/null
+++ b/library/std/src/sys/thread/uefi.rs
@@ -0,0 +1,25 @@
+use crate::io;
+use crate::num::NonZero;
+use crate::ptr::NonNull;
+use crate::time::Duration;
+
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    // UEFI is single threaded
+    Ok(NonZero::new(1).unwrap())
+}
+
+pub fn sleep(dur: Duration) {
+    let boot_services: NonNull<r_efi::efi::BootServices> =
+        crate::os::uefi::env::boot_services().expect("can't sleep").cast();
+    let mut dur_ms = dur.as_micros();
+    // ceil up to the nearest microsecond
+    if dur.subsec_nanos() % 1000 > 0 {
+        dur_ms += 1;
+    }
+
+    while dur_ms > 0 {
+        let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
+        let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
+        dur_ms -= ms;
+    }
+}
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/thread/unix.rs
index 36e53e7cadc..2d2c4f90212 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/thread/unix.rs
@@ -1,3 +1,11 @@
+#[cfg(not(any(
+    target_env = "newlib",
+    target_os = "l4re",
+    target_os = "emscripten",
+    target_os = "redox",
+    target_os = "hurd",
+    target_os = "aix",
+)))]
 use crate::ffi::CStr;
 use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
@@ -6,7 +14,7 @@ use crate::sys::weak::dlsym;
 #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
 use crate::sys::weak::weak;
 use crate::sys::{os, stack_overflow};
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{cmp, io, ptr};
 #[cfg(not(any(
     target_os = "l4re",
@@ -77,7 +85,18 @@ impl Thread {
                     let page_size = os::page_size();
                     let stack_size =
                         (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
-                    assert_eq!(libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size), 0);
+
+                    // Some libc implementations, e.g. musl, place an upper bound
+                    // on the stack size, in which case we can only gracefully return
+                    // an error here.
+                    if libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size) != 0 {
+                        assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0);
+                        drop(Box::from_raw(data));
+                        return Err(io::const_error!(
+                            io::ErrorKind::InvalidInput,
+                            "invalid stack size"
+                        ));
+                    }
                 }
             };
         }
@@ -110,272 +129,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        let ret = unsafe { libc::sched_yield() };
-        debug_assert_eq!(ret, 0);
-    }
-
-    #[cfg(target_os = "android")]
-    pub fn set_name(name: &CStr) {
-        const PR_SET_NAME: libc::c_int = 15;
-        unsafe {
-            let res = libc::prctl(
-                PR_SET_NAME,
-                name.as_ptr(),
-                0 as libc::c_ulong,
-                0 as libc::c_ulong,
-                0 as libc::c_ulong,
-            );
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "nuttx",
-        target_os = "cygwin"
-    ))]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(target_os = "linux", target_os = "cygwin"))] {
-                    // Linux and Cygwin limits the allowed length of the name.
-                    const TASK_COMM_LEN: usize = 16;
-                    let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
-                } else {
-                    // FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
-                }
-            };
-            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
-            // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
-            let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "openbsd")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
-        }
-    }
-
-    #[cfg(target_vendor = "apple")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
-            let res = libc::pthread_setname_np(name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "netbsd")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let res = libc::pthread_setname_np(
-                libc::pthread_self(),
-                c"%s".as_ptr(),
-                name.as_ptr() as *mut libc::c_void,
-            );
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
-    pub fn set_name(name: &CStr) {
-        weak!(
-            fn pthread_setname_np(
-                thread: libc::pthread_t,
-                name: *const libc::c_char,
-            ) -> libc::c_int;
-        );
-
-        if let Some(f) = pthread_setname_np.get() {
-            #[cfg(target_os = "nto")]
-            const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
-            #[cfg(any(target_os = "solaris", target_os = "illumos"))]
-            const THREAD_NAME_MAX: usize = 32;
-
-            let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
-            let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "fuchsia")]
-    pub fn set_name(name: &CStr) {
-        use super::fuchsia::*;
-        unsafe {
-            zx_object_set_property(
-                zx_thread_self(),
-                ZX_PROP_NAME,
-                name.as_ptr() as *const libc::c_void,
-                name.to_bytes().len(),
-            );
-        }
-    }
-
-    #[cfg(target_os = "haiku")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let thread_self = libc::find_thread(ptr::null_mut());
-            let res = libc::rename_thread(thread_self, name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, libc::B_OK);
-        }
-    }
-
-    #[cfg(target_os = "vxworks")]
-    pub fn set_name(name: &CStr) {
-        let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
-        let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
-        debug_assert_eq!(res, libc::OK);
-    }
-
-    #[cfg(any(
-        target_env = "newlib",
-        target_os = "l4re",
-        target_os = "emscripten",
-        target_os = "redox",
-        target_os = "hurd",
-        target_os = "aix",
-    ))]
-    pub fn set_name(_name: &CStr) {
-        // Newlib and Emscripten have no way to set a thread name.
-    }
-
-    #[cfg(not(target_os = "espidf"))]
-    pub fn sleep(dur: Duration) {
-        let mut secs = dur.as_secs();
-        let mut nsecs = dur.subsec_nanos() as _;
-
-        // If we're awoken with a signal then the return value will be -1 and
-        // nanosleep will fill in `ts` with the remaining time.
-        unsafe {
-            while secs > 0 || nsecs > 0 {
-                let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
-                    tv_nsec: nsecs,
-                };
-                secs -= ts.tv_sec as u64;
-                let ts_ptr = &raw mut ts;
-                if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
-                    assert_eq!(os::errno(), libc::EINTR);
-                    secs += ts.tv_sec as u64;
-                    nsecs = ts.tv_nsec;
-                } else {
-                    nsecs = 0;
-                }
-            }
-        }
-    }
-
-    #[cfg(target_os = "espidf")]
-    pub fn sleep(dur: Duration) {
-        // ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
-        // As per the documentation of `usleep`, it is expected to support
-        // sleep times as big as at least up to 1 second.
-        //
-        // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
-        // `usleep` implementation
-        // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
-        // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
-        // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
-        const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
-
-        // Add any nanoseconds smaller than a microsecond as an extra microsecond
-        // so as to comply with the `std::thread::sleep` contract which mandates
-        // implementations to sleep for _at least_ the provided `dur`.
-        // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
-        // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
-        // (i.e. < 1_000_000_000)
-        let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
-
-        while micros > 0 {
-            let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
-            unsafe {
-                libc::usleep(st);
-            }
-
-            micros -= st as u128;
-        }
-    }
-
-    // Any unix that has clock_nanosleep
-    // If this list changes update the MIRI chock_nanosleep shim
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "linux",
-        target_os = "android",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "dragonfly",
-        target_os = "hurd",
-        target_os = "fuchsia",
-        target_os = "vxworks",
-    ))]
-    pub fn sleep_until(deadline: Instant) {
-        let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
-            // The deadline is further in the future then can be passed to
-            // clock_nanosleep. We have to use Self::sleep instead. This might
-            // happen on 32 bit platforms, especially closer to 2038.
-            let now = Instant::now();
-            if let Some(delay) = deadline.checked_duration_since(now) {
-                Self::sleep(delay);
-            }
-            return;
-        };
-
-        unsafe {
-            // When we get interrupted (res = EINTR) call clock_nanosleep again
-            loop {
-                let res = libc::clock_nanosleep(
-                    super::time::Instant::CLOCK_ID,
-                    libc::TIMER_ABSTIME,
-                    &ts,
-                    core::ptr::null_mut(), // not required with TIMER_ABSTIME
-                );
-
-                if res == 0 {
-                    break;
-                } else {
-                    assert_eq!(
-                        res,
-                        libc::EINTR,
-                        "timespec is in range,
-                         clockid is valid and kernel should support it"
-                    );
-                }
-            }
-        }
-    }
-
-    // Any unix that does not have clock_nanosleep
-    #[cfg(not(any(
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "linux",
-        target_os = "android",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "dragonfly",
-        target_os = "hurd",
-        target_os = "fuchsia",
-        target_os = "vxworks",
-    )))]
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         let id = self.into_id();
         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
@@ -398,82 +151,9 @@ impl Drop for Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    // Most Unix platforms have a way to query an integer ID of the current thread, all with
-    // slightly different spellings.
-    //
-    // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
-    // for process inspection (debuggers, trace, `top`, etc.).
-    cfg_if::cfg_if! {
-        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
-        if #[cfg(any(target_os = "android", target_os = "linux"))] {
-            use crate::sys::weak::syscall;
-
-            // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
-            // since Linux 2.4.11.
-            syscall!(fn gettid() -> libc::pid_t;);
-
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { gettid() };
-            Some(id as u64)
-        } else if #[cfg(target_os = "nto")] {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { libc::gettid() };
-            Some(id as u64)
-        } else if #[cfg(target_os = "openbsd")] {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { libc::getthrid() };
-            Some(id as u64)
-        } else if #[cfg(target_os = "freebsd")] {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
-            Some(id as u64)
-        } else if #[cfg(target_os = "netbsd")] {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
-            Some(id as u64)
-        } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
-            // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pthread_t = unsafe { libc::pthread_self() };
-            Some(id as u64)
-        } else if #[cfg(target_vendor = "apple")] {
-            // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
-            let mut id = 0u64;
-            // SAFETY: `thread_id` is a valid pointer, no other preconditions.
-            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
-            if status == 0 {
-                Some(id)
-            } else {
-                None
-            }
-        } else {
-            // Other platforms don't have an OS thread ID or don't have a way to access it.
-            None
-        }
-    }
-}
-
-#[cfg(any(
-    target_os = "linux",
-    target_os = "nto",
-    target_os = "solaris",
-    target_os = "illumos",
-    target_os = "vxworks",
-    target_os = "cygwin",
-    target_vendor = "apple",
-))]
-fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
-    let mut result = [0; MAX_WITH_NUL];
-    for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
-        *dst = *src as libc::c_char;
-    }
-    result
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_os = "android",
             target_os = "emscripten",
             target_os = "fuchsia",
@@ -482,7 +162,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             target_os = "aix",
             target_vendor = "apple",
             target_os = "cygwin",
-        ))] {
+        ) => {
             #[allow(unused_assignments)]
             #[allow(unused_mut)]
             let mut quota = usize::MAX;
@@ -516,12 +196,13 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     Ok(unsafe { NonZero::new_unchecked(count) })
                 }
             }
-        } else if #[cfg(any(
-                   target_os = "freebsd",
-                   target_os = "dragonfly",
-                   target_os = "openbsd",
-                   target_os = "netbsd",
-               ))] {
+        }
+        any(
+           target_os = "freebsd",
+           target_os = "dragonfly",
+           target_os = "openbsd",
+           target_os = "netbsd",
+        ) => {
             use crate::ptr;
 
             #[cfg(target_os = "freebsd")]
@@ -596,7 +277,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             }
 
             Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
-        } else if #[cfg(target_os = "nto")] {
+        }
+        target_os = "nto" => {
             unsafe {
                 use libc::_syspage_ptr;
                 if _syspage_ptr.is_null() {
@@ -607,13 +289,15 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                         .ok_or(io::Error::UNKNOWN_THREAD_COUNT)
                 }
             }
-        } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
+        }
+        any(target_os = "solaris", target_os = "illumos") => {
             let mut cpus = 0u32;
             if unsafe { libc::pset_info(libc::PS_MYID, core::ptr::null_mut(), &mut cpus, core::ptr::null_mut()) } != 0 {
                 return Err(io::Error::UNKNOWN_THREAD_COUNT);
             }
             Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
-        } else if #[cfg(target_os = "haiku")] {
+        }
+        target_os = "haiku" => {
             // system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus`
             // `get_system_info` calls then `smp_get_num_cpus`
             unsafe {
@@ -626,7 +310,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
 
                 Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
             }
-        } else if #[cfg(target_os = "vxworks")] {
+        }
+        target_os = "vxworks" => {
             // Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
             // expectations than the actual cores availability.
             unsafe extern "C" {
@@ -638,13 +323,326 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 let set = vxCpuEnabledGet();
                 Ok(NonZero::new_unchecked(set.count_ones() as usize))
             }
-        } else {
+        }
+        _ => {
             // FIXME: implement on Redox, l4re
             Err(io::const_error!(io::ErrorKind::Unsupported, "getting the number of hardware threads is not supported on the target platform"))
         }
     }
 }
 
+pub fn current_os_id() -> Option<u64> {
+    // Most Unix platforms have a way to query an integer ID of the current thread, all with
+    // slightly different spellings.
+    //
+    // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
+    // for process inspection (debuggers, trace, `top`, etc.).
+    cfg_select! {
+        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
+        any(target_os = "android", target_os = "linux") => {
+            use crate::sys::pal::weak::syscall;
+
+            // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
+            // since Linux 2.4.11.
+            syscall!(fn gettid() -> libc::pid_t;);
+
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { gettid() };
+            Some(id as u64)
+        }
+        target_os = "nto" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::gettid() };
+            Some(id as u64)
+        }
+        target_os = "openbsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::getthrid() };
+            Some(id as u64)
+        }
+        target_os = "freebsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
+            Some(id as u64)
+        }
+        target_os = "netbsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
+            Some(id as u64)
+        }
+        any(target_os = "illumos", target_os = "solaris") => {
+            // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pthread_t = unsafe { libc::pthread_self() };
+            Some(id as u64)
+        }
+        target_vendor = "apple" => {
+            // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
+            let mut id = 0u64;
+            // SAFETY: `thread_id` is a valid pointer, no other preconditions.
+            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
+            if status == 0 {
+                Some(id)
+            } else {
+                None
+            }
+        }
+        // Other platforms don't have an OS thread ID or don't have a way to access it.
+        _ => None,
+    }
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "nto",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "vxworks",
+    target_os = "cygwin",
+    target_vendor = "apple",
+))]
+fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
+    let mut result = [0; MAX_WITH_NUL];
+    for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
+        *dst = *src as libc::c_char;
+    }
+    result
+}
+
+#[cfg(target_os = "android")]
+pub fn set_name(name: &CStr) {
+    const PR_SET_NAME: libc::c_int = 15;
+    unsafe {
+        let res = libc::prctl(
+            PR_SET_NAME,
+            name.as_ptr(),
+            0 as libc::c_ulong,
+            0 as libc::c_ulong,
+            0 as libc::c_ulong,
+        );
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "nuttx",
+    target_os = "cygwin"
+))]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        cfg_select! {
+            any(target_os = "linux", target_os = "cygwin") => {
+                // Linux and Cygwin limits the allowed length of the name.
+                const TASK_COMM_LEN: usize = 16;
+                let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
+            }
+            _ => {
+                // FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
+            }
+        };
+        // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
+        // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
+        let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "openbsd")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
+    }
+}
+
+#[cfg(target_vendor = "apple")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
+        let res = libc::pthread_setname_np(name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "netbsd")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let res = libc::pthread_setname_np(
+            libc::pthread_self(),
+            c"%s".as_ptr(),
+            name.as_ptr() as *mut libc::c_void,
+        );
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
+pub fn set_name(name: &CStr) {
+    weak!(
+        fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int;
+    );
+
+    if let Some(f) = pthread_setname_np.get() {
+        #[cfg(target_os = "nto")]
+        const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
+        #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+        const THREAD_NAME_MAX: usize = 32;
+
+        let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
+        let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "fuchsia")]
+pub fn set_name(name: &CStr) {
+    use crate::sys::pal::fuchsia::*;
+    unsafe {
+        zx_object_set_property(
+            zx_thread_self(),
+            ZX_PROP_NAME,
+            name.as_ptr() as *const libc::c_void,
+            name.to_bytes().len(),
+        );
+    }
+}
+
+#[cfg(target_os = "haiku")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let thread_self = libc::find_thread(ptr::null_mut());
+        let res = libc::rename_thread(thread_self, name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, libc::B_OK);
+    }
+}
+
+#[cfg(target_os = "vxworks")]
+pub fn set_name(name: &CStr) {
+    let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
+    let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
+    debug_assert_eq!(res, libc::OK);
+}
+
+#[cfg(not(target_os = "espidf"))]
+pub fn sleep(dur: Duration) {
+    let mut secs = dur.as_secs();
+    let mut nsecs = dur.subsec_nanos() as _;
+
+    // If we're awoken with a signal then the return value will be -1 and
+    // nanosleep will fill in `ts` with the remaining time.
+    unsafe {
+        while secs > 0 || nsecs > 0 {
+            let mut ts = libc::timespec {
+                tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
+                tv_nsec: nsecs,
+            };
+            secs -= ts.tv_sec as u64;
+            let ts_ptr = &raw mut ts;
+            if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
+                assert_eq!(os::errno(), libc::EINTR);
+                secs += ts.tv_sec as u64;
+                nsecs = ts.tv_nsec;
+            } else {
+                nsecs = 0;
+            }
+        }
+    }
+}
+
+#[cfg(target_os = "espidf")]
+pub fn sleep(dur: Duration) {
+    // ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
+    // As per the documentation of `usleep`, it is expected to support
+    // sleep times as big as at least up to 1 second.
+    //
+    // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
+    // `usleep` implementation
+    // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
+    // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
+    // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
+    const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
+
+    // Add any nanoseconds smaller than a microsecond as an extra microsecond
+    // so as to comply with the `std::thread::sleep` contract which mandates
+    // implementations to sleep for _at least_ the provided `dur`.
+    // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
+    // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
+    // (i.e. < 1_000_000_000)
+    let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
+
+    while micros > 0 {
+        let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
+        unsafe {
+            libc::usleep(st);
+        }
+
+        micros -= st as u128;
+    }
+}
+
+// Any unix that has clock_nanosleep
+// If this list changes update the MIRI chock_nanosleep shim
+#[cfg(any(
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "dragonfly",
+    target_os = "hurd",
+    target_os = "fuchsia",
+    target_os = "vxworks",
+))]
+pub fn sleep_until(deadline: crate::time::Instant) {
+    use crate::time::Instant;
+
+    let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
+        // The deadline is further in the future then can be passed to
+        // clock_nanosleep. We have to use Self::sleep instead. This might
+        // happen on 32 bit platforms, especially closer to 2038.
+        let now = Instant::now();
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            sleep(delay);
+        }
+        return;
+    };
+
+    unsafe {
+        // When we get interrupted (res = EINTR) call clock_nanosleep again
+        loop {
+            let res = libc::clock_nanosleep(
+                crate::sys::time::Instant::CLOCK_ID,
+                libc::TIMER_ABSTIME,
+                &ts,
+                core::ptr::null_mut(), // not required with TIMER_ABSTIME
+            );
+
+            if res == 0 {
+                break;
+            } else {
+                assert_eq!(
+                    res,
+                    libc::EINTR,
+                    "timespec is in range,
+                         clockid is valid and kernel should support it"
+                );
+            }
+        }
+    }
+}
+
+pub fn yield_now() {
+    let ret = unsafe { libc::sched_yield() };
+    debug_assert_eq!(ret, 0);
+}
+
 #[cfg(any(target_os = "android", target_os = "linux"))]
 mod cgroups {
     //! Currently not covered
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/thread/unsupported.rs
index 34d9b5ec70c..a5001efa3b4 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/thread/unsupported.rs
@@ -1,8 +1,7 @@
-use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 
 pub struct Thread(!);
 
@@ -15,23 +14,7 @@ impl Thread {
         _name: Option<&str>,
         _p: Box<dyn FnOnce()>,
     ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {
-        // do nothing
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(_dur: Duration) {
-        panic!("can't sleep");
-    }
-
-    pub fn sleep_until(_deadline: Instant) {
-        panic!("can't sleep");
+        Err(io::Error::UNSUPPORTED_PLATFORM)
     }
 
     pub fn join(self) {
@@ -39,10 +22,22 @@ impl Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    Err(io::Error::UNKNOWN_THREAD_COUNT)
+}
+
+pub fn current_os_id() -> Option<u64> {
     None
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
+pub fn yield_now() {
+    // do nothing
+}
+
+pub fn set_name(_name: &CStr) {
+    // nope
+}
+
+pub fn sleep(_dur: Duration) {
+    panic!("can't sleep");
 }
diff --git a/library/std/src/sys/thread/vexos.rs b/library/std/src/sys/thread/vexos.rs
new file mode 100644
index 00000000000..d917dde4d0b
--- /dev/null
+++ b/library/std/src/sys/thread/vexos.rs
@@ -0,0 +1,17 @@
+use crate::time::{Duration, Instant};
+
+pub fn yield_now() {
+    unsafe {
+        vex_sdk::vexTasksRun();
+    }
+}
+
+pub fn sleep(dur: Duration) {
+    let start = Instant::now();
+
+    while start.elapsed() < dur {
+        unsafe {
+            vex_sdk::vexTasksRun();
+        }
+    }
+}
diff --git a/library/std/src/sys/thread/wasip1.rs b/library/std/src/sys/thread/wasip1.rs
new file mode 100644
index 00000000000..83001fad49c
--- /dev/null
+++ b/library/std/src/sys/thread/wasip1.rs
@@ -0,0 +1,185 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+#[cfg(target_feature = "atomics")]
+use crate::io;
+use crate::mem;
+#[cfg(target_feature = "atomics")]
+use crate::num::NonZero;
+#[cfg(target_feature = "atomics")]
+use crate::sys::os;
+use crate::time::Duration;
+#[cfg(target_feature = "atomics")]
+use crate::{cmp, ptr};
+
+// Add a few symbols not in upstream `libc` just yet.
+#[cfg(target_feature = "atomics")]
+mod libc {
+    pub use libc::*;
+
+    pub use crate::ffi;
+
+    // defined in wasi-libc
+    // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
+    #[repr(C)]
+    union pthread_attr_union {
+        __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+        __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+        __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
+    }
+
+    #[repr(C)]
+    pub struct pthread_attr_t {
+        __u: pthread_attr_union,
+    }
+
+    #[allow(non_camel_case_types)]
+    pub type pthread_t = *mut ffi::c_void;
+
+    pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
+
+    unsafe extern "C" {
+        pub fn pthread_create(
+            native: *mut pthread_t,
+            attr: *const pthread_attr_t,
+            f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
+            value: *mut ffi::c_void,
+        ) -> ffi::c_int;
+        pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
+        pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
+        pub fn pthread_attr_setstacksize(
+            attr: *mut pthread_attr_t,
+            stack_size: libc::size_t,
+        ) -> ffi::c_int;
+        pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
+        pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
+    }
+}
+
+#[cfg(target_feature = "atomics")]
+pub struct Thread {
+    id: libc::pthread_t,
+}
+
+#[cfg(target_feature = "atomics")]
+impl Drop for Thread {
+    fn drop(&mut self) {
+        let ret = unsafe { libc::pthread_detach(self.id) };
+        debug_assert_eq!(ret, 0);
+    }
+}
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
+#[cfg(target_feature = "atomics")]
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
+        let p = Box::into_raw(Box::new(p));
+        let mut native: libc::pthread_t = unsafe { mem::zeroed() };
+        let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
+        assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
+
+        let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
+
+        match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
+            0 => {}
+            n => {
+                assert_eq!(n, libc::EINVAL);
+                // EINVAL means |stack_size| is either too small or not a
+                // multiple of the system page size. Because it's definitely
+                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+                // Round up to the nearest page and try again.
+                let page_size = os::page_size();
+                let stack_size =
+                    (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
+                assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
+            }
+        };
+
+        let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
+        // Note: if the thread creation fails and this assert fails, then p will
+        // be leaked. However, an alternative design could cause double-free
+        // which is clearly worse.
+        assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
+
+        return if ret != 0 {
+            // The thread failed to start and as a result p was not consumed. Therefore, it is
+            // safe to reconstruct the box so that it gets deallocated.
+            unsafe {
+                drop(Box::from_raw(p));
+            }
+            Err(io::Error::from_raw_os_error(ret))
+        } else {
+            Ok(Thread { id: native })
+        };
+
+        extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+            unsafe {
+                // Finally, let's run some code.
+                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+            }
+            ptr::null_mut()
+        }
+    }
+
+    pub fn join(self) {
+        let id = mem::ManuallyDrop::new(self).id;
+        let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+        if ret != 0 {
+            rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
+        }
+    }
+}
+
+#[cfg(target_feature = "atomics")]
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
+        -1 => Err(io::Error::last_os_error()),
+        cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
+    }
+}
+
+pub fn yield_now() {
+    let ret = unsafe { wasi::sched_yield() };
+    debug_assert_eq!(ret, Ok(()));
+}
+
+pub fn sleep(dur: Duration) {
+    let mut nanos = dur.as_nanos();
+    while nanos > 0 {
+        const USERDATA: wasi::Userdata = 0x0123_45678;
+
+        let clock = wasi::SubscriptionClock {
+            id: wasi::CLOCKID_MONOTONIC,
+            timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
+            precision: 0,
+            flags: 0,
+        };
+        nanos -= u128::from(clock.timeout);
+
+        let in_ = wasi::Subscription {
+            userdata: USERDATA,
+            u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
+        };
+        unsafe {
+            let mut event: wasi::Event = mem::zeroed();
+            let res = wasi::poll_oneoff(&in_, &mut event, 1);
+            match (res, event) {
+                (
+                    Ok(1),
+                    wasi::Event {
+                        userdata: USERDATA,
+                        error: wasi::ERRNO_SUCCESS,
+                        type_: wasi::EVENTTYPE_CLOCK,
+                        ..
+                    },
+                ) => {}
+                _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/thread/wasip2.rs b/library/std/src/sys/thread/wasip2.rs
new file mode 100644
index 00000000000..420cad2a5e4
--- /dev/null
+++ b/library/std/src/sys/thread/wasip2.rs
@@ -0,0 +1,32 @@
+use crate::time::{Duration, Instant};
+
+pub fn sleep(dur: Duration) {
+    // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is
+    // entirely drained.
+    let mut remaining = dur.as_nanos();
+    while remaining > 0 {
+        let amt = u64::try_from(remaining).unwrap_or(u64::MAX);
+        wasip2::clocks::monotonic_clock::subscribe_duration(amt).block();
+        remaining -= u128::from(amt);
+    }
+}
+
+pub fn sleep_until(deadline: Instant) {
+    match u64::try_from(deadline.into_inner().as_duration().as_nanos()) {
+        // If the point in time we're sleeping to fits within a 64-bit
+        // number of nanoseconds then directly use `subscribe_instant`.
+        Ok(deadline) => {
+            wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block();
+        }
+        // ... otherwise we're sleeping for 500+ years relative to the
+        // "start" of what the system is using as a clock so speed/accuracy
+        // is not so much of a concern. Use `sleep` instead.
+        Err(_) => {
+            let now = Instant::now();
+
+            if let Some(delay) = deadline.checked_duration_since(now) {
+                sleep(delay);
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/thread/wasm.rs b/library/std/src/sys/thread/wasm.rs
new file mode 100644
index 00000000000..e843bc992ba
--- /dev/null
+++ b/library/std/src/sys/thread/wasm.rs
@@ -0,0 +1,23 @@
+use crate::cmp;
+use crate::time::Duration;
+
+pub fn sleep(dur: Duration) {
+    #[cfg(target_arch = "wasm32")]
+    use core::arch::wasm32 as wasm;
+    #[cfg(target_arch = "wasm64")]
+    use core::arch::wasm64 as wasm;
+
+    // Use an atomic wait to block the current thread artificially with a
+    // timeout listed. Note that we should never be notified (return value
+    // of 0) or our comparison should never fail (return value of 1) so we
+    // should always only resume execution through a timeout (return value
+    // 2).
+    let mut nanos = dur.as_nanos();
+    while nanos > 0 {
+        let amt = cmp::min(i64::MAX as u128, nanos);
+        let mut x = 0;
+        let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
+        debug_assert_eq!(val, 2);
+        nanos -= amt;
+    }
+}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/thread/windows.rs
index c708da5af12..a5640c51c4a 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/thread/windows.rs
@@ -1,14 +1,14 @@
 use core::ffi::c_void;
 
-use super::time::WaitableTimer;
-use super::to_u16s;
 use crate::ffi::CStr;
 use crate::num::NonZero;
 use crate::os::windows::io::{AsRawHandle, HandleOrNull};
 use crate::sys::handle::Handle;
+use crate::sys::pal::time::WaitableTimer;
+use crate::sys::pal::{dur2timeout, to_u16s};
 use crate::sys::{c, stack_overflow};
 use crate::sys_common::FromInner;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -62,24 +62,6 @@ impl Thread {
         }
     }
 
-    pub fn set_name(name: &CStr) {
-        if let Ok(utf8) = name.to_str() {
-            if let Ok(utf16) = to_u16s(utf8) {
-                unsafe {
-                    // SAFETY: the vec returned by `to_u16s` ends with a zero value
-                    Self::set_name_wide(&utf16)
-                }
-            };
-        };
-    }
-
-    /// # Safety
-    ///
-    /// `name` must end with a zero value
-    pub unsafe fn set_name_wide(name: &[u16]) {
-        unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
-    }
-
     pub fn join(self) {
         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
         if rc == c::WAIT_FAILED {
@@ -87,37 +69,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        // This function will return 0 if there are no other threads to execute,
-        // but this also means that the yield was useless so this isn't really a
-        // case that needs to be worried about.
-        unsafe {
-            c::SwitchToThread();
-        }
-    }
-
-    pub fn sleep(dur: Duration) {
-        fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
-            let timer = WaitableTimer::high_resolution()?;
-            timer.set(dur)?;
-            timer.wait()
-        }
-        // Attempt to use high-precision sleep (Windows 10, version 1803+).
-        // On error fallback to the standard `Sleep` function.
-        // Also preserves the zero duration behavior of `Sleep`.
-        if dur.is_zero() || high_precision_sleep(dur).is_err() {
-            unsafe { c::Sleep(super::dur2timeout(dur)) }
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn handle(&self) -> &Handle {
         &self.handle
     }
@@ -127,14 +78,6 @@ impl Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    // SAFETY: FFI call with no preconditions.
-    let id: u32 = unsafe { c::GetThreadId(c::GetCurrentThread()) };
-
-    // A return value of 0 indicates failed lookup.
-    if id == 0 { None } else { Some(id.into()) }
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     let res = unsafe {
         let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
@@ -146,3 +89,52 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
         cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
+
+pub fn current_os_id() -> Option<u64> {
+    // SAFETY: FFI call with no preconditions.
+    let id: u32 = unsafe { c::GetCurrentThreadId() };
+
+    // A return value of 0 indicates failed lookup.
+    if id == 0 { None } else { Some(id.into()) }
+}
+
+pub fn set_name(name: &CStr) {
+    if let Ok(utf8) = name.to_str() {
+        if let Ok(utf16) = to_u16s(utf8) {
+            unsafe {
+                // SAFETY: the vec returned by `to_u16s` ends with a zero value
+                set_name_wide(&utf16)
+            }
+        };
+    };
+}
+
+/// # Safety
+///
+/// `name` must end with a zero value
+pub unsafe fn set_name_wide(name: &[u16]) {
+    unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
+}
+
+pub fn sleep(dur: Duration) {
+    fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
+        let timer = WaitableTimer::high_resolution()?;
+        timer.set(dur)?;
+        timer.wait()
+    }
+    // Attempt to use high-precision sleep (Windows 10, version 1803+).
+    // On error fallback to the standard `Sleep` function.
+    // Also preserves the zero duration behavior of `Sleep`.
+    if dur.is_zero() || high_precision_sleep(dur).is_err() {
+        unsafe { c::Sleep(dur2timeout(dur)) }
+    }
+}
+
+pub fn yield_now() {
+    // This function will return 0 if there are no other threads to execute,
+    // but this also means that the yield was useless so this isn't really a
+    // case that needs to be worried about.
+    unsafe {
+        c::SwitchToThread();
+    }
+}
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/thread/xous.rs
index 92803c94c6e..133e15a0928 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/thread/xous.rs
@@ -1,6 +1,5 @@
 use core::arch::asm;
 
-use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
 use crate::os::xous::ffi::{
@@ -8,7 +7,7 @@ use crate::os::xous::ffi::{
     map_memory, update_memory_flags,
 };
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 
 pub struct Thread {
     tid: ThreadId,
@@ -110,46 +109,29 @@ impl Thread {
         Ok(Thread { tid })
     }
 
-    pub fn yield_now() {
-        do_yield();
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        // Because the sleep server works on units of `usized milliseconds`, split
-        // the messages up into these chunks. This means we may run into issues
-        // if you try to sleep a thread for more than 49 days on a 32-bit system.
-        let mut millis = dur.as_millis();
-        while millis > 0 {
-            let sleep_duration =
-                if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
-            blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
-                .expect("failed to send message to ticktimer server");
-            millis -= sleep_duration as u128;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         join_thread(self.tid).unwrap();
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
     Ok(unsafe { NonZero::new_unchecked(1) })
 }
+
+pub fn yield_now() {
+    do_yield();
+}
+
+pub fn sleep(dur: Duration) {
+    // Because the sleep server works on units of `usized milliseconds`, split
+    // the messages up into these chunks. This means we may run into issues
+    // if you try to sleep a thread for more than 49 days on a 32-bit system.
+    let mut millis = dur.as_millis();
+    while millis > 0 {
+        let sleep_duration = if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
+        blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
+            .expect("failed to send message to ticktimer server");
+        millis -= sleep_duration as u128;
+    }
+}
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index 9fafac3aa5b..d5c795093cf 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -23,21 +23,24 @@
     issue = "none"
 )]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_family = "wasm", not(target_feature = "atomics")),
         target_os = "uefi",
         target_os = "zkvm",
         target_os = "trusty",
-    ))] {
+        target_os = "vexos",
+    ) => {
         mod no_threads;
         pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner};
         pub(crate) use no_threads::{LocalPointer, local_pointer};
-    } else if #[cfg(target_thread_local)] {
+    }
+    target_thread_local => {
         mod native;
         pub use native::{EagerStorage, LazyStorage, thread_local_inner};
         pub(crate) use native::{LocalPointer, local_pointer};
-    } else {
+    }
+    _ => {
         mod os;
         pub use os::{Storage, thread_local_inner};
         pub(crate) use os::{LocalPointer, local_pointer};
@@ -53,8 +56,8 @@ cfg_if::cfg_if! {
 /// single callback that runs all of the destructors in the list.
 #[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics")))))]
 pub(crate) mod destructors {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_os = "linux",
             target_os = "android",
             target_os = "fuchsia",
@@ -62,12 +65,13 @@ pub(crate) mod destructors {
             target_os = "hurd",
             target_os = "netbsd",
             target_os = "dragonfly"
-        ))] {
+        ) => {
             mod linux_like;
             mod list;
             pub(super) use linux_like::register;
             pub(super) use list::run;
-        } else {
+        }
+        _ => {
             mod list;
             pub(super) use list::register;
             pub(crate) use list::run;
@@ -79,21 +83,24 @@ pub(crate) mod destructors {
 /// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
 /// should ensure that these functions are called at the right times.
 pub(crate) mod guard {
-    cfg_if::cfg_if! {
-        if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
+    cfg_select! {
+        all(target_thread_local, target_vendor = "apple") => {
             mod apple;
             pub(crate) use apple::enable;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub(crate) use windows::enable;
-        } else if #[cfg(any(
+        }
+        any(
             all(target_family = "wasm", not(
                 all(target_os = "wasi", target_env = "p1", target_feature = "atomics")
             )),
             target_os = "uefi",
             target_os = "zkvm",
             target_os = "trusty",
-        ))] {
+            target_os = "vexos",
+        ) => {
             pub(crate) fn enable() {
                 // FIXME: Right now there is no concept of "thread exit" on
                 // wasm, but this is likely going to show up at some point in
@@ -107,17 +114,20 @@ pub(crate) mod guard {
                 #[allow(unused)]
                 use crate::rt::thread_cleanup;
             }
-        } else if #[cfg(any(
+        }
+        any(
             target_os = "hermit",
             target_os = "xous",
-        ))] {
+        ) => {
             // `std` is the only runtime, so it just calls the destructor functions
             // itself when the time comes.
             pub(crate) fn enable() {}
-        } else if #[cfg(target_os = "solid_asp3")] {
+        }
+        target_os = "solid_asp3" => {
             mod solid;
             pub(crate) use solid::enable;
-        } else {
+        }
+        _ => {
             mod key;
             pub(crate) use key::enable;
         }
@@ -131,8 +141,8 @@ pub(crate) mod guard {
 /// reference an entry in a thread-local table. This then associates each key
 /// with a pointer which we can get and set to store our data.
 pub(crate) mod key {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             all(
                 not(target_vendor = "apple"),
                 not(target_family = "wasm"),
@@ -141,7 +151,7 @@ pub(crate) mod key {
             all(not(target_thread_local), target_vendor = "apple"),
             target_os = "teeos",
             all(target_os = "wasi", target_env = "p1", target_feature = "atomics"),
-        ))] {
+        ) => {
             mod racy;
             mod unix;
             #[cfg(test)]
@@ -151,12 +161,14 @@ pub(crate) mod key {
             #[cfg(any(not(target_thread_local), test))]
             pub(super) use unix::get;
             use unix::{create, destroy};
-        } else if #[cfg(all(not(target_thread_local), target_os = "windows"))] {
+        }
+        all(not(target_thread_local), target_os = "windows") => {
             #[cfg(test)]
             mod tests;
             mod windows;
             pub(super) use windows::{Key, LazyKey, get, run_dtors, set};
-        } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        }
+        all(target_vendor = "fortanix", target_env = "sgx") => {
             mod racy;
             mod sgx;
             #[cfg(test)]
@@ -164,7 +176,8 @@ pub(crate) mod key {
             pub(super) use racy::LazyKey;
             pub(super) use sgx::{Key, get, set};
             use sgx::{create, destroy};
-        } else if #[cfg(target_os = "xous")] {
+        }
+        target_os = "xous" => {
             mod racy;
             #[cfg(test)]
             mod tests;
@@ -174,6 +187,7 @@ pub(crate) mod key {
             pub(super) use xous::{Key, get, set};
             use xous::{create, destroy};
         }
+        _ => {}
     }
 }