Skip to content

RISC-V miscompilation: Clang misaligns kprobe test arrays or omits labels, causing Linux kernel KUnit failures (GNU as works) #168308

@j1akai

Description

@j1akai

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

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 3 is added
  • places it in .data if 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:

Thank you for taking the time to read this issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions