uint8_t isPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
+ //
+ // NOTE: In Writer.cpp the field is used to mark local defined symbols
+ // which are referenced by relocations when -r or --emit-relocs is given.
uint8_t used : 1;
// True if a call to this symbol needs to be followed by a restore of the
error("failed to write to the output file: " + toString(std::move(e)));
}
+template <class ELFT, class RelTy>
+static void markUsedLocalSymbolsImpl(ObjFile<ELFT> *file,
+ llvm::ArrayRef<RelTy> rels) {
+ for (const RelTy &rel : rels) {
+ Symbol &sym = file->getRelocTargetSym(rel);
+ if (sym.isLocal())
+ sym.used = true;
+ }
+}
+
+// The function ensures that the "used" field of local symbols reflects the fact
+// that the symbol is used in a relocation from a live section.
+template <class ELFT> static void markUsedLocalSymbols() {
+ // With --gc-sections, the field is already filled.
+ // See MarkLive<ELFT>::resolveReloc().
+ if (config->gcSections)
+ return;
+ // Without --gc-sections, the field is initialized with "true".
+ // Drop the flag first and then rise for symbols referenced in relocations.
+ for (InputFile *file : objectFiles) {
+ ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
+ for (Symbol *b : f->getLocalSymbols())
+ b->used = false;
+ for (InputSectionBase *s : f->getSections()) {
+ InputSection *isec = dyn_cast_or_null<InputSection>(s);
+ if (!isec)
+ continue;
+ if (isec->type == SHT_REL)
+ markUsedLocalSymbolsImpl(f, isec->getDataAs<typename ELFT::Rel>());
+ else if (isec->type == SHT_RELA)
+ markUsedLocalSymbolsImpl(f, isec->getDataAs<typename ELFT::Rela>());
+ }
+ }
+}
+
static bool shouldKeepInSymtab(const Defined &sym) {
if (sym.isSection())
return false;
- // If --emit-reloc or -r is given, all symbols including local ones need to be
- // copied because they may be referenced by relocations.
- if (config->copyRelocs)
+ // If --emit-reloc or -r is given, preserve symbols referenced by relocations
+ // from live sections.
+ if (config->copyRelocs && sym.used)
return true;
if (config->discard == DiscardPolicy::None)
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!in.symTab)
return;
+ if (config->copyRelocs && config->discard != DiscardPolicy::None)
+ markUsedLocalSymbols<ELFT>();
for (InputFile *file : objectFiles) {
ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
for (Symbol *b : f->getLocalSymbols()) {
# REQUIRES: x86
-## Test that --emit-relocs keeps local symbols and overrides --discard-{locals,all}.
+## Test that --emit-relocs keeps local symbols which are used in relocations
+## even when --discard-{locals,all} is given.
+
+## There are two separate code paths that mark used local symbols when
+## --gc-sections is specified and when is not. The test checks both.
# RUN: llvm-mc -filetype=obj -triple=x86_64 -save-temp-labels %s -o %t.o
# RUN: ld.lld --emit-relocs --discard-locals %t.o -o %tlocal
-# RUN: llvm-readelf -s %tlocal | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tlocal | FileCheck --check-prefixes=DISCARD-LOCALS,DISCARD-LOCALS-NOGC %s
# RUN: llvm-readobj -r %tlocal | FileCheck --check-prefix=REL %s
+
## --gc-sections can discard symbols relative to GCed sections (including STT_SECTION).
# RUN: ld.lld --emit-relocs --discard-locals --gc-sections %t.o -o %tlocal.gc
-# RUN: llvm-readelf -s %tlocal.gc | FileCheck --check-prefix=SYM %s
+# RUN: llvm-readelf -s %tlocal.gc | FileCheck --check-prefix=DISCARD-LOCALS %s
# RUN: llvm-readobj -r %tlocal | FileCheck --check-prefix=REL %s
# RUN: ld.lld --emit-relocs --discard-all %t.o -o %tall
-# RUN: llvm-readelf -s %tall | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tall | FileCheck --check-prefixes=DISCARD-ALL,DISCARD-ALL-NOGC %s
# RUN: llvm-readobj -r %tall | FileCheck --check-prefix=REL %s
-# SYM: NOTYPE LOCAL DEFAULT {{.*}} .Lunused
-# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lunused_gc
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused
-# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused_gc
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
-# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
-# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} text
-# SYM-NOGC-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
-# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} .comment
-# SYM-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
+# RUN: ld.lld --emit-relocs --discard-all --gc-sections %t.o -o %tall.gc
+# RUN: llvm-readelf -s %tall.gc | FileCheck --check-prefix=DISCARD-ALL %s
+# RUN: llvm-readobj -r %tall.gc | FileCheck --check-prefix=REL %s
+
+## --discard-locals removes unused local symbols which start with ".L"
+# DISCARD-LOCALS: 0: {{0+}} 0 NOTYPE LOCAL DEFAULT UND
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused
+# DISCARD-LOCALS-NOGC-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused_gc
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} text
+# DISCARD-LOCALS-NOGC-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} .comment
+# DISCARD-LOCALS-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
+
+## --discard-all removes all unused regular local symbols.
+# DISCARD-ALL: 0: {{0+}} 0 NOTYPE LOCAL DEFAULT UND
+# DISCARD-ALL-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
+# DISCARD-ALL-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} text
+# DISCARD-ALL-NOGC-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} .comment
+# DISCARD-ALL-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
# REL: .rela.text {
# REL-NEXT: R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC
# REQUIRES: x86
-## Test that -r keeps local symbols and overrides --discard-{locals,all}.
-## Also see emit-relocs-discard-locals.s
+## Test that -r keeps local symbols which are used in relocations even when
+## --discard-{locals,all} is given.
# RUN: llvm-mc -filetype=obj -triple=x86_64 -save-temp-labels %s -o %t.o
# RUN: ld.lld -r --discard-locals %t.o -o %tlocal.ro
-# RUN: llvm-readelf -s %tlocal.ro | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tlocal.ro | FileCheck --check-prefix=DISCARD-LOCALS %s
# RUN: llvm-readobj -r %tlocal.ro | FileCheck --check-prefix=REL %s
# RUN: ld.lld -r --discard-all %t.o -o %tall.ro
-# RUN: llvm-readelf -s %tall.ro | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tall.ro | FileCheck --check-prefix=DISCARD-ALL %s
# RUN: llvm-readobj -r %tall.ro | FileCheck --check-prefix=REL %s
-# SYM: NOTYPE LOCAL DEFAULT {{.*}} .Lunused
-# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lunused_gc
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused
-# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused_gc
-# SYM-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
-# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
-# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} text
-# SYM-NOGC-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
-# SYM-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
+## --discard-locals removes unused local symbols which start with ".L"
+# DISCARD-LOCALS: 0: {{0+}} 0 NOTYPE LOCAL DEFAULT UND
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} unused_gc
+# DISCARD-LOCALS-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} text
+# DISCARD-LOCALS-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
+# DISCARD-LOCALS-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
+
+## --discard-all removes all unused regular local symbols.
+# DISCARD-ALL: 0: {{0+}} 0 NOTYPE LOCAL DEFAULT UND
+# DISCARD-ALL-NEXT: NOTYPE LOCAL DEFAULT {{.*}} .Lused
+# DISCARD-ALL-NEXT: NOTYPE LOCAL DEFAULT {{.*}} used
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} .text
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} text
+# DISCARD-ALL-NEXT: SECTION LOCAL DEFAULT {{.*}} gc
+# DISCARD-ALL-NEXT: NOTYPE GLOBAL DEFAULT {{.*}} _start
# REL: .rela.text {
# REL-NEXT: R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC