Skip to content

Commit 3708688

Browse files
author
git apple-llvm automerger
committed
Merge commit 'ebb326a51fec' from llvm.org/main into next
2 parents 927e8d4 + ebb326a commit 3708688

8 files changed

+188
-34
lines changed

lld/ELF/Driver.cpp

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,12 +2393,6 @@ static void readSymbolPartitionSection(InputSectionBase *s) {
23932393
sym->partition = newPart.getNumber();
23942394
}
23952395

2396-
static Symbol *addUnusedUndefined(StringRef name,
2397-
uint8_t binding = STB_GLOBAL) {
2398-
return symtab.addSymbol(
2399-
Undefined{ctx.internalFile, name, binding, STV_DEFAULT, 0});
2400-
}
2401-
24022396
static void markBuffersAsDontNeed(bool skipLinkedOutput) {
24032397
// With --thinlto-index-only, all buffers are nearly unused from now on
24042398
// (except symbol/section names used by infrequent passes). Mark input file
@@ -2485,15 +2479,15 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
24852479
continue;
24862480

24872481
Symbol *wrap =
2488-
addUnusedUndefined(saver().save("__wrap_" + name), sym->binding);
2482+
symtab.addUnusedUndefined(saver().save("__wrap_" + name), sym->binding);
24892483

24902484
// If __real_ is referenced, pull in the symbol if it is lazy. Do this after
24912485
// processing __wrap_ as that may have referenced __real_.
24922486
StringRef realName = saver().save("__real_" + name);
24932487
if (symtab.find(realName))
2494-
addUnusedUndefined(name, sym->binding);
2488+
symtab.addUnusedUndefined(name, sym->binding);
24952489

2496-
Symbol *real = addUnusedUndefined(realName);
2490+
Symbol *real = symtab.addUnusedUndefined(realName);
24972491
v.push_back({sym, real, wrap});
24982492

24992493
// We want to tell LTO not to inline symbols to be overwritten
@@ -2723,7 +2717,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
27232717
// Handle -u/--undefined before input files. If both a.a and b.so define foo,
27242718
// -u foo a.a b.so will extract a.a.
27252719
for (StringRef name : config->undefined)
2726-
addUnusedUndefined(name)->referenced = true;
2720+
symtab.addUnusedUndefined(name)->referenced = true;
27272721

27282722
parseFiles(files, armCmseImpLib);
27292723

@@ -2736,13 +2730,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
27362730
config->hasDynSymTab =
27372731
!ctx.sharedFiles.empty() || config->isPic || config->exportDynamic;
27382732

2739-
// Some symbols (such as __ehdr_start) are defined lazily only when there
2740-
// are undefined symbols for them, so we add these to trigger that logic.
2741-
for (StringRef name : script->referencedSymbols) {
2742-
Symbol *sym = addUnusedUndefined(name);
2743-
sym->isUsedInRegularObj = true;
2744-
sym->referenced = true;
2745-
}
2733+
script->addScriptReferencedSymbolsToSymTable();
27462734

27472735
// Prevent LTO from removing any definition referenced by -u.
27482736
for (StringRef name : config->undefined)

lld/ELF/LinkerScript.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,7 @@ static bool shouldDefineSym(SymbolAssignment *cmd) {
198198
if (cmd->name == ".")
199199
return false;
200200

201-
if (!cmd->provide)
202-
return true;
203-
204-
// If a symbol was in PROVIDE(), we need to define it only
205-
// when it is a referenced undefined symbol.
206-
Symbol *b = symtab.find(cmd->name);
207-
if (b && !b->isDefined() && !b->isCommon())
208-
return true;
209-
return false;
201+
return !cmd->provide || LinkerScript::shouldAddProvideSym(cmd->name);
210202
}
211203

212204
// Called by processSymbolAssignments() to assign definitions to
@@ -1517,3 +1509,41 @@ void LinkerScript::checkFinalScriptConditions() const {
15171509
checkMemoryRegion(lmaRegion, sec, sec->getLMA());
15181510
}
15191511
}
1512+
1513+
void LinkerScript::addScriptReferencedSymbolsToSymTable() {
1514+
// Some symbols (such as __ehdr_start) are defined lazily only when there
1515+
// are undefined symbols for them, so we add these to trigger that logic.
1516+
auto reference = [](StringRef name) {
1517+
Symbol *sym = symtab.addUnusedUndefined(name);
1518+
sym->isUsedInRegularObj = true;
1519+
sym->referenced = true;
1520+
};
1521+
for (StringRef name : referencedSymbols)
1522+
reference(name);
1523+
1524+
// Keeps track of references from which PROVIDE symbols have been added to the
1525+
// symbol table.
1526+
DenseSet<StringRef> added;
1527+
SmallVector<const SmallVector<StringRef, 0> *, 0> symRefsVec;
1528+
for (const auto &[name, symRefs] : provideMap)
1529+
if (LinkerScript::shouldAddProvideSym(name) && added.insert(name).second)
1530+
symRefsVec.push_back(&symRefs);
1531+
while (symRefsVec.size()) {
1532+
for (StringRef name : *symRefsVec.pop_back_val()) {
1533+
reference(name);
1534+
// Prevent the symbol from being discarded by --gc-sections.
1535+
script->referencedSymbols.push_back(name);
1536+
auto it = script->provideMap.find(name);
1537+
if (it != script->provideMap.end() &&
1538+
LinkerScript::shouldAddProvideSym(name) &&
1539+
added.insert(name).second) {
1540+
symRefsVec.push_back(&it->second);
1541+
}
1542+
}
1543+
}
1544+
}
1545+
1546+
bool LinkerScript::shouldAddProvideSym(StringRef symName) {
1547+
Symbol *sym = symtab.find(symName);
1548+
return sym && !sym->isDefined() && !sym->isCommon();
1549+
}

lld/ELF/LinkerScript.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/ADT/ArrayRef.h"
1717
#include "llvm/ADT/DenseMap.h"
1818
#include "llvm/ADT/MapVector.h"
19+
#include "llvm/ADT/SmallVector.h"
1920
#include "llvm/ADT/StringRef.h"
2021
#include "llvm/Support/Compiler.h"
2122
#include <cstddef>
@@ -348,6 +349,18 @@ class LinkerScript final {
348349
// Check backward location counter assignment and memory region/LMA overflows.
349350
void checkFinalScriptConditions() const;
350351

352+
// Add symbols that are referenced in the linker script to the symbol table.
353+
// Symbols referenced in a PROVIDE command are only added to the symbol table
354+
// if the PROVIDE command actually provides the symbol.
355+
// It also adds the symbols referenced by the used PROVIDE symbols to the
356+
// linker script referenced symbols list.
357+
void addScriptReferencedSymbolsToSymTable();
358+
359+
// Returns true if the PROVIDE symbol should be added to the link.
360+
// A PROVIDE symbol is added to the link only if it satisfies an
361+
// undefined reference.
362+
static bool shouldAddProvideSym(StringRef symName);
363+
351364
// SECTIONS command list.
352365
SmallVector<SectionCommand *, 0> sectionCommands;
353366

@@ -379,6 +392,14 @@ class LinkerScript final {
379392

380393
// Sections that will be warned/errored by --orphan-handling.
381394
SmallVector<const InputSectionBase *, 0> orphanSections;
395+
396+
// Stores the mapping: PROVIDE symbol -> symbols referred in the PROVIDE
397+
// expression. For example, if the PROVIDE command is:
398+
//
399+
// PROVIDE(v = a + b + c);
400+
//
401+
// then provideMap should contain the mapping: 'v' -> ['a', 'b', 'c']
402+
llvm::MapVector<StringRef, SmallVector<StringRef, 0>> provideMap;
382403
};
383404

384405
LLVM_LIBRARY_VISIBILITY extern std::unique_ptr<LinkerScript> script;

lld/ELF/ScriptParser.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/Support/TimeProfiler.h"
3737
#include <cassert>
3838
#include <limits>
39+
#include <optional>
3940
#include <vector>
4041

4142
using namespace llvm;
@@ -138,6 +139,10 @@ class ScriptParser final : ScriptLexer {
138139

139140
// A set to detect an INCLUDE() cycle.
140141
StringSet<> seen;
142+
143+
// If we are currently parsing a PROVIDE|PROVIDE_HIDDEN command,
144+
// then this member is set to the PROVIDE symbol name.
145+
std::optional<llvm::StringRef> activeProvideSym;
141146
};
142147
} // namespace
143148

