You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While x86 (i.e. 32-bit) will become less important over time, it is a key architecture of the kernel (and the original one, too). In addition, it is a non-64 bit target (which helps widening our tests to uncover potential issues) and it is a target that pretty much everyone can natively run. Thus we should support it.
Linux x86 targets with official Ubuntu binutils etc. support:
Linux arch QEMU target LLVM target Ubuntu binutils Example Rust triple
---------- -------------- ----------- ------------------------- ----------------------
x86 i386-softmmu X86 binutils-i686-linux-gnu i686-unknown-linux-gnu
x86 x86_64-softmmu X86 binutils-x86-64-linux-gnu x86_64-linux-kernel
From trixie, i386 is no longer supported as a regular architecture: there is no official kernel and no Debian installer for i386 systems. Fewer packages are available for i386 because many projects no longer support it. The architecture’s sole remaining purpose is to support running legacy code, for example, by way of multiarch or a chroot on a 64-bit (amd64) system.
Has anybody tested i386 with -Zregparm and -Zreg-struct-return, or are there other blockers? It seems like it should work now, but I haven't seen anything on the lists.
I just gave it a quick try, and there are some cleanups to do (block uses AtomicU64, DRM panic QR has a 64-bit div, Nova needs a couple cleanups, including this one).
I created a similar case in Compiler Explorer, and indeed it seems to me that the ABI change is not getting applied for extern "C" { fn memset(...); }. If another name is used, it does:
Is there a way to force the ABI for those too (e.g. @llvm.memset) or to avoid special handling at all of those well-known symbols perhaps (like -fno-builtin)?
Cc: @sulix and the old #966 PR, @bjorn3 as well since he was there, @azhogin who worked on the flags, @nbdd0121 who knows a lot about ABIs etc.
(By the way, @azhogin, I don't see any tests/assembly* tests in Rust for e.g. -Zregparm -- I think we should have those as well, not just the LLVM IR one, like we do in other flags.)
Looks like some info is missing when Rust invokes LLVM, as the generated LLVM from Rust compiles correctly when I give it to a clang with -mregparm=3 -freg-struct-return: https://godbolt.org/z/dd17EY1xx
Looks like some info is missing when Rust invokes LLVM, as the generated LLVM from Rust compiles correctly when I give it to a clang with -mregparm=3 -freg-struct-return: https://godbolt.org/z/dd17EY1xx
Nice, that was fast guys :) Then it should be easy to fix (at least implementation-wise, I saw your other comment on the LLVM LangRef).
There were a bunch of KUnit failures which I'd also mostly tracked down to LLVM not using the regparm ABI options for builtins.
Yeah, I had bad derefs in KUnit, but it also happened when loading one of the new sample modules, i.e. I think we will be hitting this as soon as we have non-trivial modules.
The good news is that with the builtins fix above, all of those tests are passing for me.
The bad news is that I think we've got another -Zregparm=3 bug, which is triggered by the LKMM atomics work. It looks like rustc is spilling 64-bit arguments to the stack, even if there are enough registers to go around.
See, for instance https://godbolt.org/z/feb7addG7 — the argument is pushed onto the stack in rust, but in gcc (and also clang), it's stored in edx:eax. Given all of the rust_atomic64_* helpers accept a 64-bit integer argument, this makes the new rust_atomics tests fail and/or crash.
Thanks for taking a look David! I linked it in our lists. It seems to be that inreg is not annotated in extern declarations the same way as Clang would.
(Never mind, I just saw the messages in the other thread and that you already took a look).
Activity
rust: support x86 (i.e. 32-bit)
bpf: Fix a few selftest failures due to llvm18 change
kcsan, seqlock: Support seqcount_latch_t
wifi: iwlwifi: Fix botched indexing conversion
ojeda commentedon Aug 10, 2025
While we likely still want to get i386 to work, Debian Trixie does not support i386 kernels anymore -- from https://www.debian.org/releases/trixie/release-notes/issues.en.html#reduced-support-for-i386:
tgross35 commentedon Aug 11, 2025
Has anybody tested i386 with -Zregparm and -Zreg-struct-return, or are there other blockers? It seems like it should work now, but I haven't seen anything on the lists.
ojeda commentedon Aug 11, 2025
I don't think people has tried yet.
I just gave it a quick try, and there are some cleanups to do (block uses
AtomicU64, DRM panic QR has a 64-bit div, Nova needs a couple cleanups, including this one).In addition, we need https://lore.kernel.org/rust-for-linux/20250727092317.2930617-1-ojeda@kernel.org/ (which will land soon) plus a change on top of that for the two new flags.
All in all, one can play with it with a draft patch like (ignoring mitigations and cleanups):
Details
With it, I can build fine, but I get null and
0x1pointer derefs, which sound like wrong ABI, like when I tried years ago.I took a quick look, and one of the crashes is on calling
memset, which passes argumentspushing:<bindings::bindings_raw::{impl#1376}::default+11>: push $0xb0 <bindings::bindings_raw::{impl#1376}::default+16>: push $0x0 <bindings::bindings_raw::{impl#1376}::default+18>: push %esi <bindings::bindings_raw::{impl#1376}::default+19>: call 0xc15dd5e0 <memset>I created a similar case in Compiler Explorer, and indeed it seems to me that the ABI change is not getting applied for
extern "C" { fn memset(...); }. If another name is used, it does:Is there a way to force the ABI for those too (e.g.
@llvm.memset) or to avoid special handling at all of those well-known symbols perhaps (like-fno-builtin)?https://godbolt.org/z/sPzeqxh3K
Cc: @sulix and the old #966 PR, @bjorn3 as well since he was there, @azhogin who worked on the flags, @nbdd0121 who knows a lot about ABIs etc.
(By the way, @azhogin, I don't see any
tests/assembly*tests in Rust for e.g.-Zregparm-- I think we should have those as well, not just the LLVM IR one, like we do in other flags.)nbdd0121 commentedon Aug 11, 2025
Looks like some info is missing when Rust invokes LLVM, as the generated LLVM from Rust compiles correctly when I give it to a clang with
-mregparm=3 -freg-struct-return: https://godbolt.org/z/dd17EY1xxbjorn3 commentedon Aug 11, 2025
#![no_builtins]fixes it I think.tgross35 commentedon Aug 11, 2025
It's the
NumRegisterParametersmodule flag https://llvm.godbolt.org/z/zoP199bPj. Good catch Miguel :)tgross35 commentedon Aug 11, 2025
Created rust-lang/rust#145271
sulix commentedon Aug 12, 2025
As of my last attempt a couple of months ago, I ended up basically with the same set of issues Miguel mentioned.
The block device/atomics issues are fixed by https://lore.kernel.org/rust-for-linux/20250723233312.3304339-5-gary@kernel.org/
There were a bunch of KUnit failures which I'd also mostly tracked down to LLVM not using the regparm ABI options for builtins.
For proper support,
arch/x86/Makefile_32.cpuneeds the appropriate rustflags set, too (though that should be relatively easy).But other than the -Zregparm issue, the resulting kernel was booting okay even on ancient hardware:
https://davidgow.net/stuff/rust-for-linux-i486-kunit.log
ojeda commentedon Aug 12, 2025
Thanks all!
Nice, that was fast guys :) Then it should be easy to fix (at least implementation-wise, I saw your other comment on the LLVM LangRef).
Yeah, I had bad derefs in KUnit, but it also happened when loading one of the new sample modules, i.e. I think we will be hitting this as soon as we have non-trivial modules.
sulix commentedon Aug 21, 2025
The good news is that with the builtins fix above, all of those tests are passing for me.
The bad news is that I think we've got another -Zregparm=3 bug, which is triggered by the LKMM atomics work. It looks like rustc is spilling 64-bit arguments to the stack, even if there are enough registers to go around.
See, for instance https://godbolt.org/z/feb7addG7 — the argument is pushed onto the stack in rust, but in gcc (and also clang), it's stored in edx:eax. Given all of the rust_atomic64_* helpers accept a 64-bit integer argument, this makes the new rust_atomics tests fail and/or crash.
I've filed a rustc bug here: rust-lang/rust#145694
ojeda commentedon Aug 21, 2025
Thanks for taking a look David! I linked it in our lists. It seems to be that
inregis not annotated inexterndeclarations the same way as Clang would.(Never mind, I just saw the messages in the other thread and that you already took a look).