-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ABI mismatch between rustc and clang for passing ZSTs using the win64 ABI. #132893
Comments
@rustbot label: +A-ABI +A-FFI +O-windows-msvc |
This code fails to compile if you target |
clang matches gcc here, so I think this is a rustc bug rather than a clang bug. the reason the assert fails is instead because the msvc target has different struct layout rules so you don't get a ZST by default, there may be some attribute or pragma that lets you get a ZST on the msvc target, but I haven't found it (though didn't particularly look). |
ZSTs aren't a thing in the MSVC ABI (nor are they in standard C or standard C++, they're a GCC extension). The only reason you can have a ZST in a MS ABI C function is because you're targeting the GNU ABI, but as the MSVC ABI doesn't have ZSTs, Clang doesn't elide the parameter. It would have made more sense for GCC and Clang to recognize that ZSTs aren't a thing in the ABI and completely elide the parameter, since you can never call that function with a non-ZST struct anyway due an to ABI mismatch, and you can't define that struct as a ZST in MSVC, but they didn't do that. (How much sense it makes for GCC and Clang to allow that construct without even a single diagnostic is a different question.) It would be a rustc bug if rustc promised to have exactly the same ABI for its ZST as a compiler extension to standard C, which to my knowledge it doesn't. And even if it did and therefore were to pessimize Rust for an obscure usecase, you're also comparing Clang targeting the GNU target to Rust targeting the MSVC target, which is rather pointless - why should rustc targeting MSVC care what Clang does in the GNU target? |
We only preserve ZST arguments for the win64 call conv on windows gnu targets, not on msvc targets or non-windows targets: rust/compiler/rustc_target/src/callconv/x86_win64.rs Lines 44 to 50 in 3a258d1
|
because they're both using the win64 ABI here, which is supposed to interoperate between those two targets, since that's how you access windows APIs using the MSVC calling convention from the GNU target |
ZSTs will be a non-issue for Windows APIs. Surely it's only a subset of the ABI that GNU declares compatible with system APIs? |
well, the way I see it, if you can pass a ZST through the win64 ABI from both GCC and clang and they agree on an ABI (which they do), then rustc should also support that and have the same ABI for any targets that can access the x86-64 win64 ABI (so, windows msvc, windows gnu, linux (for Wine-style things or assembly or JIT-compiled code), etc.). |
I'm not sure that we can promise that because it's outside our control if it depends on everyone else agreeing on an Windows x86-64 ABI beyond what's needed to interop with the system. If clang with a windows-gnu target has an ABI that differs from clang with a windows-msvc target then what can we do about it? |
afaict they don't differ for passing ZSTs, the issue is more that that is vacuously true on the windows-msvc target since I don't think you can make a ZST (if you can figure out how, please share!). |
We can discuss that case when it comes up. These are all case-by-case decisions anyway. But that's not the case we have here. What we have here is two older compilers implementing this ABI in a certain way, and us doing something else. Seems fairly clear to me that rustc should change here. Maybe we should change to "stop compilation if a ZST is passed via that ABI", but that's generally not what we do for any ABI, so "skip ZST like clang and gcc do" seems best. |
@programmerjake the original example is quite confusing since it compares a |
added a short tldr to the top comment |
note for future readers that #135204 only fixes the function argument ABI, the function return ABI isn't fixed for ZSTs pending the decision in rust-lang/unsafe-code-guidelines#521 |
fix handling of ZST in win64 ABI on windows-msvc targets The Microsoft calling conventions do not really say anything about ZST since they do not seem to exist in MSVC. However, both GCC and clang allow passing ZST over `__attribute__((ms_abi))` functions (which matches our `extern "win64" fn`) on `windows-gnu` targets, and therefore implicitly define a de-facto ABI for these types (and lucky enough they seem to define the same ABI). This ABI should be the same for windows-msvc and windows-gnu targets, so we use this as a hint for how to implement this ABI everywhere: we always pass ZST by-ref. The best alternative would be to just reject compiling functions which cannot exist in MSVC, but that would be a breaking change. Cc `@programmerjake` `@ChrisDenton` Fixes rust-lang/rust#132893
tldr: the win64 ABI is intended to be the exact same ABI across all x86-64 windows targets, however rustc on one target currently doesn't match what clang and gcc do when passing ZSTs as function arguments.
I tried this code:
https://clang.godbolt.org/z/eT5xEz757
rustc -O -C debuginfo=0 --target=x86_64-pc-windows-msvc
clang -O -g0 --target=x86_64-pc-windows-gnu
I expected to see this happen:
the generated assembly reads from the same register no matter if using clang or rustc.
Instead, this happened: rustc's
f
reads fromrcx
whereas clang'sf
reads fromrdx
.Meta
rustc --version --verbose
:It also does the exact same thing on:
clang version: 19.1.0
Generated Assembly
clang's assembly:
rustc's assembly
The text was updated successfully, but these errors were encountered: