-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLD][COFF] Add support for hybrid exports on ARM64X #123724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Depends on #123723. |
@llvm/pr-subscribers-lld-coff @llvm/pr-subscribers-platform-windows Author: Jacek Caban (cjacek) ChangesFull diff: https://github.com/llvm/llvm-project/pull/123724.diff 6 Files Affected:
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index ff3c89884c24df..2ef74cb4ce6259 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1167,7 +1167,7 @@ uint32_t ImportThunkChunkARM64EC::extendRanges() {
}
uint64_t Arm64XRelocVal::get() const {
- return (sym ? sym->getRVA() : 0) + value;
+ return (sym ? sym->getRVA() : 0) + (chunk ? chunk->getRVA() : 0) + value;
}
size_t Arm64XDynamicRelocEntry::getSize() const {
@@ -1230,6 +1230,16 @@ void DynamicRelocsChunk::finalize() {
size = alignTo(size, sizeof(uint32_t));
}
+// Set the reloc value. The reloc entry must be allocated beforehand.
+void DynamicRelocsChunk::set(uint32_t rva, Arm64XRelocVal value) {
+ Arm64XDynamicRelocEntry &entry =
+ *llvm::find_if(arm64xRelocs, [rva](const Arm64XDynamicRelocEntry &e) {
+ return e.offset.get() == rva;
+ });
+ assert(!entry.value.get());
+ entry.value = value;
+}
+
void DynamicRelocsChunk::writeTo(uint8_t *buf) const {
auto table = reinterpret_cast<coff_dynamic_reloc_table *>(buf);
table->Version = 1;
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 7ba58e336451fc..d6216efdd90bdd 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -840,10 +840,13 @@ class Arm64XRelocVal {
public:
Arm64XRelocVal(uint64_t value = 0) : value(value) {}
Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {}
+ Arm64XRelocVal(Chunk *chunk, int32_t offset = 0)
+ : chunk(chunk), value(offset) {}
uint64_t get() const;
private:
Defined *sym = nullptr;
+ Chunk *chunk = nullptr;
uint64_t value;
};
@@ -874,10 +877,12 @@ class DynamicRelocsChunk : public NonSectionChunk {
void finalize();
void add(llvm::COFF::Arm64XFixupType type, uint8_t size,
- Arm64XRelocVal offset, Arm64XRelocVal value) {
+ Arm64XRelocVal offset, Arm64XRelocVal value = Arm64XRelocVal()) {
arm64xRelocs.emplace_back(type, size, offset, value);
}
+ void set(uint32_t rva, Arm64XRelocVal value);
+
private:
std::vector<Arm64XDynamicRelocEntry> arm64xRelocs;
size_t size;
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 3d95d219a493cd..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();
@@ -2392,6 +2415,19 @@ void Writer::setECSymbols() {
symtab->findUnderscore("__arm64x_native_entrypoint")
->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) +
+ offsetof(data_directory, Size),
+ hybridPdata.last->getRVA() - hybridPdata.first->getRVA() +
+ hybridPdata.last->getSize());
}
}
@@ -2644,6 +2680,32 @@ 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 +
+ EXCEPTION_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, RelativeVirtualAddress),
+ hybridPdata.first);
+ // The Size value is assigned after addresses are finalized.
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ dataDirOffset64 +
+ EXCEPTION_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, Size));
+ }
+
// Set the hybrid load config to the EC load config.
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"
diff --git a/lld/test/COFF/pdata-arm64ec.test b/lld/test/COFF/pdata-arm64ec.test
index 7f20c460dc1099..fbec797525f7f8 100644
--- a/lld/test/COFF/pdata-arm64ec.test
+++ b/lld/test/COFF/pdata-arm64ec.test
@@ -6,6 +6,7 @@ Test handlign of hybrid .pdata section on ARM64EC target.
RUN: llvm-mc -filetype=obj -triple=arm64-windows arm64-func-sym.s -o arm64-func-sym.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func-sym.s -o arm64ec-func-sym.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %p/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
Only arm64ec code:
@@ -55,11 +56,21 @@ DATA3: 180005000 00100000 11000001 00200000 0e200000
Mixed arm64x code:
RUN: lld-link -out:test4.dll -machine:arm64x arm64-func-sym.obj arm64ec-func-sym.obj \
-RUN: x86_64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: x86_64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test4.dll | FileCheck -check-prefix=DIR3 %s
-DIR3: ExceptionTableRVA: 0x6000
-DIR3-NEXT: ExceptionTableSize: 0x10
+DIR3: ImageOptionalHeader {
+DIR3: DataDirectory {
+DIR3: ExceptionTableRVA: 0x6000
+DIR3-NEXT: ExceptionTableSize: 0x10
+DIR3: }
+DIR3: }
+DIR3: HybridObject {
+DIR3: ImageOptionalHeader {
+DIR3: ExceptionTableRVA: 0x6010
+DIR3-NEXT: ExceptionTableSize: 0xC
+DIR3: }
+DIR3: }
RUN: llvm-objdump -s --section=.pdata test4.dll | FileCheck -check-prefix=DATA4 %s
DATA4: 180006000 00100000 11000001 00200000 11000001 ......... ......
@@ -74,12 +85,12 @@ RUN: llvm-readobj --headers test5.dll | FileCheck -check-prefix=DIR2 %s
RUN: llvm-objdump -s --section=.pdata test5.dll | FileCheck -check-prefix=DATA3 %s
RUN: lld-link -out:test6.dll -machine:arm64x arm64ec-func-sym.obj x86_64-func-sym.obj \
-RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test6.dll | FileCheck -check-prefix=DIR3 %s
RUN: llvm-objdump -s --section=.pdata test6.dll | FileCheck -check-prefix=DATA4 %s
RUN: lld-link -out:test7.dll -machine:arm64x x86_64-func-sym.obj arm64ec-func-sym.obj \
-RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test7.dll | FileCheck -check-prefix=DIR3 %s
RUN: llvm-objdump -s --section=.pdata test7.dll | FileCheck -check-prefix=DATA4 %s
|
@llvm/pr-subscribers-lld Author: Jacek Caban (cjacek) ChangesFull diff: https://github.com/llvm/llvm-project/pull/123724.diff 6 Files Affected:
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index ff3c89884c24df..2ef74cb4ce6259 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1167,7 +1167,7 @@ uint32_t ImportThunkChunkARM64EC::extendRanges() {
}
uint64_t Arm64XRelocVal::get() const {
- return (sym ? sym->getRVA() : 0) + value;
+ return (sym ? sym->getRVA() : 0) + (chunk ? chunk->getRVA() : 0) + value;
}
size_t Arm64XDynamicRelocEntry::getSize() const {
@@ -1230,6 +1230,16 @@ void DynamicRelocsChunk::finalize() {
size = alignTo(size, sizeof(uint32_t));
}
+// Set the reloc value. The reloc entry must be allocated beforehand.
+void DynamicRelocsChunk::set(uint32_t rva, Arm64XRelocVal value) {
+ Arm64XDynamicRelocEntry &entry =
+ *llvm::find_if(arm64xRelocs, [rva](const Arm64XDynamicRelocEntry &e) {
+ return e.offset.get() == rva;
+ });
+ assert(!entry.value.get());
+ entry.value = value;
+}
+
void DynamicRelocsChunk::writeTo(uint8_t *buf) const {
auto table = reinterpret_cast<coff_dynamic_reloc_table *>(buf);
table->Version = 1;
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 7ba58e336451fc..d6216efdd90bdd 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -840,10 +840,13 @@ class Arm64XRelocVal {
public:
Arm64XRelocVal(uint64_t value = 0) : value(value) {}
Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {}
+ Arm64XRelocVal(Chunk *chunk, int32_t offset = 0)
+ : chunk(chunk), value(offset) {}
uint64_t get() const;
private:
Defined *sym = nullptr;
+ Chunk *chunk = nullptr;
uint64_t value;
};
@@ -874,10 +877,12 @@ class DynamicRelocsChunk : public NonSectionChunk {
void finalize();
void add(llvm::COFF::Arm64XFixupType type, uint8_t size,
- Arm64XRelocVal offset, Arm64XRelocVal value) {
+ Arm64XRelocVal offset, Arm64XRelocVal value = Arm64XRelocVal()) {
arm64xRelocs.emplace_back(type, size, offset, value);
}
+ void set(uint32_t rva, Arm64XRelocVal value);
+
private:
std::vector<Arm64XDynamicRelocEntry> arm64xRelocs;
size_t size;
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 3d95d219a493cd..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();
@@ -2392,6 +2415,19 @@ void Writer::setECSymbols() {
symtab->findUnderscore("__arm64x_native_entrypoint")
->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) +
+ offsetof(data_directory, Size),
+ hybridPdata.last->getRVA() - hybridPdata.first->getRVA() +
+ hybridPdata.last->getSize());
}
}
@@ -2644,6 +2680,32 @@ 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 +
+ EXCEPTION_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, RelativeVirtualAddress),
+ hybridPdata.first);
+ // The Size value is assigned after addresses are finalized.
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ dataDirOffset64 +
+ EXCEPTION_TABLE * sizeof(data_directory) +
+ offsetof(data_directory, Size));
+ }
+
// Set the hybrid load config to the EC load config.
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"
diff --git a/lld/test/COFF/pdata-arm64ec.test b/lld/test/COFF/pdata-arm64ec.test
index 7f20c460dc1099..fbec797525f7f8 100644
--- a/lld/test/COFF/pdata-arm64ec.test
+++ b/lld/test/COFF/pdata-arm64ec.test
@@ -6,6 +6,7 @@ Test handlign of hybrid .pdata section on ARM64EC target.
RUN: llvm-mc -filetype=obj -triple=arm64-windows arm64-func-sym.s -o arm64-func-sym.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func-sym.s -o arm64ec-func-sym.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %p/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
Only arm64ec code:
@@ -55,11 +56,21 @@ DATA3: 180005000 00100000 11000001 00200000 0e200000
Mixed arm64x code:
RUN: lld-link -out:test4.dll -machine:arm64x arm64-func-sym.obj arm64ec-func-sym.obj \
-RUN: x86_64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: x86_64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test4.dll | FileCheck -check-prefix=DIR3 %s
-DIR3: ExceptionTableRVA: 0x6000
-DIR3-NEXT: ExceptionTableSize: 0x10
+DIR3: ImageOptionalHeader {
+DIR3: DataDirectory {
+DIR3: ExceptionTableRVA: 0x6000
+DIR3-NEXT: ExceptionTableSize: 0x10
+DIR3: }
+DIR3: }
+DIR3: HybridObject {
+DIR3: ImageOptionalHeader {
+DIR3: ExceptionTableRVA: 0x6010
+DIR3-NEXT: ExceptionTableSize: 0xC
+DIR3: }
+DIR3: }
RUN: llvm-objdump -s --section=.pdata test4.dll | FileCheck -check-prefix=DATA4 %s
DATA4: 180006000 00100000 11000001 00200000 11000001 ......... ......
@@ -74,12 +85,12 @@ RUN: llvm-readobj --headers test5.dll | FileCheck -check-prefix=DIR2 %s
RUN: llvm-objdump -s --section=.pdata test5.dll | FileCheck -check-prefix=DATA3 %s
RUN: lld-link -out:test6.dll -machine:arm64x arm64ec-func-sym.obj x86_64-func-sym.obj \
-RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test6.dll | FileCheck -check-prefix=DIR3 %s
RUN: llvm-objdump -s --section=.pdata test6.dll | FileCheck -check-prefix=DATA4 %s
RUN: lld-link -out:test7.dll -machine:arm64x x86_64-func-sym.obj arm64ec-func-sym.obj \
-RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry
+RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry
RUN: llvm-readobj --headers test7.dll | FileCheck -check-prefix=DIR3 %s
RUN: llvm-objdump -s --section=.pdata test7.dll | FileCheck -check-prefix=DATA4 %s
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
dc7153d
to
dd81be3
Compare
No description provided.