Skip to content

Commit cb5cb69

Browse files
committed
[LLD][COFF] Check both mangled and demangled symbols before adding a lazy archive symbol to the symbol table on ARM64EC
On ARM64EC, a function symbol may appear in both mangled and demangled forms: - ARM64EC archives contain only the mangled name, while the demangled symbol is defined by the object file as an alias. - x86_64 archives contain only the demangled name (the mangled name is usually defined by an object referencing the symbol as an alias to a guess exit thunk). - ARM64EC import files contain both the mangled and demangled names for thunks. If more than one archive defines the same function, this could lead to different libraries being used for the same function depending on how they are referenced. Avoid this by checking if the paired symbol is already defined before adding a symbol to the table.
1 parent 0c80919 commit cb5cb69

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

lld/COFF/SymbolTable.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "lld/Common/Timer.h"
1919
#include "llvm/DebugInfo/DIContext.h"
2020
#include "llvm/IR/LLVMContext.h"
21+
#include "llvm/IR/Mangler.h"
2122
#include "llvm/LTO/LTO.h"
2223
#include "llvm/Support/Debug.h"
2324
#include "llvm/Support/Parallel.h"
@@ -631,8 +632,47 @@ Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
631632
return s;
632633
}
633634

635+
// On ARM64EC, a function symbol may appear in both mangled and demangled forms:
636+
// - ARM64EC archives contain only the mangled name, while the demangled symbol
637+
// is defined by the object file as an alias.
638+
// - x86_64 archives contain only the demangled name (the mangled name is
639+
// usually defined by an object referencing the symbol as an alias to a guess
640+
// exit thunk).
641+
// - ARM64EC import files contain both the mangled and demangled names for
642+
// thunks.
643+
// If more than one archive defines the same function, this could lead
644+
// to different libraries being used for the same function depending on how they
645+
// are referenced. Avoid this by checking if the paired symbol is already
646+
// defined before adding a symbol to the table.
647+
template <typename T>
648+
bool checkLazyECPair(SymbolTable *symtab, StringRef name, InputFile *f) {
649+
if (name.starts_with("__imp_"))
650+
return true;
651+
std::string pairName;
652+
if (std::optional<std::string> mangledName =
653+
getArm64ECMangledFunctionName(name))
654+
pairName = std::move(*mangledName);
655+
else
656+
pairName = *getArm64ECDemangledFunctionName(name);
657+
658+
Symbol *sym = symtab->find(pairName);
659+
if (!sym)
660+
return true;
661+
if (sym->pendingArchiveLoad)
662+
return false;
663+
if (auto u = dyn_cast<Undefined>(sym))
664+
return !u->weakAlias || u->isAntiDep;
665+
// If the symbol is lazy, allow it only if it originates from the same
666+
// archive.
667+
auto lazy = dyn_cast<T>(sym);
668+
return lazy && lazy->file == f;
669+
}
670+
634671
void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
635672
StringRef name = sym.getName();
673+
if (isArm64EC(ctx.config.machine) &&
674+
!checkLazyECPair<LazyArchive>(this, name, f))
675+
return;
636676
auto [s, wasInserted] = insert(name);
637677
if (wasInserted) {
638678
replaceSymbol<LazyArchive>(s, f, sym);
@@ -648,6 +688,8 @@ void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
648688

649689
void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
650690
assert(f->lazy);
691+
if (isArm64EC(ctx.config.machine) && !checkLazyECPair<LazyObject>(this, n, f))
692+
return;
651693
auto [s, wasInserted] = insert(n, f);
652694
if (wasInserted) {
653695
replaceSymbol<LazyObject>(s, f, n);

lld/test/COFF/arm64ec-lib.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64
1717
RUN: llvm-lib -machine:amd64 -out:sym-x86_64.lib sym-x86_64.obj
1818
RUN: llvm-lib -machine:arm64ec -out:func.lib func.obj
1919
RUN: llvm-lib -machine:arm64ec -out:func-x86_64.lib func-x86_64.obj
20+
RUN: llvm-lib -machine:arm64ec -out:func-imp.lib -def:func.def
2021

2122
Verify that a symbol can be referenced from ECSYMBOLS.
2223
RUN: lld-link -machine:arm64ec -dll -noentry -out:test.dll symref-arm64ec.obj sym-arm64ec.lib loadconfig-arm64ec.obj
@@ -57,6 +58,15 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:ref-thunk-2.dll func.lib ref-t
5758
RUN: llvm-objdump -d ref-thunk-2.dll | FileCheck -check-prefix=DISASM %s
5859
RUN: llvm-readobj --hex-dump=.test ref-thunk-2.dll | FileCheck -check-prefix=TESTSEC %s
5960

61+
Pass multiple libraries containing `func` with different manglings and ensure they don't conflict with each other.
62+
RUN: lld-link -machine:arm64ec -dll -noentry -out:ref-thunk-3.dll func.lib loadconfig-arm64ec.obj func-x86_64.lib func-imp.lib ref-thunk.obj
63+
RUN: llvm-objdump -d ref-thunk-3.dll | FileCheck -check-prefix=DISASM %s
64+
RUN: llvm-readobj --hex-dump=.test ref-thunk-3.dll | FileCheck -check-prefix=TESTSEC %s
65+
66+
RUN: lld-link -machine:arm64ec -dll -noentry -out:ref-thunk-4.dll ref-thunk.obj func.lib loadconfig-arm64ec.obj func-x86_64.lib func-imp.lib
67+
RUN: llvm-objdump -d ref-thunk-4.dll | FileCheck -check-prefix=DISASM %s
68+
RUN: llvm-readobj --hex-dump=.test ref-thunk-4.dll | FileCheck -check-prefix=TESTSEC %s
69+
6070
Test linking against an x86_64 library (which uses a demangled function name).
6171
RUN: lld-link -machine:arm64ec -dll -noentry -out:ref-x86-1.dll ref-thunk.obj func-x86_64.lib loadconfig-arm64ec.obj
6272
RUN: llvm-objdump -d ref-x86-1.dll | FileCheck -check-prefix=DISASM-X86 %s
@@ -75,6 +85,11 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:start-lib-1.dll ref-thunk.obj
7585
RUN: llvm-objdump -d start-lib-1.dll | FileCheck -check-prefix=DISASM %s
7686
RUN: llvm-readobj --hex-dump=.test start-lib-1.dll | FileCheck -check-prefix=TESTSEC %s
7787

88+
RUN: lld-link -machine:arm64ec -dll -noentry -out:start-lib-2.dll ref-thunk.obj -start-lib func.obj -end-lib loadconfig-arm64ec.obj \
89+
RUN: -start-lib func-x86_64.obj -end-lib func-imp.lib
90+
RUN: llvm-objdump -d ref-thunk-3.dll | FileCheck -check-prefix=DISASM %s
91+
RUN: llvm-readobj --hex-dump=.test ref-thunk-3.dll | FileCheck -check-prefix=TESTSEC %s
92+
7893
#--- symref.s
7994
.data
8095
.rva sym
@@ -130,3 +145,8 @@ thunksym:
130145
.globl func
131146
func:
132147
ret
148+
149+
#--- func.def
150+
LIBRARY func.dll
151+
EXPORTS
152+
func

0 commit comments

Comments
 (0)