Skip to content

release/21.x: [LLD][COFF] Avoid resolving symbols with -alternatename if the target is undefined (#149496) #151027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 1 addition & 22 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2554,28 +2554,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
e.symbolName = symtab.mangleMaybe(e.sym);
}

// Add weak aliases. Weak aliases is a mechanism to give remaining
// undefined symbols final chance to be resolved successfully.
for (auto pair : symtab.alternateNames) {
StringRef from = pair.first;
StringRef to = pair.second;
Symbol *sym = symtab.find(from);
if (!sym)
continue;
if (auto *u = dyn_cast<Undefined>(sym)) {
if (u->weakAlias) {
// On ARM64EC, anti-dependency aliases are treated as undefined
// symbols unless a demangled symbol aliases a defined one, which
// is part of the implementation.
if (!symtab.isEC() || !u->isAntiDep)
continue;
if (!isa<Undefined>(u->weakAlias) &&
!isArm64ECMangledFunctionName(u->getName()))
continue;
}
u->setWeakAlias(symtab.addUndefined(to));
}
}
symtab.resolveAlternateNames();
});

ctx.forEachActiveSymtab([&](SymbolTable &symtab) {
Expand Down
37 changes: 37 additions & 0 deletions lld/COFF/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,43 @@ void SymbolTable::parseAlternateName(StringRef s) {
alternateNames.insert(it, std::make_pair(from, to));
}

void SymbolTable::resolveAlternateNames() {
// Add weak aliases. Weak aliases is a mechanism to give remaining
// undefined symbols final chance to be resolved successfully.
for (auto pair : alternateNames) {
StringRef from = pair.first;
StringRef to = pair.second;
Symbol *sym = find(from);
if (!sym)
continue;
if (auto *u = dyn_cast<Undefined>(sym)) {
if (u->weakAlias) {
// On ARM64EC, anti-dependency aliases are treated as undefined
// symbols unless a demangled symbol aliases a defined one, which
// is part of the implementation.
if (!isEC() || !u->isAntiDep)
continue;
if (!isa<Undefined>(u->weakAlias) &&
!isArm64ECMangledFunctionName(u->getName()))
continue;
}

// Check if the destination symbol is defined. If not, skip it.
// It may still be resolved later if more input files are added.
// Also skip anti-dependency targets, as they can't be chained anyway.
Symbol *toSym = find(to);
if (!toSym)
continue;
auto toUndef = dyn_cast<Undefined>(toSym);
if (toUndef && (!toUndef->weakAlias || toUndef->isAntiDep))
continue;
if (toSym->isLazy())
forceLazy(toSym);
u->setWeakAlias(toSym);
}
}
}

// Parses /aligncomm option argument.
void SymbolTable::parseAligncomm(StringRef s) {
auto [name, align] = s.split(',');
Expand Down
3 changes: 3 additions & 0 deletions lld/COFF/SymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class SymbolTable {
// symbols and warn about imported local symbols.
void resolveRemainingUndefines();

// Try to resolve undefined symbols with alternate names.
void resolveAlternateNames();

// Load lazy objects that are needed for MinGW automatic import and for
// doing stdcall fixups.
void loadMinGWSymbols();
Expand Down
15 changes: 15 additions & 0 deletions lld/test/COFF/alternatename-alias.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// REQUIRES: x86

// Check that a weak alias can be used as an alternate name target.
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
// RUN: lld-link -dll -noentry %t.obj -alternatename:sym=altsym

.data
.rva sym

.weak altsym
.set altsym,a

.globl a
a:
.word 1
16 changes: 16 additions & 0 deletions lld/test/COFF/alternatename-antidep.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// REQUIRES: x86

// Check that an anti-dependency alias can't be used as an alternate name target.
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
// RUN: not lld-link -dll -noentry %t.obj -alternatename:sym=altsym 2>&1 | FileCheck %s
// CHECK: error: undefined symbol: sym

.data
.rva sym

.weak_anti_dep altsym
.set altsym,a

.globl a
a:
.word 1
43 changes: 43 additions & 0 deletions lld/test/COFF/alternatename-lib.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// REQUIRES: x86
// RUN: split-file %s %t.dir && cd %t.dir

// RUN: llvm-mc -filetype=obj -triple=x86_64-windows refab.s -o refab.obj
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows aa.s -o aa.obj
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows b.s -o b.obj
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows antidep.s -o antidep.obj
// RUN: llvm-lib -out:aa.lib aa.obj
// RUN: llvm-lib -out:b.lib b.obj

// Check that -alternatename with an undefined target does not prevent the symbol from being resolved to a library,
// once another alternate name is resolved and pulls in the source symbol.
// RUN: lld-link -out:out.dll -dll -noentry -machine:amd64 refab.obj aa.lib -alternatename:a=aa -alternatename:b=undef

// Check that -alternatename with an anti-dependency target does not prevent the symbol from being resolved to a library,
// after another alternate name is resolved and pulls in the source symbol.
// RUN: lld-link -out:out2.dll -dll -noentry -machine:amd64 antidep.obj refab.obj aa.lib -alternatename:a=aa -alternatename:b=u

#--- refab.s
.data
.rva a
.rva b

#--- aa.s
.globl aa
aa:
.word 1

.section .drectve, "yn"
.ascii "/defaultlib:b.lib"

#--- b.s
.globl b
b:
.word 2

#--- antidep.s
.weak_anti_dep u
.set u,d

.globl d
d:
.word 3
39 changes: 39 additions & 0 deletions lld/test/COFF/arm64ec-altnames.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ REQUIRES: aarch64
RUN: split-file %s %t.dir && cd %t.dir

RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext.s -o ext.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext-mangled.s -o ext-mangled.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl.s -o impl.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl-cpp.s -o impl-cpp.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig.obj
Expand Down Expand Up @@ -49,6 +50,20 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:out4.dll impl-cpp.obj loadconf
RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
RUN: llvm-readobj --hex-dump=.test out4.dll | FileCheck --check-prefix=TESTSEC %s

# Check that when both mangled and demangled alternate names are used,
# only the one whose target is defined is used (the mangled one in this case).

RUN: lld-link -machine:arm64ec -dll -noentry -out:out5.dll ext-mangled.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym
RUN: llvm-objdump -d out5.dll | FileCheck --check-prefix=DISASM %s
RUN: llvm-readobj --hex-dump=.test out5.dll | FileCheck --check-prefix=TESTSEC %s

# Check that when both mangled and demangled alternate names are used,
# only the one whose target is defined is used (the demangled one in this case).

RUN: lld-link -machine:arm64ec -dll -noentry -out:out6.dll ext.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym
RUN: llvm-objdump -d out6.dll | FileCheck --check-prefix=DISASM2 %s
RUN: llvm-readobj --hex-dump=.test out6.dll | FileCheck --check-prefix=TESTSEC2 %s

#--- ext.s
.weak_anti_dep func
.set func, "#func"
Expand All @@ -70,6 +85,30 @@ altsym:
mov w0, #1
ret

#--- ext-mangled.s
.weak_anti_dep func
.set func, "#func"
.weak_anti_dep "#func"
.set "#func", thunksym

.section .test, "r"
.rva func
.rva "#func"

.section .thnk,"xr",discard,thunksym
thunksym:
mov w0, #2
ret

.section .text,"xr",discard,"#altsym"
.globl "#altsym"
"#altsym":
mov w0, #1
ret

.weak_anti_dep altsym
.set altsym,"#altsym"

#--- impl.s
.weak_anti_dep func
.set func, "#func"
Expand Down
Loading