Skip to content

[lld] CIEs do not get garbage-collected #165097

@Noratrieb

Description

@Noratrieb

I originally found this via Rust, where a Rust shared library (cdylib) contained the personality function (rust_eh_personality), despite the one single exported function not unwinding anywhere. Digging deeper, I saw that the personality function was still referenced by a CIE in .eh_frame, a CIE that did not have any associated FDEs but was still not removed. binutils ld removes the CIE and therefore also the personality function.

This is an assembly reproducer of this problem (adapted from #28949).

.section .text.dead,"ax"
dead:
    .cfi_startproc
    .cfi_personality 3, mypersonality
    ret
    .cfi_endproc

.section .text.mypersonality,"ax"
mypersonality:
    ret

.section .text
.globl main
main:
    ret

Running clang main.s -no-pie -Wl,--gc-sections -fuse-ld=lld (no-pie seems to be necessary due to the way the assembler generates relocations) will have a CIE referencing mypersonality in the final binary. Removing the -fuse-ld=lld, so linking with binutils ld, will cause the CIE and personality function to not be present in the binary.

The CIE from llvm-dwarfdump:

00000044 00000018 00000000 CIE
  Format:                DWARF32
  Version:               1
  Augmentation:          "zPR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Personality Address: 00000000002016e9
  Augmentation data:     03 E9 16 20 00 1B

  DW_CFA_def_cfa: RSP +8
  DW_CFA_offset: RIP -8

  CFA=RSP+8: RIP=[CFA-8]

readelf -s lists mypersonality as a present symbol when linked with LLD.

    11: 00000000002016e9     0 NOTYPE  LOCAL  DEFAULT   11 mypersonality

I found https://maskray.me/blog/2021-02-28-linker-garbage-collection which mentions

Personality routines or language-specific data area referenced by .eh_frame. ld.lld handles --gc-sections before .eh_frame deduplication, so this may retain sections than needed.

So I am not fully sure if this is deliberate behavior, since I would expect the CIE to still be removed (with the personality function present) if ".eh_frame deduplication" removed unused CIEs.

In the original case, due to unfortunate circumstances around Rusts personality function (rust-lang/rust#148105), the difference in binary size here between binutils ld and LLD was actually several hundred kilobytes because of this.

mold also appears to not remove the CIE.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions