Skip to content

Commit f1ba894

Browse files
authored
[LLD][COFF] Support anti-dependency symbols (#112542)
Co-authored-by: Billy Laws <[email protected]> Anti-dependency symbols are allowed to be duplicated, with the first definition taking precedence. If a regular weak alias is present, it is preferred over an anti-dependency definition. Chaining anti-dependencies is not allowed.
1 parent 8507dba commit f1ba894

File tree

7 files changed

+163
-19
lines changed

7 files changed

+163
-19
lines changed

lld/COFF/Driver.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) {
737737
// If we find a similar mangled symbol, make this an alias to it and return
738738
// its name.
739739
log(unmangled->getName() + " aliased to " + mangled->getName());
740-
unmangled->weakAlias = ctx.symtab.addUndefined(mangled->getName());
740+
unmangled->setWeakAlias(ctx.symtab.addUndefined(mangled->getName()));
741741
return mangled->getName();
742742
}
743743

@@ -2520,7 +2520,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
25202520
continue;
25212521
if (auto *u = dyn_cast<Undefined>(sym))
25222522
if (!u->weakAlias)
2523-
u->weakAlias = ctx.symtab.addUndefined(to);
2523+
u->setWeakAlias(ctx.symtab.addUndefined(to));
25242524
}
25252525

25262526
// If any inputs are bitcode files, the LTO code generator may create

