Skip to content

Commit 46617ff

Browse files
committed
More tests and comments
1 parent faa2b2c commit 46617ff

File tree

2 files changed

+81
-14
lines changed

2 files changed

+81
-14
lines changed

lld/COFF/DLL.cpp

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -716,32 +716,49 @@ class ExportOrdinalChunk : public NonSectionChunk {
716716
void IdataContents::create(COFFLinkerContext &ctx) {
717717
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
718718

719-
// Merge compatible EC and native import files in hybrid images.
719+
// In hybrid images, EC and native code are usually very similar,
720+
// resulting in a highly similar set of imported symbols. Consequently,
721+
// their import tables can be shared, with ARM64X relocations handling any
722+
// differences. Identify matching import files used by EC and native code, and
723+
// merge them into a single hybrid import entry.
720724
if (ctx.hybridSymtab) {
721725
for (std::vector<DefinedImportData *> &syms : v) {
722-
// At this point, symbols are sorted by base name, ensuring that
723-
// compatible import files, if present, are adjacent.
724726
std::vector<DefinedImportData *> hybridSyms;
725727
ImportFile *prev = nullptr;
726728
for (DefinedImportData *sym : syms) {
727729
ImportFile *file = sym->file;
730+
// At this stage, symbols are sorted by base name, ensuring that
731+
// compatible import files, if present, are adjacent. Check if the
732+
// current symbol's file imports the same symbol as the previously added
733+
// one (if any and if it was not already merged). Additionally, verify
734+
// that one of them is native while the other is EC. In rare cases,
735+
// separate matching import entries may exist within the same namespace,
736+
// which cannot be merged.
728737
if (!prev || file->isEC() == prev->isEC() ||
729738
!file->isSameImport(prev)) {
739+
// We can't merge the import file, just add it to hybridSyms
740+
// and set prev to its file so that we can try to match the next
741+
// symbol.
730742
hybridSyms.push_back(sym);
731743
prev = file;
732744
continue;
733745
}
734746

735-
// The native variant exposes a subset of EC symbols and chunks. Use the
736-
// EC variant to represent both.
747+
// A matching symbol may appear in syms in any order. The native variant
748+
// exposes a subset of EC symbols and chunks, so always use the EC
749+
// variant as the hybrid import file. If the native file was already
750+
// added, replace it with the EC symbol in hybridSyms. Otherwise, the EC
751+
// variant is already pushed, so we can simply merge it.
737752
if (file->isEC()) {
738753
hybridSyms.pop_back();
739754
hybridSyms.push_back(sym);
740755
}
741756

757+
// Merge import files by storing their hybrid form in the corresponding
758+
// file class.
742759
prev->hybridFile = file;
743760
file->hybridFile = prev;
744-
prev = nullptr;
761+
prev = nullptr; // A hybrid import file cannot be merged again.
745762
}
746763

747764
// Sort symbols by type: native-only files first, followed by merged
@@ -780,11 +797,15 @@ void IdataContents::create(COFFLinkerContext &ctx) {
780797
}
781798

782799
// Detect the first EC-only import in the hybrid IAT. Emit null chunks
783-
// and add an ARM64X relocation to replace it with the import for the EC
784-
// view. Additionally, use the original chunks as import terminators
785-
// and zero them with ARM64X relocations. Since these chunks appear
786-
// after the null terminator in the native view, they are always ignored
787-
// by the loader. However, MSVC emits them for some reason.
800+
// as a terminator for the native view, and add an ARM64X relocation to
801+
// replace it with the correct import for the EC view.
802+
//
803+
// Additionally, for MSVC compatibility, store the lookup and address
804+
// chunks and append them at the end of EC-only imports, where a null
805+
// terminator chunk would typically be placed. Since they appear after
806+
// the native terminator, they will be ignored in the native view.
807+
// In the EC view, they should act as terminators, so emit ZEROFILL
808+
// relocations overriding them.
788809
if (ctx.hybridSymtab && !lookupsTerminator && s->file->isEC() &&
789810
!s->file->hybridFile) {
790811
lookupsTerminator = lookupsChunk;
@@ -846,8 +867,8 @@ void IdataContents::create(COFFLinkerContext &ctx) {
846867
dirs.push_back(dir);
847868

848869
if (ctx.hybridSymtab) {
849-
// If native-only imports exist, emit ARM64X relocations, skipping them in
850-
// the EC view.
870+
// If native-only imports exist, they will appear as a prefix to all
871+
// imports. Emit ARM64X relocations to skip them in the EC view.
851872
uint32_t nativeOnly =
852873
llvm::find_if(syms,
853874
[](DefinedImportData *s) { return s->file->isEC(); }) -

lld/test/COFF/arm64x-import.test

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func123-arm64ec.s -o func123-
99
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func12-arm64.s -o func12-arm64.obj
1010
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func234-arm64.s -o func234-arm64.obj
1111
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func12o-arm64ec.s -o func12o-arm64ec.obj
12+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func34-arm64.s -o func34-arm64.obj
1213
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func34o-arm64.s -o func34o-arm64.obj
1314
RUN: llvm-mc -filetype=obj -triple=aarch64-windows funco-arm64.s -o funco-arm64.obj
1415
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows icall.s -o icall.obj
@@ -21,6 +22,7 @@ RUN: llvm-lib -machine:arm64x -def:imp-ord10.def -defArm64Native:imp.def -out:im
2122
RUN: llvm-lib -machine:arm64x -def:imp-ord10.def -defArm64Native:imp-ord20.def -out:imp-ecord.lib
2223
RUN: llvm-lib -machine:arm64x -def:imp2.def -defArm64Native:imp2.def -out:imp2.lib
2324
RUN: llvm-lib -machine:arm64x -def:noname-ec.def -defArm64Native:noname-native.def -out:noname.lib
25+
RUN: llvm-lib -machine:arm64x -def:dup-ec.def -defArm64Native:dup-native.def -out:dup.lib
2426

2527

2628
# Link to the imported func1, func2, and func1's thunks from both native and EC code.
@@ -244,7 +246,7 @@ RUN: llvm-readobj --hex-dump=.testa test-234-123.dll | FileCheck --check-prefix=
244246
TEST-234-123A: 0x180008000 08200000 10200000 00200000
245247

246248

247-
# Link to the imported func3 and func4 from both native code, and func1 and func2 from EC code.
249+
# Link to the imported func3 and func4 from native code, and func1 and func2 from EC code.
248250

249251
RUN: lld-link -machine:arm64x -dll -noentry -out:test-34-12.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
250252
RUN: icall.obj func12o-arm64ec.obj func34o-arm64.obj imp-arm64x.lib imp2.lib
@@ -356,6 +358,33 @@ IMPORTS-N12-NEXT: }
356358
IMPORTS-N12-NEXT: }
357359

358360

361+
RUN: lld-link -machine:arm64x -dll -noentry -out:test-dup.dll loadconfig-arm64.obj loadconfig-arm64ec.obj icall.obj \
362+
RUN: func12-arm64ec.obj func34-arm64.obj dup.lib
363+
364+
RUN: llvm-readobj --coff-imports test-dup.dll | FileCheck --check-prefix=IMPORTS-DUP %s
365+
IMPORTS-DUP: Format: COFF-ARM64X
366+
IMPORTS-DUP-NEXT: Arch: aarch64
367+
IMPORTS-DUP-NEXT: AddressSize: 64bit
368+
IMPORTS-DUP-NEXT: Import {
369+
IMPORTS-DUP-NEXT: Name: test.dll
370+
IMPORTS-DUP-NEXT: ImportLookupTableRVA: 0x3338
371+
IMPORTS-DUP-NEXT: ImportAddressTableRVA: 0x2000
372+
IMPORTS-DUP-NEXT: Symbol: func4 (0)
373+
IMPORTS-DUP-NEXT: Symbol: func4 (0)
374+
IMPORTS-DUP-NEXT: }
375+
IMPORTS-DUP-NEXT: HybridObject {
376+
IMPORTS-DUP-NEXT: Format: COFF-ARM64EC
377+
IMPORTS-DUP-NEXT: Arch: aarch64
378+
IMPORTS-DUP-NEXT: AddressSize: 64bit
379+
IMPORTS-DUP-NEXT: Import {
380+
IMPORTS-DUP-NEXT: Name: test.dll
381+
IMPORTS-DUP-NEXT: ImportLookupTableRVA: 0x3348
382+
IMPORTS-DUP-NEXT: ImportAddressTableRVA: 0x2010
383+
IMPORTS-DUP-NEXT: Symbol: func1 (0)
384+
IMPORTS-DUP-NEXT: Symbol: func1 (0)
385+
IMPORTS-DUP-NEXT: }
386+
IMPORTS-DUP-NEXT: }
387+
359388
#--- func12-thunks-arm64ec.s
360389
.section .test, "r"
361390
.rva __imp_func1
@@ -413,6 +442,11 @@ IMPORTS-N12-NEXT: }
413442
.rva __imp_otherfunc
414443
.rva __imp_aux_otherfunc
415444

445+
#--- func34-arm64.s
446+
.section .testa, "r"
447+
.rva __imp_func3
448+
.rva __imp_func4
449+
416450
#--- func34o-arm64.s
417451
.section .testa, "r"
418452
.rva __imp_func3
@@ -485,3 +519,15 @@ NAME test.dll
485519
EXPORTS
486520
func1 @12 NONAME
487521
func2 @11 NONAME
522+
523+
#--- dup-ec.def
524+
NAME test.dll
525+
EXPORTS
526+
func1
527+
func2 EXPORTAS func1
528+
529+
#--- dup-native.def
530+
NAME test.dll
531+
EXPORTS
532+
func3 EXPORTAS func4
533+
func4

0 commit comments

Comments
 (0)