Skip to content

Commit 8fc4eaa

Browse files
committed
[lld][ELF] Demote symbols in discarded sections to Undefined.
After linker script processing, it may be the case that sections were discarded via /DISCARD/, but relocations to symbols in those sections remain. Currently, such symbols are still considered Defined even though their section is not live and will not be placed anywhere. This results in a silently broken binary. This patch goes through the symbols after placement and changes them from Defined to Undefined if their section is no longer live at that point. During relocation processing, we will catch such undefined symbols and report an error. See #58891.
1 parent 557299c commit 8fc4eaa

File tree

7 files changed

+90
-10
lines changed

7 files changed

+90
-10
lines changed

lld/ELF/Driver.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,6 +3061,37 @@ void LinkerDriver::link(opt::InputArgList &args) {
30613061
script->addOrphanSections();
30623062
}
30633063

3064+
// Demote symbols defined relative to input sections that are discarded by
3065+
// /DISCARD/ so that relocations referencing them will get reported.
3066+
if (script->seenDiscard) {
3067+
llvm::TimeTraceScope timeScope("Demote symbols in discarded sections");
3068+
parallelForEach(symtab.getSymbols(), [](Symbol *sym) {
3069+
Defined *d = dyn_cast<Defined>(sym);
3070+
if (!d)
3071+
return;
3072+
if (d->section && !d->section->isLive()) {
3073+
uint32_t secIdx = 0;
3074+
if (d->file) {
3075+
uint32_t idx = 0;
3076+
for (SectionBase *s : d->file->getSections()) {
3077+
if (s == d->section) {
3078+
secIdx = idx;
3079+
break;
3080+
}
3081+
idx++;
3082+
}
3083+
}
3084+
// If we don't change the binding from WEAK to GLOBAL here, the
3085+
// undefined symbol reporting will think this is undefined weak and
3086+
// not give a warning.
3087+
Undefined(d->file, sym->getName(),
3088+
sym->isWeak() ? (uint8_t)STB_GLOBAL : sym->binding,
3089+
sym->stOther, sym->type, secIdx)
3090+
.overwrite(*sym);
3091+
}
3092+
});
3093+
}
3094+
30643095
{
30653096
llvm::TimeTraceScope timeScope("Merge/finalize input sections");
30663097

lld/ELF/LinkerScript.cpp

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

lld/ELF/LinkerScript.h

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

357357
bool hasSectionsCommand = false;
358358
bool seenDataAlign = false;
359+
bool seenDiscard = false;
359360
bool seenRelroEnd = false;
360361
bool errorOnMissingSection = false;
361362
std::string backwardDotErr;

lld/ELF/Relocations.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,7 @@ int64_t RelocationScanner::computeMipsAddend(const RelTy &rel, RelExpr expr,
507507
template <class ELFT>
508508
static std::string maybeReportDiscarded(Undefined &sym) {
509509
auto *file = dyn_cast_or_null<ObjFile<ELFT>>(sym.file);
510-
if (!file || !sym.discardedSecIdx ||
511-
file->getSections()[sym.discardedSecIdx] != &InputSection::discarded)
510+
if (!file || !sym.discardedSecIdx)
512511
return "";
513512
ArrayRef<typename ELFT::Shdr> objSections =
514513
file->template getELFShdrs<ELFT>();
@@ -1575,7 +1574,8 @@ template <class ELFT> void elf::scanRelocations() {
15751574
scanner.template scanSection<ELFT>(*sec);
15761575
if (part.armExidx && part.armExidx->isLive())
15771576
for (InputSection *sec : part.armExidx->exidxSections)
1578-
scanner.template scanSection<ELFT>(*sec);
1577+
if (sec->isLive())
1578+
scanner.template scanSection<ELFT>(*sec);
15791579
}
15801580
});
15811581
}