lld/COFF/InputFiles.cpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,25 @@ std::string lld::toString(const coff::InputFile *file) {
7474
/// If Source is Undefined and has no weak alias set, makes it a weak
7575
/// alias to Target.
7676
static void checkAndSetWeakAlias(COFFLinkerContext &ctx, InputFile *f,
77-
Symbol *source, Symbol *target) {
77+
Symbol *source, Symbol *target,
78+
bool isAntiDep) {
7879
if (auto *u = dyn_cast<Undefined>(source)) {
7980
if (u->weakAlias && u->weakAlias != target) {
80-
// Weak aliases as produced by GCC are named in the form
81-
// .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
82-
// of another symbol emitted near the weak symbol.
83-
// Just use the definition from the first object file that defined
84-
// this weak symbol.
85-
if (ctx.config.allowDuplicateWeak)
81+
// Ignore duplicated anti-dependency symbols.
82+
if (isAntiDep)
8683
return;
87-
ctx.symtab.reportDuplicate(source, f);
84+
if (!u->isAntiDep) {
85+
// Weak aliases as produced by GCC are named in the form
86+
// .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
87+
// of another symbol emitted near the weak symbol.
88+
// Just use the definition from the first object file that defined
89+
// this weak symbol.
90+
if (ctx.config.allowDuplicateWeak)
91+
return;
92+
ctx.symtab.reportDuplicate(source, f);
93+
}
8894
}
89-
u->weakAlias = target;
95+
u->setWeakAlias(target, isAntiDep);
9096
}
9197
}
9298

@@ -436,7 +442,8 @@ void ObjFile::initializeSymbols() {
436442
uint32_t numSymbols = coffObj->getNumberOfSymbols();
437443
symbols.resize(numSymbols);
438444

439-
SmallVector<std::pair<Symbol *, uint32_t>, 8> weakAliases;
445+
SmallVector<std::pair<Symbol *, const coff_aux_weak_external *>, 8>
446+
weakAliases;
440447
std::vector<uint32_t> pendingIndexes;
441448
pendingIndexes.reserve(numSymbols);
442449

@@ -451,8 +458,8 @@ void ObjFile::initializeSymbols() {
451458
symbols[i] = createUndefined(coffSym);
452459
} else if (coffSym.isWeakExternal()) {
453460
symbols[i] = createUndefined(coffSym);
454-
uint32_t tagIndex = coffSym.getAux<coff_aux_weak_external>()->TagIndex;
455-
weakAliases.emplace_back(symbols[i], tagIndex);
461+
weakAliases.emplace_back(symbols[i],
462+
coffSym.getAux<coff_aux_weak_external>());
456463
} else if (std::optional<Symbol *> optSym =
457464
createDefined(coffSym, comdatDefs, prevailingComdat)) {
458465
symbols[i] = *optSym;
@@ -491,8 +498,10 @@ void ObjFile::initializeSymbols() {
491498

492499
for (auto &kv : weakAliases) {
493500
Symbol *sym = kv.first;
494-
uint32_t idx = kv.second;
495-
checkAndSetWeakAlias(ctx, this, sym, symbols[idx]);
501+
const coff_aux_weak_external *aux = kv.second;
502+
checkAndSetWeakAlias(ctx, this, sym, symbols[aux->TagIndex],
503+
aux->Characteristics ==
504+
IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY);
496505
}
497506

498507
// Free the memory used by sparseChunks now that symbol loading is finished.
@@ -1202,7 +1211,7 @@ void BitcodeFile::parse() {
12021211
sym = ctx.symtab.addUndefined(symName, this, true);
12031212
std::string fallback = std::string(objSym.getCOFFWeakExternalFallback());
12041213
Symbol *alias = ctx.symtab.addUndefined(saver.save(fallback));
1205-
checkAndSetWeakAlias(ctx, this, sym, alias);
1214+
checkAndSetWeakAlias(ctx, this, sym, alias, false);
12061215
} else if (comdatIndex != -1) {
12071216
if (symName == obj->getComdatTable()[comdatIndex].first) {
12081217
sym = comdat[comdatIndex].first;

lld/COFF/SymbolTable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ void SymbolTable::loadMinGWSymbols() {
315315
warn("Resolving " + origName + " by linking to " + newName);
316316
else
317317
log("Resolving " + origName + " by linking to " + newName);
318-
undef->weakAlias = l;
318+
undef->setWeakAlias(l);
319319
continue;
320320
}
321321
}

lld/COFF/Symbols.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ Symbol *Undefined::getWeakAlias() {
116116
// A weak alias may be a weak alias to another symbol, so check recursively.
117117
DenseSet<Symbol *> weakChain;
118118
for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias) {
119+
// Anti-dependency symbols can't be chained.
120+
if (a->isAntiDep)
121+
break;
119122
if (!isa<Undefined>(a))
120123
return a;
121124
if (!weakChain.insert(a).second)
@@ -135,6 +138,7 @@ bool Undefined::resolveWeakAlias() {
135138
// Symbols. For that reason we need to check which type of symbol we
136139
// are dealing with and copy the correct number of bytes.
137140
StringRef name = getName();
141+
bool wasAntiDep = isAntiDep;
138142
if (isa<DefinedRegular>(d))
139143
memcpy(this, d, sizeof(DefinedRegular));
140144
else if (isa<DefinedAbsolute>(d))
@@ -144,6 +148,7 @@ bool Undefined::resolveWeakAlias() {
144148

145149
nameData = name.data();
146150
nameSize = name.size();
151+
isAntiDep = wasAntiDep;
147152
return true;
148153
}
149154

lld/COFF/Symbols.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class Symbol {
100100
: symbolKind(k), isExternal(true), isCOMDAT(false),
101101
writtenToSymtab(false), isUsedInRegularObj(false),
102102
pendingArchiveLoad(false), isGCRoot(false), isRuntimePseudoReloc(false),
103-
deferUndefined(false), canInline(true), isWeak(false),
103+
deferUndefined(false), canInline(true), isWeak(false), isAntiDep(false),
104104
nameSize(n.size()), nameData(n.empty() ? nullptr : n.data()) {
105105
assert((!n.empty() || k <= LastDefinedCOFFKind) &&
106106
"If the name is empty, the Symbol must be a DefinedCOFF.");
@@ -145,6 +145,9 @@ class Symbol {
145145
// managing weak symbol overrides.
146146
unsigned isWeak : 1;
147147

148+
// True if the symbol is an anti-dependency.
149+
unsigned isAntiDep : 1;
150+
148151
protected:
149152
// Symbol name length. Assume symbol lengths fit in a 32-bit integer.
150153
uint32_t nameSize;
@@ -345,6 +348,11 @@ class Undefined : public Symbol {
345348
return dyn_cast_or_null<Defined>(getWeakAlias());
346349
}
347350

351+
void setWeakAlias(Symbol *sym, bool antiDep = false) {
352+
weakAlias = sym;
353+
isAntiDep = antiDep;
354+
}
355+
348356
// If this symbol is external weak, replace this object with aliased symbol.
349357
bool resolveWeakAlias();
350358
};

lld/test/COFF/weak-antidep-chain.test

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
REQUIRES: x86
2+
RUN: split-file %s %t.dir && cd %t.dir
3+
4+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows chain-bad.s -o chain-bad.obj
5+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows chain-bad2.s -o chain-bad2.obj
6+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows globals-bad.s -o globals-bad.obj
7+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows chain-good.s -o chain-good.obj
8+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows chain-good2.s -o chain-good2.obj
9+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows globals-good.s -o globals-good.obj
10+
11+
Temporary anti-dependency chains are allowed as long as they are broken by non-alias symbols.
12+
13+
RUN: lld-link -machine:amd64 -dll -noentry -out:test.dll chain-good.obj globals-good.obj
14+
RUN: lld-link -machine:amd64 -dll -noentry -out:test.dll chain-good2.obj globals-good.obj
15+
16+
Chaining of anti-dependency symbols is not allowed.
17+
18+
RUN: not lld-link -machine:amd64 -dll -noentry -out:test.dll chain-bad.obj globals-bad.obj 2>&1 \
19+
RUN: | FileCheck -check-prefix=ANTIDEP %s
20+
RUN: not lld-link -machine:amd64 -dll -noentry -out:test.dll chain-bad2.obj globals-bad.obj 2>&1 \
21+
RUN: | FileCheck -check-prefix=ANTIDEP %s
22+
23+
ANTIDEP: lld-link: error: undefined symbol: sym
24+
ANTIDEP-NEXT: >>> referenced by chain-bad
25+
26+
#--- chain-bad.s
27+
.weak_anti_dep sym
28+
.set sym,sym2
29+
.weak_anti_dep sym2
30+
.set sym2,sym3
31+
32+
#--- chain-bad2.s
33+
.weak_anti_dep sym2
34+
.set sym2,sym3
35+
.weak sym
36+
.set sym,sym2
37+
38+
#--- globals-bad.s
39+
.section .test,"r"
40+
.global sym3
41+
.set sym3,3
42+
43+
#--- chain-good.s
44+
.weak_anti_dep sym
45+
.set sym,sym2
46+
.weak_anti_dep sym2
47+
.set sym2,sym3
48+
.weak_anti_dep sym3
49+
.set sym3,sym4
50+
.weak_anti_dep sym4
51+
52+
#--- chain-good2.s
53+
.weak_anti_dep sym
54+
.set sym,sym2
55+
.weak_anti_dep sym2
56+
.set sym2,sym3
57+
.weak_anti_dep sym3
58+
.set sym3,weak_sym
59+
.weak weak_sym
60+
.set weak_sym,sym4
61+
.weak_anti_dep sym4
62+
63+
#--- globals-good.s
64+
.section .test,"r"
65+
.global sym2
66+
.set sym2,2
67+
.global sym4
68+
.set sym4,4

lld/test/COFF/weak-antidep.test

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
REQUIRES: x86
2+
RUN: split-file %s %t.dir && cd %t.dir
3+
4+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows antidep.s -o antidep.obj
5+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows antidep2.s -o antidep2.obj
6+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows weak.s -o weak.obj
7+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows test.s -o test.obj
8+
9+
Check that a regular weak alias overrides an anti-dependency symbol.
10+
11+
RUN: lld-link -dll -noentry -out:out1.dll antidep.obj weak.obj test.obj
12+
RUN: llvm-readobj --hex-dump=.test out1.dll | FileCheck --check-prefix=CHECK2 %s
13+
14+
RUN: lld-link -dll -noentry -out:out2.dll weak.obj antidep.obj test.obj
15+
RUN: llvm-readobj --hex-dump=.test out2.dll | FileCheck --check-prefix=CHECK2 %s
16+
17+
RUN: lld-link -dll -noentry -out:out3.dll antidep.obj weak.obj test.obj -lld-allow-duplicate-weak
18+
RUN: llvm-readobj --hex-dump=.test out3.dll | FileCheck --check-prefix=CHECK2 %s
19+
20+
RUN: lld-link -dll -noentry -out:out4.dll weak.obj antidep.obj test.obj -lld-allow-duplicate-weak
21+
RUN: llvm-readobj --hex-dump=.test out4.dll | FileCheck --check-prefix=CHECK2 %s
22+
23+
When an anti-dependency symbol is duplicated, the first definition takes precedence over subsequent ones.
24+
25+
RUN: lld-link -dll -noentry -out:out5.dll antidep.obj antidep2.obj test.obj
26+
RUN: llvm-readobj --hex-dump=.test out5.dll | FileCheck --check-prefix=CHECK1 %s
27+
28+
RUN: lld-link -dll -noentry -out:out6.dll antidep2.obj antidep.obj test.obj
29+
RUN: llvm-readobj --hex-dump=.test out6.dll | FileCheck --check-prefix=CHECK2 %s
30+
31+
CHECK1: 01000000
32+
CHECK2: 02000000
33+
34+
#--- antidep.s
35+
.weak_anti_dep sym
36+
.set sym,target1
37+
38+
#--- antidep2.s
39+
.weak_anti_dep sym
40+
.set sym,target2
41+
42+
#--- weak.s
43+
.weak sym
44+
.set sym,target2
45+
46+
#--- test.s
47+
.section .target,"dr"
48+
.globl target1
49+
.set target1,1
50+
.globl target2
51+
.set target2,2
52+
53+
.section .test,"dr"
54+
.long sym

0 commit comments

Comments
 (0)