[lld] [LLD][COFF] Implement support for hybrid IAT on ARM64X (PR #124189)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 23 12:55:29 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Jacek Caban (cjacek)
<details>
<summary>Changes</summary>
In hybrid images, the PE header references a single IAT for both native and EC views, merging entries where possible. When merging isn't feasible, different imports are grouped together, and ARM64X relocations are emitted as needed.
---
Patch is 29.68 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/124189.diff
5 Files Affected:
- (modified) lld/COFF/Chunks.cpp (+23-4)
- (modified) lld/COFF/DLL.cpp (+114-11)
- (modified) lld/COFF/InputFiles.cpp (+10-4)
- (modified) lld/COFF/InputFiles.h (+5-1)
- (added) lld/test/COFF/arm64x-import.test (+487)
``````````diff
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 11e7cf4346b236..a01c69c709876b 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1172,11 +1172,12 @@ uint64_t Arm64XRelocVal::get() const {
size_t Arm64XDynamicRelocEntry::getSize() const {
switch (type) {
+ case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
+ return sizeof(uint16_t); // Just a header.
case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:
return sizeof(uint16_t) + size; // A header and a payload.
case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:
- case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
- llvm_unreachable("unsupported type");
+ return 2 * sizeof(uint16_t); // A header and a delta.
}
llvm_unreachable("invalid type");
}
@@ -1186,6 +1187,9 @@ void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const {
*out = (offset.get() & 0xfff) | (type << 12);
switch (type) {
+ case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
+ *out |= ((bit_width(size) - 1) << 14); // Encode the size.
+ break;
case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:
*out |= ((bit_width(size) - 1) << 14); // Encode the size.
switch (size) {
@@ -1203,8 +1207,23 @@ void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const {
}
break;
case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:
- case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
- llvm_unreachable("unsupported type");
+ int delta = value.get();
+ // Negative offsets use a sign bit in the header.
+ if (delta < 0) {
+ *out |= 1 << 14;
+ delta = -delta;
+ }
+ // Depending on the value, the delta is encoded with a shift of 2 or 3 bits.
+ if (delta & 7) {
+ assert(!(delta & 3));
+ delta >>= 2;
+ } else {
+ *out |= (1 << 15);
+ delta >>= 3;
+ }
+ out[1] = delta;
+ assert(!(delta & ~0xffff));
+ break;
}
}
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 6a3f8eb21e8475..98d7760a6b663b 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -717,6 +717,46 @@ class ExportOrdinalChunk : public NonSectionChunk {
void IdataContents::create(COFFLinkerContext &ctx) {
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
+ // Merge compatible EC and native import files in hybrid images.
+ if (ctx.hybridSymtab) {
+ for (std::vector<DefinedImportData *> &syms : v) {
+ // At this point, symbols are sorted by base name, ensuring that
+ // compatible import files, if present, are adjacent.
+ std::vector<DefinedImportData *> hybridSyms;
+ ImportFile *prev = nullptr;
+ for (DefinedImportData *sym : syms) {
+ ImportFile *file = sym->file;
+ if (!prev || file->isEC() == prev->isEC() ||
+ !file->isSameImport(prev)) {
+ hybridSyms.push_back(sym);
+ prev = file;
+ continue;
+ }
+
+ // The native variant exposes a subset of EC symbols and chunks. Use the
+ // EC variant to represent both.
+ if (file->isEC()) {
+ hybridSyms.pop_back();
+ hybridSyms.push_back(sym);
+ }
+
+ prev->hybridFile = file;
+ file->hybridFile = prev;
+ prev = nullptr;
+ }
+
+ // Sort symbols by type: native-only files first, followed by merged
+ // hybrid files, and then EC-only files.
+ llvm::stable_sort(hybridSyms,
+ [](DefinedImportData *a, DefinedImportData *b) {
+ if (a->file->hybridFile)
+ return !b->file->hybridFile && b->file->isEC();
+ return !a->file->isEC() && b->file->isEC();
+ });
+ syms = std::move(hybridSyms);
+ }
+ }
+
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &syms : v) {
// Create lookup and address tables. If they have external names,
@@ -724,19 +764,52 @@ void IdataContents::create(COFFLinkerContext &ctx) {
// If they don't (if they are import-by-ordinals), we store only
// ordinal values to the table.
size_t base = lookups.size();
+ Chunk *lookupsTerminator = nullptr, *addressesTerminator = nullptr;
for (DefinedImportData *s : syms) {
uint16_t ord = s->getOrdinal();
+ HintNameChunk *hintChunk = nullptr;
+ Chunk *lookupsChunk, *addressesChunk;
+
if (s->getExternalName().empty()) {
- lookups.push_back(make<OrdinalOnlyChunk>(ctx, ord));
- addresses.push_back(make<OrdinalOnlyChunk>(ctx, ord));
+ lookupsChunk = make<OrdinalOnlyChunk>(ctx, ord);
+ addressesChunk = make<OrdinalOnlyChunk>(ctx, ord);
} else {
- auto *c = make<HintNameChunk>(s->getExternalName(), ord);
- lookups.push_back(make<LookupChunk>(ctx, c));
- addresses.push_back(make<LookupChunk>(ctx, c));
- hints.push_back(c);
+ hintChunk = make<HintNameChunk>(s->getExternalName(), ord);
+ lookupsChunk = make<LookupChunk>(ctx, hintChunk);
+ addressesChunk = make<LookupChunk>(ctx, hintChunk);
+ hints.push_back(hintChunk);
}
- if (s->file->impECSym) {
+ // Detect the first EC-only import in the hybrid IAT. Emit null chunks
+ // and add an ARM64X relocation to replace it with the import for the EC
+ // view. Additionally, use the original chunks as import terminators
+ // and zero them with ARM64X relocations. Since these chunks appear
+ // after the null terminator in the native view, they are always ignored
+ // by the loader. However, MSVC emits them for some reason.
+ if (ctx.hybridSymtab && !lookupsTerminator && s->file->isEC() &&
+ !s->file->hybridFile) {
+ lookupsTerminator = lookupsChunk;
+ addressesTerminator = addressesChunk;
+ lookupsChunk = make<NullChunk>(ctx);
+ addressesChunk = make<NullChunk>(ctx);
+
+ Arm64XRelocVal relocVal = hintChunk;
+ if (!hintChunk)
+ relocVal = (1ULL << 63) | ord;
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE,
+ sizeof(uint64_t), lookupsChunk, relocVal);
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE,
+ sizeof(uint64_t), addressesChunk, relocVal);
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL,
+ sizeof(uint64_t), lookupsTerminator);
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL,
+ sizeof(uint64_t), addressesTerminator);
+ }
+
+ lookups.push_back(lookupsChunk);
+ addresses.push_back(addressesChunk);
+
+ if (s->file->isEC()) {
auto chunk = make<AuxImportChunk>(s->file);
auxIat.push_back(chunk);
s->file->impECSym->setLocation(chunk);
@@ -744,18 +817,27 @@ void IdataContents::create(COFFLinkerContext &ctx) {
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-only imports.
+ auxIat.push_back(make<NullChunk>(ctx));
+ auxIatCopy.push_back(make<NullChunk>(ctx));
}
}
// Terminate with null values.
- lookups.push_back(make<NullChunk>(ctx));
- addresses.push_back(make<NullChunk>(ctx));
- if (ctx.config.machine == ARM64EC) {
+ lookups.push_back(lookupsTerminator ? lookupsTerminator
+ : make<NullChunk>(ctx));
+ addresses.push_back(addressesTerminator ? addressesTerminator
+ : make<NullChunk>(ctx));
+ if (ctx.symtabEC) {
auxIat.push_back(make<NullChunk>(ctx));
auxIatCopy.push_back(make<NullChunk>(ctx));
}
- for (int i = 0, e = syms.size(); i < e; ++i)
+ for (int i = 0, e = syms.size(); i < e; ++i) {
syms[i]->setLocation(addresses[base + i]);
+ if (syms[i]->file->hybridFile)
+ syms[i]->file->hybridFile->impSym->setLocation(addresses[base + i]);
+ }
// Create the import table header.
dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
@@ -763,6 +845,27 @@ void IdataContents::create(COFFLinkerContext &ctx) {
dir->lookupTab = lookups[base];
dir->addressTab = addresses[base];
dirs.push_back(dir);
+
+ if (ctx.hybridSymtab) {
+ // If native-only imports exist, emit ARM64X relocations, skipping them in
+ // the EC view.
+ uint32_t nativeOnly =
+ llvm::find_if(syms,
+ [](DefinedImportData *s) { return s->file->isEC(); }) -
+ syms.begin();
+ if (nativeOnly) {
+ ctx.dynamicRelocs->add(
+ IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA, 0,
+ Arm64XRelocVal(
+ dir, offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA)),
+ nativeOnly * sizeof(uint64_t));
+ ctx.dynamicRelocs->add(
+ IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA, 0,
+ Arm64XRelocVal(dir, offsetof(ImportDirectoryTableEntry,
+ ImportAddressTableRVA)),
+ nativeOnly * sizeof(uint64_t));
+ }
+ }
}
// Add null terminator.
dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry), 4));
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 5ee73d4dc4f8b7..f92a8549a6cfb1 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -1100,15 +1100,21 @@ void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {
}
ImportFile::ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
- : InputFile(ctx.symtab, ImportKind, m), live(!ctx.config.doGC) {}
+ : InputFile(ctx.getSymtab(getMachineType(m)), ImportKind, m),
+ live(!ctx.config.doGC) {}
-MachineTypes ImportFile::getMachineType() const {
+MachineTypes ImportFile::getMachineType(MemoryBufferRef m) {
uint16_t machine =
- reinterpret_cast<const coff_import_header *>(mb.getBufferStart())
- ->Machine;
+ reinterpret_cast<const coff_import_header *>(m.getBufferStart())->Machine;
return MachineTypes(machine);
}
+bool ImportFile::isSameImport(const ImportFile *other) const {
+ if (!externalName.empty())
+ return other->externalName == externalName;
+ return hdr->OrdinalHint == other->hdr->OrdinalHint;
+}
+
ImportThunkChunk *ImportFile::makeImportThunk() {
switch (hdr->Machine) {
case AMD64:
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 823561cda247a0..21b9aeef21d4f8 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -351,11 +351,15 @@ class ImportFile : public InputFile {
explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m);
static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
- MachineTypes getMachineType() const override;
+ MachineTypes getMachineType() const override { return getMachineType(mb); }
+ static MachineTypes getMachineType(MemoryBufferRef m);
+ bool isSameImport(const ImportFile *other) const;
+ bool isEC() const { return impECSym != nullptr; }
DefinedImportData *impSym = nullptr;
Defined *thunkSym = nullptr;
ImportThunkChunkARM64EC *impchkThunk = nullptr;
+ ImportFile *hybridFile = nullptr;
std::string dllName;
private:
diff --git a/lld/test/COFF/arm64x-import.test b/lld/test/COFF/arm64x-import.test
new file mode 100644
index 00000000000000..b9ccac9a01d329
--- /dev/null
+++ b/lld/test/COFF/arm64x-import.test
@@ -0,0 +1,487 @@
+REQUIRES: aarch64
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func12-thunks-arm64ec.s -o func12-thunks-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows func12-thunks-arm64.s -o func12-thunks-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func12-arm64ec.s -o func12-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows func123-arm64.s -o func123-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func123-arm64ec.s -o func123-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows func12-arm64.s -o func12-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows func234-arm64.s -o func234-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func12o-arm64ec.s -o func12o-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows func34o-arm64.s -o func34o-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows funco-arm64.s -o funco-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows icall.s -o icall.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:imp.def -out:imp-arm64ec.lib
+RUN: llvm-lib -machine:arm64 -def:imp.def -out:imp-arm64.lib
+RUN: llvm-lib -machine:arm64x -def:imp.def -defArm64Native:imp.def -out:imp-arm64x.lib
+RUN: llvm-lib -machine:arm64x -def:imp-ord10.def -defArm64Native:imp.def -out:imp-ecord.lib
+RUN: llvm-lib -machine:arm64x -def:imp-ord10.def -defArm64Native:imp-ord20.def -out:imp-ecord.lib
+RUN: llvm-lib -machine:arm64x -def:imp2.def -defArm64Native:imp2.def -out:imp2.lib
+RUN: llvm-lib -machine:arm64x -def:noname-ec.def -defArm64Native:noname-native.def -out:noname.lib
+
+
+# Link to the imported func1, func2, and func1's thunks from both native and EC code.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:test-12-thunks.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: icall.obj func12-thunks-arm64ec.obj func12-thunks-arm64.obj imp-arm64ec.lib imp-arm64.lib
+
+RUN: llvm-objdump -d test-12-thunks.dll | FileCheck --check-prefix=DISASM-12T %s
+DISASM-12T: 0000000180001000 <.text>:
+DISASM-12T-NEXT: 180001000: f0000010 adrp x16, 0x180004000
+DISASM-12T-NEXT: 180001004: f9400610 ldr x16, [x16, #0x8]
+DISASM-12T-NEXT: 180001008: d61f0200 br x16
+DISASM-12T-NEXT: ...
+DISASM-12T-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+DISASM-12T-NEXT: 180002004: d65f03c0 ret
+DISASM-12T-NEXT: 180002008: 90000030 adrp x16, 0x180006000
+DISASM-12T-NEXT: 18000200c: f9400210 ldr x16, [x16]
+DISASM-12T-NEXT: 180002010: d61f0200 br x16
+DISASM-12T-NEXT: 180002014: d000000b adrp x11, 0x180004000
+DISASM-12T-NEXT: 180002018: f940016b ldr x11, [x11]
+DISASM-12T-NEXT: 18000201c: 9000000a adrp x10, 0x180002000 <.text+0x1000>
+DISASM-12T-NEXT: 180002020: 9100f14a add x10, x10, #0x3c
+DISASM-12T-NEXT: 180002024: 17fffff7 b 0x180002000 <.text+0x1000>
+DISASM-12T-NEXT: 180002028: d000000b adrp x11, 0x180004000
+DISASM-12T-NEXT: 18000202c: f940056b ldr x11, [x11, #0x8]
+DISASM-12T-NEXT: 180002030: d0ffffea adrp x10, 0x180000000
+DISASM-12T-NEXT: 180002034: 9100014a add x10, x10, #0x0
+DISASM-12T-NEXT: 180002038: 17fffff2 b 0x180002000 <.text+0x1000>
+DISASM-12T-NEXT: 18000203c: 52800060 mov w0, #0x3 // =3
+DISASM-12T-NEXT: 180002040: d65f03c0 ret
+DISASM-12T-NEXT: ...
+DISASM-12T-NEXT: 180003000: ff 25 fa 0f 00 00 jmpq *0xffa(%rip) # 0x180004000
+
+RUN: llvm-readobj --coff-imports test-12-thunks.dll | FileCheck --check-prefix=IMPORTS-12 %s
+IMPORTS-12: Import {
+IMPORTS-12-NEXT: Name: test.dll
+IMPORTS-12-NEXT: ImportLookupTableRVA: 0x5348
+IMPORTS-12-NEXT: ImportAddressTableRVA: 0x4000
+IMPORTS-12-NEXT: Symbol: func1 (0)
+IMPORTS-12-NEXT: Symbol: func2 (0)
+IMPORTS-12-NEXT: }
+IMPORTS-12-NEXT: HybridObject {
+IMPORTS-12: Import {
+IMPORTS-12-NEXT: Name: test.dll
+IMPORTS-12-NEXT: ImportLookupTableRVA: 0x5348
+IMPORTS-12-NEXT: ImportAddressTableRVA: 0x4000
+IMPORTS-12-NEXT: Symbol: func1 (0)
+IMPORTS-12-NEXT: Symbol: func2 (0)
+IMPORTS-12-NEXT: }
+IMPORTS-12-NEXT: }
+
+RUN: llvm-readobj --hex-dump=.test test-12-thunks.dll | FileCheck --check-prefix=FUNC-12-THUNKS %s
+FUNC-12-THUNKS: 0x180009000 00600000 00400000 00300000 08200000
+FUNC-12-THUNKS-NEXT: 0x180009010 08600000 08400000
+
+RUN: llvm-readobj --hex-dump=.testa test-12-thunks.dll | FileCheck --check-prefix=FUNC-12-THUNKSA %s
+FUNC-12-THUNKSA: 0x18000a000 00400000 08400000 00100000
+
+
+# If the ordinals of named imports don't match, use the EC value.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:test-12-thunks-ord.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: icall.obj func12-thunks-arm64ec.obj func12-thunks-arm64.obj imp-ecord.lib
+RUN: llvm-readobj --coff-imports test-12-thunks-ord.dll | FileCheck --check-prefix=IMPORTS-ORD %s
+
+IMPORTS-ORD: Format: COFF-ARM64X
+IMPORTS-ORD-NEXT: Arch: aarch64
+IMPORTS-ORD-NEXT: AddressSize: 64bit
+IMPORTS-ORD-NEXT: Import {
+IMPORTS-ORD-NEXT: Name: test.dll
+IMPORTS-ORD-NEXT: ImportLookupTableRVA: 0x5348
+IMPORTS-ORD-NEXT: ImportAddressTableRVA: 0x4000
+IMPORTS-ORD-NEXT: Symbol: func1 (11)
+IMPORTS-ORD-NEXT: Symbol: func2 (12)
+IMPORTS-ORD-NEXT: }
+IMPORTS-ORD-NEXT: HybridObject {
+IMPORTS-ORD-NEXT: Format: COFF-ARM64EC
+IMPORTS-ORD-NEXT: Arch: aarch64
+IMPORTS-ORD-NEXT: AddressSize: 64bit
+IMPORTS-ORD-NEXT: Import {
+IMPORTS-ORD-NEXT: Name: test.dll
+IMPORTS-ORD-NEXT: ImportLookupTableRVA: 0x5348
+IMPORTS-ORD-NEXT: ImportAddressTableRVA: 0x4000
+IMPORTS-ORD-NEXT: Symbol: func1 (11)
+IMPORTS-ORD-NEXT: Symbol: func2 (12)
+IMPORTS-ORD-NEXT: }
+IMPORTS-ORD-NEXT: }
+
+
+# Link to NONAME imports.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:test-noname.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: icall.obj func12-thunks-arm64ec.obj func12-thunks-arm64.obj noname.lib
+RUN: llvm-readobj --coff-imports test-noname.dll | FileCheck --check-prefix=IMPORTS-ORD2 %s
+
+IMPORTS-ORD2: Format: COFF-ARM64X
+IMPORTS-ORD2-NEXT: Arch: aarch64
+IMPORTS-ORD2-NEXT: AddressSize: 64bit
+IMPORTS-ORD2-NEXT: Import {
+IMPORTS-ORD2-NEXT: Name: test.dll
+IMPORTS-ORD2-NEXT: ImportLookupTableRVA: 0x5348
+IMPORTS-ORD2-NEXT: ImportAddressTableRVA: 0x4000
+IMPORTS-ORD2-NEXT: Symbol: (12)
+IMPORTS-ORD2-NEXT: Symbol: (11)
+IMPORTS-ORD2-NEXT: }
+IMPORTS-ORD2-NEXT: HybridObject {
+IMPORTS-ORD2-NEXT: Format: COFF-ARM64EC
+IMPORTS-ORD2-NEXT: Arch: aarch64
+IMPORTS-ORD2-NEXT: AddressSize: 64bit
+IMPORTS-ORD2-NEXT: Import {
+IMPORTS-ORD2-NEXT: Name: test.dll
+IMPORTS-ORD2-NEXT: ImportLookupTableRVA: 0x5350
+IMPORTS-ORD2-NEXT: ImportAddressTableRVA: 0x4008
+IMPORTS-ORD2-NEXT: Symbol: (11)
+IMPORTS-ORD2-NEXT: Symbol: (10)
+IMPORTS-ORD2-NEXT: }
+IMPORTS-ORD2-NEXT: }
+
+# Link to the imported func1 and func2 from both native and EC code, and func3 from native code.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:test2.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: icall.obj func12-arm64ec.obj func123-arm64.obj imp-arm64x.lib
+
+RUN: llvm-readobj --coff-imports test2.dll | FileCheck --check-prefix=IMPORTS-123-12 %s
+IMPORTS-123-12: Import {
+IMPORTS-123-12-NEXT: Name: test.dll
+IMPORTS-123-12-NEXT: ImportLookupTableRVA: 0x3338
+IMPORTS-123-12-NEXT: ImportAddressTableRVA: 0x2000
+IMPORTS-123-12-NEXT: Symbol: func3 (0)
+IMPORTS-123-12-NEXT: Symbol: func1 (0)
+IMPORTS-123-12-NEXT: Symbol: func2 (0)
+IMPORTS-123-12-NEXT: }
+IMPORTS-123-12-NEXT: HybridObject {
+IMPORTS-123-12: Import {
+IMPORTS-123-12-NEXT: Name: test.dll
+IMPORTS-123-12-NEXT: ImportLookupTableRVA: 0x3340
+IMPORTS-123-12-NEXT: ImportAddressTableRVA: 0x2008
+IMPORTS-123-12-NEXT: Symbol: func1 (0)
+IMPORTS-123-12-NEXT: Symbol: func2 (0)
+IMPORTS-123-12-NEXT: }
+IMPORTS-123-12-NEXT: }
+
+RUN: llvm-readobj --hex-dump=.test test2.dll | FileCheck --check-prefix=TEST-123-12 %s
+TEST-123-12: 0x180007000 08400000 08200000 10400000 10200000
+
+RUN: llvm-readobj --hex-dump=.testa test2.dll | FileCheck --check-prefix=TEST-123-12A %s
+TEST-123-12A: 0x180008000 08200000 10200000 00200000
+
+RUN: llvm-readobj --hex-dump=.rdata test2.dll | FileCheck --check-prefix=TEST-123-12AUX %s
+TEST-123-12AUX: 0x180004000 00000000 00000000 08100080 01000000
+TEST-123-12AUX-NEXT: 0x180004010 1c100080 01000000 00000000 00000000
+
+
+# Link to the imported func1 and func2 from both native and EC code, and func3 from EC code.
+
+RUN: lld-link -machine:arm64x...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/124189
More information about the llvm-commits
mailing list