-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Description
Summary (Miscompilation)
This is a miscompilation issue:
The compiler successfully produces an executable Linux kernel Image, but the kernel does not run correctly.
When compiling the Linux RISC-V kernel with Clang, the kernel boots but crashes during KUnit kprobes selftests due to corrupted data in test_kprobes_addresses[] and test_kprobes_functions[]. The same kernel built with GCC does not exhibit the issue.
I suspect this is caused by Clang misaligning .rodata arrays or failing to emit local labels that are referenced later as symbols.
Environment
- Clang version used:
https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.5/LLVM-21.1.5-Linux-X64.tar.xz - Linux kernel version:
https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/snapshot/linux-riscv-for-linus-6.18-rc6.tar.gz - Target:
riscv64
Observed Behavior
The kernel builds successfully with Clang, producing a valid Image.
However, when booted under QEMU, it fails during initialization of the RISC-V KUnit kprobes tests:
Log:
https://github.com/j1akai/temp/blob/main/20251113/report0.log
The root cause appears to be that the linker-visible arrays:
test_kprobes_addresses[]test_kprobes_functions[]
defined in:
arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S
are corrupted when assembled with Clang, but correct when assembled with riscv64-linux-gnu-as.
This eventually leads to:
num_kprobe is overestimated
kcalloc() attempts to allocate an excessively large block
allocation fails -> KUnit fails
Analysis
Details:
https://github.com/j1akai/temp/blob/main/20251113/readme.md
Summary of findings:
1. Clang does not emit local labels unless explicitly marked .globl
test_kprobes_add_addr1: and similar labels inside functions do not appear as symbols unless manually marked .globl.
GNU as does emit these labels, so RISCV_PTR label produces valid addresses.
With Clang, many entries in test_kprobes_addresses[] become:
0x0000000000000000- uninitialized memory
- garbage values
This corrupts the array.
2. Clang aligns and places .rodata differently
Even with identical assembly:
.section .rodata
RISCV_PTR test_kprobes_add_addr1
RISCV_PTR test_kprobes_add_addr2
...GNU as guarantees:
- 8-byte alignment for pointer arrays
- placement in
.rodata
Clang sometimes:
- does not align the array at 8 bytes unless
.align 3is added - places it in
.dataif attributes are missing - produces a larger-than-expected section that confuses the kernel logic
This causes:
test_kprobes_addresses[] appears larger than it actually is
while (test_kprobes_addresses[num_kprobe]) runs past the end
leading to invalid memory accesses
Linux community discussion
I reported this issue to the Linux RISC-V community; the maintainers recommended seeking the LLVM community's opinion on this behavior so they can decide whether to accept a workaround in the kernel. See the Linux discussion:
- https://lists.infradead.org/pipermail/linux-riscv/2025-November/080819.html
- https://lists.infradead.org/pipermail/linux-riscv/2025-November/080950.html
Thank you for taking the time to read this issue.