@@ -1055,6 +1060,9 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
10551060
;
10561061
return nullptr;
10571062
}
1063+
llvm::SaveAndRestore saveActiveProvideSym(activeProvideSym);
1064+
if (provide)
1065+
activeProvideSym = name;
10581066
SymbolAssignment *cmd = readSymbolAssignment(name);
10591067
cmd->provide = provide;
10601068
cmd->hidden = hidden;
@@ -1570,7 +1578,10 @@ Expr ScriptParser::readPrimary() {
15701578
tok = unquote(tok);
15711579
else if (!isValidSymbolName(tok))
15721580
setError("malformed number: " + tok);
1573-
script->referencedSymbols.push_back(tok);
1581+
if (activeProvideSym)
1582+
script->provideMap[*activeProvideSym].push_back(tok);
1583+
else
1584+
script->referencedSymbols.push_back(tok);
15741585
return [=] { return script->getSymbolValue(tok, location); };
15751586
}
15761587

lld/ELF/SymbolTable.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,7 @@ void SymbolTable::scanVersionScript() {
333333
// --dynamic-list.
334334
handleDynamicList();
335335
}
336+
337+
Symbol *SymbolTable::addUnusedUndefined(StringRef name, uint8_t binding) {
338+
return addSymbol(Undefined{ctx.internalFile, name, binding, STV_DEFAULT, 0});
339+
}

