[lld] 671ec34 - [LLD][COFF] Add support for hybrid exports on ARM64X (#123724)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 21 13:56:02 PST 2025
Author: Jacek Caban
Date: 2025-01-21T22:55:58+01:00
New Revision: 671ec34fb2d6b2cb1f82a69991d2aebb3bdc24bd
URL: https://github.com/llvm/llvm-project/commit/671ec34fb2d6b2cb1f82a69991d2aebb3bdc24bd
DIFF: https://github.com/llvm/llvm-project/commit/671ec34fb2d6b2cb1f82a69991d2aebb3bdc24bd.diff
LOG: [LLD][COFF] Add support for hybrid exports on ARM64X (#123724)
Added:
Modified:
lld/COFF/SymbolTable.h
lld/COFF/Writer.cpp
lld/test/COFF/arm64x-export.test
Removed:
################################################################################
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index a0acf5db469032..e5b02ce5904c49 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -155,6 +155,9 @@ class SymbolTable {
llvm::DenseSet<StringRef> directivesExports;
bool hadExplicitExports;
+ Chunk *edataStart = nullptr;
+ Chunk *edataEnd = nullptr;
+
void fixupExports();
void assignExportOrdinals();
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 507621d1e95f80..bef2ced9f2957d 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -288,8 +288,6 @@ class Writer {
IdataContents idata;
Chunk *importTableStart = nullptr;
uint64_t importTableSize = 0;
- Chunk *edataStart = nullptr;
- Chunk *edataEnd = nullptr;
Chunk *iatStart = nullptr;
uint64_t iatSize = 0;
DelayLoadContents delayIdata;
@@ -1331,22 +1329,46 @@ void Writer::createExportTable() {
if (!edataSec->chunks.empty()) {
// Allow using a custom built export table from input object files, instead
// of having the linker synthesize the tables.
- if (ctx.symtab.hadExplicitExports)
- Warn(ctx) << "literal .edata sections override exports";
- } else if (!ctx.symtab.exports.empty()) {
- std::vector<Chunk *> edataChunks;
- createEdataChunks(ctx.symtab, edataChunks);
- for (Chunk *c : edataChunks)
- edataSec->addChunk(c);
- }
- if (!edataSec->chunks.empty()) {
- edataStart = edataSec->chunks.front();
- edataEnd = edataSec->chunks.back();
+ if (!ctx.hybridSymtab) {
+ ctx.symtab.edataStart = edataSec->chunks.front();
+ ctx.symtab.edataEnd = edataSec->chunks.back();
+ } else {
+ // On hybrid target, split EC and native chunks.
+ llvm::stable_sort(edataSec->chunks, [=](const Chunk *a, const Chunk *b) {
+ return (a->getMachine() != ARM64) < (b->getMachine() != ARM64);
+ });
+
+ for (auto chunk : edataSec->chunks) {
+ if (chunk->getMachine() != ARM64) {
+ ctx.hybridSymtab->edataStart = chunk;
+ ctx.hybridSymtab->edataEnd = edataSec->chunks.back();
+ break;
+ }
+
+ if (!ctx.symtab.edataStart)
+ ctx.symtab.edataStart = chunk;
+ ctx.symtab.edataEnd = chunk;
+ }
+ }
}
- // Warn on exported deleting destructor.
- for (auto e : ctx.symtab.exports)
- if (e.sym && e.sym->getName().starts_with("??_G"))
- Warn(ctx) << "export of deleting dtor: " << e.sym;
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.edataStart) {
+ if (symtab.hadExplicitExports)
+ Warn(ctx) << "literal .edata sections override exports";
+ } else if (!symtab.exports.empty()) {
+ std::vector<Chunk *> edataChunks;
+ createEdataChunks(symtab, edataChunks);
+ for (Chunk *c : edataChunks)
+ edataSec->addChunk(c);
+ symtab.edataStart = edataChunks.front();
+ symtab.edataEnd = edataChunks.back();
+ }
+
+ // Warn on exported deleting destructor.
+ for (auto e : symtab.exports)
+ if (e.sym && e.sym->getName().starts_with("??_G"))
+ Warn(ctx) << "export of deleting dtor: " << toString(ctx, *e.sym);
+ });
}
void Writer::removeUnusedSections() {
@@ -1819,10 +1841,11 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
dataDirOffset64 == buf - buffer->getBufferStart());
auto *dir = reinterpret_cast<data_directory *>(buf);
buf += sizeof(*dir) * numberOfDataDirectory;
- if (edataStart) {
- dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();
- dir[EXPORT_TABLE].Size =
- edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();
+ if (ctx.symtab.edataStart) {
+ dir[EXPORT_TABLE].RelativeVirtualAddress = ctx.symtab.edataStart->getRVA();
+ dir[EXPORT_TABLE].Size = ctx.symtab.edataEnd->getRVA() +
+ ctx.symtab.edataEnd->getSize() -
+ ctx.symtab.edataStart->getRVA();
}
if (importTableStart) {
dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();
@@ -2393,6 +2416,12 @@ void Writer::setECSymbols() {
->replaceKeepingName(altEntrySym, sizeof(SymbolUnion));
}
+ if (symtab->edataStart)
+ ctx.dynamicRelocs->set(
+ dataDirOffset64 + EXPORT_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, Size),
+ symtab->edataEnd->getRVA() - symtab->edataStart->getRVA() +
+ symtab->edataEnd->getSize());
if (hybridPdata.first)
ctx.dynamicRelocs->set(
dataDirOffset64 + EXCEPTION_TABLE * sizeof(data_directory) +
@@ -2651,6 +2680,19 @@ void Writer::createDynamicRelocs() {
Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target";
}
+ if (ctx.symtab.edataStart != ctx.hybridSymtab->edataStart) {
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ dataDirOffset64 +
+ EXPORT_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, RelativeVirtualAddress),
+ ctx.hybridSymtab->edataStart);
+ // The Size value is assigned after addresses are finalized.
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ dataDirOffset64 +
+ EXPORT_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, Size));
+ }
+
if (pdata.first != hybridPdata.first) {
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
dataDirOffset64 +
diff --git a/lld/test/COFF/arm64x-export.test b/lld/test/COFF/arm64x-export.test
index e5d0307e570efd..526be633973581 100644
--- a/lld/test/COFF/arm64x-export.test
+++ b/lld/test/COFF/arm64x-export.test
@@ -5,6 +5,8 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-fun
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-drectve.s -o arm64ec-drectve.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func-drectve.s -o arm64-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows edata.s -o arm64-edata.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows edata.s -o arm64ec-edata.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
@@ -36,6 +38,15 @@ RUN: llvm-readobj --headers --coff-exports out-cmd.dll | FileCheck --check-prefi
EXPORTS-EC: ExportTableRVA: 0x0
EXPORTS-EC-NEXT: ExportTableSize: 0x0
EXPORTS-EC-NOT: Name: func
+EXPORTS-EC: HybridObject {
+EXPORTS-EC: ExportTableRVA: 0x3{{.*}}
+EXPORTS-EC-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-EC: Export {
+EXPORTS-EC-NEXT: Ordinal: 1
+EXPORTS-EC-NEXT: Name: func
+EXPORTS-EC-NEXT: RVA: 0x2000
+EXPORTS-EC-NEXT: }
+EXPORTS-EC-NEXT: }
# Export using the EC .drectve section.
@@ -44,6 +55,30 @@ RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-drectve.obj -n
RUN: llvm-objdump -d out-drectve-ec.dll | FileCheck --check-prefix=DISASM-EC %s
RUN: llvm-readobj --headers --coff-exports out-drectve-ec.dll | FileCheck --check-prefix=EXPORTS-EC %s
+# Export using the EC .edata section.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata-ec.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-edata.obj -noentry
+
+RUN: llvm-objdump -d out-edata-ec.dll | FileCheck --check-prefix=DISASM-EDATA-EC %s
+DISASM-EDATA-EC: 0000000180001000 <.text>:
+DISASM-EDATA-EC-NEXT: 180001000: 52800040 mov w0, #0x2 // =2
+DISASM-EDATA-EC-NEXT: 180001004: d65f03c0 ret
+
+RUN: llvm-readobj --headers --coff-exports out-edata-ec.dll | FileCheck --check-prefix=EXPORTS-EDATA-EC %s
+EXPORTS-EDATA-EC: ExportTableRVA: 0x0
+EXPORTS-EDATA-EC-NEXT: ExportTableSize: 0x0
+EXPORTS-EDATA-EC-NOT: Name: func
+EXPORTS-EDATA-EC: HybridObject {
+EXPORTS-EDATA-EC: ExportTableRVA: 0x2{{.*}}
+EXPORTS-EDATA-EC-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-EC: Export {
+EXPORTS-EDATA-EC-NEXT: Ordinal: 1
+EXPORTS-EDATA-EC-NEXT: Name: func
+EXPORTS-EDATA-EC-NEXT: RVA: 0x1000
+EXPORTS-EDATA-EC-NEXT: }
+EXPORTS-EDATA-EC-NEXT: }
+
# Export using the native .drectve section.
RUN: lld-link -machine:arm64x -dll -out:out-drectve-native.dll arm64ec-func.obj arm64-func.obj \
@@ -64,6 +99,17 @@ EXPORTS-NATIVE-NEXT: Ordinal: 1
EXPORTS-NATIVE-NEXT: Name: func
EXPORTS-NATIVE-NEXT: RVA: 0x1000
EXPORTS-NATIVE-NEXT: }
+EXPORTS-NATIVE: HybridObject {
+EXPORTS-NATIVE: ExportTableRVA: 0x0
+EXPORTS-NATIVE-NEXT: ExportTableSize: 0x0
+EXPORTS-NATIVE-NOT: Name: func
+
+# Export using the native .edata section.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj -noentry
+RUN: llvm-objdump -d out-edata.dll | FileCheck --check-prefix=DISASM-NATIVE %s
+RUN: llvm-readobj --headers --coff-exports out-edata.dll | FileCheck --check-prefix=EXPORTS-NATIVE %s
# Export using both the native and EC .drectve sections.
@@ -99,6 +145,37 @@ EXPORTS-BOTH-NEXT: Ordinal: 1
EXPORTS-BOTH-NEXT: Name: func
EXPORTS-BOTH-NEXT: RVA: 0x1000
EXPORTS-BOTH-NEXT: }
+EXPORTS-BOTH: HybridObject {
+EXPORTS-BOTH: ExportTableRVA: 0x4{{.*}}
+EXPORTS-BOTH-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-BOTH: Export {
+EXPORTS-BOTH-NEXT: Ordinal: 1
+EXPORTS-BOTH-NEXT: Name: func
+EXPORTS-BOTH-NEXT: RVA: 0x3000
+EXPORTS-BOTH-NEXT: }
+EXPORTS-BOTH-NEXT: }
+
+# Export using both the native and EC .edata sections.
+
+RUN: lld-link -machine:arm64x -dll -out:out-edata-both.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj arm64ec-edata.obj -noentry
+RUN: llvm-readobj --headers --coff-exports out-edata-both.dll | FileCheck --check-prefix=EXPORTS-EDATA-BOTH %s
+EXPORTS-EDATA-BOTH: ExportTableRVA: 0x3{{.*}}
+EXPORTS-EDATA-BOTH-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-BOTH: Export {
+EXPORTS-EDATA-BOTH-NEXT: Ordinal: 1
+EXPORTS-EDATA-BOTH-NEXT: Name: func
+EXPORTS-EDATA-BOTH-NEXT: RVA: 0x1000
+EXPORTS-EDATA-BOTH-NEXT: }
+EXPORTS-EDATA-BOTH: HybridObject {
+EXPORTS-EDATA-BOTH: ExportTableRVA: 0x3{{.*}}
+EXPORTS-EDATA-BOTH-NEXT: ExportTableSize: 0x4{{.*}}
+EXPORTS-EDATA-BOTH: Export {
+EXPORTS-EDATA-BOTH-NEXT: Ordinal: 1
+EXPORTS-EDATA-BOTH-NEXT: Name: func
+EXPORTS-EDATA-BOTH-NEXT: RVA: 0x2000
+EXPORTS-EDATA-BOTH-NEXT: }
+EXPORTS-EDATA-BOTH-NEXT: }
#--- arm64-func.s
.section .text,"xr",discard,func
@@ -119,3 +196,34 @@ func:
#--- func-drectve.s
.section .drectve
.ascii "-export:func"
+
+#--- edata.s
+ .section .edata, "dr"
+ .align 4
+exports:
+ .long 0 // ExportFlags
+ .long 0 // TimeDateStamp
+ .long 0 // MajorVersion + MinorVersion
+ .rva name // NameRVA
+ .long 1 // OrdinalBase
+ .long 1 // AddressTableEntries
+ .long 1 // NumberOfNamePointers
+ .rva functions // ExportAddressTableRVA
+ .rva names // NamePointerRVA
+ .rva nameordinals // OrdinalTableRVA
+
+names:
+ .rva funcname_func
+
+nameordinals:
+ .short 0
+
+functions:
+ .rva func
+ .long 0
+
+funcname_func:
+ .asciz "func"
+
+name:
+ .asciz "out-edata.dll"
More information about the llvm-commits
mailing list