TCB: compile the assembly only on little-endian targets with the ABI's pointer width - #248
Conversation
…s pointer width Each target's functions were compiled under `target_arch` alone, which also holds on aarch64_be (and armeb), where the little-endian ISA models are wrong, and on x32 (and aarch64 ILP32), where pointers are narrower than the 64-bit calling convention the contracts assume (#242): the crate built for aarch64_be and returned a wrong SHA-256. `Rust.cfg` adds `target_endian = "little"` and the pointer width of the target's `Abi.ptrBits` to its `rustCfg` in the generated `src/asm/mod.rs`, and src/lib.rs fails to compile, with a message saying why, on any configuration of the four architectures that excludes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017k2Cxdn15GPq2CYjNJDRh1
|
|
||
| #[cfg(target_arch = "x86")] | ||
| #[cfg(all(target_arch = "x86", target_endian = "little", target_pointer_width = "32"))] | ||
| #[rustfmt::skip] | ||
| pub(crate) mod x86; |
There was a problem hiding this comment.
these are too many checks -- it's only arm that has multiple endianesses, and I don't think target_pointer_width is ambigious anywhere at all...
There was a problem hiding this comment.
Both conditions do exclude real targets. I checked each against main:
- Endianness beyond arm:
target_arch = "aarch64"also holds onaarch64_be-unknown-linux-gnuandaarch64_be-unknown-none-softfloat. Onmain,cargo +nightly check -Zbuild-std=core,alloc --target aarch64_be-unknown-none-softfloatsucceeds, and it fails on this branch. That's the issue's wrong-SHA-256 case. - Pointer width:
x86_64-unknown-linux-gnux32(tier 2, with std) hastarget_arch = "x86_64"andtarget_pointer_width = "32", and so doesaarch64-unknown-linux-gnu_ilp32.cargo check --target x86_64-unknown-linux-gnux32succeeds onmain, sousizeand pointers are 32-bit while the model and contracts assume 64-bit.
You're right that some conditions are redundant: x86 is always little-endian and 32-bit, arm is always 32-bit, and x86_64 is always little-endian. The emitted cfg is uniform because Rust.cfg derives it from Abi.ptrBits rather than listing targets. That way a new target is covered without anyone remembering to add it (e.g. powerpc64 in #108 covers both endiannesses). If you'd rather have minimal cfgs, I can instead put the exact predicate in each target's rustCfg: aarch64 gets endian and width, x86_64 width, arm endian, x86 nothing. I'd also trim the compile_error! in lib.rs to match. Which do you prefer?
Generated by Claude Code
There was a problem hiding this comment.
hi, this still needs action
There was a problem hiding this comment.
Done in 8ac58bb: each target's rustCfg now has only the conditions its architecture needs.
aarch64:target_endian = "little"andtarget_pointer_width = "64"(foraarch64_beand ILP32)x86_64:target_pointer_width = "64"(for x32)arm:target_endian = "little"(forarmeb)x86:target_arch = "x86", unchanged
Rust.cfg is gone. lib.rs's compile_error! covers the same configurations: big-endian aarch64 or arm, and 32-bit aarch64 or x86_64. aarch64_be-unknown-none-softfloat, armebv7r-none-eabi and x86_64-unknown-linux-gnux32 fail with its message. aarch64, armv7r, i686 and x86_64 still build.
Generated by Claude Code
|
merge conflicts |
…-yjg3gl-endian-width # Conflicts: # src/asm/mod.rs
…-yjg3gl-endian-width
Review: `target_endian` and `target_pointer_width` are only ambiguous on some architectures. Each target's `rustCfg` now says exactly what its architecture needs, instead of `Rust.cfg` adding both to all four: aarch64 its endianness (aarch64_be) and pointer width (ILP32), x86_64 its pointer width (x32), arm its endianness (armeb), and x86 nothing. The `compile_error!` in src/lib.rs covers the same configurations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017k2Cxdn15GPq2CYjNJDRh1
| //! against its contract. | ||
|
|
||
| #[cfg(target_arch = "aarch64")] | ||
| #[cfg(all(target_arch = "aarch64", target_endian = "little", target_pointer_width = "64"))] |
There was a problem hiding this comment.
wat, how you can have aarch64 that doesn't have target_poitner_width of 64???
There was a problem hiding this comment.
rustc has three (all tier 3), from rustc +nightly -Z unstable-options --print target-spec-json --target …:
aarch64-unknown-linux-gnu_ilp32:"arch": "aarch64","target-pointer-width": 32aarch64_be-unknown-linux-gnu_ilp32: the same, big-endianarm64_32-apple-watchos:"arch": "aarch64","target-pointer-width": 32(Apple Watch)
All three are AArch64 instructions with a 32-bit data model (ILP32). Pointers and usize are 32 bits in memory and in x registers, whose upper halves the calling convention leaves unspecified. The AArch64 model and contracts assume 64-bit usize and pointers, so without the width check the crate would compile for these targets against the wrong contracts.
Generated by Claude Code
Addresses the last finding of #242 ("Endianness and pointer width are assumed and not enforced").
Each target's functions were compiled under
target_arch = "…"alone. That also holds on:aarch64_beandarmeb, where the ISA models, which are little-endian (TCB/Mem.lean), are wrong;Abi.ptrBits).On
mainthe crate builds foraarch64_be, where, per the issue, it returns a wrong SHA-256 for "abc".This changes three target definitions, and the doc of
Target.rustCfginTCB/Artifact.lean. It changes no model, contract orVerified.Each
rustCfgnow excludes exactly the configurations its architecture has that the model doesn't describe:rustCfgall(target_arch = "aarch64", target_endian = "little", target_pointer_width = "64")all(target_arch = "x86_64", target_pointer_width = "64")all(target_arch = "arm", target_endian = "little")target_arch = "x86"(unchanged)TCB/Artifact.leandocuments that arustCfgmust exclude any configuration whose endianness or pointer width differs from the model's.src/lib.rshas acompile_error!for the same configurations (big-endian aarch64 or arm, 32-bit aarch64 or x86_64), next to the existing one for x86 without SSE2. Otherwise the build would fail with a confusingunresolved import asm::….Validation
lake buildandlake env lean --run Emit.lean --check: the only change tosrc/asm/is the threecfgs inmod.rs.compile_error!message:x86_64-unknown-linux-gnux32, and, with nightly-Zbuild-std=core,alloc,aarch64_be-unknown-none-softfloatandarmebv7r-none-eabi.x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,i686-unknown-linux-gnu,aarch64-unknown-none-softfloatandarmv7r-none-eabi.cargo test,cargo fmt --check,cargo clippy --all-targets -- -D warningsandci/check_arch_gates.pypass.🤖 Generated with Claude Code
https://claude.ai/code/session_017k2Cxdn15GPq2CYjNJDRh1