[lld] [ELF] --why-live: Skip symbol at index 0 and section symbols (PR #177099)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 21 09:32:14 PST 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/177099
>From 5982a041aa873f1cf5977f332c22c25b71490fef Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Tue, 20 Jan 2026 21:45:05 -0800
Subject: [PATCH] [ELF] --why-live: Skip symbol at index 0 and section symbols.
Handle .eh_frame symbols
Symbols of empty names can be matched by `--why-live='*'`, which are
generally not useful.
* The first entry in a symbol table (STB_LOCAL and undefined)
* `STT_SECTION` symbols (emitted by LLVM integrated assembler when
needed by relocations). These input section symbols will be demoted by
`demoteAndCopyLocalSymbols`, so technically not really live.
In addition, such symbols of non-allocable sections currently lead to
crashes: `whyLive` does not record the section, causing the second
iteration of the `while (true)` loop in printWhyLive to call
`std::get<Symbol *>(cur)` when `cur` is an `InputSectionBase *`.
In addition, handle GCC crtendS.o `__FRAME_END__`, which is defined
relative to a `.eh_frame` section created with
`__attribute__((used, section(".eh_frame")))`.
Fix #176890
---
lld/ELF/MarkLive.cpp | 15 ++++++++++++---
lld/test/ELF/why-live.test | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index a7b0f08c8d954..b2e5dfc8107c2 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -327,8 +327,13 @@ void MarkLive<ELFT, TrackWhyLive>::printWhyLive(Symbol *s) const {
if (std::holds_alternative<Symbol *>(cur))
printSymbol(std::get<Symbol *>(cur));
- else
- msg << std::get<InputSectionBase *>(cur);
+ else {
+ auto *sec = std::get<InputSectionBase *>(cur);
+ msg << sec;
+ // Live EhInputSection has no tracked reason. Break.
+ if (isa<EhInputSection>(sec))
+ break;
+ }
}
}
@@ -443,9 +448,13 @@ void MarkLive<ELFT, TrackWhyLive>::run() {
for (Symbol *sym : ctx.symtab->getSymbols())
handleSym(sym);
+ // Handle local symbols, skipping the symbol at index 0 and section
+ // symbols, which usually have empty names and technically not live. Note:
+ // a live section may lack an associated section symbol, making them
+ // unreliable liveness indicators.
for (ELFFileBase *file : ctx.objectFiles)
for (Symbol *sym : file->getSymbols())
- if (sym->isLocal())
+ if (sym->isLocal() && sym->isDefined() && !sym->isSection())
handleSym(sym);
}
}
diff --git a/lld/test/ELF/why-live.test b/lld/test/ELF/why-live.test
index d8f8cc7b6db64..c4ae0ad447d24 100644
--- a/lld/test/ELF/why-live.test
+++ b/lld/test/ELF/why-live.test
@@ -4,6 +4,7 @@
# RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o shared.o shared.s
# RUN: ld.lld -shared shared.o -o a.so
# RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o a.o a.s
+# RUN: llvm-mc -n -filetype=obj -triple=x86_64 -o b.o b.s
#--- shared.s
.globl test_shared
@@ -159,3 +160,40 @@ test_local:
# MULTIPLE-DAG: live symbol: a.o:(test_section_offset)
# MULTIPLE-DAG: live symbol: a.o:(test_section_offset_within_symbol)
# MULTIPLE-NOT: live symbol
+
+#--- b.s
+## --why-live='*' skips symbol at index 0 and section symbols.
+# RUN: ld.lld b.o --threads=1 --gc-sections --why-live="*" | FileCheck %s --check-prefix=STAR --implicit-check-not='live symbol:'
+# STAR: live symbol: b.o:(_start) (entry point)
+# STAR-NEXT: live symbol: b.o:(b.s) (no section)
+# STAR-NEXT: live symbol: b.o:(str1){{$}}
+# STAR-NEXT: >>> referenced by: b.o:(.alloc)
+# STAR-NEXT: >>> referenced by: b.o:(.text)
+# STAR-NEXT: >>> contained live symbol: b.o:(_start) (entry point)
+# STAR-NEXT: live symbol: b.o:(__FRAME_END__)
+# STAR-NEXT: >>> in live section: b.o:(.eh_frame)
+# STAR-EMPTY:
+
+## STT_FILE symbol
+.file "b.s"
+
+.text
+.globl _start
+_start:
+ call .alloc
+
+.section .alloc,"a"
+ lea str1(%rip), %rax
+
+.section .nonalloc
+ .long .nonalloc
+
+## GCC crtendS.o has such a local symbol relative to an explicit .eh_frame
+## section.
+.section .eh_frame,"a"
+__FRAME_END__:
+ .long 0
+
+.section .rodata.str1.1,"aMS", at progbits,1
+str1:
+ .asciz "str1"
More information about the llvm-commits
mailing list