llvm / llvm/llvm-project

[lld][ELF] lld drops live FDEs from .eh_frame_hdr with zero-sized functions at same address

Open
#218,124 2 comments 0 reactions 0 assignees View on GitHub
lld:ELF
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

https://godbolt.org/z/547Gbej7f
```C++
__attribute__((cold))
void empty() {
__builtin_unreachable();
}

__attribute__((cold))
int main() {
try {
throw 42;
} catch (int x) {
return x;
}
}
```

The above should return 42, however it instead doesn't find the unwind table for `main` and terminates with
```
terminate called after throwing an instance of 'int'
Program terminated with signal: SIGSEGV
```

This happens because `empty` compiles to a zero-byte function and lands on the same address as `main` in the final binary, where the `.eh_frame_hdr` then only points to the FDE of `empty`.

(The `__attribute__((cold))` is just so that both functions land in the same section.)

`readelf -wf` output on above code compiled with `clang -O2 -fuse-ld=lld`

```
Contents of the .eh_frame_hdr section:

Version: 1
Pointer Encoding Format: 0x1b (sdata4, pcrel)
Count Encoding Format: 0x3 (udata4, absolute)
Table Encoding Format: 0x3b (sdata4, datarel)
Start of frame section: 0x20 (offset: 0x788)
Entries in search table: 0x2
0x10cc (offset: 0x1830) -> 0x3c fde=[ 18]
0x11b8 (offset: 0x191c) -> 0x68 fde=[ 44]

Contents of the .eh_frame section:

00000000 0000000000000014 00000000 CIE
Version: 1
Augmentation: "zR"
Code alignment factor: 1
Data alignment factor: -8
Return address column: 16
Augmentation data: 1b
DW_CFA_def_cfa: r7 (rsp) ofs 8
DW_CFA_offset: r16 (rip) at cfa-8
DW_CFA_undefined: r16 (rip)

00000018 0000000000000010 0000001c FDE cie=00000000 pc=0000000000001830..0000000000001852
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop

0000002c 0000000000000014 00000000 CIE
Version: 1
Augmentation: "zR"
Code alignment factor: 1
Data alignment factor: -8
Return address column: 16
Augmentation data: 1b
DW_CFA_def_cfa: r7 (rsp) ofs 8
DW_CFA_offset: r16 (rip) at cfa-8
DW_CFA_nop
DW_CFA_nop

00000044 0000000000000010 0000001c FDE cie=0000002c pc=000000000000191c..000000000000191c
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop

00000058 000000000000001c 00000000 CIE
Version: 1
Augmentation: "zPLR"
Code alignment factor: 1
Data alignment factor: -8
Return address column: 16
Augmentation data: 9b 15 34 00 00 1b 1b
DW_CFA_def_cfa: r7 (rsp) ofs 8
DW_CFA_offset: r16 (rip) at cfa-8
DW_CFA_nop
DW_CFA_nop

00000078 0000000000000020 00000024 FDE cie=00000058 pc=000000000000191c..0000000000001951
Augmentation data: 3b ff ff ff
DW_CFA_advance_loc: 1 to 000000000000191d
DW_CFA_def_cfa_offset: 16
DW_CFA_offset: r3 (rbx) at cfa-16
DW_CFA_advance_loc: 51 to 0000000000001950
DW_CFA_def_cfa_offset: 8
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop

0000009c ZERO terminator
```

Contributor guide

Open the contributing guide

Research direction

Start with the Godbolt reproducer and inspect lld's ELF .eh_frame_hdr generation, using the supplied readelf -wf output to trace why the zero-sized function's entry replaces main's FDE. Done means the compiled program finds main's unwind table, returns 42, and preserves the relevant live FDE entries in .eh_frame_hdr.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.