Skip to content

Commit ec0e556

Browse files
authored
[ELF] Merge copyLocalSymbols and demoteLocalSymbolsInDiscardedSections (#69425)
Follow-up to #69295: In `Writer<ELFT>::run`, the symbol passes are flexible: they can be placed almost everywhere before `scanRelocations`, with a constraint that the `computeIsPreemptible` pass must be invoked for linker-defined non-local symbols. Merge copyLocalSymbols and demoteLocalSymbolsInDiscardedSections to simplify code: * Demoting local symbols can be made unconditional, not constrainted to /DISCARD/ uses due to performance concerns * `includeInSymtab` can be made faster * Make symbol passes close to each other * Decrease data cache misses due to saving an iteration over local symbols There is no speedup, likely due to the unconditional `dr->section` access in `demoteAndCopyLocalSymbols`. `gc-sections-tls.s` no longer reports an error because the TLS symbol is converted to an Undefined.
1 parent 9f49509 commit ec0e556

File tree

4 files changed

+27
-50
lines changed

4 files changed

+27
-50
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,6 @@ void LinkerScript::processSectionCommands() {
613613
discard(*s);
614614
discardSynthetic(*osec);
615615
osec->commands.clear();
616-
seenDiscard = true;
617616
return false;
618617
}
619618

lld/ELF/LinkerScript.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ class LinkerScript final {
356356

357357
bool hasSectionsCommand = false;
358358
bool seenDataAlign = false;
359-
bool seenDiscard = false;
360359
bool seenRelroEnd = false;
361360
bool errorOnMissingSection = false;
362361
std::string backwardDotErr;

lld/ELF/Writer.cpp

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ template <class ELFT> class Writer {
5353
void run();
5454

5555
private:
56-
void copyLocalSymbols();
5756
void addSectionSymbols();
5857
void sortSections();
5958
void resolveShfLinkOrder();
@@ -292,18 +291,6 @@ static void demoteSymbolsAndComputeIsPreemptible() {
292291
}
293292
}
294293

295-
static void demoteLocalSymbolsInDiscardedSections() {
296-
llvm::TimeTraceScope timeScope("Demote local symbols");
297-
parallelForEach(ctx.objectFiles, [&](ELFFileBase *file) {
298-
DenseMap<SectionBase *, size_t> sectionIndexMap;
299-
for (Symbol *sym : file->getLocalSymbols()) {
300-
Defined *d = dyn_cast<Defined>(sym);
301-
if (d && d->section && !d->section->isLive())
302-
demoteDefined(*d, sectionIndexMap);
303-
}
304-
});
305-
}
306-
307294
// Fully static executables don't support MTE globals at this point in time, as
308295
// we currently rely on:
309296
// - A dynamic loader to process relocations, and
@@ -598,11 +585,6 @@ template <class ELFT> void elf::createSyntheticSections() {
598585

599586
// The main function of the writer.
600587
template <class ELFT> void Writer<ELFT>::run() {
601-
copyLocalSymbols();
602-
603-
if (config->copyRelocs)
604-
addSectionSymbols();
605-
606588
// Now that we have a complete set of output sections. This function
607589
// completes section contents. For example, we need to add strings
608590
// to the string table, and add entries to .got and .plt.
@@ -751,31 +733,33 @@ bool lld::elf::includeInSymtab(const Symbol &b) {
751733
SectionBase *sec = d->section;
752734
if (!sec)
753735
return true;
736+
assert(sec->isLive());
754737

755738
if (auto *s = dyn_cast<MergeInputSection>(sec))
756739
return s->getSectionPiece(d->value).live;
757-
return sec->isLive();
740+
return true;
758741
}
759742
return b.used || !config->gcSections;
760743
}
761744

762-
// Local symbols are not in the linker's symbol table. This function scans
763-
// each object file's symbol table to copy local symbols to the output.
764-
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
765-
if (!in.symTab)
766-
return;
745+
// Scan local symbols to:
746+
//
747+
// - demote symbols defined relative to /DISCARD/ discarded input sections so
748+
// that relocations referencing them will lead to errors.
749+
// - copy eligible symbols to .symTab
750+
static void demoteAndCopyLocalSymbols() {
767751
llvm::TimeTraceScope timeScope("Add local symbols");
768-
if (config->copyRelocs && config->discard != DiscardPolicy::None)
769-
markUsedLocalSymbols<ELFT>();
770752
for (ELFFileBase *file : ctx.objectFiles) {
753+
DenseMap<SectionBase *, size_t> sectionIndexMap;
771754
for (Symbol *b : file->getLocalSymbols()) {
772755
assert(b->isLocal() && "should have been caught in initializeSymbols()");
773756
auto *dr = dyn_cast<Defined>(b);
774-
775-
// No reason to keep local undefined symbol in symtab.
776757
if (!dr)
777758
continue;
778-
if (includeInSymtab(*b) && shouldKeepInSymtab(*dr))
759+
760+
if (dr->section && !dr->section->isLive())
761+
demoteDefined(*dr, sectionIndexMap);
762+
else if (in.symTab && includeInSymtab(*b) && shouldKeepInSymtab(*dr))
779763
in.symTab->addSymbol(b);
780764
}
781765
}
@@ -1991,12 +1975,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
19911975
}
19921976

19931977
demoteSymbolsAndComputeIsPreemptible();
1994-
// Also demote local symbols defined relative to discarded input sections so
1995-
// that relocations referencing them will lead to errors. To avoid unneeded
1996-
// work, we only do this when /DISCARD/ is seen, but this demotation also
1997-
// applies to --gc-sections discarded sections.
1998-
if (script->seenDiscard)
1999-
demoteLocalSymbolsInDiscardedSections();
1978+
1979+
if (config->copyRelocs && config->discard != DiscardPolicy::None)
1980+
markUsedLocalSymbols<ELFT>();
1981+
demoteAndCopyLocalSymbols();
1982+
1983+
if (config->copyRelocs)
1984+
addSectionSymbols();
20001985

20011986
// Change values of linker-script-defined symbols from placeholders (assigned
20021987
// by declareSymbols) to actual definitions.

lld/test/ELF/gc-sections-tls.s

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
11
# REQUIRES: x86
22
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
33

4-
## Relocation in a non .debug_* referencing a discarded TLS symbol is invalid.
5-
## If we happen to have no PT_TLS, we will emit an error.
6-
# RUN: not ld.lld %t.o --gc-sections -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
7-
8-
# ERR: error: {{.*}}.o has an STT_TLS symbol but doesn't have an SHF_TLS section
9-
10-
## TODO As a corner case, when /DISCARD/ is present, demoteLocalSymbolsInDiscardedSections
11-
## demotes tls and the error is not triggered.
12-
# RUN: echo 'SECTIONS { /DISCARD/ : {} }' > %t.lds
13-
# RUN: ld.lld %t.o --gc-sections -T %t.lds -o /dev/null
4+
## When a TLS section is discarded, we will resolve the relocation in a non-SHF_ALLOC
5+
## section to the addend. Technically, we can emit an error in this case as the
6+
## relocation type is not TLS.
7+
# RUN: ld.lld %t.o --gc-sections -o %t
8+
# RUN: llvm-readelf -x .noalloc %t | FileCheck %s
149

15-
## If we happen to have a PT_TLS, we will resolve the relocation to
16-
## an arbitrary value (current implementation uses a negative value).
1710
# RUN: echo '.section .tbss,"awT"; .globl root; root: .long 0' | \
1811
# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
1912
# RUN: ld.lld --gc-sections -u root %t.o %t1.o -o %t
2013
# RUN: llvm-readelf -x .noalloc %t | FileCheck %s
2114

2215
# CHECK: Hex dump of section '.noalloc':
23-
# CHECK-NEXT: 0x00000000 {{[0-9a-f]+}} ffffffff
16+
# CHECK-NEXT: 0x00000000 00800000 00000000
2417

2518
.globl _start
2619
_start:
2720

2821
.section .tbss,"awT",@nobits
22+
.long 0
2923
tls:
3024
.long 0
3125

0 commit comments

Comments
 (0)