[LLD][COFF] Avoid resolving symbols with -alternatename if the target is undefined (#149496)

This change fixes an issue with the use of `-alternatename` in the MSVC
CRT on ARM64EC, where both mangled and demangled symbol names are
specified. Without this patch, the demangled name could be resolved to
an anti-dependency alias of the target. Since chaining anti-dependency
aliases is not allowed, this results in an undefined symbol.

The root cause isn't specific to ARM64EC, it can affect other targets as
well, even when anti-dependency aliases aren't involved. The
accompanying test case demonstrates a scenario where the symbol could be
resolved from an archive. However, because the archive member is pulled
in after the first pass of alternate name resolution, and archive
members don't override weak aliases, eager resolution would incorrectly
skip it.

(cherry picked from commit ac31d64a64e8a648f6834f4cf9de10c56c8d1083)
This commit is contained in:
Jacek Caban 2025-07-28 10:26:25 -07:00 committed by Tobias Hieta
parent f1bca175af
commit bbc8346e6b
5 changed files with 126 additions and 1 deletions

View File

@ -1364,7 +1364,19 @@ void SymbolTable::resolveAlternateNames() {
!isArm64ECMangledFunctionName(u->getName()))
continue;
}
u->setWeakAlias(addUndefined(to));
// 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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
@ -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"
@ -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"