[lld] a3bcc01 - [LLD] [COFF] Fix linking directly against an ARM64X DLL without import library (#210080)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 02:24:46 PDT 2026
Author: Jacek Caban
Date: 2026-07-17T11:24:41+02:00
New Revision: a3bcc010c7b7d5fa43ab7928a88312841c4322dd
URL: https://github.com/llvm/llvm-project/commit/a3bcc010c7b7d5fa43ab7928a88312841c4322dd
DIFF: https://github.com/llvm/llvm-project/commit/a3bcc010c7b7d5fa43ab7928a88312841c4322dd.diff
LOG: [LLD] [COFF] Fix linking directly against an ARM64X DLL without import library (#210080)
In mingw mode, when linking against a DLL, the user can either provide a
regular import library, or provide the actual DLL. When importing ARM64X
image, add both native and EC views to the symbol table on EC targets.
Also getMachine() on such images returns ARM64X, treat it as ARM64
instead.
Added:
lld/test/COFF/link-dll-arm64x.s
Modified:
lld/COFF/Driver.cpp
lld/COFF/InputFiles.cpp
lld/COFF/InputFiles.h
Removed:
################################################################################
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index dc4903a5fe126..17dbe3cb8d895 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -356,7 +356,21 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
break;
case file_magic::pecoff_executable:
if (ctx.config.mingw) {
- addFile(make<DLLFile>(ctx.symtab, mbref));
+ std::unique_ptr<COFFObjectFile> obj =
+ ObjFile::createCOFFObject(ctx, mbref);
+ if (ctx.symtab.isEC()) {
+ // When importing an ARM64X image, add both the native and EC views.
+ if (std::unique_ptr<MemoryBuffer> hybridView =
+ obj->getHybridObjectView()) {
+ std::unique_ptr<COFFObjectFile> hybridObj = ObjFile::createCOFFObject(
+ ctx, hybridView.release()->getMemBufferRef());
+ addFile(make<DLLFile>(ctx.symtab, hybridObj));
+ addFile(make<DLLFile>(*ctx.hybridSymtab, obj));
+ break;
+ }
+ }
+ auto machine = static_cast<MachineTypes>(obj->getMachine());
+ addFile(make<DLLFile>(ctx.getSymtab(machine), obj));
break;
}
if (filename.ends_with_insensitive(".dll")) {
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 757a0f7be9b36..cd146cf24312d 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -1506,22 +1506,6 @@ static bool isRVACode(COFFObjectFile *coffObj, uint64_t rva, InputFile *file) {
}
void DLLFile::parse() {
- // Parse a memory buffer as a PE-COFF executable.
- std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
-
- if (auto *obj = dyn_cast<COFFObjectFile>(bin.get())) {
- bin.release();
- coffObj.reset(obj);
- } else {
- Err(symtab.ctx) << toString(this) << " is not a COFF file";
- return;
- }
-
- if (!coffObj->getPE32Header() && !coffObj->getPE32PlusHeader()) {
- Err(symtab.ctx) << toString(this) << " is not a PE-COFF executable";
- return;
- }
-
for (const auto &exp : coffObj->export_directories()) {
StringRef dllName, symbolName;
uint32_t exportRVA;
@@ -1564,9 +1548,8 @@ void DLLFile::parse() {
}
MachineTypes DLLFile::getMachineType() const {
- if (coffObj)
- return static_cast<MachineTypes>(coffObj->getMachine());
- return IMAGE_FILE_MACHINE_UNKNOWN;
+ auto machine = static_cast<MachineTypes>(coffObj->getMachine());
+ return machine == ARM64X ? ARM64 : machine;
}
void DLLFile::makeImport(DLLFile::Symbol *s) {
@@ -1581,7 +1564,7 @@ void DLLFile::makeImport(DLLFile::Symbol *s) {
auto *imp = reinterpret_cast<coff_import_header *>(p);
p += sizeof(*imp);
imp->Sig2 = 0xFFFF;
- imp->Machine = coffObj->getMachine();
+ imp->Machine = static_cast<uint16_t>(getMachineType());
imp->SizeOfData = impSize;
imp->OrdinalHint = 0; // Only linking by name
imp->TypeInfo = (s->nameType << 2) | s->importType;
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index b8a2acf6e1b41..3d92de8492940 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -424,8 +424,10 @@ class BitcodeFile : public InputFile {
// .dll file. MinGW only.
class DLLFile : public InputFile {
public:
- explicit DLLFile(SymbolTable &symtab, MemoryBufferRef m)
- : InputFile(symtab, DLLKind, m) {}
+ explicit DLLFile(SymbolTable &symtab, std::unique_ptr<COFFObjectFile> &obj)
+ : InputFile(symtab, DLLKind, obj->getMemoryBufferRef()) {
+ coffObj.swap(obj);
+ }
static bool classof(const InputFile *f) { return f->kind() == DLLKind; }
void parse() override;
MachineTypes getMachineType() const override;
diff --git a/lld/test/COFF/link-dll-arm64x.s b/lld/test/COFF/link-dll-arm64x.s
new file mode 100644
index 0000000000000..b97a61aa3f5be
--- /dev/null
+++ b/lld/test/COFF/link-dll-arm64x.s
@@ -0,0 +1,81 @@
+REQUIRES: aarch64, x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows sym-ec.s -o sym-ec.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-ec.s -o ref-ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows sym-native.s -o sym-native.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows ref-native.s -o ref-native.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:import.dll sym-ec.obj sym-native.obj loadconfig-arm64ec.obj loadconfig-arm64.obj
+
+RUN: lld-link -machine:arm64 -dll -noentry -out:out-arm64.dll ref-native.obj import.dll \
+RUN: -lldmingw -exclude-all-symbols -auto-import:no
+
+RUN: llvm-readobj --coff-imports out-arm64.dll | FileCheck --check-prefix=NATIVE %s
+NATIVE: Import {
+NATIVE-NEXT: Name: import.dll
+NATIVE-NEXT: ImportLookupTableRVA:
+NATIVE-NEXT: ImportAddressTableRVA:
+NATIVE-NEXT: Symbol: native_data (0)
+NATIVE-NEXT: }
+
+RUN: lld-link -machine:arm64ec -dll -noentry -out:out-arm64ec.dll ref-ec.obj import.dll \
+RUN: loadconfig-arm64ec.obj -lldmingw -exclude-all-symbols -auto-import:no
+
+RUN: llvm-readobj --coff-imports out-arm64ec.dll | FileCheck --check-prefix=EC %s
+EC: Import {
+EC-NEXT: Name: import.dll
+EC-NEXT: ImportLookupTableRVA:
+EC-NEXT: ImportAddressTableRVA:
+EC-NEXT: Symbol: ec_data (0)
+EC-NEXT: }
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-arm64x.dll ref-ec.obj ref-native.obj import.dll \
+RUN: loadconfig-arm64ec.obj loadconfig-arm64.obj -lldmingw -exclude-all-symbols -auto-import:no
+
+RUN: llvm-readobj --coff-imports out-arm64x.dll | FileCheck --check-prefix=ARM64X %s
+ARM64X: Import {
+ARM64X-NEXT: Name: import.dll
+ARM64X-NEXT: ImportLookupTableRVA:
+ARM64X-NEXT: ImportAddressTableRVA:
+ARM64X-NEXT: Symbol: native_data (0)
+ARM64X-NEXT: }
+ARM64X-NEXT: HybridObject {
+ARM64X-NEXT: Format: COFF-ARM64EC
+ARM64X-NEXT: Arch: aarch64
+ARM64X-NEXT: AddressSize: 64bit
+ARM64X-NEXT: Import {
+ARM64X-NEXT: Name: import.dll
+ARM64X-NEXT: ImportLookupTableRVA:
+ARM64X-NEXT: ImportAddressTableRVA:
+ARM64X-NEXT: Symbol: ec_data (0)
+ARM64X-NEXT: }
+ARM64X-NEXT: }
+
+#--- sym-ec.s
+ .data
+ .globl ec_data
+ec_data:
+ .word 0
+
+ .section .drectve, "yn"
+ .ascii " -export:ec_data"
+
+#--- sym-native.s
+ .data
+ .globl native_data
+native_data:
+ .word 0
+
+ .section .drectve, "yn"
+ .ascii " -export:native_data"
+
+#--- ref-ec.s
+ .data
+ .rva __imp_ec_data
+
+#--- ref-native.s
+ .data
+ .rva __imp_native_data
More information about the llvm-commits
mailing list