Repository navigation
Unable to link code containing naked functions on ARM64 macOS with ThinLTO enabled #148307
Description
I have originally reported this issue in wasmtime repository and was redirected here: bytecodealliance/wasmtime#11957. I have tried to minimize the reproduction, but I failed to do so in reasonable time. The complexity of wasmtime crates is critical here. I would appreciate any hints that would help me minimize this.
Compiling Wasmtime 38.0.3 produces a linker error on ARM64 macOS when building with ThinLTO enabled. The error indicates that wasmtime_fiber_switch symbol is undefined during linking.
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "<426 object files omitted>" "/var/folders/8c/r_zrp9mj12xd414t08zrks940000gn/T/rustc2wYYXA/{libwasmtime-e843f7bbc21927d3,libzstd_sys-7eabaf414ee67d02,libwasmtime_internal_jit_debug-9043bb9a4e496da8}.rlib" "<sysroot>/lib/rustlib/aarch64-apple-darwin/lib/libcompiler_builtins-*.rlib" "-liconv" "-lSystem" "-lc" "-lm" "-arch" "arm64" "-mmacosx-version-min=11.0.0" "-L" "/Users/mk/Developer/software-mansion/scarb/linker-repro/wasmtime-only-test/target/release/build/wasmtime-15671f59b24bbe0f/out" "-L" "/Users/mk/Developer/software-mansion/scarb/linker-repro/wasmtime-only-test/target/release/build/zstd-sys-1ea01473940232bc/out" "-L" "/Users/mk/Developer/software-mansion/scarb/linker-repro/wasmtime-only-test/target/release/build/wasmtime-internal-jit-debug-2aaf81cce8508d62/out" "-o" "/Users/mk/Developer/software-mansion/scarb/linker-repro/wasmtime-only-test/target/release/deps/wasmtime_only_test-69cba5150eff8962" "-Wl,-dead_strip" "-nodefaultlibs"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: ld: warning: object file (/private/var/folders/8c/r_zrp9mj12xd414t08zrks940000gn/T/rustc2wYYXA/libwasmtime-e843f7bbc21927d3.rlib[2](242b1992def1ef0b-helpers.o)) was built for newer 'macOS' version (26.0) than being linked (11.0)
ld: warning: object file (/private/var/folders/8c/r_zrp9mj12xd414t08zrks940000gn/T/rustc2wYYXA/libwasmtime_internal_jit_debug-9043bb9a4e496da8.rlib[2](db3b6bfb95261072-gdbjit.o)) was built for newer 'macOS' version (26.0) than being linked (11.0)
Undefined symbols for architecture arm64:
"wasmtime_internal_fiber::stackswitch::aarch64::wasmtime_fiber_switch::h0b241ee887e10750", referenced from:
wasmtime_internal_fiber::unix::Suspend::switch::hfd4514b4efef3e13 in wasmtime_only_test-69cba5150eff8962.wasmtime-e843f7bbc21927d3.wasmtime.7e3b8021754df0c4-cgu.05.rcgu.o.rcgu.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What's important is that this issue only pops up with ThinLTO enabled. It didn't fail with either LTO disabled, set to FatLTO, or Wasmtime 37.
Steps to Reproduce
- Architecture: ARM64 (Apple Silicon)
- OS: macOS 26.0
- Rust: 1.90.0
- Wasmtime: 38.0.3
- Build Profile:
releasewithlto = "thin"
Cargo.toml:
[package]
name = "linker-repro"
version = "0.1.0"
edition = "2021"
[dependencies]
wasmtime = "38"
[profile.release]
lto = "thin"
src/main.rs:
fn main() {
let engine = wasmtime::Engine::default();
println!("Engine created: {:?}", engine);
}Build command:
cargo build --releaseThis will fail with the linker error shown above.
I think the wasmtime commit that triggers this regression is: bytecodealliance/wasmtime@3e9eca8
Meta
I have tested this reproduction on all stable+beta+nightly at the time of submitting this issue:
rustc --version --verbose:
rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: aarch64-apple-darwin
release: 1.90.0
LLVM version: 20.1.8
rustc 1.92.0-beta.1 (3b4dd9bf1 2025-10-28)
binary: rustc
commit-hash: 3b4dd9bf1410f8da6329baa36ce5e37673cbbd1f
commit-date: 2025-10-28
host: aarch64-apple-darwin
release: 1.92.0-beta.1
LLVM version: 21.1.3
rustc 1.93.0-nightly (292be5c7c 2025-10-29)
binary: rustc
commit-hash: 292be5c7c05138d753bbd4b30db7a3f1a5c914f7
commit-date: 2025-10-29
host: aarch64-apple-darwin
release: 1.93.0-nightly
LLVM version: 21.1.3
Activity
folkertdev commentedon Oct 31, 2025
I extracted the before and after version of the offending function here https://godbolt.org/z/5a16njzE8
becomes
The
.globland.private_externlines have disappeared. As you can see, these were added specifically by the oldasm_func!macro. Experimentally, either is sufficient to make the example link correctly.a quick fix is to make this function
#[unsafe(no_mangle)]: that will emit the.globl.We do have code to emit
.globlon macos, here:rust/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
Lines 160 to 198 in 23c7bad
So somehow the linkage is such that this does not fire, I think? It seems plausible that it is
Linkage::Internal, maybe on macos we should emit a directive even then?folkertdev commentedon Oct 31, 2025
I suspect that the fix here is to emit
.private_extern {asm_name}when the linkage isLinkage::Internal.bjorn3 commentedon Oct 31, 2025
I think what happens is that rustc sees that the naked function is only callable from functions within the same codegen unit and thus marks the naked function as private, but then ThinLTO decides to inline the caller into another codegen unit. Normally it would make the callee public, but it can't for symbols defined in assembly.
folkertdev commentedon Oct 31, 2025
Does that mean that the linkage becomes
Linkage::Internal?Right. The docs on
.private_externare pretty sparse, but to me it seems at least not incorrect to add it to internal naked functions.bjorn3 commentedon Oct 31, 2025
Yes
I think so
alexcrichton commentedon Jan 6, 2026
A bit smaller as a reproduction:
yields:
Rollup merge of rust-lang#148339 - folkertdev:naked-macos-private-ext…
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu
Rollup merge of rust-lang#148339 - folkertdev:naked-macos-private-ext…
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu
Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu