[lld] [LLD][COFF] Add support for importing ARM64X images (PR #210080)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 08:46:31 PDT 2026


https://github.com/cjacek updated https://github.com/llvm/llvm-project/pull/210080

>From c94b90b01bf6a52915a5a9dcffba8b272a0d3b0b Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Thu, 16 Jul 2026 17:11:08 +0200
Subject: [PATCH] [LLD][COFF] Add support for importing ARM64X images

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.
---
 lld/COFF/Driver.cpp             | 16 ++++++-
 lld/COFF/InputFiles.cpp         |  8 ++--
 lld/COFF/InputFiles.h           |  4 +-
 lld/test/COFF/link-dll-arm64x.s | 81 +++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+), 6 deletions(-)
 create mode 100644 lld/test/COFF/link-dll-arm64x.s

diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index dc4903a5fe126..23ea24e621057 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.release()));
+          addFile(make<DLLFile>(*ctx.hybridSymtab, obj.release()));
+          break;
+        }
+      }
+      auto machine = static_cast<MachineTypes>(obj->getMachine());
+      addFile(make<DLLFile>(ctx.getSymtab(machine), obj.release()));
       break;
     }
     if (filename.ends_with_insensitive(".dll")) {
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 757a0f7be9b36..6db9da2f5fab5 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -1564,8 +1564,10 @@ void DLLFile::parse() {
 }
 
 MachineTypes DLLFile::getMachineType() const {
-  if (coffObj)
-    return static_cast<MachineTypes>(coffObj->getMachine());
+  if (coffObj) {
+    auto machine = static_cast<MachineTypes>(coffObj->getMachine());
+    return machine == ARM64X ? ARM64 : machine;
+  }
   return IMAGE_FILE_MACHINE_UNKNOWN;
 }
 
@@ -1581,7 +1583,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..7c88b7cec3bd8 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -424,8 +424,8 @@ 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, COFFObjectFile *coffObj)
+      : InputFile(symtab, DLLKind, coffObj->getMemoryBufferRef()) {}
   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