llvm / llvm/llvm-project

Clang generates jump tables in .rodata.cst* instead of custom .rodata.<section> causing EFI runtime failures

Open
#161,055 2 comments 0 reactions 0 assignees View on GitHub
clang llvm:mc
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

When compiling u-boot with Clang, we observed that certain functions marked with a custom section attribute (e.g. .text.efi_runtime) may produce jump tables in a separate .rodata.cst* section. This behavior breaks the expected layout, because the U-Boot linker script only includes .rodata.efi_runtime* but not .rodata.cst*.

This leads to missing jump tables at runtime and ultimately boot failure.

GCC does not show this issue:
GCC emits jump tables into .rodata.efi_runtime.*, which naturally matches the linker script.
Clang emits jump tables into .rodata.cst*, which is excluded by the current linker script.

Reproducer: [u-boot: psci.c](https://github.com/u-boot/u-boot/blob/master/drivers/firmware/psci.c#L254)

```c
unsigned long invoke_psci_fn(unsigned long, unsigned long, unsigned long, unsigned long);

enum efi_reset_type {
EFI_RESET_COLD = 0,
EFI_RESET_WARM = 1,
EFI_RESET_SHUTDOWN = 2,
EFI_RESET_PLATFORM_SPECIFIC = 3,
};

typedef unsigned long efi_status_t;

__attribute__((__section__(".text.efi_runtime")))
void efi_reset_system(enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size,
void *reset_data) {
if (reset_type == EFI_RESET_COLD ||
reset_type == EFI_RESET_WARM ||
reset_type == EFI_RESET_PLATFORM_SPECIFIC) {
invoke_psci_fn((0x84000000 + 9), 0, 0, 0);
} else if (reset_type == EFI_RESET_SHUTDOWN) {
invoke_psci_fn((0x84000000 + 8), 0, 0, 0);
}
while (1) ;
}
```

The linker script only collects: [u-boot: u-boot.lds](https://github.com/u-boot/u-boot/blob/master/arch/arm/cpu/armv8/u-boot.lds#L31)

```
.efi_runtime : {
__efi_runtime_start = .;
*(.text.efi_runtime*)
*(.rodata.efi_runtime*)
*(.data.efi_runtime*)
__efi_runtime_stop = .;
}
```
https://godbolt.org/z/nr5qahqsf

Actual behavior (Clang)

- Jump table emitted into .rodata.cst*
- Not captured by .efi_runtime in the linker script

Expected behavior (GCC-compatible)

- Jump table emitted into .rodata.efi_runtime.*
- Automatically included in .efi_runtime section by existing linker script

It seems GCC propagates the custom section naming to associated constant data (such as jump tables), while Clang defaults to placing them into .rodata.cst*.

**Possible solutions:**
Clang to emit jump tables into a section derived from the enclosing function’s custom section (e.g., .rodata.efi_runtime.*).
Or provide an attribute / option to control jump table section placement explicitly.

Contributor guide

Open the contributing guide

Research direction

Start with the reproducer in drivers/firmware/psci.c and compare Clang and GCC output using the linked Godbolt example. Read arch/arm/cpu/armv8/u-boot.lds to understand the expected .efi_runtime layout, then trace the LLVM code responsible for jump-table and constant section placement. Done means the Clang-generated jump table is included by the existing runtime section layout.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.