lld/ELF/SymbolTable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ class SymbolTable {
5757

5858
void handleDynamicList();
5959

60+
Symbol *addUnusedUndefined(StringRef name,
61+
uint8_t binding = llvm::ELF::STB_GLOBAL);
62+
6063
// Set of .so files to not link the same shared object file more than once.
6164
llvm::DenseMap<llvm::CachedHashStringRef, SharedFile *> soNames;
6265

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# REQUIRES: x86
2+
3+
# This test verifies that garbage-collection is correctly garbage collecting
4+
# unused sections when the symbol of the unused section is only referred by
5+
# an unused PROVIDE symbol.
6+
7+
# RUN: rm -rf %t && split-file %s %t && cd %t
8+
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
9+
# RUN: ld.lld -o a_nogc a.o -T script.t
10+
# RUN: llvm-nm a_nogc | FileCheck -check-prefix=NOGC %s
11+
# RUN: ld.lld -o a_gc a.o --gc-sections --print-gc-sections -T script.t | FileCheck --check-prefix=GC_LINK %s
12+
# RUN: llvm-nm a_gc | FileCheck -check-prefix=GC %s
13+
14+
NOGC-NOT: another_unused
15+
NOGC: another_used
16+
NOGC: bar
17+
NOGC: baz
18+
NOGC: baz_ref
19+
NOGC: foo
20+
NOGC-NOT: unused
21+
NOGC: used
22+
23+
GC_LINK: removing unused section a.o:(.text.bar)
24+
25+
GC-NOT: another_unused
26+
GC: another_used
27+
GC-NOT: bar
28+
GC: baz
29+
GC: baz_ref
30+
GC: foo
31+
GC-NOT: unused
32+
GC: used
33+
34+
#--- a.s
35+
.global _start
36+
_start:
37+
call foo
38+
call used
39+
40+
.section .text.foo,"ax",@progbits
41+
foo:
42+
nop
43+
44+
.section .text.bar,"ax",@progbits
45+
.global bar
46+
bar:
47+
nop
48+
49+
.section .text.baz,"ax",@progbits
50+
.global baz
51+
baz:
52+
nop
53+
54+
55+
#--- script.t
56+
PROVIDE(unused = bar + used);
57+
PROVIDE(used = another_used);
58+
PROVIDE(baz_ref = baz);
59+
PROVIDE(another_used = baz_ref);
60+
PROVIDE(another_unused = unused + bar + 0x1);

lld/test/ELF/linkerscript/symbolreferenced.s

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,31 @@
2121
# RUN: ld.lld -o chain -T chain.t a.o
2222
# RUN: llvm-nm chain | FileCheck %s
2323

24-
# CHECK: 0000000000001000 a f1
25-
# CHECK-NEXT: 0000000000001000 A f2
26-
# CHECK-NEXT: 0000000000001000 a g1
27-
# CHECK-NEXT: 0000000000001000 A g2
28-
# CHECK-NEXT: 0000000000001000 A newsym
24+
# CHECK-NOT: another_unused
25+
# CHECK: 0000000000007000 a f1
26+
# CHECK-NEXT: 0000000000007000 A f2
27+
# CHECK-NEXT: 0000000000007000 A f3
28+
# CHECK-NEXT: 0000000000007000 A f4
29+
# CHECK-NEXT: 0000000000006000 A f5
30+
# CHECK-NEXT: 0000000000003000 A f6
31+
# CHECK-NEXT: 0000000000001000 A f7
32+
# CHECK-NOT: g1
33+
# CHECK-NOT: g2
34+
# CHECK-NEXT: 0000000000007500 A newsym
35+
# CHECK: 0000000000002000 A u
36+
# CHECK-NOT: unused
37+
# CHECK-NEXT: 0000000000002000 A v
38+
# CHECK-NEXT: 0000000000002000 A w
39+
40+
41+
# RUN: ld.lld -o chain_with_cycle -T chain_with_cycle.t a.o
42+
# RUN: llvm-nm chain_with_cycle | FileCheck %s --check-prefix=CHAIN_WITH_CYCLE
43+
44+
# CHAIN_WITH_CYCLE: 000 A f1
45+
# CHAIN_WITH_CYCLE: 000 A f2
46+
# CHAIN_WITH_CYCLE: 000 A f3
47+
# CHAIN_WITH_CYCLE: 000 A f4
48+
# CHAIN_WITH_CYCLE: 000 A newsym
2949

3050
# RUN: not ld.lld -T chain2.t a.o 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
3151
# ERR-COUNT-3: error: chain2.t:1: symbol not found: undef
@@ -40,13 +60,30 @@ patatino:
4060
movl newsym, %eax
4161

4262
#--- chain.t
43-
PROVIDE(f2 = 0x1000);
63+
PROVIDE(f7 = 0x1000);
64+
PROVIDE(f5 = f6 + 0x3000);
65+
PROVIDE(f6 = f7 + 0x2000);
66+
PROVIDE(f4 = f5 + 0x1000);
67+
PROVIDE(f3 = f4);
68+
PROVIDE(f2 = f3);
4469
PROVIDE_HIDDEN(f1 = f2);
45-
PROVIDE(newsym = f1);
70+
PROVIDE(newsym = f1 + 0x500);
71+
72+
u = v;
73+
PROVIDE(w = 0x2000);
74+
PROVIDE(v = w);
4675

4776
PROVIDE(g2 = 0x1000);
4877
PROVIDE_HIDDEN(g1 = g2);
4978
PROVIDE(unused = g1);
79+
PROVIDE_HIDDEN(another_unused = g1);
80+
81+
#--- chain_with_cycle.t
82+
PROVIDE(f1 = f2 + f3);
83+
PROVIDE(f2 = f3 + f4);
84+
PROVIDE(f3 = f4);
85+
PROVIDE(f4 = f1);
86+
PROVIDE(newsym = f1);
5087

5188
#--- chain2.t
5289
PROVIDE(f2 = undef);

0 commit comments

Comments
 (0)