[lld] [LLD][COFF] Add support for delay-load imports on ARM64X (PR #124600)
Jacek Caban via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 27 09:54:09 PST 2025
https://github.com/cjacek created https://github.com/llvm/llvm-project/pull/124600
For each imported module, emit null-terminated native import entries, followed by null-terminated EC entries. If a view lacks imports for a given module, only terminators are emitted. Use ARM64X relocations to skip native entries in the EC view.
Move `delayLoadHelper` and `tailMergeUnwindInfoChunk` to `SymbolTable` since they are different for each symbol table.
>From 5d0ca886b96294605db2a8a89ee859a0392040e6 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Tue, 21 Jan 2025 19:51:38 +0100
Subject: [PATCH] [LLD][COFF] Add support for delay-load imports on ARM64X
For each imported module, emit null-terminated native import entries, followed by
null-terminated EC entries. If a view lacks imports for a given module,
only terminators are emitted. Use ARM64X relocations to skip native entries in
the EC view.
Move delayLoadHelper and tailMergeUnwindInfoChunk to SymbolTable since they are
different for each symbol table.
---
lld/COFF/Config.h | 1 -
lld/COFF/DLL.cpp | 158 ++++++-----
lld/COFF/DLL.h | 8 +-
lld/COFF/Driver.cpp | 13 +-
lld/COFF/SymbolTable.h | 3 +
lld/COFF/Writer.cpp | 3 +-
lld/test/COFF/arm64x-delayimport.test | 363 ++++++++++++++++++++++++++
7 files changed, 470 insertions(+), 79 deletions(-)
create mode 100644 lld/test/COFF/arm64x-delayimport.test
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index cd280aa09964d7..0c7c4e91402f18 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -164,7 +164,6 @@ struct Configuration {
bool noimplib = false;
std::set<std::string> delayLoads;
std::map<std::string, int> dllOrder;
- Symbol *delayLoadHelper = nullptr;
Symbol *arm64ECIcallHelper = nullptr;
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index b6fbd5a484b5e7..198b6e1cddd1ee 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -911,12 +911,9 @@ uint64_t DelayLoadContents::getDirSize() {
return dirs.size() * sizeof(delay_import_directory_table_entry);
}
-void DelayLoadContents::create(Defined *h) {
- helper = h;
+void DelayLoadContents::create() {
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
- Chunk *unwind = newTailMergeUnwindInfoChunk();
-
// Create .didat contents for each DLL.
for (std::vector<DefinedImportData *> &syms : v) {
// Create the delay import table header.
@@ -924,54 +921,89 @@ void DelayLoadContents::create(Defined *h) {
auto *dir = make<DelayDirectoryChunk>(dllNames.back());
size_t base = addresses.size();
- Chunk *tm = newTailMergeChunk(dir);
- Chunk *pdataChunk = unwind ? newTailMergePDataChunk(tm, unwind) : nullptr;
- for (DefinedImportData *s : syms) {
- Chunk *t = newThunkChunk(s, tm);
- auto *a = make<DelayAddressChunk>(ctx, t);
- addresses.push_back(a);
- thunks.push_back(t);
- StringRef extName = s->getExternalName();
- if (extName.empty()) {
- names.push_back(make<OrdinalOnlyChunk>(ctx, s->getOrdinal()));
- } else {
- auto *c = make<HintNameChunk>(extName, 0);
- names.push_back(make<LookupChunk>(ctx, c));
- hintNames.push_back(c);
- // Add a synthetic symbol for this load thunk, using the "__imp___load"
- // prefix, in case this thunk needs to be added to the list of valid
- // call targets for Control Flow Guard.
- StringRef symName = saver().save("__imp___load_" + extName);
- s->loadThunkSym =
- cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (ctx.hybridSymtab && symtab.isEC()) {
+ // For hybrid images, emit null-terminated native import entries
+ // followed by null-terminated EC entries. If a view is missing imports
+ // for a given module, only terminators are emitted. Emit ARM64X
+ // relocations to skip native entries in the EC view.
+ ctx.dynamicRelocs->add(
+ IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA, 0,
+ Arm64XRelocVal(dir, offsetof(delay_import_directory_table_entry,
+ DelayImportAddressTable)),
+ (addresses.size() - base) * sizeof(uint64_t));
+ ctx.dynamicRelocs->add(
+ IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA, 0,
+ Arm64XRelocVal(dir, offsetof(delay_import_directory_table_entry,
+ DelayImportNameTable)),
+ (addresses.size() - base) * sizeof(uint64_t));
}
- if (s->file->impECSym) {
- auto chunk = make<AuxImportChunk>(s->file);
- auxIat.push_back(chunk);
- s->file->impECSym->setLocation(chunk);
+ Chunk *tm = nullptr;
- chunk = make<AuxImportChunk>(s->file);
- auxIatCopy.push_back(chunk);
- s->file->auxImpCopySym->setLocation(chunk);
+ for (DefinedImportData *s : syms) {
+ // Process only the symbols belonging to the current symtab.
+ if (symtab.isEC() != s->file->isEC())
+ continue;
+
+ if (!tm) {
+ tm = newTailMergeChunk(symtab, dir);
+ Chunk *pdataChunk = newTailMergePDataChunk(symtab, tm);
+ if (pdataChunk)
+ pdata.push_back(pdataChunk);
+ }
+
+ Chunk *t = newThunkChunk(s, tm);
+ auto *a = make<DelayAddressChunk>(ctx, t);
+ addresses.push_back(a);
+ s->setLocation(a);
+ thunks.push_back(t);
+ StringRef extName = s->getExternalName();
+ if (extName.empty()) {
+ names.push_back(make<OrdinalOnlyChunk>(ctx, s->getOrdinal()));
+ } else {
+ auto *c = make<HintNameChunk>(extName, 0);
+ names.push_back(make<LookupChunk>(ctx, c));
+ hintNames.push_back(c);
+ // Add a synthetic symbol for this load thunk, using the
+ // "__imp___load" prefix, in case this thunk needs to be added to the
+ // list of valid call targets for Control Flow Guard.
+ StringRef symName = saver().save("__imp___load_" + extName);
+ s->loadThunkSym =
+ cast<DefinedSynthetic>(symtab.addSynthetic(symName, t));
+ }
+
+ if (symtab.isEC()) {
+ auto chunk = make<AuxImportChunk>(s->file);
+ auxIat.push_back(chunk);
+ s->file->impECSym->setLocation(chunk);
+
+ chunk = make<AuxImportChunk>(s->file);
+ auxIatCopy.push_back(chunk);
+ s->file->auxImpCopySym->setLocation(chunk);
+ } else if (ctx.hybridSymtab) {
+ // Fill the auxiliary IAT with null chunks for native imports.
+ auxIat.push_back(make<NullChunk>(ctx));
+ auxIatCopy.push_back(make<NullChunk>(ctx));
+ }
}
- }
- thunks.push_back(tm);
- if (pdataChunk)
- pdata.push_back(pdataChunk);
- StringRef tmName =
- saver().save("__tailMerge_" + syms[0]->getDLLName().lower());
- ctx.symtab.addSynthetic(tmName, tm);
- // Terminate with null values.
- addresses.push_back(make<NullChunk>(ctx, 8));
- names.push_back(make<NullChunk>(ctx, 8));
- if (ctx.config.machine == ARM64EC) {
- auxIat.push_back(make<NullChunk>(ctx, 8));
- auxIatCopy.push_back(make<NullChunk>(ctx, 8));
- }
- for (int i = 0, e = syms.size(); i < e; ++i)
- syms[i]->setLocation(addresses[base + i]);
+ if (tm) {
+ thunks.push_back(tm);
+ StringRef tmName =
+ saver().save("__tailMerge_" + syms[0]->getDLLName().lower());
+ symtab.addSynthetic(tmName, tm);
+ }
+
+ // Terminate with null values.
+ addresses.push_back(make<NullChunk>(ctx, 8));
+ names.push_back(make<NullChunk>(ctx, 8));
+ if (ctx.symtabEC) {
+ auxIat.push_back(make<NullChunk>(ctx, 8));
+ auxIatCopy.push_back(make<NullChunk>(ctx, 8));
+ }
+ });
+
auto *mh = make<NullChunk>(8, 8);
moduleHandles.push_back(mh);
@@ -982,15 +1014,18 @@ void DelayLoadContents::create(Defined *h) {
dirs.push_back(dir);
}
- if (unwind)
- unwindinfo.push_back(unwind);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.tailMergeUnwindInfoChunk)
+ unwindinfo.push_back(symtab.tailMergeUnwindInfoChunk);
+ });
// Add null terminator.
dirs.push_back(
make<NullChunk>(sizeof(delay_import_directory_table_entry), 4));
}
-Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
- switch (ctx.config.machine) {
+Chunk *DelayLoadContents::newTailMergeChunk(SymbolTable &symtab, Chunk *dir) {
+ auto helper = cast<Defined>(symtab.delayLoadHelper);
+ switch (symtab.machine) {
case AMD64:
case ARM64EC:
return make<TailMergeChunkX64>(dir, helper);
@@ -1005,21 +1040,14 @@ Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
}
}
-Chunk *DelayLoadContents::newTailMergeUnwindInfoChunk() {
- switch (ctx.config.machine) {
- case AMD64:
- case ARM64EC:
- return make<TailMergeUnwindInfoX64>();
- // FIXME: Add support for other architectures.
- default:
- return nullptr; // Just don't generate unwind info.
- }
-}
-Chunk *DelayLoadContents::newTailMergePDataChunk(Chunk *tm, Chunk *unwind) {
- switch (ctx.config.machine) {
+Chunk *DelayLoadContents::newTailMergePDataChunk(SymbolTable &symtab,
+ Chunk *tm) {
+ switch (symtab.machine) {
case AMD64:
case ARM64EC:
- return make<TailMergePDataChunkX64>(tm, unwind);
+ if (!symtab.tailMergeUnwindInfoChunk)
+ symtab.tailMergeUnwindInfoChunk = make<TailMergeUnwindInfoX64>();
+ return make<TailMergePDataChunkX64>(tm, symtab.tailMergeUnwindInfoChunk);
// FIXME: Add support for other architectures.
default:
return nullptr; // Just don't generate unwind info.
@@ -1028,7 +1056,7 @@ Chunk *DelayLoadContents::newTailMergePDataChunk(Chunk *tm, Chunk *unwind) {
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s,
Chunk *tailMerge) {
- switch (ctx.config.machine) {
+ switch (s->file->getMachineType()) {
case AMD64:
case ARM64EC:
return make<ThunkChunkX64>(s, tailMerge);
diff --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h
index 724a323d62d205..5105b79f15d31a 100644
--- a/lld/COFF/DLL.h
+++ b/lld/COFF/DLL.h
@@ -42,7 +42,7 @@ class DelayLoadContents {
DelayLoadContents(COFFLinkerContext &ctx) : ctx(ctx) {}
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
- void create(Defined *helper);
+ void create();
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
ArrayRef<Chunk *> getCodeChunks() { return thunks; }
@@ -56,11 +56,9 @@ class DelayLoadContents {
private:
Chunk *newThunkChunk(DefinedImportData *s, Chunk *tailMerge);
- Chunk *newTailMergeChunk(Chunk *dir);
- Chunk *newTailMergePDataChunk(Chunk *tm, Chunk *unwind);
- Chunk *newTailMergeUnwindInfoChunk();
+ Chunk *newTailMergeChunk(SymbolTable &symtab, Chunk *dir);
+ Chunk *newTailMergePDataChunk(SymbolTable &symtab, Chunk *tm);
- Defined *helper;
std::vector<DefinedImportData *> imports;
std::vector<Chunk *> dirs;
std::vector<Chunk *> moduleHandles;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 6eea11f5f451fd..ac3ac57bd17f44 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2353,12 +2353,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
llvm::TimeTraceScope timeScope("Delay load");
for (auto *arg : args.filtered(OPT_delayload)) {
config->delayLoads.insert(StringRef(arg->getValue()).lower());
- if (config->machine == I386) {
- config->delayLoadHelper = ctx.symtab.addGCRoot("___delayLoadHelper2 at 8");
- } else {
- config->delayLoadHelper =
- ctx.symtab.addGCRoot("__delayLoadHelper2", true);
- }
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.machine == I386) {
+ symtab.delayLoadHelper = symtab.addGCRoot("___delayLoadHelper2 at 8");
+ } else {
+ symtab.delayLoadHelper = symtab.addGCRoot("__delayLoadHelper2", true);
+ }
+ });
}
}
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index c8d7251838842f..ff6e8487f07344 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -158,6 +158,9 @@ class SymbolTable {
Chunk *edataStart = nullptr;
Chunk *edataEnd = nullptr;
+ Symbol *delayLoadHelper = nullptr;
+ Chunk *tailMergeUnwindInfoChunk = nullptr;
+
void fixupExports();
void assignExportOrdinals();
void parseModuleDefs(StringRef path);
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index bef2ced9f2957d..2bdaeb58ab432d 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1307,8 +1307,7 @@ void Writer::appendImportThunks() {
}
if (!delayIdata.empty()) {
- Defined *helper = cast<Defined>(ctx.config.delayLoadHelper);
- delayIdata.create(helper);
+ delayIdata.create();
for (Chunk *c : delayIdata.getChunks())
didatSec->addChunk(c);
for (Chunk *c : delayIdata.getDataChunks())
diff --git a/lld/test/COFF/arm64x-delayimport.test b/lld/test/COFF/arm64x-delayimport.test
new file mode 100644
index 00000000000000..56923ef748d09d
--- /dev/null
+++ b/lld/test/COFF/arm64x-delayimport.test
@@ -0,0 +1,363 @@
+REQUIRES: aarch64, x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-arm64ec.s -o test-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows test-arm64.s -o test-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-helper.s -o arm64ec-helper.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-helper.s -o arm64-helper.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-lib -machine:arm64ec -def:test.def -out:test-arm64ec.lib
+RUN: llvm-lib -machine:arm64 -def:test.def -out:test-arm64.lib
+
+# Test delayed-load import from both native and EC code.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: arm64-helper.obj arm64ec-helper.obj test-arm64.obj test-arm64ec.obj test-arm64.lib test-arm64ec.lib -delayload:test.dll
+
+RUN: llvm-readobj --coff-imports out.dll | FileCheck --check-prefix=IMPORTS %s
+IMPORTS: DelayImport {
+IMPORTS-NEXT: Name: test.dll
+IMPORTS-NEXT: Attributes: 0x1
+IMPORTS-NEXT: ModuleHandle: 0x6080
+IMPORTS-NEXT: ImportAddressTable: 0x6088
+IMPORTS-NEXT: ImportNameTable: 0x4390
+IMPORTS-NEXT: BoundDelayImportTable: 0x0
+IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+IMPORTS-NEXT: Import {
+IMPORTS-NEXT: Symbol: func (0)
+IMPORTS-NEXT: Address: 0x180001014
+IMPORTS-NEXT: }
+IMPORTS-NEXT: }
+IMPORTS-NEXT: HybridObject {
+IMPORTS: DelayImport {
+IMPORTS-NEXT: Name: test.dll
+IMPORTS-NEXT: Attributes: 0x1
+IMPORTS-NEXT: ModuleHandle: 0x6080
+IMPORTS-NEXT: ImportAddressTable: 0x6098
+IMPORTS-NEXT: ImportNameTable: 0x43A0
+IMPORTS-NEXT: BoundDelayImportTable: 0x0
+IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+IMPORTS-NEXT: Import {
+IMPORTS-NEXT: Symbol: func (0)
+IMPORTS-NEXT: Address: 0x180003006
+IMPORTS-NEXT: }
+IMPORTS-NEXT: }
+IMPORTS-NEXT: }
+
+RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
+TESTSEC: 0x180009000 10500000 98600000 00300000 10200000
+
+RUN: llvm-readobj --hex-dump=.testa out.dll | FileCheck --check-prefix=TESTSECA %s
+TESTSECA: 0x18000a000 88600000 08100000
+
+RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
+DISASM: 0000000180001000 <.text>:
+DISASM-NEXT: 180001000: 52800060 mov w0, #0x3 // =3
+DISASM-NEXT: 180001004: d65f03c0 ret
+DISASM-NEXT: 180001008: b0000030 adrp x16, 0x180006000
+DISASM-NEXT: 18000100c: f9404610 ldr x16, [x16, #0x88]
+DISASM-NEXT: 180001010: d61f0200 br x16
+DISASM-NEXT: 180001014: b0000031 adrp x17, 0x180006000
+DISASM-NEXT: 180001018: 91022231 add x17, x17, #0x88
+DISASM-NEXT: 18000101c: 14000001 b 0x180001020 <.text+0x20>
+DISASM-NEXT: 180001020: a9b37bfd stp x29, x30, [sp, #-0xd0]!
+DISASM-NEXT: 180001024: 910003fd mov x29, sp
+DISASM-NEXT: 180001028: a90107e0 stp x0, x1, [sp, #0x10]
+DISASM-NEXT: 18000102c: a9020fe2 stp x2, x3, [sp, #0x20]
+DISASM-NEXT: 180001030: a90317e4 stp x4, x5, [sp, #0x30]
+DISASM-NEXT: 180001034: a9041fe6 stp x6, x7, [sp, #0x40]
+DISASM-NEXT: 180001038: ad0287e0 stp q0, q1, [sp, #0x50]
+DISASM-NEXT: 18000103c: ad038fe2 stp q2, q3, [sp, #0x70]
+DISASM-NEXT: 180001040: ad0497e4 stp q4, q5, [sp, #0x90]
+DISASM-NEXT: 180001044: ad059fe6 stp q6, q7, [sp, #0xb0]
+DISASM-NEXT: 180001048: aa1103e1 mov x1, x17
+DISASM-NEXT: 18000104c: f0000000 adrp x0, 0x180004000
+DISASM-NEXT: 180001050: 910d4000 add x0, x0, #0x350
+DISASM-NEXT: 180001054: 97ffffeb bl 0x180001000 <.text>
+DISASM-NEXT: 180001058: aa0003f0 mov x16, x0
+DISASM-NEXT: 18000105c: ad459fe6 ldp q6, q7, [sp, #0xb0]
+DISASM-NEXT: 180001060: ad4497e4 ldp q4, q5, [sp, #0x90]
+DISASM-NEXT: 180001064: ad438fe2 ldp q2, q3, [sp, #0x70]
+DISASM-NEXT: 180001068: ad4287e0 ldp q0, q1, [sp, #0x50]
+DISASM-NEXT: 18000106c: a9441fe6 ldp x6, x7, [sp, #0x40]
+DISASM-NEXT: 180001070: a94317e4 ldp x4, x5, [sp, #0x30]
+DISASM-NEXT: 180001074: a9420fe2 ldp x2, x3, [sp, #0x20]
+DISASM-NEXT: 180001078: a94107e0 ldp x0, x1, [sp, #0x10]
+DISASM-NEXT: 18000107c: a8cd7bfd ldp x29, x30, [sp], #0xd0
+DISASM-NEXT: 180001080: d61f0200 br x16
+DISASM-NEXT: ...
+DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+DISASM-NEXT: 180002004: d65f03c0 ret
+DISASM-NEXT: 180002008: 52800060 mov w0, #0x3 // =3
+DISASM-NEXT: 18000200c: d65f03c0 ret
+DISASM-NEXT: 180002010: f0000010 adrp x16, 0x180005000
+DISASM-NEXT: 180002014: f9400a10 ldr x16, [x16, #0x10]
+DISASM-NEXT: 180002018: d61f0200 br x16
+DISASM-NEXT: 18000201c: 9000002b adrp x11, 0x180006000
+DISASM-NEXT: 180002020: f9404d6b ldr x11, [x11, #0x98]
+DISASM-NEXT: 180002024: 9000000a adrp x10, 0x180002000 <.text+0x1000>
+DISASM-NEXT: 180002028: 9100c14a add x10, x10, #0x30
+DISASM-NEXT: 18000202c: 17fffff5 b 0x180002000 <.text+0x1000>
+DISASM-NEXT: 180002030: 52800080 mov w0, #0x4 // =4
+DISASM-NEXT: 180002034: d65f03c0 ret
+DISASM-NEXT: ...
+DISASM-NEXT: 180003000: ff 25 92 30 00 00 jmpq *0x3092(%rip) # 0x180006098
+DISASM-NEXT: 180003006: 48 8d 05 8b 30 00 00 leaq 0x308b(%rip), %rax # 0x180006098
+DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012>
+DISASM-NEXT: 180003012: 51 pushq %rcx
+DISASM-NEXT: 180003013: 52 pushq %rdx
+DISASM-NEXT: 180003014: 41 50 pushq %r8
+DISASM-NEXT: 180003016: 41 51 pushq %r9
+DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp
+DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp)
+DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
+DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
+DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
+DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx
+DISASM-NEXT: 180003036: 48 8d 0d 13 13 00 00 leaq 0x1313(%rip), %rcx # 0x180004350
+DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008>
+DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
+DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
+DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2
+DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3
+DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp
+DISASM-NEXT: 18000305d: 41 59 popq %r9
+DISASM-NEXT: 18000305f: 41 58 popq %r8
+DISASM-NEXT: 180003061: 5a popq %rdx
+DISASM-NEXT: 180003062: 59 popq %rcx
+DISASM-NEXT: 180003063: ff e0 jmpq *%rax
+
+RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s
+LOADCFG: AuxiliaryDelayloadIAT: 0x5000
+LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x4140
+
+RUN: llvm-readobj --hex-dump=.rdata out.dll | FileCheck --check-prefix=AUXIAT %s
+AUXIAT: 0x180005000 00000000 00000000 00000000 00000000
+AUXIAT-NEXT: 0x180005010 1c200080 01000000 00000000 00000000
+
+
+# Test delayed-load import from native code only.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-native.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: arm64-helper.obj arm64ec-helper.obj test-arm64.obj test-arm64.lib test-arm64ec.lib -delayload:test.dll
+
+RUN: llvm-readobj --coff-imports out-native.dll | FileCheck --check-prefix=NATIVE-IMPORTS %s
+NATIVE-IMPORTS: DelayImport {
+NATIVE-IMPORTS-NEXT: Name: test.dll
+NATIVE-IMPORTS-NEXT: Attributes: 0x1
+NATIVE-IMPORTS-NEXT: ModuleHandle: 0x5080
+NATIVE-IMPORTS-NEXT: ImportAddressTable: 0x5088
+NATIVE-IMPORTS-NEXT: ImportNameTable: 0x3370
+NATIVE-IMPORTS-NEXT: BoundDelayImportTable: 0x0
+NATIVE-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+NATIVE-IMPORTS-NEXT: Import {
+NATIVE-IMPORTS-NEXT: Symbol: func (0)
+NATIVE-IMPORTS-NEXT: Address: 0x180001014
+NATIVE-IMPORTS-NEXT: }
+NATIVE-IMPORTS-NEXT: }
+NATIVE-IMPORTS-NEXT: HybridObject {
+NATIVE-IMPORTS-NEXT: Format: COFF-ARM64EC
+NATIVE-IMPORTS-NEXT: Arch: aarch64
+NATIVE-IMPORTS-NEXT: AddressSize: 64bit
+NATIVE-IMPORTS-NEXT: DelayImport {
+NATIVE-IMPORTS-NEXT: Name: test.dll
+NATIVE-IMPORTS-NEXT: Attributes: 0x1
+NATIVE-IMPORTS-NEXT: ModuleHandle: 0x5080
+NATIVE-IMPORTS-NEXT: ImportAddressTable: 0x5098
+NATIVE-IMPORTS-NEXT: ImportNameTable: 0x3380
+NATIVE-IMPORTS-NEXT: BoundDelayImportTable: 0x0
+NATIVE-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+NATIVE-IMPORTS-NEXT: }
+NATIVE-IMPORTS-NEXT: }
+
+RUN: llvm-readobj --hex-dump=.testa out-native.dll | FileCheck --check-prefix=NATIVE-TESTSECA %s
+NATIVE-TESTSECA: 0x180007000 88500000 08100000
+
+RUN: llvm-objdump -d out-native.dll | FileCheck --check-prefix=NATIVE-DISASM %s
+NATIVE-DISASM: 0000000180001000 <.text>:
+NATIVE-DISASM-NEXT: 180001000: 52800060 mov w0, #0x3 // =3
+NATIVE-DISASM-NEXT: 180001004: d65f03c0 ret
+NATIVE-DISASM-NEXT: 180001008: 90000030 adrp x16, 0x180005000
+NATIVE-DISASM-NEXT: 18000100c: f9404610 ldr x16, [x16, #0x88]
+NATIVE-DISASM-NEXT: 180001010: d61f0200 br x16
+NATIVE-DISASM-NEXT: 180001014: 90000031 adrp x17, 0x180005000
+NATIVE-DISASM-NEXT: 180001018: 91022231 add x17, x17, #0x88
+NATIVE-DISASM-NEXT: 18000101c: 14000001 b 0x180001020 <.text+0x20>
+NATIVE-DISASM-NEXT: 180001020: a9b37bfd stp x29, x30, [sp, #-0xd0]!
+NATIVE-DISASM-NEXT: 180001024: 910003fd mov x29, sp
+NATIVE-DISASM-NEXT: 180001028: a90107e0 stp x0, x1, [sp, #0x10]
+NATIVE-DISASM-NEXT: 18000102c: a9020fe2 stp x2, x3, [sp, #0x20]
+NATIVE-DISASM-NEXT: 180001030: a90317e4 stp x4, x5, [sp, #0x30]
+NATIVE-DISASM-NEXT: 180001034: a9041fe6 stp x6, x7, [sp, #0x40]
+NATIVE-DISASM-NEXT: 180001038: ad0287e0 stp q0, q1, [sp, #0x50]
+NATIVE-DISASM-NEXT: 18000103c: ad038fe2 stp q2, q3, [sp, #0x70]
+NATIVE-DISASM-NEXT: 180001040: ad0497e4 stp q4, q5, [sp, #0x90]
+NATIVE-DISASM-NEXT: 180001044: ad059fe6 stp q6, q7, [sp, #0xb0]
+NATIVE-DISASM-NEXT: 180001048: aa1103e1 mov x1, x17
+NATIVE-DISASM-NEXT: 18000104c: d0000000 adrp x0, 0x180003000
+NATIVE-DISASM-NEXT: 180001050: 910cc000 add x0, x0, #0x330
+NATIVE-DISASM-NEXT: 180001054: 97ffffeb bl 0x180001000 <.text>
+NATIVE-DISASM-NEXT: 180001058: aa0003f0 mov x16, x0
+NATIVE-DISASM-NEXT: 18000105c: ad459fe6 ldp q6, q7, [sp, #0xb0]
+NATIVE-DISASM-NEXT: 180001060: ad4497e4 ldp q4, q5, [sp, #0x90]
+NATIVE-DISASM-NEXT: 180001064: ad438fe2 ldp q2, q3, [sp, #0x70]
+NATIVE-DISASM-NEXT: 180001068: ad4287e0 ldp q0, q1, [sp, #0x50]
+NATIVE-DISASM-NEXT: 18000106c: a9441fe6 ldp x6, x7, [sp, #0x40]
+NATIVE-DISASM-NEXT: 180001070: a94317e4 ldp x4, x5, [sp, #0x30]
+NATIVE-DISASM-NEXT: 180001074: a9420fe2 ldp x2, x3, [sp, #0x20]
+NATIVE-DISASM-NEXT: 180001078: a94107e0 ldp x0, x1, [sp, #0x10]
+NATIVE-DISASM-NEXT: 18000107c: a8cd7bfd ldp x29, x30, [sp], #0xd0
+NATIVE-DISASM-NEXT: 180001080: d61f0200 br x16
+
+RUN: llvm-readobj --coff-load-config out-native.dll | FileCheck --check-prefix=NATIVE-LOADCFG %s
+NATIVE-LOADCFG: AuxiliaryDelayloadIAT: 0x4000
+NATIVE-LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x3140
+
+RUN: llvm-readobj --hex-dump=.rdata out-native.dll | FileCheck --check-prefix=NATIVE-AUXIAT %s
+NATIVE-AUXIAT: 0x180004000 00000000 00000000 00000000 00000000
+NATIVE-AUXIAT-NEXT: 0x180004010 00000000 00000000
+
+
+# Test delayed-load import from EC code only.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-ec.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: arm64-helper.obj arm64ec-helper.obj test-arm64ec.obj test-arm64.lib test-arm64ec.lib -delayload:test.dll
+
+RUN: llvm-readobj --coff-imports out-ec.dll | FileCheck --check-prefix=EC-IMPORTS %s
+EC-IMPORTS: DelayImport {
+EC-IMPORTS-NEXT: Name: test.dll
+EC-IMPORTS-NEXT: Attributes: 0x1
+EC-IMPORTS-NEXT: ModuleHandle: 0x6080
+EC-IMPORTS-NEXT: ImportAddressTable: 0x6088
+EC-IMPORTS-NEXT: ImportNameTable: 0x4388
+EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0
+EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+EC-IMPORTS-NEXT: }
+EC-IMPORTS-NEXT: HybridObject {
+EC-IMPORTS-NEXT: Format: COFF-ARM64EC
+EC-IMPORTS-NEXT: Arch: aarch64
+EC-IMPORTS-NEXT: AddressSize: 64bit
+EC-IMPORTS-NEXT: DelayImport {
+EC-IMPORTS-NEXT: Name: test.dll
+EC-IMPORTS-NEXT: Attributes: 0x1
+EC-IMPORTS-NEXT: ModuleHandle: 0x6080
+EC-IMPORTS-NEXT: ImportAddressTable: 0x6090
+EC-IMPORTS-NEXT: ImportNameTable: 0x4390
+EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0
+EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
+EC-IMPORTS-NEXT: Import {
+EC-IMPORTS-NEXT: Symbol: func (0)
+EC-IMPORTS-NEXT: Address: 0x180003006
+EC-IMPORTS-NEXT: }
+EC-IMPORTS-NEXT: }
+EC-IMPORTS-NEXT: }
+
+RUN: llvm-readobj --hex-dump=.test out-ec.dll | FileCheck --check-prefix=EC-TESTSEC %s
+EC-TESTSEC: 0x180009000 08500000 90600000 00300000 10200000
+
+RUN: llvm-objdump -d out-ec.dll | FileCheck --check-prefix=EC-DISASM %s
+EC-DISASM: 0000000180001000 <.text>:
+EC-DISASM-NEXT: 180001000: 52800060 mov w0, #0x3 // =3
+EC-DISASM-NEXT: 180001004: d65f03c0 ret
+EC-DISASM-NEXT: ...
+EC-DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+EC-DISASM-NEXT: 180002004: d65f03c0 ret
+EC-DISASM-NEXT: 180002008: 52800060 mov w0, #0x3 // =3
+EC-DISASM-NEXT: 18000200c: d65f03c0 ret
+EC-DISASM-NEXT: 180002010: f0000010 adrp x16, 0x180005000
+EC-DISASM-NEXT: 180002014: f9400610 ldr x16, [x16, #0x8]
+EC-DISASM-NEXT: 180002018: d61f0200 br x16
+EC-DISASM-NEXT: 18000201c: 9000002b adrp x11, 0x180006000
+EC-DISASM-NEXT: 180002020: f940496b ldr x11, [x11, #0x90]
+EC-DISASM-NEXT: 180002024: 9000000a adrp x10, 0x180002000 <.text+0x1000>
+EC-DISASM-NEXT: 180002028: 9100c14a add x10, x10, #0x30
+EC-DISASM-NEXT: 18000202c: 17fffff5 b 0x180002000 <.text+0x1000>
+EC-DISASM-NEXT: 180002030: 52800080 mov w0, #0x4 // =4
+EC-DISASM-NEXT: 180002034: d65f03c0 ret
+EC-DISASM-NEXT: ...
+EC-DISASM-NEXT: 180003000: ff 25 8a 30 00 00 jmpq *0x308a(%rip) # 0x180006090
+EC-DISASM-NEXT: 180003006: 48 8d 05 83 30 00 00 leaq 0x3083(%rip), %rax # 0x180006090
+EC-DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012>
+EC-DISASM-NEXT: 180003012: 51 pushq %rcx
+EC-DISASM-NEXT: 180003013: 52 pushq %rdx
+EC-DISASM-NEXT: 180003014: 41 50 pushq %r8
+EC-DISASM-NEXT: 180003016: 41 51 pushq %r9
+EC-DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp
+EC-DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp)
+EC-DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
+EC-DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
+EC-DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
+EC-DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx
+EC-DISASM-NEXT: 180003036: 48 8d 0d 0b 13 00 00 leaq 0x130b(%rip), %rcx # 0x180004348
+EC-DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008>
+EC-DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
+EC-DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
+EC-DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2
+EC-DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3
+EC-DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp
+EC-DISASM-NEXT: 18000305d: 41 59 popq %r9
+EC-DISASM-NEXT: 18000305f: 41 58 popq %r8
+EC-DISASM-NEXT: 180003061: 5a popq %rdx
+EC-DISASM-NEXT: 180003062: 59 popq %rcx
+EC-DISASM-NEXT: 180003063: ff e0 jmpq *%rax
+
+RUN: llvm-readobj --coff-load-config out-ec.dll | FileCheck --check-prefix=EC-LOADCFG %s
+EC-LOADCFG: AuxiliaryDelayloadIAT: 0x5000
+EC-LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x4140
+
+RUN: llvm-readobj --hex-dump=.rdata out-ec.dll | FileCheck --check-prefix=EC-AUXIAT %s
+EC-AUXIAT: 0x180005000 00000000 00000000 1c200080 01000000
+EC-AUXIAT-NEXT: 0x180005010 00000000 00000000
+
+
+#--- test-arm64ec.s
+ .section .test, "rd"
+ .rva __imp_func
+ .rva __imp_aux_func
+ .rva func
+ .rva "#func"
+
+#--- test-arm64.s
+ .section .testa, "rd"
+ .rva __imp_func
+ .rva func
+
+#--- arm64ec-helper.s
+ .section .text,"xr",discard,__icall_helper_arm64ec
+ .globl __icall_helper_arm64ec
+ .p2align 2, 0x0
+__icall_helper_arm64ec:
+ mov w0, #2
+ ret
+
+ .section .text,"xr",discard,"#__delayLoadHelper2"
+ .globl "#__delayLoadHelper2"
+ .p2align 2, 0x0
+"#__delayLoadHelper2":
+ mov w0, #3
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx __imp_func
+ .symidx func_exit_thunk
+ .word 4
+
+ .section .wowthk$aa,"xr",discard,func_exit_thunk
+ .globl func_exit_thunk
+func_exit_thunk:
+ mov w0, #4
+ ret
+
+#--- arm64-helper.s
+ .section .text,"xr",discard,__delayLoadHelper2
+ .globl __delayLoadHelper2
+ .p2align 2, 0x0
+__delayLoadHelper2:
+ mov w0, #3
+ ret
+
+#--- test.def
+NAME test.dll
+EXPORTS
+ func
More information about the llvm-commits
mailing list