[lld] [LLD][COFF] Add support for multi-arch ARM64X object files (PR #207868)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 7 12:08:49 PDT 2026


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

>From ea47ed4f3ef28cf01d4edf366a41472b40cc2933 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Mon, 8 Jun 2026 18:02:40 +0200
Subject: [PATCH] [LLD][COFF] Add support for multi-arch ARM64X object files

---
 lld/COFF/Driver.cpp              | 12 ++++
 lld/test/COFF/arm64x-hybridobj.s | 98 ++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 lld/test/COFF/arm64x-hybridobj.s

diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 38dad4ef71050..dc4903a5fe126 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -269,6 +269,18 @@ InputFile *LinkerDriver::addObjectFile(COFFLinkerContext &ctx,
   std::unique_ptr<COFFObjectFile> coffObj = ObjFile::createCOFFObject(ctx, mb);
   InputFile *obj = nullptr;
 
+  // On ARM64EC, check for a hybrid object section and use it for the EC object.
+  if (ctx.symtab.isEC()) {
+    if (std::optional<MemoryBufferRef> hybridSec =
+            coffObj->findHybridObjectSection()) {
+      InputFile *hybridObj =
+          addObjectFile(ctx, *hybridSec, archiveName, offsetInArchive, lazy);
+      // For the ARM64X target, continue processing the native file.
+      if (ctx.config.machine != ARM64X)
+        return hybridObj;
+    }
+  }
+
   if (ctx.config.fatLTOObjects) {
     Expected<MemoryBufferRef> fatLTOData =
         IRObjectFile::findBitcodeInObject(*coffObj);
diff --git a/lld/test/COFF/arm64x-hybridobj.s b/lld/test/COFF/arm64x-hybridobj.s
new file mode 100644
index 0000000000000..4eef518a9d055
--- /dev/null
+++ b/lld/test/COFF/arm64x-hybridobj.s
@@ -0,0 +1,98 @@
+// REQUIRES: aarch64
+// RUN: split-file %s %t.dir && cd %t.dir
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows sym.s -o sym-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows sym.s -o sym-arm64ec.obj
+// RUN: llvm-objcopy --add-section=.obj.arm64ec=sym-arm64ec.obj --set-section-flags=.obj.arm64ec=exclude \
+// RUN:              sym-arm64.obj sym.obj
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows ref.s -o ref-arm64.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref.s -o ref-arm64ec.obj
+// RUN: llvm-objcopy --add-section=.obj.arm64ec=ref-arm64ec.obj --set-section-flags=.obj.arm64ec=exclude \
+// RUN:              ref-arm64.obj ref.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: llvm-objcopy --add-section=.obj.arm64ec=loadconfig-arm64ec.obj --set-section-flags=.obj.arm64ec=exclude \
+// RUN:              loadconfig-arm64.obj loadconfig.obj
+
+// Test linking hybrid object files, verify that both native and EC exports are present.
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out.dll sym.obj loadconfig.obj
+// RUN: llvm-readobj --coff-exports out.dll | FileCheck %s
+
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-ec.dll sym.obj loadconfig.obj
+// RUN: llvm-readobj --coff-exports out-ec.dll | FileCheck --check-prefix=ARM64EC %s
+// RUN: lld-link -machine:arm64 -dll -noentry -out:out-native.dll sym.obj loadconfig.obj
+// RUN: llvm-readobj --coff-exports out-native.dll | FileCheck --check-prefix=NATIVE %s
+
+// Test linking symbols from an archive.
+// RUN: llvm-ar cr sym.lib sym.obj
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out2.dll ref.obj sym.lib loadconfig.obj
+// RUN: llvm-readobj --coff-exports out2.dll | FileCheck %s
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-ec2.dll sym.obj loadconfig.obj
+// RUN: llvm-readobj --coff-exports out-ec2.dll | FileCheck --check-prefix=ARM64EC %s
+// RUN: lld-link -machine:arm64 -dll -noentry -out:out-native2.dll sym.obj loadconfig.obj
+// RUN: llvm-readobj --coff-exports out-native2.dll | FileCheck --check-prefix=NATIVE %s
+
+// Test linking symbols from a thin archive.
+// RUN: llvm-ar cr --thin sym-thin.lib sym.obj
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out3.dll ref.obj sym-thin.lib loadconfig.obj
+// RUN: llvm-readobj --coff-exports out3.dll | FileCheck %s
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out4.dll -wholearchive:sym-thin.lib loadconfig.obj
+// RUN: llvm-readobj --coff-exports out4.dll | FileCheck %s
+
+// Test -start-lib/-end-lib with hybrid object files.
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out5.dll ref.obj -start-lib sym.obj loadconfig.obj -end-lib
+// RUN: llvm-readobj --coff-exports out5.dll | FileCheck %s
+
+// CHECK:      Format: COFF-ARM64X
+// CHECK-NEXT: Arch: aarch64
+// CHECK-NEXT: AddressSize: 64bit
+// CHECK-NEXT: Export {
+// CHECK-NEXT:   Ordinal: 1
+// CHECK-NEXT:   Name: sym
+// CHECK-NEXT:   RVA: 0x4004
+// CHECK-NEXT: }
+// CHECK-NEXT: HybridObject {
+// CHECK-NEXT:   Format: COFF-ARM64EC
+// CHECK-NEXT:   Arch: aarch64
+// CHECK-NEXT:   AddressSize: 64bit
+// CHECK-NEXT:   Export {
+// CHECK-NEXT:     Ordinal: 1
+// CHECK-NEXT:     Name: sym
+// CHECK-NEXT:     RVA: 0x4000
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+// ARM64EC:      Format: COFF-ARM64EC
+// ARM64EC-NEXT: Arch: aarch64
+// ARM64EC-NEXT: AddressSize: 64bit
+// ARM64EC-NEXT: Export {
+// ARM64EC-NEXT:   Ordinal: 1
+// ARM64EC-NEXT:   Name: sym
+// ARM64EC-NEXT:   RVA: 0x4000
+// ARM64EC-NEXT: }
+// ARM64EC-NOT:  HybridObject
+
+// NATIVE:      Format: COFF-ARM64
+// NATIVE-NEXT: Arch: aarch64
+// NATIVE-NEXT: AddressSize: 64bit
+// NATIVE-NEXT: Export {
+// NATIVE-NEXT:   Ordinal: 1
+// NATIVE-NEXT:   Name: sym
+// NATIVE-NEXT:   RVA: 0x2000
+// NATIVE-NEXT: }
+// NATIVE-NOT:  HybridObject
+
+#--- sym.s
+        .section .sym,"dr"
+        .globl sym
+sym:
+        .long 0
+
+        .section .drectve
+        .ascii "-export:sym"
+
+#--- ref.s
+        .data
+        .rva sym



More information about the llvm-commits mailing list