From 9a90c0e3a684950d06819f9a1a426d5f62efbd23 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 26 Aug 2024 10:14:00 +0200 Subject: [PATCH 01/36] Suppress warning in test --- tests/simple.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/simple.rs b/tests/simple.rs index d4c7820..bb10937 100644 --- a/tests/simple.rs +++ b/tests/simple.rs @@ -13,6 +13,7 @@ fn recurse(n: usize) { if n != 0 { ensure_sufficient_stack(|| recurse(n - 1)); } + #[allow(dropping_copy_types)] drop(x); } From e238c224404e01343d833c23eec56861db02c915 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 26 Aug 2024 10:16:48 +0200 Subject: [PATCH 02/36] Upgrade windows-sys to 0.52-0.59 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f072a7f..3f82297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ libc = "0.2.156" psm = { path = "psm", version = "0.1.7" } [target.'cfg(windows)'.dependencies.windows-sys] -version = ">=0.34.0, <0.42.0" +version = ">=0.52.0, <0.60.0" features = [ "Win32_System_Memory", "Win32_System_Threading", From aec0b3056f1524e3f2785978bd6bd377354c2fb7 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 26 Aug 2024 10:17:10 +0200 Subject: [PATCH 03/36] Add rust-version metadata --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 3f82297..c5f41fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "stacker" version = "0.1.16" +rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] build = "build.rs" license = "MIT OR Apache-2.0" From f9300b79bd220d803f8548d3a12f3b101e2869f8 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 26 Aug 2024 10:19:42 +0200 Subject: [PATCH 04/36] Bump version to 0.1.17 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c5f41fc..21a8288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.16" +version = "0.1.17" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] build = "build.rs" From 6059c7b8b01e0593cbf93a1a9d46599e4c64a40d Mon Sep 17 00:00:00 2001 From: Alex Touchet <26315797+atouchet@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:21:37 -0700 Subject: [PATCH 05/36] Update Readme --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 94858e4..d280fa1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # stacker -[![Build Status](https://github.com/rust-lang/stacker/workflows/Test%20stacker/badge.svg)](https://github.com/rust-lang/stacker/actions) +[![Build Status](https://github.com/rust-lang/stacker/actions/workflows/test.yml/badge.svg)](https://github.com/rust-lang/stacker/actions) [Documentation](https://docs.rs/stacker) @@ -18,13 +18,13 @@ stacker = "0.1" ## Platform Support -This library currently uses psm for its cross platform capabilities, with a notable exception of -Windows, which uses an implementation based on Fibers. See the README for psm for the support -table. +This library currently uses psm for its cross platform capabilities, with a +notable exception of Windows, which uses an implementation based on Fibers. See +the README for psm for the support table. -On all unsupported platforms this library is a noop. It should compile and run, but it -won't actually grow the stack and code will continue to hit the guard pages -typically in place. +On all unsupported platforms this library is a noop. It should compile and run, +but it won't actually grow the stack and code will continue to hit the guard +pages typically in place. # License @@ -33,7 +33,7 @@ This project is licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or - https://opensource.org/licenses/MIT) + https://opensource.org/license/mit) at your option. From 9f8cf8f96959d39dd9d4f4d933f11274f1a62039 Mon Sep 17 00:00:00 2001 From: Asger Hautop Drewsen Date: Tue, 6 Aug 2024 21:47:45 +0200 Subject: [PATCH 06/36] Fix typo in expect message --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d8a1971..389e6d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -231,7 +231,7 @@ psm_stack_manipulation! { .expect("unreasonably large stack requested") / page_size; let stack_pages = std::cmp::max(1, requested_pages) + 2; let stack_bytes = stack_pages.checked_mul(page_size) - .expect("unreasonably large stack requesteed"); + .expect("unreasonably large stack requested"); // Next, there are a couple of approaches to how we allocate the new stack. We take the // most obvious path and use `mmap`. We also `mprotect` a guard page into our From d0c34d5220064cc793c3c4c3ae2c4ca798d4f3da Mon Sep 17 00:00:00 2001 From: Austin Seipp Date: Mon, 26 Aug 2024 16:25:11 -0500 Subject: [PATCH 07/36] psm: allow manual opt out of `#cfg[link("psm_s")]` Currenty, when using the `asm` configuration, the `lib.rs` file will manually add a `link("psm_s")` attribute to the build causing a flag like `-lpsm_s` to appear on the link line. `psm_s` is the library of assembly code, built by `build.rs` in Cargo projects. However, when using Cargo packages with build systems like Buck2, we have to manually replace the `build.rs` script, and build the bits of C/assembly code that come with `psm` and `stacker` as a separate build item (an actual library), then link them into the Rust libraries. The name of the library often can't be easily made identical to `psm_s` as desired by the `link()` call, meaning that just blindly compiling this crate causes an inevitable linking failure. But we're building the code and explicitly linking the library anyway, removing the need for this `#[link]` clause. Therefore, introduce a new `link_asm` cfg option to give "expert" users the ability to link in code manually. This is always enabled by the Cargo build for `asm`-compatible targets, but Buck users can leave it off. Signed-off-by: Austin Seipp --- psm/build.rs | 3 ++- psm/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/psm/build.rs b/psm/build.rs index 7ffb45d..77b9af9 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -7,7 +7,7 @@ fn find_assembly( env: &str, masm: bool, ) -> Option<(&'static str, bool)> { - println!("cargo::rustc-check-cfg=cfg(switchable_stack,asm)"); + println!("cargo::rustc-check-cfg=cfg(switchable_stack,asm,link_asm)"); match (arch, endian, os, env) { // The implementations for stack switching exist, but, officially, doing so without Fibers // is not supported in Windows. For x86_64 the implementation actually works locally, @@ -79,6 +79,7 @@ fn main() { let asm = if let Some((asm, canswitch)) = find_assembly(&arch, &endian, &os, &env, masm) { println!("cargo:rustc-cfg=asm"); + println!("cargo:rustc-cfg=link_asm"); if canswitch { println!("cargo:rustc-cfg=switchable_stack") } diff --git a/psm/src/lib.rs b/psm/src/lib.rs index b9050c8..de74146 100644 --- a/psm/src/lib.rs +++ b/psm/src/lib.rs @@ -56,7 +56,7 @@ macro_rules! extern_item { // NB: this could be nicer across multiple blocks but we cannot do it because of // https://github.com/rust-lang/rust/issues/65847 extern_item! { { - #![cfg_attr(asm, link(name="psm_s"))] + #![cfg_attr(link_asm, link(name="psm_s"))] #[cfg(asm)] fn rust_psm_stack_direction() -> u8; From 7d6aebea50e3471df7ed52ebadb7c9b67d0f746b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 1 Sep 2024 10:59:38 +0300 Subject: [PATCH 08/36] Release psm 0.1.22 --- psm/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index 9a3c56a..6ab2882 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "psm" -version = "0.1.21" +version = "0.1.22" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "Portable Stack Manipulation: stack manipulation and introspection routines" keywords = ["stack", "no_std"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/stacker/" -documentation = "https://docs.rs/psm/0.1.20" +documentation = "https://docs.rs/psm/0.1.22" readme = "README.mkd" [dependencies] From f7f1e58db6fd9faec9304b689c0d825183c208cd Mon Sep 17 00:00:00 2001 From: Colin D Bennett Date: Tue, 3 Sep 2024 11:09:55 -0700 Subject: [PATCH 09/36] fix: avoid macOS linker error for rust_psm_on_stack_end On macOS targets, don't define the symbol `rust_psm_on_stack_end` since it isn't used (and somehow this causes the build to fail). Fixes #87 --- psm/src/arch/aarch_aapcs64.s | 17 +++++++---------- psm/src/arch/x86_64.s | 14 ++++++-------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/psm/src/arch/aarch_aapcs64.s b/psm/src/arch/aarch_aapcs64.s index 06a6245..d3d3ef7 100644 --- a/psm/src/arch/aarch_aapcs64.s +++ b/psm/src/arch/aarch_aapcs64.s @@ -7,13 +7,14 @@ #define GLOBL(fnname) .globl _##fnname #define TYPE(fnname) #define FUNCTION(fnname) _##fnname -#define SIZE(fnname,endlabel) +#define END_FUNCTION(fnname) #elif CFG_TARGET_OS_windows #define GLOBL(fnname) .globl fnname #define TYPE(fnname) #define FUNCTION(fnname) fnname +#define LABEL_FOR_SIZE(endlabel) #define SIZE(fnname,endlabel) #else @@ -21,7 +22,7 @@ #define GLOBL(fnname) .globl fnname #define TYPE(fnname) .type fnname,@function #define FUNCTION(fnname) fnname -#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname +#define END_FUNCTION(fnname) .size fnname,.-fnname #endif @@ -34,8 +35,7 @@ FUNCTION(rust_psm_stack_direction): .cfi_startproc orr w0, wzr, #STACK_DIRECTION_DESCENDING ret -.rust_psm_stack_direction_end: -SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end) +END_FUNCTION(rust_psm_stack_direction) .cfi_endproc @@ -47,8 +47,7 @@ FUNCTION(rust_psm_stack_pointer): .cfi_startproc mov x0, sp ret -.rust_psm_stack_pointer_end: -SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end) +END_FUNCTION(rust_psm_stack_pointer) .cfi_endproc @@ -61,8 +60,7 @@ FUNCTION(rust_psm_replace_stack): /* All we gotta do is set the stack pointer to %rdx & tail-call the callback in %rsi */ mov sp, x2 br x1 -.rust_psm_replace_stack_end: -SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end) +END_FUNCTION(rust_psm_replace_stack) .cfi_endproc @@ -87,6 +85,5 @@ FUNCTION(rust_psm_on_stack): .cfi_restore x29 .cfi_restore x30 ret -.rust_psm_on_stack_end: -SIZE(rust_psm_on_stack,.rust_psm_on_stack_end) +END_FUNCTION(rust_psm_on_stack) .cfi_endproc diff --git a/psm/src/arch/x86_64.s b/psm/src/arch/x86_64.s index 5f5ece5..49ff031 100644 --- a/psm/src/arch/x86_64.s +++ b/psm/src/arch/x86_64.s @@ -8,14 +8,14 @@ #define GLOBL(fnname) .globl _##fnname #define TYPE(fnname) #define FUNCTION(fnname) _##fnname -#define SIZE(fnname,endlabel) +#define END_FUNCTION(fnname) #else #define GLOBL(fnname) .globl fnname #define TYPE(fnname) .type fnname,@function #define FUNCTION(fnname) fnname -#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname +#define END_FUNCTION(fnname) .size fnname,.-fnname #endif @@ -28,8 +28,7 @@ FUNCTION(rust_psm_stack_direction): .cfi_startproc movb $STACK_DIRECTION_DESCENDING, %al # always descending on x86_64 retq -.rust_psm_stack_direction_end: -SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end) +END_FUNCTION(rust_psm_stack_direction) .cfi_endproc @@ -42,7 +41,7 @@ FUNCTION(rust_psm_stack_pointer): leaq 8(%rsp), %rax retq .rust_psm_stack_pointer_end: -SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end) +END_FUNCTION(rust_psm_stack_pointer) .cfi_endproc @@ -61,7 +60,7 @@ FUNCTION(rust_psm_replace_stack): leaq -8(%rdx), %rsp jmpq *%rsi .rust_psm_replace_stack_end: -SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end) +END_FUNCTION(rust_psm_replace_stack) .cfi_endproc @@ -82,6 +81,5 @@ FUNCTION(rust_psm_on_stack): popq %rbp .cfi_def_cfa %rsp, 8 retq -.rust_psm_on_stack_end: -SIZE(rust_psm_on_stack,.rust_psm_on_stack_end) +END_FUNCTION(rust_psm_on_stack) .cfi_endproc From c60bfc35dbcd7e3ccc42ba43f238e718cdb0ae48 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 3 Sep 2024 23:28:01 +0300 Subject: [PATCH 10/36] Release 0.1.23 Fixes #96 --- psm/Cargo.toml | 2 +- psm/build.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index 6ab2882..758ae30 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psm" -version = "0.1.22" +version = "0.1.23" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "Portable Stack Manipulation: stack manipulation and introspection routines" diff --git a/psm/build.rs b/psm/build.rs index 77b9af9..bc84149 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -7,7 +7,7 @@ fn find_assembly( env: &str, masm: bool, ) -> Option<(&'static str, bool)> { - println!("cargo::rustc-check-cfg=cfg(switchable_stack,asm,link_asm)"); + println!("cargo:rustc-check-cfg=cfg(switchable_stack,asm,link_asm)"); match (arch, endian, os, env) { // The implementations for stack switching exist, but, officially, doing so without Fibers // is not supported in Windows. For x86_64 the implementation actually works locally, From ee7727f1a44514e1b922470d20014fab96b32d3a Mon Sep 17 00:00:00 2001 From: Artyom Tetyukhin <51746822+arttet@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:12:17 +0400 Subject: [PATCH 11/36] Bump cc dependency --- Cargo.toml | 2 +- psm/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 21a8288..b78bf13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,4 +34,4 @@ features = [ [build-dependencies] -cc = "1.0.2" +cc = "1.1.22" diff --git a/psm/Cargo.toml b/psm/Cargo.toml index 758ae30..bb27700 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -13,4 +13,4 @@ readme = "README.mkd" [dependencies] [build-dependencies] -cc = "1.0.2" +cc = "1.1.22" From 6aa771cd16d973c47552ecec0a205d5457f093b1 Mon Sep 17 00:00:00 2001 From: Artyom Tetyukhin <51746822+arttet@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:26:21 +0400 Subject: [PATCH 12/36] Fix CI --- .github/workflows/test.yml | 93 +++++++++++++++++++------------------- Cross.toml | 2 - 2 files changed, 47 insertions(+), 48 deletions(-) delete mode 100644 Cross.toml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 53e887c..1bc4945 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,12 +3,13 @@ name: Test on: push: branches: - - master + - master paths-ignore: - - '*.mkd' - - 'LICENSE' + - '*.mkd' + - 'LICENSE' pull_request: types: [opened, reopened, synchronize] + workflow_dispatch: jobs: native-test: @@ -32,9 +33,9 @@ jobs: - name: Install Rust ${{ matrix.rust_toolchain }} uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.rust_toolchain }} - profile: minimal - default: true + toolchain: ${{ matrix.rust_toolchain }} + profile: minimal + default: true - name: Test ${{ matrix.manifest}} with ${{ matrix.mode }} uses: actions-rs/cargo@v1 with: @@ -71,10 +72,10 @@ jobs: install: ${{ matrix.package }} - uses: actions-rs/toolchain@v1 with: - toolchain: stable - profile: minimal - default: true - target: ${{ matrix.rust_target }} + toolchain: stable + profile: minimal + default: true + target: ${{ matrix.rust_target }} - uses: actions-rs/cargo@v1 with: command: test @@ -111,10 +112,10 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.rust_toolchain }} - profile: minimal - target: ${{ matrix.rust_target }} - default: true + toolchain: ${{ matrix.rust_toolchain }} + profile: minimal + target: ${{ matrix.rust_target }} + default: true - uses: actions-rs/cargo@v1 with: command: test @@ -153,16 +154,16 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: nightly - profile: minimal - target: ${{ matrix.rust_target }} - default: true + toolchain: nightly + profile: minimal + target: ${{ matrix.rust_target }} + default: true + - name: Install cross + run: | + cargo install cross --git https://github.com/cross-rs/cross - name: Test - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: test - args: --target ${{ matrix.rust_target }} --manifest-path=${{ matrix.manifest }} ${{ matrix.mode }} -- --test-threads=1 --nocapture + run: | + cross test --target ${{ matrix.rust_target }} --manifest-path=${{ matrix.manifest }} ${{ matrix.mode }} -- --test-threads=1 --nocapture native-build: name: Build ${{ matrix.manifest }} to ${{ matrix.rust_target }} on nightly @@ -181,10 +182,10 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: nightly - profile: minimal - target: ${{ matrix.rust_target }} - default: true + toolchain: nightly + profile: minimal + target: ${{ matrix.rust_target }} + default: true - name: Build ${{ matrix.rust_target }} uses: actions-rs/cargo@v1 with: @@ -220,10 +221,10 @@ jobs: - name: Install Rust nightly uses: actions-rs/toolchain@v1 with: - toolchain: nightly - profile: minimal - target: ${{ matrix.rust_target }} - default: true + toolchain: nightly + profile: minimal + target: ${{ matrix.rust_target }} + default: true - name: Build ${{ matrix.rust_target }} uses: actions-rs/cargo@v1 with: @@ -248,10 +249,10 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.rust_toolchain }} - profile: minimal - target: ${{ matrix.rust_target }} - default: true + toolchain: ${{ matrix.rust_toolchain }} + profile: minimal + target: ${{ matrix.rust_target }} + default: true - name: Build uses: actions-rs/cargo@v1 with: @@ -268,7 +269,7 @@ jobs: - x86_64-pc-windows-msvc - i686-pc-windows-msvc manifest: ['psm/Cargo.toml', 'Cargo.toml'] - xwin_version: ["0.1.6"] + xwin_version: ['0.1.6'] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -297,17 +298,17 @@ jobs: xwin --accept-license 1 splat --output /tmp/xwin - name: Test env: - CC: "clang-cl" - CXX: "clang-cl" - AR: "llvm-lib" - CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: "lld-link" - CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER: "lld-link" + CC: 'clang-cl' + CXX: 'clang-cl' + AR: 'llvm-lib' + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: 'lld-link' + CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER: 'lld-link' # Note that we only disable unused-command-line-argument here since clang-cl # doesn't implement all of the options supported by cl, but the ones it doesn't # are _generally_ not interesting. - CFLAGS: "-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/tmp/xwin/crt/include /imsvc/tmp/xwin/sdk/include/ucrt /imsvc/tmp/xwin/sdk/include/um /imsvc/tmp/xwin/sdk/include/shared" + CFLAGS: '-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/tmp/xwin/crt/include /imsvc/tmp/xwin/sdk/include/ucrt /imsvc/tmp/xwin/sdk/include/um /imsvc/tmp/xwin/sdk/include/shared' # Inform the linker where to search for libraries - RUSTFLAGS: "-Lnative=/tmp/xwin/crt/lib/x86_64 -Lnative=/tmp/xwin/sdk/lib/um/x86_64 -Lnative=/tmp/xwin/sdk/lib/ucrt/x86_64" + RUSTFLAGS: '-Lnative=/tmp/xwin/crt/lib/x86_64 -Lnative=/tmp/xwin/sdk/lib/um/x86_64 -Lnative=/tmp/xwin/sdk/lib/ucrt/x86_64' run: | set -eux cargo build --target ${{ matrix.rust_target }} --manifest-path ${{ matrix.manifest }} @@ -321,9 +322,9 @@ jobs: - name: Install Rust nightly uses: actions-rs/toolchain@v1 with: - toolchain: nightly - default: true - target: wasm32-wasi + toolchain: nightly + default: true + target: wasm32-wasi - run: | curl -Lf https://github.com/bytecodealliance/wasmtime/releases/download/v24.0.0/wasmtime-v24.0.0-x86_64-linux.tar.xz | tar xJf - -C ${{ runner.tool_cache }} echo "${{ runner.tool_cache }}/wasmtime-v24.0.0-x86_64-linux" >> $GITHUB_PATH diff --git a/Cross.toml b/Cross.toml deleted file mode 100644 index 7e330ab..0000000 --- a/Cross.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.x86_64-linux-android] -image = "rustembedded/cross:x86_64-linux-android" From c94a424e1dc1c1d7f0e7cdb5150d1c0fe4e0489b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 10 Nov 2024 14:24:54 +0100 Subject: [PATCH 13/36] fix: make Windows AArch64 asm buildable again --- psm/src/arch/aarch_aapcs64.s | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/psm/src/arch/aarch_aapcs64.s b/psm/src/arch/aarch_aapcs64.s index d3d3ef7..d2851a9 100644 --- a/psm/src/arch/aarch_aapcs64.s +++ b/psm/src/arch/aarch_aapcs64.s @@ -14,8 +14,7 @@ #define GLOBL(fnname) .globl fnname #define TYPE(fnname) #define FUNCTION(fnname) fnname -#define LABEL_FOR_SIZE(endlabel) -#define SIZE(fnname,endlabel) +#define END_FUNCTION(fnname) #else From 762438e37556ba79ebe148c81f8dc0b3738288af Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Tue, 12 Nov 2024 10:51:49 +0800 Subject: [PATCH 14/36] ci: add support for loongarch64-unknown-linux-gnu --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1bc4945..cee4170 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -135,6 +135,7 @@ jobs: - aarch64-unknown-linux-gnu - arm-unknown-linux-gnueabi - armv7-unknown-linux-gnueabihf + - loongarch64-unknown-linux-gnu - i686-unknown-linux-gnu - i686-unknown-linux-musl # No libstd available :( From bdb1a188dccbf2c7b61b898d322541da03b1b06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 10 Nov 2024 15:11:03 +0100 Subject: [PATCH 15/36] chore: add gnullvm cross check to the CI --- .github/workflows/test.yml | 76 ++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cee4170..91609e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,8 +5,8 @@ on: branches: - master paths-ignore: - - '*.mkd' - - 'LICENSE' + - "*.mkd" + - "LICENSE" pull_request: types: [opened, reopened, synchronize] workflow_dispatch: @@ -20,8 +20,8 @@ jobs: matrix: rust_toolchain: [nightly, stable, 1.63.0] os: [ubuntu-latest, windows-latest, macOS-latest] - mode: ['--release', '-Zminimal-versions', ''] - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + mode: ["--release", "-Zminimal-versions", ""] + manifest: ["psm/Cargo.toml", "Cargo.toml"] exclude: - rust_toolchain: stable mode: -Zminimal-versions @@ -53,7 +53,7 @@ jobs: strategy: fail-fast: false matrix: - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] rust_target: - x86_64-pc-windows-msvc - i686-pc-windows-msvc @@ -93,7 +93,7 @@ jobs: rust_target: - x86_64-pc-windows-gnu - i686-pc-windows-gnu - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] include: - rust_target: x86_64-pc-windows-gnu mingw_path: C:/msys64/mingw64/bin @@ -121,6 +121,42 @@ jobs: command: test args: --target ${{ matrix.rust_target }} --manifest-path=${{ matrix.manifest }} + cross-windows-gnullvm-check: + name: Check ${{ matrix.manifest }} to ${{ matrix.rust_target }} with stable + runs-on: ubuntu-latest + env: + LLVM_MINGW_VERSION: "20241030" + strategy: + fail-fast: false + matrix: + rust_target: + - aarch64-pc-windows-gnullvm + - i686-pc-windows-gnullvm + - x86_64-pc-windows-gnullvm + manifest: ["psm/Cargo.toml", "Cargo.toml"] + steps: + - uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + path: llvm-mingw-version + key: ${{ env.LLVM_MINGW_VERSION }} + - name: Install llvm-mingw + if: steps.cache.outputs.cache-hit != 'true' + run: curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/${{ env.LLVM_MINGW_VERSION }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-20.04-x86_64.tar.xz | tar xJf - + - name: Add llvm-mingw to PATH + run: echo "${{ github.workspace }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-20.04-x86_64/bin" >> $GITHUB_PATH + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + target: ${{ matrix.rust_target }} + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --target ${{ matrix.rust_target }} --manifest-path=${{ matrix.manifest }} + cross-linux-test: name: Test ${{ matrix.manifest }} on ${{ matrix.rust_target }} with nightly ${{ matrix.mode }} runs-on: ubuntu-latest @@ -147,8 +183,8 @@ jobs: # https://github.com/rust-embedded/cross/pull/440 # - powerpc64-unknown-linux-gnu - x86_64-unknown-linux-musl - manifest: ['psm/Cargo.toml', 'Cargo.toml'] - mode: ['--release', '-Zminimal-versions', ''] + manifest: ["psm/Cargo.toml", "Cargo.toml"] + mode: ["--release", "-Zminimal-versions", ""] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -176,7 +212,7 @@ jobs: # BSDs: could be tested with full system emulation - i686-unknown-freebsd - x86_64-unknown-freebsd - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -215,7 +251,7 @@ jobs: # - sparc64-unknown-linux-gnu # BSDs: could be tested with full system emulation - x86_64-unknown-netbsd - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -243,7 +279,7 @@ jobs: rust_target: - aarch64-apple-ios - x86_64-apple-ios - manifest: ['psm/Cargo.toml', 'Cargo.toml'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -269,8 +305,8 @@ jobs: rust_target: - x86_64-pc-windows-msvc - i686-pc-windows-msvc - manifest: ['psm/Cargo.toml', 'Cargo.toml'] - xwin_version: ['0.1.6'] + manifest: ["psm/Cargo.toml", "Cargo.toml"] + xwin_version: ["0.1.6"] timeout-minutes: 10 steps: - uses: actions/checkout@v2 @@ -299,17 +335,17 @@ jobs: xwin --accept-license 1 splat --output /tmp/xwin - name: Test env: - CC: 'clang-cl' - CXX: 'clang-cl' - AR: 'llvm-lib' - CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: 'lld-link' - CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER: 'lld-link' + CC: "clang-cl" + CXX: "clang-cl" + AR: "llvm-lib" + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: "lld-link" + CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER: "lld-link" # Note that we only disable unused-command-line-argument here since clang-cl # doesn't implement all of the options supported by cl, but the ones it doesn't # are _generally_ not interesting. - CFLAGS: '-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/tmp/xwin/crt/include /imsvc/tmp/xwin/sdk/include/ucrt /imsvc/tmp/xwin/sdk/include/um /imsvc/tmp/xwin/sdk/include/shared' + CFLAGS: "-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/tmp/xwin/crt/include /imsvc/tmp/xwin/sdk/include/ucrt /imsvc/tmp/xwin/sdk/include/um /imsvc/tmp/xwin/sdk/include/shared" # Inform the linker where to search for libraries - RUSTFLAGS: '-Lnative=/tmp/xwin/crt/lib/x86_64 -Lnative=/tmp/xwin/sdk/lib/um/x86_64 -Lnative=/tmp/xwin/sdk/lib/ucrt/x86_64' + RUSTFLAGS: "-Lnative=/tmp/xwin/crt/lib/x86_64 -Lnative=/tmp/xwin/sdk/lib/um/x86_64 -Lnative=/tmp/xwin/sdk/lib/ucrt/x86_64" run: | set -eux cargo build --target ${{ matrix.rust_target }} --manifest-path ${{ matrix.manifest }} From 0e525ab0074ea1b3ce312644a2dacb64edfb1006 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 13 Nov 2024 13:12:02 +0200 Subject: [PATCH 16/36] fix wasi test --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 91609e8..42ad6ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -361,9 +361,9 @@ jobs: with: toolchain: nightly default: true - target: wasm32-wasi + target: wasm32-wasip1 - run: | curl -Lf https://github.com/bytecodealliance/wasmtime/releases/download/v24.0.0/wasmtime-v24.0.0-x86_64-linux.tar.xz | tar xJf - -C ${{ runner.tool_cache }} echo "${{ runner.tool_cache }}/wasmtime-v24.0.0-x86_64-linux" >> $GITHUB_PATH - echo "CARGO_TARGET_WASM32_WASI_RUNNER=wasmtime run --" >> $GITHUB_ENV - - run: cargo test --target wasm32-wasi --all -- --nocapture + echo "CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime run --" >> $GITHUB_ENV + - run: cargo test --target wasm32-wasip1 --all -- --nocapture From cf52a70cef8548843b29a1f1e378d79b83bbf16b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 13 Nov 2024 13:10:30 +0200 Subject: [PATCH 17/36] psm: release 0.1.24 --- psm/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index bb27700..0f75bdf 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "psm" -version = "0.1.23" +version = "0.1.24" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "Portable Stack Manipulation: stack manipulation and introspection routines" keywords = ["stack", "no_std"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/stacker/" -documentation = "https://docs.rs/psm/0.1.22" +documentation = "https://docs.rs/psm/0.1.24" readme = "README.mkd" [dependencies] From 8b9c70df9c48a5610e53a02372d45c4de6538725 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:29:56 +0000 Subject: [PATCH 18/36] Use edition 2021 to suppress cargo warning --- Cargo.toml | 1 + psm/Cargo.toml | 1 + psm/build.rs | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b78bf13..7b707c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "stacker" version = "0.1.17" +edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] build = "build.rs" diff --git a/psm/Cargo.toml b/psm/Cargo.toml index 0f75bdf..bddc685 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "psm" version = "0.1.24" +edition = "2021" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "Portable Stack Manipulation: stack manipulation and introspection routines" diff --git a/psm/build.rs b/psm/build.rs index bc84149..4f3121f 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -1,5 +1,3 @@ -extern crate cc; - fn find_assembly( arch: &str, endian: &str, From 4045bf90689773d894dcc90f37780728e453cb27 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:31:06 +0000 Subject: [PATCH 19/36] Support running on miri --- psm/build.rs | 8 +++++++- src/lib.rs | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/psm/build.rs b/psm/build.rs index 4f3121f..0201308 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -5,7 +5,6 @@ fn find_assembly( env: &str, masm: bool, ) -> Option<(&'static str, bool)> { - println!("cargo:rustc-check-cfg=cfg(switchable_stack,asm,link_asm)"); match (arch, endian, os, env) { // The implementations for stack switching exist, but, officially, doing so without Fibers // is not supported in Windows. For x86_64 the implementation actually works locally, @@ -58,6 +57,13 @@ fn find_assembly( fn main() { use std::env::var; + println!("cargo:rustc-check-cfg=cfg(switchable_stack,asm,link_asm)"); + + if var("CARGO_CFG_MIRI").is_ok() { + // Miri doesn't have a stack limit and the inline asm wouldn't work on miri anyway. + return; + } + let arch = var("CARGO_CFG_TARGET_ARCH").unwrap(); let env = var("CARGO_CFG_TARGET_ENV").unwrap(); let os = var("CARGO_CFG_TARGET_OS").unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 389e6d1..9f61d7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -268,14 +268,20 @@ psm_stack_manipulation! { no { #[cfg(not(windows))] fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { - drop(stack_size); + let _ = stack_size; callback(); } } } cfg_if! { - if #[cfg(windows)] { + if #[cfg(miri)] { + // Miri doesn't have a stack limit + #[inline(always)] + unsafe fn guess_os_stack_limit() -> Option { + None + } + } else if #[cfg(windows)] { use std::ptr; use std::io; use libc::c_void; From ff738b7a2c8f0eac368c89fe0b89abadc975e069 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 10 Feb 2025 12:14:54 +0200 Subject: [PATCH 20/36] stacker: release 0.1.18 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7b707c7..a613202 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.17" +version = "0.1.18" edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] From a4027ca2613ad1b6b0a53a640cc07166263e94d7 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 14 Feb 2025 13:59:50 +0200 Subject: [PATCH 21/36] psm: release 0.1.25 --- psm/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index bddc685..d7dda6e 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psm" -version = "0.1.24" +version = "0.1.25" edition = "2021" authors = ["Simonas Kazlauskas "] build = "build.rs" @@ -8,7 +8,7 @@ description = "Portable Stack Manipulation: stack manipulation and introspection keywords = ["stack", "no_std"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/stacker/" -documentation = "https://docs.rs/psm/0.1.24" +documentation = "https://docs.rs/psm/0.1.25" readme = "README.mkd" [dependencies] From 5eed05f39c2c71cb9153a94e27826535ed6d545b Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Fri, 21 Feb 2025 13:41:44 +0100 Subject: [PATCH 22/36] improve error handling (#116) * improve error handling see https://github.com/rust-lang/stacker/issues/115 See https://github.com/sqlpage/SQLPage/issues/814 * improve error message in destroy_pthread_attr * remove code duplication * cleanup code and add comments * Make error handling code easier to read * update formatting https://github.com/rust-lang/stacker/pull/116/files#r1961535064 * put the beautiful unicode apostrophe back https://github.com/rust-lang/stacker/pull/116/files#r1961536979 * use one file per guess_os_stack_limit implementation * fix error handling on openbsd too * beautiful unicode apostrophe * format * fix windows build * remove unused unsafe * fix error handling on windows VirtualQuery is a faillible function that was treated as infaillible https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery * SetThreadStackGuarantee can also error on windows * simplify pthread error handling --- src/backends/fallback.rs | 4 + src/backends/macos.rs | 6 ++ src/backends/mod.rs | 28 +++++ src/backends/openbsd.rs | 8 ++ src/backends/unix.rs | 58 +++++++++++ src/backends/windows.rs | 142 ++++++++++++++++++++++++++ src/lib.rs | 213 ++++----------------------------------- 7 files changed, 263 insertions(+), 196 deletions(-) create mode 100644 src/backends/fallback.rs create mode 100644 src/backends/macos.rs create mode 100644 src/backends/mod.rs create mode 100644 src/backends/openbsd.rs create mode 100644 src/backends/unix.rs create mode 100644 src/backends/windows.rs diff --git a/src/backends/fallback.rs b/src/backends/fallback.rs new file mode 100644 index 0000000..a812cbc --- /dev/null +++ b/src/backends/fallback.rs @@ -0,0 +1,4 @@ +#[inline(always)] +pub unsafe fn guess_os_stack_limit() -> Option { + None +} diff --git a/src/backends/macos.rs b/src/backends/macos.rs new file mode 100644 index 0000000..42b2851 --- /dev/null +++ b/src/backends/macos.rs @@ -0,0 +1,6 @@ +pub unsafe fn guess_os_stack_limit() -> Option { + Some( + libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize + - libc::pthread_get_stacksize_np(libc::pthread_self()) as usize, + ) +} diff --git a/src/backends/mod.rs b/src/backends/mod.rs new file mode 100644 index 0000000..8da895d --- /dev/null +++ b/src/backends/mod.rs @@ -0,0 +1,28 @@ +cfg_if! { + if #[cfg(miri)] { + mod fallback; + pub use fallback::guess_os_stack_limit; + } else if #[cfg(windows)] { + pub(crate) mod windows; + pub use windows::guess_os_stack_limit; + } else if #[cfg(any( + target_os = "linux", + target_os = "solaris", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "illumos" + ))] { + mod unix; + pub use unix::guess_os_stack_limit; + } else if #[cfg(target_os = "openbsd")] { + mod openbsd; + pub use openbsd::guess_os_stack_limit; + } else if #[cfg(target_os = "macos")] { + mod macos; + pub use macos::guess_os_stack_limit; + } else { + mod fallback; + pub use fallback::guess_os_stack_limit; + } +} diff --git a/src/backends/openbsd.rs b/src/backends/openbsd.rs new file mode 100644 index 0000000..3a6dd71 --- /dev/null +++ b/src/backends/openbsd.rs @@ -0,0 +1,8 @@ +pub unsafe fn guess_os_stack_limit() -> Option { + let mut stackinfo = std::mem::MaybeUninit::::uninit(); + let res = libc::pthread_stackseg_np(libc::pthread_self(), stackinfo.as_mut_ptr()); + if res != 0 { + return None; + } + Some(stackinfo.assume_init().ss_sp as usize - stackinfo.assume_init().ss_size) +} diff --git a/src/backends/unix.rs b/src/backends/unix.rs new file mode 100644 index 0000000..21ce3b1 --- /dev/null +++ b/src/backends/unix.rs @@ -0,0 +1,58 @@ +#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "illumos"))] +use libc::pthread_attr_get_np as get_attr; +#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "netbsd"))] +use libc::pthread_getattr_np as get_attr; + +pub unsafe fn guess_os_stack_limit() -> Option { + let mut attr = PthreadAttr::new()?; + + handle_pthread_err(get_attr(libc::pthread_self(), attr.as_mut_ptr()))?; + + let mut stackaddr = std::ptr::null_mut(); + let mut stacksize = 0; + handle_pthread_err(libc::pthread_attr_getstack( + attr.as_mut_ptr(), + &mut stackaddr, + &mut stacksize, + ))?; + + Some(stackaddr as usize) +} + +struct PthreadAttr(std::mem::MaybeUninit); + +impl Drop for PthreadAttr { + fn drop(&mut self) { + unsafe { + let ret = libc::pthread_attr_destroy(self.0.as_mut_ptr()); + if ret != 0 { + let err = std::io::Error::last_os_error(); + panic!( + "pthread_attr_destroy failed with error code {}: {}", + ret, err + ); + } + } + } +} + +fn handle_pthread_err(ret: libc::c_int) -> Option<()> { + if ret != 0 { + return None; + } + Some(()) +} + +impl PthreadAttr { + unsafe fn new() -> Option { + let mut attr = std::mem::MaybeUninit::::uninit(); + if libc::pthread_attr_init(attr.as_mut_ptr()) != 0 { + return None; + } + Some(PthreadAttr(attr)) + } + + fn as_mut_ptr(&mut self) -> *mut libc::pthread_attr_t { + self.0.as_mut_ptr() + } +} diff --git a/src/backends/windows.rs b/src/backends/windows.rs new file mode 100644 index 0000000..69c7613 --- /dev/null +++ b/src/backends/windows.rs @@ -0,0 +1,142 @@ +use libc::c_void; +use std::io; +use std::ptr; +use windows_sys::Win32::Foundation::BOOL; +use windows_sys::Win32::System::Memory::VirtualQuery; +use windows_sys::Win32::System::Threading::{ + ConvertFiberToThread, ConvertThreadToFiber, CreateFiber, DeleteFiber, IsThreadAFiber, + SetThreadStackGuarantee, SwitchToFiber, +}; + +// Make sure the libstacker.a (implemented in C) is linked. +// See https://github.com/rust-lang/rust/issues/65610 +#[link(name = "stacker")] +extern "C" { + fn __stacker_get_current_fiber() -> *mut c_void; +} + +struct FiberInfo { + callback: std::mem::MaybeUninit, + panic: Option>, + parent_fiber: *mut c_void, +} + +unsafe extern "system" fn fiber_proc(data: *mut c_void) { + // This function is the entry point to our inner fiber, and as argument we get an + // instance of `FiberInfo`. We will set-up the "runtime" for the callback and execute + // it. + let data = &mut *(data as *mut FiberInfo); + let old_stack_limit = crate::get_stack_limit(); + crate::set_stack_limit(guess_os_stack_limit()); + let callback = data.callback.as_ptr(); + data.panic = std::panic::catch_unwind(std::panic::AssertUnwindSafe(callback.read())).err(); + + // Restore to the previous Fiber + crate::set_stack_limit(old_stack_limit); + SwitchToFiber(data.parent_fiber); +} + +pub fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { + // Fibers (or stackful coroutines) is the only official way to create new stacks on the + // same thread on Windows. So in order to extend the stack we create fiber and switch + // to it so we can use it's stack. After running `callback` within our fiber, we switch + // back to the current stack and destroy the fiber and its associated stack. + unsafe { + let was_fiber = IsThreadAFiber() == 1 as BOOL; + let mut data = FiberInfo { + callback: std::mem::MaybeUninit::new(callback), + panic: None, + parent_fiber: { + if was_fiber { + // Get a handle to the current fiber. We need to use a C implementation + // for this as GetCurrentFiber is an header only function. + __stacker_get_current_fiber() + } else { + // Convert the current thread to a fiber, so we are able to switch back + // to the current stack. Threads coverted to fibers still act like + // regular threads, but they have associated fiber data. We later + // convert it back to a regular thread and free the fiber data. + ConvertThreadToFiber(ptr::null_mut()) + } + }, + }; + + if data.parent_fiber.is_null() { + panic!( + "unable to convert thread to fiber: {}", + io::Error::last_os_error() + ); + } + + let fiber = CreateFiber( + stack_size as usize, + Some(fiber_proc::<&mut dyn FnMut()>), + &mut data as *mut FiberInfo<&mut dyn FnMut()> as *mut _, + ); + if fiber.is_null() { + panic!("unable to allocate fiber: {}", io::Error::last_os_error()); + } + + // Switch to the fiber we created. This changes stacks and starts executing + // fiber_proc on it. fiber_proc will run `callback` and then switch back to run the + // next statement. + SwitchToFiber(fiber); + DeleteFiber(fiber); + + // Clean-up. + if !was_fiber && ConvertFiberToThread() == 0 { + // FIXME: Perhaps should not panic here? + panic!( + "unable to convert back to thread: {}", + io::Error::last_os_error() + ); + } + + if let Some(p) = data.panic { + std::panic::resume_unwind(p); + } + } +} + +#[inline(always)] +fn get_thread_stack_guarantee() -> Option { + let min_guarantee = if cfg!(target_pointer_width = "32") { + 0x1000 + } else { + 0x2000 + }; + let mut stack_guarantee = 0; + unsafe { + // Read the current thread stack guarantee + // This is the stack reserved for stack overflow + // exception handling. + // This doesn't return the true value so we need + // some further logic to calculate the real stack + // guarantee. This logic is what is used on x86-32 and + // x86-64 Windows 10. Other versions and platforms may differ + let ret = SetThreadStackGuarantee(&mut stack_guarantee); + if ret == 0 { + return None; + } + }; + Some(std::cmp::max(stack_guarantee, min_guarantee) as usize + 0x1000) +} + +#[inline(always)] +pub unsafe fn guess_os_stack_limit() -> Option { + // Query the allocation which contains our stack pointer in order + // to discover the size of the stack + // + // FIXME: we could read stack base from the TIB, specifically the 3rd element of it. + type QueryT = windows_sys::Win32::System::Memory::MEMORY_BASIC_INFORMATION; + let mut mi = std::mem::MaybeUninit::::uninit(); + let res = VirtualQuery( + psm::stack_pointer() as *const _, + mi.as_mut_ptr(), + std::mem::size_of::() as usize, + ); + if res == 0 { + return None; + } + Some(mi.assume_init().AllocationBase as usize + get_thread_stack_guarantee()? + 0x1000) +} diff --git a/src/lib.rs b/src/lib.rs index 9f61d7f..3f98ce8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,8 @@ extern crate windows_sys; #[macro_use] extern crate psm; +mod backends; + use std::cell::Cell; /// Grows the call stack if necessary. @@ -116,7 +118,7 @@ psm_stack_information!( thread_local! { static STACK_LIMIT: Cell> = Cell::new(unsafe { - guess_os_stack_limit() + backends::guess_os_stack_limit() }) } @@ -163,10 +165,12 @@ psm_stack_manipulation! { -1, // Some implementations assert fd = -1 if MAP_ANON is specified 0 ); - if new_stack == libc::MAP_FAILED { - let error = std::io::Error::last_os_error(); - panic!("allocating stack failed with: {}", error) - } + assert_ne!( + new_stack, + libc::MAP_FAILED, + "mmap failed to allocate stack: {}", + std::io::Error::last_os_error() + ); let guard = StackRestoreGuard { new_stack, stack_bytes, @@ -191,11 +195,12 @@ psm_stack_manipulation! { } else { -1 }; - if result == -1 { - let error = std::io::Error::last_os_error(); - drop(guard); - panic!("setting stack permissions failed with: {}", error) - } + assert_ne!( + result, + -1, + "mprotect/mmap failed: {}", + std::io::Error::last_os_error() + ); guard } } @@ -271,191 +276,7 @@ psm_stack_manipulation! { let _ = stack_size; callback(); } - } -} - -cfg_if! { - if #[cfg(miri)] { - // Miri doesn't have a stack limit - #[inline(always)] - unsafe fn guess_os_stack_limit() -> Option { - None - } - } else if #[cfg(windows)] { - use std::ptr; - use std::io; - use libc::c_void; - use windows_sys::Win32::System::Threading::{SwitchToFiber, IsThreadAFiber, ConvertThreadToFiber, - CreateFiber, DeleteFiber, ConvertFiberToThread, SetThreadStackGuarantee - }; - use windows_sys::Win32::Foundation::BOOL; - use windows_sys::Win32::System::Memory::VirtualQuery; - - // Make sure the libstacker.a (implemented in C) is linked. - // See https://github.com/rust-lang/rust/issues/65610 - #[link(name="stacker")] - extern { - fn __stacker_get_current_fiber() -> *mut c_void; - } - - struct FiberInfo { - callback: std::mem::MaybeUninit, - panic: Option>, - parent_fiber: *mut c_void, - } - - unsafe extern "system" fn fiber_proc(data: *mut c_void) { - // This function is the entry point to our inner fiber, and as argument we get an - // instance of `FiberInfo`. We will set-up the "runtime" for the callback and execute - // it. - let data = &mut *(data as *mut FiberInfo); - let old_stack_limit = get_stack_limit(); - set_stack_limit(guess_os_stack_limit()); - let callback = data.callback.as_ptr(); - data.panic = std::panic::catch_unwind(std::panic::AssertUnwindSafe(callback.read())).err(); - - // Restore to the previous Fiber - set_stack_limit(old_stack_limit); - SwitchToFiber(data.parent_fiber); - } - - fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { - // Fibers (or stackful coroutines) is the only official way to create new stacks on the - // same thread on Windows. So in order to extend the stack we create fiber and switch - // to it so we can use it's stack. After running `callback` within our fiber, we switch - // back to the current stack and destroy the fiber and its associated stack. - unsafe { - let was_fiber = IsThreadAFiber() == 1 as BOOL; - let mut data = FiberInfo { - callback: std::mem::MaybeUninit::new(callback), - panic: None, - parent_fiber: { - if was_fiber { - // Get a handle to the current fiber. We need to use a C implementation - // for this as GetCurrentFiber is an header only function. - __stacker_get_current_fiber() - } else { - // Convert the current thread to a fiber, so we are able to switch back - // to the current stack. Threads coverted to fibers still act like - // regular threads, but they have associated fiber data. We later - // convert it back to a regular thread and free the fiber data. - ConvertThreadToFiber(ptr::null_mut()) - } - }, - }; - - if data.parent_fiber.is_null() { - panic!("unable to convert thread to fiber: {}", io::Error::last_os_error()); - } - - let fiber = CreateFiber( - stack_size as usize, - Some(fiber_proc::<&mut dyn FnMut()>), - &mut data as *mut FiberInfo<&mut dyn FnMut()> as *mut _, - ); - if fiber.is_null() { - panic!("unable to allocate fiber: {}", io::Error::last_os_error()); - } - - // Switch to the fiber we created. This changes stacks and starts executing - // fiber_proc on it. fiber_proc will run `callback` and then switch back to run the - // next statement. - SwitchToFiber(fiber); - DeleteFiber(fiber); - - // Clean-up. - if !was_fiber && ConvertFiberToThread() == 0 { - // FIXME: Perhaps should not panic here? - panic!("unable to convert back to thread: {}", io::Error::last_os_error()); - } - - if let Some(p) = data.panic { - std::panic::resume_unwind(p); - } - } - } - - #[inline(always)] - fn get_thread_stack_guarantee() -> usize { - let min_guarantee = if cfg!(target_pointer_width = "32") { - 0x1000 - } else { - 0x2000 - }; - let mut stack_guarantee = 0; - unsafe { - // Read the current thread stack guarantee - // This is the stack reserved for stack overflow - // exception handling. - // This doesn't return the true value so we need - // some further logic to calculate the real stack - // guarantee. This logic is what is used on x86-32 and - // x86-64 Windows 10. Other versions and platforms may differ - SetThreadStackGuarantee(&mut stack_guarantee) - }; - std::cmp::max(stack_guarantee, min_guarantee) as usize + 0x1000 - } - - #[inline(always)] - unsafe fn guess_os_stack_limit() -> Option { - // Query the allocation which contains our stack pointer in order - // to discover the size of the stack - // - // FIXME: we could read stack base from the TIB, specifically the 3rd element of it. - type QueryT = windows_sys::Win32::System::Memory::MEMORY_BASIC_INFORMATION; - let mut mi = std::mem::MaybeUninit::::uninit(); - VirtualQuery( - psm::stack_pointer() as *const _, - mi.as_mut_ptr(), - std::mem::size_of::() as usize, - ); - Some(mi.assume_init().AllocationBase as usize + get_thread_stack_guarantee() + 0x1000) - } - } else if #[cfg(any(target_os = "linux", target_os="solaris", target_os = "netbsd"))] { - unsafe fn guess_os_stack_limit() -> Option { - let mut attr = std::mem::MaybeUninit::::uninit(); - assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); - assert_eq!(libc::pthread_getattr_np(libc::pthread_self(), - attr.as_mut_ptr()), 0); - let mut stackaddr = std::ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(libc::pthread_attr_getstack( - attr.as_ptr(), &mut stackaddr, &mut stacksize - ), 0); - assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); - Some(stackaddr as usize) - } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "illumos"))] { - unsafe fn guess_os_stack_limit() -> Option { - let mut attr = std::mem::MaybeUninit::::uninit(); - assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); - assert_eq!(libc::pthread_attr_get_np(libc::pthread_self(), attr.as_mut_ptr()), 0); - let mut stackaddr = std::ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(libc::pthread_attr_getstack( - attr.as_ptr(), &mut stackaddr, &mut stacksize - ), 0); - assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); - Some(stackaddr as usize) - } - } else if #[cfg(target_os = "openbsd")] { - unsafe fn guess_os_stack_limit() -> Option { - let mut stackinfo = std::mem::MaybeUninit::::uninit(); - assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), stackinfo.as_mut_ptr()), 0); - Some(stackinfo.assume_init().ss_sp as usize - stackinfo.assume_init().ss_size) - } - } else if #[cfg(target_os = "macos")] { - unsafe fn guess_os_stack_limit() -> Option { - Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()) as usize) - } - } else { - // fallback for other platforms is to always increase the stack if we're on - // the root stack. After we increased the stack once, we know the new stack - // size and don't need this pessimization anymore - #[inline(always)] - unsafe fn guess_os_stack_limit() -> Option { - None - } + #[cfg(windows)] + use backends::windows::_grow; } } From 61411cfe169c426aed5104967ab2a60244ca0171 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 21 Feb 2025 14:52:48 +0200 Subject: [PATCH 23/36] stacker: 0.1.19 --- Cargo.toml | 4 ++-- src/backends/openbsd.rs | 3 ++- src/backends/unix.rs | 28 +++++----------------------- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a613202..ad492fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.18" +version = "0.1.19" edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/stacker" homepage = "https://github.com/rust-lang/stacker" -documentation = "https://docs.rs/stacker/0.1.15" +documentation = "https://docs.rs/stacker/0.1.19" description = """ A stack growth library useful when implementing deeply recursive algorithms that may accidentally blow the stack. diff --git a/src/backends/openbsd.rs b/src/backends/openbsd.rs index 3a6dd71..ee582d8 100644 --- a/src/backends/openbsd.rs +++ b/src/backends/openbsd.rs @@ -4,5 +4,6 @@ pub unsafe fn guess_os_stack_limit() -> Option { if res != 0 { return None; } - Some(stackinfo.assume_init().ss_sp as usize - stackinfo.assume_init().ss_size) + let stackinfo = stackinfo.assume_init(); + Some(stackinfo.ss_sp as usize - stackinfo.ss_size) } diff --git a/src/backends/unix.rs b/src/backends/unix.rs index 21ce3b1..97ef209 100644 --- a/src/backends/unix.rs +++ b/src/backends/unix.rs @@ -5,26 +5,19 @@ use libc::pthread_getattr_np as get_attr; pub unsafe fn guess_os_stack_limit() -> Option { let mut attr = PthreadAttr::new()?; - - handle_pthread_err(get_attr(libc::pthread_self(), attr.as_mut_ptr()))?; - + (get_attr(libc::pthread_self(), &mut attr.0) == 0).then_some(())?; let mut stackaddr = std::ptr::null_mut(); let mut stacksize = 0; - handle_pthread_err(libc::pthread_attr_getstack( - attr.as_mut_ptr(), - &mut stackaddr, - &mut stacksize, - ))?; - + (libc::pthread_attr_getstack(&attr.0, &mut stackaddr, &mut stacksize) == 0).then_some(())?; Some(stackaddr as usize) } -struct PthreadAttr(std::mem::MaybeUninit); +struct PthreadAttr(libc::pthread_attr_t); impl Drop for PthreadAttr { fn drop(&mut self) { unsafe { - let ret = libc::pthread_attr_destroy(self.0.as_mut_ptr()); + let ret = libc::pthread_attr_destroy(&mut self.0); if ret != 0 { let err = std::io::Error::last_os_error(); panic!( @@ -36,23 +29,12 @@ impl Drop for PthreadAttr { } } -fn handle_pthread_err(ret: libc::c_int) -> Option<()> { - if ret != 0 { - return None; - } - Some(()) -} - impl PthreadAttr { unsafe fn new() -> Option { let mut attr = std::mem::MaybeUninit::::uninit(); if libc::pthread_attr_init(attr.as_mut_ptr()) != 0 { return None; } - Some(PthreadAttr(attr)) - } - - fn as_mut_ptr(&mut self) -> *mut libc::pthread_attr_t { - self.0.as_mut_ptr() + Some(PthreadAttr(attr.assume_init())) } } From 1c532e628c34ccccaba7692ff016dfa5df66664a Mon Sep 17 00:00:00 2001 From: m-mueller678 Date: Wed, 11 Dec 2024 14:58:56 +0100 Subject: [PATCH 24/36] treat hermit like wasm32 --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3f98ce8..9affdd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,7 +142,7 @@ psm_stack_manipulation! { } impl StackRestoreGuard { - #[cfg(target_arch = "wasm32")] + #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] unsafe fn new(stack_bytes: usize, _page_size: usize) -> StackRestoreGuard { let layout = std::alloc::Layout::from_size_align(stack_bytes, 16).unwrap(); let ptr = std::alloc::alloc(layout); @@ -154,7 +154,7 @@ psm_stack_manipulation! { } } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] unsafe fn new(stack_bytes: usize, page_size: usize) -> StackRestoreGuard { let new_stack = libc::mmap( std::ptr::null_mut(), @@ -207,14 +207,14 @@ psm_stack_manipulation! { impl Drop for StackRestoreGuard { fn drop(&mut self) { - #[cfg(target_arch = "wasm32")] + #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] unsafe { std::alloc::dealloc( self.new_stack as *mut u8, std::alloc::Layout::from_size_align_unchecked(self.stack_bytes, 16), ); } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] unsafe { // FIXME: check the error code and decide what to do with it. // Perhaps a debug_assertion? @@ -263,9 +263,9 @@ psm_stack_manipulation! { fn page_size() -> usize { // FIXME: consider caching the page size. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize } - #[cfg(target_arch = "wasm32")] + #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] { 65536 } } } From 5128a0ed5603f319af28bf36010af3682527d3b5 Mon Sep 17 00:00:00 2001 From: m-mueller678 Date: Mon, 17 Mar 2025 15:50:50 +0100 Subject: [PATCH 25/36] move page rounding logic into `StackRestoreGuard` and split mmap and non-mmap implementations --- src/alloc_stack_restore_guard.rs | 47 +++++++++++ src/lib.rs | 139 +++++-------------------------- src/mmap_stack_restore_guard.rs | 107 ++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 120 deletions(-) create mode 100644 src/alloc_stack_restore_guard.rs create mode 100644 src/mmap_stack_restore_guard.rs diff --git a/src/alloc_stack_restore_guard.rs b/src/alloc_stack_restore_guard.rs new file mode 100644 index 0000000..ef2babb --- /dev/null +++ b/src/alloc_stack_restore_guard.rs @@ -0,0 +1,47 @@ +use crate::{get_stack_limit, set_stack_limit}; + +pub struct StackRestoreGuard { + new_stack: *mut u8, + stack_bytes: usize, + old_stack_limit: Option, +} + +const ALIGNMENT: usize = 16; + +impl StackRestoreGuard { + pub fn new(stack_bytes: usize) -> StackRestoreGuard { + // On these platforms we do not use stack guards. this is very unfortunate, + // but there is not much we can do about it without OS support. + // We simply allocate the requested size from the global allocator with a suitable + // alignment. + let stack_bytes = stack_bytes + .checked_add(ALIGNMENT - 1) + .expect("unreasonably large stack requested") + / ALIGNMENT + * ALIGNMENT; + let layout = std::alloc::Layout::from_size_align(stack_bytes, ALIGNMENT).unwrap(); + let ptr = unsafe { std::alloc::alloc(layout) }; + assert!(!ptr.is_null(), "unable to allocate stack"); + StackRestoreGuard { + new_stack: ptr, + stack_bytes, + old_stack_limit: get_stack_limit(), + } + } + + pub fn stack_area(&self) -> (*mut u8, usize) { + (self.new_stack, self.stack_bytes) + } +} + +impl Drop for StackRestoreGuard { + fn drop(&mut self) { + unsafe { + std::alloc::dealloc( + self.new_stack, + std::alloc::Layout::from_size_align_unchecked(self.stack_bytes, ALIGNMENT), + ); + } + set_stack_limit(self.old_stack_limit); + } +} diff --git a/src/lib.rs b/src/lib.rs index 9affdd0..421dc34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,123 +135,30 @@ fn set_stack_limit(l: Option) { psm_stack_manipulation! { yes { - struct StackRestoreGuard { - new_stack: *mut std::ffi::c_void, - stack_bytes: usize, - old_stack_limit: Option, - } - - impl StackRestoreGuard { - #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] - unsafe fn new(stack_bytes: usize, _page_size: usize) -> StackRestoreGuard { - let layout = std::alloc::Layout::from_size_align(stack_bytes, 16).unwrap(); - let ptr = std::alloc::alloc(layout); - assert!(!ptr.is_null(), "unable to allocate stack"); - StackRestoreGuard { - new_stack: ptr as *mut _, - stack_bytes, - old_stack_limit: get_stack_limit(), - } - } - - #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] - unsafe fn new(stack_bytes: usize, page_size: usize) -> StackRestoreGuard { - let new_stack = libc::mmap( - std::ptr::null_mut(), - stack_bytes, - libc::PROT_NONE, - libc::MAP_PRIVATE | - libc::MAP_ANON, - -1, // Some implementations assert fd = -1 if MAP_ANON is specified - 0 - ); - assert_ne!( - new_stack, - libc::MAP_FAILED, - "mmap failed to allocate stack: {}", - std::io::Error::last_os_error() - ); - let guard = StackRestoreGuard { - new_stack, - stack_bytes, - old_stack_limit: get_stack_limit(), - }; - let above_guard_page = new_stack.add(page_size); - #[cfg(not(target_os = "openbsd"))] - let result = libc::mprotect( - above_guard_page, - stack_bytes - page_size, - libc::PROT_READ | libc::PROT_WRITE - ); - #[cfg(target_os = "openbsd")] - let result = if libc::mmap( - above_guard_page, - stack_bytes - page_size, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_STACK, - -1, - 0) == above_guard_page { - 0 - } else { - -1 - }; - assert_ne!( - result, - -1, - "mprotect/mmap failed: {}", - std::io::Error::last_os_error() - ); - guard - } - } + #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] + #[path = "mmap_stack_restore_guard.rs"] + mod stack_restore_guard; - impl Drop for StackRestoreGuard { - fn drop(&mut self) { - #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] - unsafe { - std::alloc::dealloc( - self.new_stack as *mut u8, - std::alloc::Layout::from_size_align_unchecked(self.stack_bytes, 16), - ); - } - #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] - unsafe { - // FIXME: check the error code and decide what to do with it. - // Perhaps a debug_assertion? - libc::munmap(self.new_stack, self.stack_bytes); - } - set_stack_limit(self.old_stack_limit); - } - } + #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] + #[path = "alloc_stack_restore_guard.rs"] + mod stack_restore_guard; - fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { - // Calculate a number of pages we want to allocate for the new stack. - // For maximum portability we want to produce a stack that is aligned to a page and has - // a size that’s a multiple of page size. Furthermore we want to allocate two extras pages - // for the stack guard. To achieve that we do our calculations in number of pages and - // convert to bytes last. - let page_size = page_size(); - let requested_pages = stack_size - .checked_add(page_size - 1) - .expect("unreasonably large stack requested") / page_size; - let stack_pages = std::cmp::max(1, requested_pages) + 2; - let stack_bytes = stack_pages.checked_mul(page_size) - .expect("unreasonably large stack requested"); + use stack_restore_guard::StackRestoreGuard; - // Next, there are a couple of approaches to how we allocate the new stack. We take the - // most obvious path and use `mmap`. We also `mprotect` a guard page into our - // allocation. - // - // We use a guard pattern to ensure we deallocate the allocated stack when we leave - // this function and also try to uphold various safety invariants required by `psm` - // (such as not unwinding from the callback we pass to it). - // + fn _grow(requested_stack_size: usize, callback: &mut dyn FnMut()) { // Other than that this code has no meaningful gotchas. unsafe { - let guard = StackRestoreGuard::new(stack_bytes, page_size); - let above_guard_page = guard.new_stack.add(page_size); - set_stack_limit(Some(above_guard_page as usize)); - let panic = psm::on_stack(above_guard_page as *mut _, stack_size, move || { + // We use a guard pattern to ensure we deallocate the allocated stack when we leave + // this function and also try to uphold various safety invariants required by `psm` + // (such as not unwinding from the callback we pass to it). + // `StackRestoreGuard` allocates a memory area with suitable size and alignment. + // It also sets up stack guards if supported on target. + let guard = StackRestoreGuard::new(requested_stack_size); + let (stack_base,allocated_stack_size) = guard.stack_area(); + debug_assert!(allocated_stack_size >= requested_stack_size); + set_stack_limit(Some(stack_base as usize)); + // TODO should we not pass `allocated_stack_size` here? + let panic = psm::on_stack(stack_base, requested_stack_size, move || { std::panic::catch_unwind(std::panic::AssertUnwindSafe(callback)).err() }); drop(guard); @@ -260,14 +167,6 @@ psm_stack_manipulation! { } } } - - fn page_size() -> usize { - // FIXME: consider caching the page size. - #[cfg(not(any(target_arch = "wasm32",target_os = "hermit")))] - unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize } - #[cfg(any(target_arch = "wasm32",target_os = "hermit"))] - { 65536 } - } } no { diff --git a/src/mmap_stack_restore_guard.rs b/src/mmap_stack_restore_guard.rs new file mode 100644 index 0000000..77c7ced --- /dev/null +++ b/src/mmap_stack_restore_guard.rs @@ -0,0 +1,107 @@ +use crate::{get_stack_limit, set_stack_limit}; + +pub struct StackRestoreGuard { + mapping: *mut u8, + size_with_guard: usize, + page_size: usize, + old_stack_limit: Option, +} + +impl StackRestoreGuard { + pub fn new(requested_size: usize) -> StackRestoreGuard { + // For maximum portability we want to produce a stack that is aligned to a page and has + // a size that’s a multiple of page size. It is natural to use mmap to allocate + // these pages. Furthermore, we want to allocate two extras pages for the stack guard. + // To achieve that we do our calculations in number of pages and convert to bytes last. + let page_size = page_size(); + let requested_pages = requested_size + .checked_add(page_size - 1) + .expect("unreasonably large stack requested") + / page_size; + let page_count_with_guard = std::cmp::max(1, requested_pages) + 2; + let size_with_guard = page_count_with_guard + .checked_mul(page_size) + .expect("unreasonably large stack requested"); + + // Next, there are a couple of approaches to how we allocate the new stack. If it is + // available, we take the most obvious path and use `mmap`. + unsafe { + let new_stack = libc::mmap( + std::ptr::null_mut(), + size_with_guard, + libc::PROT_NONE, + libc::MAP_PRIVATE | libc::MAP_ANON, + -1, // Some implementations assert fd = -1 if MAP_ANON is specified + 0, + ); + assert_ne!( + new_stack, + libc::MAP_FAILED, + "mmap failed to allocate stack: {}", + std::io::Error::last_os_error() + ); + let guard = StackRestoreGuard { + mapping: new_stack as *mut u8, + page_size, + size_with_guard, + old_stack_limit: get_stack_limit(), + }; + // We leave a guard page without read/write access in our allocation. + // TODO we allocated two extra pages for guard pages, but here we only use one? + let above_guard_page = new_stack.add(page_size); + #[cfg(not(target_os = "openbsd"))] + let result = libc::mprotect( + above_guard_page, + size_with_guard - page_size, + libc::PROT_READ | libc::PROT_WRITE, + ); + #[cfg(target_os = "openbsd")] + let result = if libc::mmap( + above_guard_page, + size_with_guard - page_size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_STACK, + -1, + 0, + ) == above_guard_page + { + 0 + } else { + -1 + }; + assert_ne!( + result, + -1, + "mprotect/mmap failed: {}", + std::io::Error::last_os_error() + ); + guard + } + } + + // TODO this should return a *mut [u8], but pointer slices only got proper support with Rust 1.79. + pub fn stack_area(&self) -> (*mut u8, usize) { + unsafe { + ( + self.mapping.add(self.page_size), + self.size_with_guard - self.page_size, + ) + } + } +} + +impl Drop for StackRestoreGuard { + fn drop(&mut self) { + unsafe { + // FIXME: check the error code and decide what to do with it. + // Perhaps a debug_assertion? + libc::munmap(self.mapping as *mut std::ffi::c_void, self.size_with_guard); + } + set_stack_limit(self.old_stack_limit); + } +} + +fn page_size() -> usize { + // FIXME: consider caching the page size. + unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize } +} From b0a87ec3334fae2b48d24d94bdfcbc0d1790b1cf Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 18 Mar 2025 21:47:07 +0200 Subject: [PATCH 26/36] Apply suggestions from code review --- src/lib.rs | 2 +- src/mmap_stack_restore_guard.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 421dc34..ea58ee9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,7 +154,7 @@ psm_stack_manipulation! { // `StackRestoreGuard` allocates a memory area with suitable size and alignment. // It also sets up stack guards if supported on target. let guard = StackRestoreGuard::new(requested_stack_size); - let (stack_base,allocated_stack_size) = guard.stack_area(); + let (stack_base, allocated_stack_size) = guard.stack_area(); debug_assert!(allocated_stack_size >= requested_stack_size); set_stack_limit(Some(stack_base as usize)); // TODO should we not pass `allocated_stack_size` here? diff --git a/src/mmap_stack_restore_guard.rs b/src/mmap_stack_restore_guard.rs index 77c7ced..ba378ed 100644 --- a/src/mmap_stack_restore_guard.rs +++ b/src/mmap_stack_restore_guard.rs @@ -23,8 +23,6 @@ impl StackRestoreGuard { .checked_mul(page_size) .expect("unreasonably large stack requested"); - // Next, there are a couple of approaches to how we allocate the new stack. If it is - // available, we take the most obvious path and use `mmap`. unsafe { let new_stack = libc::mmap( std::ptr::null_mut(), @@ -47,7 +45,7 @@ impl StackRestoreGuard { old_stack_limit: get_stack_limit(), }; // We leave a guard page without read/write access in our allocation. - // TODO we allocated two extra pages for guard pages, but here we only use one? + // There is one guard page below the stack and another above it. let above_guard_page = new_stack.add(page_size); #[cfg(not(target_os = "openbsd"))] let result = libc::mprotect( From d2e5fe8ecc794e6045782b094990360bd6dbd9b9 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 18 Mar 2025 21:51:34 +0200 Subject: [PATCH 27/36] update old github actions --- .github/workflows/test.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42ad6ac..2ce6089 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: mode: -Zminimal-versions timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust ${{ matrix.rust_toolchain }} uses: actions-rs/toolchain@v1 with: @@ -65,7 +65,7 @@ jobs: clang_cl: C:/msys64/mingw32/bin/clang-cl.exe package: mingw-w64-i686-clang steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: release: false @@ -102,7 +102,7 @@ jobs: mingw_path: C:/msys64/mingw32/bin package: mingw-w64-i686-gcc steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: release: false @@ -135,8 +135,8 @@ jobs: - x86_64-pc-windows-gnullvm manifest: ["psm/Cargo.toml", "Cargo.toml"] steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: path: llvm-mingw-version key: ${{ env.LLVM_MINGW_VERSION }} @@ -187,7 +187,7 @@ jobs: mode: ["--release", "-Zminimal-versions", ""] timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -215,7 +215,7 @@ jobs: manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -254,7 +254,7 @@ jobs: manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust nightly uses: actions-rs/toolchain@v1 with: @@ -282,7 +282,7 @@ jobs: manifest: ["psm/Cargo.toml", "Cargo.toml"] timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -309,7 +309,7 @@ jobs: xwin_version: ["0.1.6"] timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -355,7 +355,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Install Rust nightly uses: actions-rs/toolchain@v1 with: From 5c4a33f8ea76afe63b1ddccbfd0aa1c3492187f3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 18 Mar 2025 21:52:18 +0200 Subject: [PATCH 28/36] stacker 0.1.20 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad492fe..ef48a05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.19" +version = "0.1.20" edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/stacker" homepage = "https://github.com/rust-lang/stacker" -documentation = "https://docs.rs/stacker/0.1.19" +documentation = "https://docs.rs/stacker/0.1.20" description = """ A stack growth library useful when implementing deeply recursive algorithms that may accidentally blow the stack. From 9a52970e9a6b5eccd969db8ea9c4f92f4c644680 Mon Sep 17 00:00:00 2001 From: m-mueller678 Date: Wed, 19 Mar 2025 15:55:19 +0100 Subject: [PATCH 29/36] fix high guard page --- src/mmap_stack_restore_guard.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mmap_stack_restore_guard.rs b/src/mmap_stack_restore_guard.rs index ba378ed..1e021c2 100644 --- a/src/mmap_stack_restore_guard.rs +++ b/src/mmap_stack_restore_guard.rs @@ -44,19 +44,19 @@ impl StackRestoreGuard { size_with_guard, old_stack_limit: get_stack_limit(), }; - // We leave a guard page without read/write access in our allocation. + // We leave two guard pages without read/write access in our allocation. // There is one guard page below the stack and another above it. let above_guard_page = new_stack.add(page_size); #[cfg(not(target_os = "openbsd"))] let result = libc::mprotect( above_guard_page, - size_with_guard - page_size, + size_with_guard - 2 * page_size, libc::PROT_READ | libc::PROT_WRITE, ); #[cfg(target_os = "openbsd")] let result = if libc::mmap( above_guard_page, - size_with_guard - page_size, + size_with_guard - 2 * page_size, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_STACK, -1, From 1350e25411d76fde55bd9f72f59da25bb2fded68 Mon Sep 17 00:00:00 2001 From: Ookiineko Date: Tue, 16 Jan 2024 16:52:44 +0000 Subject: [PATCH 30/36] use MinGW implementation on Cygwin Signed-off-by: Ookiineko --- psm/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/psm/build.rs b/psm/build.rs index 0201308..1747466 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -24,6 +24,9 @@ fn find_assembly( Some(("src/arch/x86_64_windows_gnu.s", false)) } } + ("x86_64", _, "cygwin", _) => { + Some(("src/arch/x86_64_windows_gnu.s", false)) + } ("arm", _, "windows", "msvc") => Some(("src/arch/arm_armasm.asm", false)), ("aarch64", _, "windows", _) => { if masm { From 479529695172bb5bd86167fc24cb5644e90b62db Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 26 Apr 2025 01:56:13 +0300 Subject: [PATCH 31/36] psm: release 0.1.26 --- .github/workflows/test.yml | 16 ++++++++-------- psm/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2ce6089..4dd7d3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -123,9 +123,9 @@ jobs: cross-windows-gnullvm-check: name: Check ${{ matrix.manifest }} to ${{ matrix.rust_target }} with stable - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 env: - LLVM_MINGW_VERSION: "20241030" + LLVM_MINGW_VERSION: "20250417" strategy: fail-fast: false matrix: @@ -142,9 +142,9 @@ jobs: key: ${{ env.LLVM_MINGW_VERSION }} - name: Install llvm-mingw if: steps.cache.outputs.cache-hit != 'true' - run: curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/${{ env.LLVM_MINGW_VERSION }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-20.04-x86_64.tar.xz | tar xJf - + run: curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/${{ env.LLVM_MINGW_VERSION }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-22.04-x86_64.tar.xz | tar xJf - - name: Add llvm-mingw to PATH - run: echo "${{ github.workspace }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-20.04-x86_64/bin" >> $GITHUB_PATH + run: echo "${{ github.workspace }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-22.04-x86_64/bin" >> $GITHUB_PATH - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -298,7 +298,7 @@ jobs: cross-windows-build: name: Cross-compile ${{ matrix.manifest }} for ${{ matrix.rust_target }} from x86_64-unknown-linux-gnu - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: true matrix: @@ -319,9 +319,9 @@ jobs: - name: Add toolchain shims run: | set -eux - sudo ln -s clang-12 /usr/bin/clang-cl - sudo ln -s llvm-ar-12 /usr/bin/llvm-lib - sudo ln -s lld-link-12 /usr/bin/lld-link + sudo ln -s clang-14 /usr/bin/clang-cl + sudo ln -s llvm-ar-14 /usr/bin/llvm-lib + sudo ln -s lld-link-14 /usr/bin/lld-link - name: Install Windows SDK run: | set -eux diff --git a/psm/Cargo.toml b/psm/Cargo.toml index d7dda6e..af561b3 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psm" -version = "0.1.25" +version = "0.1.26" edition = "2021" authors = ["Simonas Kazlauskas "] build = "build.rs" From 7a3ff32d72bcd0a12a938abb21deddf9f1449cdc Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 26 Apr 2025 02:17:46 +0300 Subject: [PATCH 32/36] stacker: make remaining stack computation more resilient Sounds like it is plausible for the stack pointer to end up past the computed stack limit depending on the implementation of stack growing and the exact timing at which the stack limit is determined. Supersedes #51 Co-authored-by: Jude Nelson Co-authored-by: Reagan Bohan --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ef48a05..ccb231d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.20" +version = "0.1.21" edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] diff --git a/src/lib.rs b/src/lib.rs index ea58ee9..ee5803c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,7 +91,7 @@ pub fn grow R>(stack_size: usize, callback: F) -> R { /// to determine whether a stack switch should be made or not. pub fn remaining_stack() -> Option { let current_ptr = current_stack_ptr(); - get_stack_limit().map(|limit| current_ptr - limit) + get_stack_limit().map(|limit| current_ptr.saturating_sub(limit)) } psm_stack_information!( From c5b0f277e44769c5a154974f6191a773890b7138 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 2 Oct 2025 16:27:03 -0700 Subject: [PATCH 33/36] Add support for Arm64EC (#129) --- .github/workflows/test.yml | 21 +++++++++++++++++- Cargo.toml | 14 +++++++++--- psm/Cargo.toml | 2 +- psm/build.rs | 1 + psm/src/arch/arm64ec_armasm.asm | 38 +++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 psm/src/arch/arm64ec_armasm.asm diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4dd7d3d..68c2013 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: rust_toolchain: [nightly, stable, 1.63.0] - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest, windows-11-arm] mode: ["--release", "-Zminimal-versions", ""] manifest: ["psm/Cargo.toml", "Cargo.toml"] exclude: @@ -27,6 +27,12 @@ jobs: mode: -Zminimal-versions - rust_toolchain: 1.63.0 mode: -Zminimal-versions + include: + - os: windows-latest + extra_target: i686-pc-windows-msvc + - os: windows-11-arm + rust_toolchain: nightly + extra_target: arm64ec-pc-windows-msvc timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -36,6 +42,7 @@ jobs: toolchain: ${{ matrix.rust_toolchain }} profile: minimal default: true + target: ${{ matrix.extra_target }} - name: Test ${{ matrix.manifest}} with ${{ matrix.mode }} uses: actions-rs/cargo@v1 with: @@ -46,6 +53,18 @@ jobs: with: command: test args: --manifest-path=${{ matrix.manifest }} ${{ matrix.mode }} --examples -- --nocapture + - if: ${{ matrix.extra_target }} + name: Test ${{ matrix.manifest}} with ${{ matrix.mode }} as ${{ matrix.extra_target }} + uses: actions-rs/cargo@v1 + with: + command: test + args: --target=${{ matrix.extra_target }} --manifest-path=${{ matrix.manifest }} ${{ matrix.mode }} -- --nocapture + - if: ${{ matrix.extra_target }} + name: Test ${{ matrix.manifest}} examples with ${{ matrix.mode }} as ${{ matrix.extra_target }} + uses: actions-rs/cargo@v1 + with: + command: test + args: --target=${{ matrix.extra_target }} --manifest-path=${{ matrix.manifest }} ${{ matrix.mode }} --examples -- --nocapture clang-cl-test: name: Test ${{ matrix.manifest }} on ${{ matrix.rust_target }} with ${{ matrix.clang_cl }} diff --git a/Cargo.toml b/Cargo.toml index ccb231d..243f822 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.21" +version = "0.1.22" edition = "2021" rust-version = "1.63" authors = ["Alex Crichton ", "Simonas Kazlauskas "] @@ -25,7 +25,7 @@ cfg-if = "1.0.0" libc = "0.2.156" psm = { path = "psm", version = "0.1.7" } -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(all(windows, not(target_arch = "arm64ec")))'.dependencies.windows-sys] version = ">=0.52.0, <0.60.0" features = [ "Win32_System_Memory", @@ -33,6 +33,14 @@ features = [ "Win32_Foundation", ] +[target.arm64ec-pc-windows-msvc.dependencies.windows-sys] +version = ">=0.59.0, <0.60.0" +features = [ + "Win32_System_Memory", + "Win32_System_Threading", + "Win32_Foundation", +] + [build-dependencies] -cc = "1.1.22" +cc = "1.2.33" diff --git a/psm/Cargo.toml b/psm/Cargo.toml index af561b3..03d5c01 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -14,4 +14,4 @@ readme = "README.mkd" [dependencies] [build-dependencies] -cc = "1.1.22" +cc = "1.2.33" diff --git a/psm/build.rs b/psm/build.rs index 1747466..0d4aab8 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -28,6 +28,7 @@ fn find_assembly( Some(("src/arch/x86_64_windows_gnu.s", false)) } ("arm", _, "windows", "msvc") => Some(("src/arch/arm_armasm.asm", false)), + ("arm64ec", _, "windows", "msvc") => Some(("src/arch/arm64ec_armasm.asm", false)), ("aarch64", _, "windows", _) => { if masm { Some(("src/arch/aarch64_armasm.asm", false)) diff --git a/psm/src/arch/arm64ec_armasm.asm b/psm/src/arch/arm64ec_armasm.asm new file mode 100644 index 0000000..2b0fa9a --- /dev/null +++ b/psm/src/arch/arm64ec_armasm.asm @@ -0,0 +1,38 @@ + AREA |.text|, CODE, READONLY + + GLOBAL |#rust_psm_stack_direction| + ALIGN 4 +|#rust_psm_stack_direction| PROC + orr w0, wzr, #2 + ret + ENDP + + + GLOBAL |#rust_psm_stack_pointer| + ALIGN 4 +|#rust_psm_stack_pointer| PROC + mov x0, sp + ret + ENDP + + + GLOBAL |#rust_psm_replace_stack| + ALIGN 4 +|#rust_psm_replace_stack| PROC + mov sp, x2 + br x1 + ENDP + + GLOBAL |#rust_psm_on_stack| + ALIGN 4 +|#rust_psm_on_stack| PROC + stp x29, x30, [sp, #-16]! + mov x29, sp + mov sp, x3 + blr x2 + mov sp, x29 + ldp x29, x30, [sp], #16 + ret + ENDP + + END From 7fc1d955e471fcc8314f0c8b9b48b5aba8486d09 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Oct 2025 02:33:27 +0300 Subject: [PATCH 34/36] psm: release 0.1.27 --- psm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index 03d5c01..fdd06c0 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psm" -version = "0.1.26" +version = "0.1.27" edition = "2021" authors = ["Simonas Kazlauskas "] build = "build.rs" From f73fc4ad2af6141b5201872f107e61eb347128e0 Mon Sep 17 00:00:00 2001 From: Nick <24689722+ntjohnson1@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:58:40 -0400 Subject: [PATCH 35/36] Mac compatibility (#128) * Add bytes to be divisible by 8, add mac test support * Revert changes to base object file and make pad dependent on ar * Minor cleanup and make padding selection narrower * Try one more time with wasmtime 34 before removing and just adding macos wasmtime ci test to match ubuntu * Prune wasmtime dep because CI unhappy * Revert build changes * Just update assembly and use single padded object * Try using rust archiver tool for better portability * Downgrade ar_archiver to meet rust 1.63 requirements --- psm/Cargo.toml | 1 + psm/build.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index fdd06c0..b2b906c 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -14,4 +14,5 @@ readme = "README.mkd" [dependencies] [build-dependencies] +ar_archive_writer = "0.2.0" cc = "1.2.33" diff --git a/psm/build.rs b/psm/build.rs index 0d4aab8..1fd1f79 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -111,10 +111,61 @@ fn main() { // directly to `ar` to assemble an archive. Otherwise we're actually // compiling the source assembly file. if asm.ends_with(".o") { - cfg.object(asm); + use ar_archive_writer::{write_archive_to_stream, NewArchiveMember, ArchiveKind}; + use std::fs::{read, metadata}; + use std::path::PathBuf; + use std::io::Cursor; + + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable not set"); + let output_path = PathBuf::from(&out_dir).join("libpsm_s.a"); + + let object_data = read(asm).expect("Failed to read object file"); + let file_metadata = metadata(asm).expect("Failed to read file metadata"); + + // Extract file metadata + let mtime = file_metadata.modified().ok() + .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|duration| duration.as_secs()) + .unwrap_or(0); + + #[cfg(unix)] + let (uid, gid, perms) = { + use std::os::unix::fs::MetadataExt; + (file_metadata.uid(), file_metadata.gid(), file_metadata.mode()) + }; + + #[cfg(not(unix))] + let (uid, gid, perms) = (0, 0, 0o644); + + let filename = asm.rsplit('/').next().unwrap_or(asm); + let member = NewArchiveMember { + buf: Box::new(object_data), + get_symbols: |_data: &[u8], _callback: &mut dyn FnMut(&[u8]) -> Result<(), std::io::Error>| Ok(true), + member_name: filename.to_string(), + mtime, + uid, + gid, + perms, + }; + + let mut output_bytes = Cursor::new(Vec::new()); + write_archive_to_stream( + &mut output_bytes, + &[member], + // Unfortunately, getDefaultKind() is not available in ar_archive_writer + // however looking at the llvm-ar source it looks like for wasm32-any-any + // it falls through to Gnu https://llvm.org/doxygen/Object_2Archive_8cpp_source.html + ArchiveKind::Gnu, + false, + ).expect("Failed to write archive"); + + std::fs::write(&output_path, output_bytes.into_inner()).expect("Failed to write archive file"); + + println!("cargo:rustc-link-search=native={}", out_dir); + println!("cargo:rustc-link-lib=static=psm_s"); } else { cfg.file(asm); + cfg.compile("libpsm_s.a"); } - cfg.compile("libpsm_s.a"); -} +} \ No newline at end of file From bc775cf3ed3f16835c10e3951272bb2c8d1f8202 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 27 Oct 2025 18:18:28 +0200 Subject: [PATCH 36/36] psm: release 0.1.28 --- psm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psm/Cargo.toml b/psm/Cargo.toml index b2b906c..be5a9bd 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "psm" -version = "0.1.27" +version = "0.1.28" edition = "2021" authors = ["Simonas Kazlauskas "] build = "build.rs"