lld/ELF/Symbols.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *sym) {
321321
//
322322
// Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols,
323323
// but we don't have to be compatible here.
324-
if (sym->isUndefined() &&
324+
if (sym->isUndefined() && !cast<Undefined>(sym)->discardedSecIdx &&
325325
config->unresolvedSymbols == UnresolvedPolicy::Ignore)
326326
return;
327327

@@ -330,9 +330,12 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *sym) {
330330

331331
auto report = [&](StringRef s) { warn(toString(file) + s + sym->getName()); };
332332

333-
if (sym->isUndefined())
334-
report(": unable to order undefined symbol: ");
335-
else if (sym->isShared())
333+
if (sym->isUndefined()) {
334+
if (cast<Undefined>(sym)->discardedSecIdx)
335+
report(": unable to order discarded symbol: ");
336+
else
337+
report(": unable to order undefined symbol: ");
338+
} else if (sym->isShared())
336339
report(": unable to order shared symbol: ");
337340
else if (d && !d->section)
338341
report(": unable to order absolute symbol: ");

lld/ELF/Writer.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,27 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
722722
// No reason to keep local undefined symbol in symtab.
723723
if (!dr)
724724
continue;
725+
726+
// Demote locals which did not end up in any partition. This is similar
727+
// to what we do in Driver.cpp, but that only works on globals.
728+
if (script->seenDiscard && dr->section && !dr->section->isLive()) {
729+
uint32_t secIdx = 0;
730+
if (dr->file) {
731+
uint32_t idx = 0;
732+
for (SectionBase *s : dr->file->getSections()) {
733+
if (s == dr->section) {
734+
secIdx = idx;
735+
break;
736+
}
737+
idx++;
738+
}
739+
}
740+
Undefined(dr->file, b->getName(), b->binding, b->stOther, b->type,
741+
secIdx)
742+
.overwrite(*b);
743+
continue;
744+
}
745+
725746
if (includeInSymtab(*b) && shouldKeepInSymtab(*dr))
726747
in.symTab->addSymbol(b);
727748
}

lld/test/ELF/linkerscript/discard-section.s

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,32 @@
44
# RUN: rm -rf %t && split-file %s %t && cd %t
55
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
66
# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
7-
# RUN: ld.lld -T a.lds a.o b.o -z undefs -o /dev/null 2>&1 | count 0
8-
# RUN: ld.lld -T a.lds a.o b.o -o /dev/null 2>&1 | count 0
9-
# RUN: ld.lld -r -T a.lds a.o b.o -o /dev/null 2>&1 | count 0
7+
# RUN: not ld.lld --threads=1 -T a.lds a.o b.o -z undefs -o /dev/null 2>&1 | FileCheck %s --check-prefix=SECTION --implicit-check-not=error:
8+
# RUN: not ld.lld --threads=1 -T a.lds a.o b.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=SECTION,SYMBOL --implicit-check-not=error:
9+
# RUN: ld.lld -r -T a.lds a.o b.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARNING --implicit-check-not=error:
10+
11+
# SECTION: error: relocation refers to a discarded section: .aaa
12+
# SECTION-NEXT: >>> defined in a.o
13+
# SECTION-NEXT: >>> referenced by a.o:(.bbb+0x0)
14+
15+
# SYMBOL: error: relocation refers to a symbol in a discarded section: global
16+
# SYMBOL-NEXT: >>> defined in a.o
17+
# SYMBOL-NEXT: >>> referenced by b.o:(.data+0x0)
18+
19+
# SYMBOL: error: relocation refers to a symbol in a discarded section: weak
20+
# SYMBOL-NEXT: >>> defined in a.o
21+
# SYMBOL-NEXT: >>> referenced by b.o:(.data+0x8)
22+
23+
# SYMBOL: error: relocation refers to a symbol in a discarded section: weakref1
24+
# SYMBOL-NEXT: >>> defined in a.o
25+
# SYMBOL-NEXT: >>> referenced by b.o:(.data+0x10)
26+
27+
# SYMBOL: error: relocation refers to a symbol in a discarded section: weakref2
28+
# SYMBOL-NEXT: >>> defined in a.o
29+
# SYMBOL-NEXT: >>> referenced by b.o:(.data+0x18)
30+
31+
# WARNING: warning: relocation refers to a discarded section: .aaa
32+
# WARNING-NEXT: >>> referenced by a.o:(.rela.bbb+0x0)
1033

1134
#--- a.s
1235
.globl _start

0 commit comments

Comments
 (0)