[lld] [LLD][COFF] Add support for CHPE code ranges metadata. (PR #105741)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 22 14:51:36 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Jacek Caban (cjacek)
<details>
<summary>Changes</summary>
This is part of CHPE metadata containing a sorted list of x86_64 export thunks RVAs and sizes.
---
Full diff: https://github.com/llvm/llvm-project/pull/105741.diff
7 Files Affected:
- (modified) lld/COFF/Chunks.cpp (+29)
- (modified) lld/COFF/Chunks.h (+22)
- (modified) lld/COFF/Driver.cpp (+4)
- (modified) lld/COFF/Writer.cpp (+35-1)
- (modified) lld/test/COFF/Inputs/loadconfig-arm64ec.s (+4-4)
- (modified) lld/test/COFF/arm64ec-export-thunks.test (+32-2)
- (modified) lld/test/COFF/arm64ec-patchable-thunks.test (+7-1)
``````````diff
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index be44950a1720e3..72a9ad05ca11c1 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -1078,4 +1078,33 @@ void ECExportThunkChunk::writeTo(uint8_t *buf) const {
write32le(buf + 10, target->getRVA() - rva - 14);
}
+size_t CHPECodeRangesChunk::getSize() const {
+ return exportThunks.size() * sizeof(chpe_code_range_entry);
+}
+
+void CHPECodeRangesChunk::writeTo(uint8_t *buf) const {
+ auto ranges = reinterpret_cast<chpe_code_range_entry *>(buf);
+
+ for (uint32_t i = 0; i < exportThunks.size(); i++) {
+ Chunk *thunk = exportThunks[i].first;
+ uint32_t start = thunk->getRVA();
+ ranges[i].StartRva = start;
+ ranges[i].EndRva = start + thunk->getSize();
+ ranges[i].EntryPoint = start;
+ }
+}
+
+size_t CHPERedirectionChunk::getSize() const {
+ return exportThunks.size() * sizeof(chpe_redirection_entry);
+}
+
+void CHPERedirectionChunk::writeTo(uint8_t *buf) const {
+ auto entries = reinterpret_cast<chpe_redirection_entry *>(buf);
+
+ for (uint32_t i = 0; i < exportThunks.size(); i++) {
+ entries[i].Source = exportThunks[i].first->getRVA();
+ entries[i].Destination = exportThunks[i].second->getRVA();
+ }
+}
+
} // namespace lld::coff
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 5443d4619a977e..fe202008971a54 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -749,6 +749,28 @@ class ECCodeMapChunk : public NonSectionChunk {
std::vector<ECCodeMapEntry> ↦
};
+class CHPECodeRangesChunk : public NonSectionChunk {
+public:
+ CHPECodeRangesChunk(std::vector<std::pair<Chunk *, Defined *>> &exportThunks)
+ : exportThunks(exportThunks) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *buf) const override;
+
+private:
+ std::vector<std::pair<Chunk *, Defined *>> &exportThunks;
+};
+
+class CHPERedirectionChunk : public NonSectionChunk {
+public:
+ CHPERedirectionChunk(std::vector<std::pair<Chunk *, Defined *>> &exportThunks)
+ : exportThunks(exportThunks) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *buf) const override;
+
+private:
+ std::vector<std::pair<Chunk *, Defined *>> &exportThunks;
+};
+
static const uint8_t ECExportThunkCode[] = {
0x48, 0x8b, 0xc4, // movq %rsp, %rax
0x48, 0x89, 0x58, 0x20, // movq %rbx, 0x20(%rax)
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index c09c91fe4b1719..3ef9fa3f65c6a6 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2440,8 +2440,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (isArm64EC(config->machine)) {
ctx.symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
ctx.symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
+ ctx.symtab.addAbsolute("__arm64x_redirection_metadata", 0);
+ ctx.symtab.addAbsolute("__arm64x_redirection_metadata_count", 0);
ctx.symtab.addAbsolute("__hybrid_code_map", 0);
ctx.symtab.addAbsolute("__hybrid_code_map_count", 0);
+ ctx.symtab.addAbsolute("__x64_code_ranges_to_entry_points", 0);
+ ctx.symtab.addAbsolute("__x64_code_ranges_to_entry_points_count", 0);
}
if (config->pseudoRelocs) {
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 776595d98c391d..0360e186ecf0cf 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -298,6 +298,9 @@ class Writer {
CVDebugRecordChunk *buildId = nullptr;
ArrayRef<uint8_t> sectionTable;
+ // List of Arm64EC export thunks.
+ std::vector<std::pair<Chunk *, Defined *>> exportThunks;
+
uint64_t fileSize;
uint32_t pointerToSymbolTable = 0;
uint64_t sizeOfImage;
@@ -312,6 +315,7 @@ class Writer {
OutputSection *idataSec;
OutputSection *edataSec;
OutputSection *didatSec;
+ OutputSection *a64xrmSec;
OutputSection *rsrcSec;
OutputSection *relocSec;
OutputSection *ctorsSec;
@@ -995,6 +999,8 @@ void Writer::createSections() {
idataSec = createSection(".idata", data | r);
edataSec = createSection(".edata", data | r);
didatSec = createSection(".didat", data | r);
+ if (isArm64EC(ctx.config.machine))
+ a64xrmSec = createSection(".a64xrm", data | r);
rsrcSec = createSection(".rsrc", data | r);
relocSec = createSection(".reloc", data | discardable | r);
ctorsSec = createSection(".ctors", data | r | w);
@@ -2053,8 +2059,10 @@ void Writer::createECChunks() {
auto sym = dyn_cast<Defined>(s);
if (!sym || !sym->getChunk())
continue;
- if (auto thunk = dyn_cast<ECExportThunkChunk>(sym->getChunk()))
+ if (auto thunk = dyn_cast<ECExportThunkChunk>(sym->getChunk())) {
hexpthkSec->addChunk(thunk);
+ exportThunks.push_back({thunk, thunk->target});
+ }
}
auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
@@ -2062,6 +2070,19 @@ void Writer::createECChunks() {
Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),
codeMapChunk);
+
+ CHPECodeRangesChunk *ranges = make<CHPECodeRangesChunk>(exportThunks);
+ rdataSec->addChunk(ranges);
+ Symbol *rangesSym =
+ ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points");
+ replaceSymbol<DefinedSynthetic>(rangesSym, rangesSym->getName(), ranges);
+
+ CHPERedirectionChunk *entryPoints = make<CHPERedirectionChunk>(exportThunks);
+ a64xrmSec->addChunk(entryPoints);
+ Symbol *entryPointsSym =
+ ctx.symtab.findUnderscore("__arm64x_redirection_metadata");
+ replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
+ entryPoints);
}
// MinGW specific. Gather all relocations that are imported from a DLL even
@@ -2154,6 +2175,11 @@ void Writer::setECSymbols() {
if (!isArm64EC(ctx.config.machine))
return;
+ llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,
+ const std::pair<Chunk *, Defined *> &b) {
+ return a.first->getRVA() < b.first->getRVA();
+ });
+
Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");
replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
pdata.first);
@@ -2165,6 +2191,14 @@ void Writer::setECSymbols() {
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
pdata.first->getRVA());
}
+
+ Symbol *rangesCountSym =
+ ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
+ cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());
+
+ Symbol *entryPointCountSym =
+ ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
+ cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
}
// Write section contents to a mmap'ed file.
diff --git a/lld/test/COFF/Inputs/loadconfig-arm64ec.s b/lld/test/COFF/Inputs/loadconfig-arm64ec.s
index a270d281095dd6..78e7fba43a0a4d 100644
--- a/lld/test/COFF/Inputs/loadconfig-arm64ec.s
+++ b/lld/test/COFF/Inputs/loadconfig-arm64ec.s
@@ -66,8 +66,8 @@ __chpe_metadata:
.word 1
.rva __hybrid_code_map
.word __hybrid_code_map_count
- .word 0 // __x64_code_ranges_to_entry_points
- .word 0 //__arm64x_redirection_metadata
+ .rva __x64_code_ranges_to_entry_points
+ .rva __arm64x_redirection_metadata
.rva __os_arm64x_dispatch_call_no_redirect
.rva __os_arm64x_dispatch_ret
.rva __os_arm64x_check_call
@@ -75,8 +75,8 @@ __chpe_metadata:
.rva __os_arm64x_check_icall_cfg
.word 0 // __arm64x_native_entrypoint
.word 0 // __hybrid_auxiliary_iat
- .word 0 // __x64_code_ranges_to_entry_points_count
- .word 0 // __arm64x_redirection_metadata_count
+ .word __x64_code_ranges_to_entry_points_count
+ .word __arm64x_redirection_metadata_count
.rva __os_arm64x_get_x64_information
.rva __os_arm64x_set_x64_information
.rva __arm64x_extra_rfe_table
diff --git a/lld/test/COFF/arm64ec-export-thunks.test b/lld/test/COFF/arm64ec-export-thunks.test
index 6ed0514d4b17f3..809fac1f24a7dc 100644
--- a/lld/test/COFF/arm64ec-export-thunks.test
+++ b/lld/test/COFF/arm64ec-export-thunks.test
@@ -49,7 +49,7 @@ EXP-DISASM-NEXT: 18000301f: cc int3
RUN: llvm-objdump -p exports.dll | FileCheck -check-prefix=EXP-EXPORT %s
EXP-EXPORT: Ordinal RVA Name
EXP-EXPORT-NEXT: 1 0x3010 arm64ec_func
-EXP-EXPORT-NEXT: 2 0x6000 data_sym
+EXP-EXPORT-NEXT: 2 0x7000 data_sym
EXP-EXPORT-NEXT: 3 0x3000 func
EXP-EXPORT-NEXT: 4 0x2000 x86_64_func
@@ -58,9 +58,33 @@ EXP-CHPE: CodeMap [
EXP-CHPE-NEXT: 0x1000 - 0x100C ARM64EC
EXP-CHPE-NEXT: 0x2000 - 0x3020 X64
EXP-CHPE-NEXT: ]
+EXP-CHPE-NEXT: CodeRangesToEntryPoints [
+EXP-CHPE-NEXT: 0x3000 - 0x3010 -> 0x3000
+EXP-CHPE-NEXT: 0x3010 - 0x3020 -> 0x3010
+EXP-CHPE-NEXT: ]
+EXP-CHPE-NEXT: RedirectionMetadata [
+EXP-CHPE-NEXT: 0x3000 -> 0x1000
+EXP-CHPE-NEXT: 0x3010 -> 0x1000
+EXP-CHPE-NEXT: ]
+
+RUN: llvm-readobj --sections exports.dll | FileCheck --check-prefix=A64XRM %s
+
+A64XRM: Name: .a64xrm (2E 61 36 34 78 72 6D 00)
+A64XRM-NEXT: VirtualSize: 0x10
+A64XRM-NEXT: VirtualAddress: 0x6000
+A64XRM-NEXT: RawDataSize: 512
+A64XRM-NEXT: PointerToRawData:
+A64XRM-NEXT: PointerToRelocations: 0x0
+A64XRM-NEXT: PointerToLineNumbers: 0x0
+A64XRM-NEXT: RelocationCount: 0
+A64XRM-NEXT: LineNumberCount: 0
+A64XRM-NEXT: Characteristics [ (0x40000040)
+A64XRM-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+A64XRM-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+A64XRM-NEXT: ]
RUN: llvm-objdump -s --section=.test exports.dll | FileCheck --check-prefix=EXP-DATA %s
-EXP-DATA: 180006000 00300000 10300000
+EXP-DATA: 180007000 00300000 10300000
RUN: lld-link -out:exports2.dll -machine:arm64ec antidep-func.obj x86_64-func.obj loadconfig-arm64ec.obj \
RUN: arm64ec-data.obj -dll -noentry -export:arm64ec_func -export:func=arm64ec_func \
@@ -100,6 +124,12 @@ ENTRY-CHPE: CodeMap [
ENTRY-CHPE-NEXT: 0x1000 - 0x100C ARM64EC
ENTRY-CHPE-NEXT: 0x2000 - 0x2010 X64
ENTRY-CHPE-NEXT: ]
+ENTRY-CHPE-NEXT: CodeRangesToEntryPoints [
+ENTRY-CHPE-NEXT: 0x2000 - 0x2010 -> 0x2000
+ENTRY-CHPE-NEXT: ]
+ENTRY-CHPE-NEXT: RedirectionMetadata [
+ENTRY-CHPE-NEXT: 0x2000 -> 0x1000
+ENTRY-CHPE-NEXT: ]
Test exporting data symbol as a function:
diff --git a/lld/test/COFF/arm64ec-patchable-thunks.test b/lld/test/COFF/arm64ec-patchable-thunks.test
index cccd42eebfd367..5cebe7cc27ad63 100644
--- a/lld/test/COFF/arm64ec-patchable-thunks.test
+++ b/lld/test/COFF/arm64ec-patchable-thunks.test
@@ -27,13 +27,19 @@ PATCH-DISASM-NEXT: 18000200e: cc int3
PATCH-DISASM-NEXT: 18000200f: cc int3
RUN: llvm-readobj --hex-dump=.test test.dll | FileCheck -check-prefix=RVA %s
-RVA: 0x180005000 00200000
+RVA: 0x180006000 00200000
RUN: llvm-readobj --coff-load-config test.dll | FileCheck -check-prefix=PATCH-CHPE %s
PATCH-CHPE: CodeMap [
PATCH-CHPE-NEXT: 0x1000 - 0x1008 ARM64EC
PATCH-CHPE-NEXT: 0x2000 - 0x2010 X64
PATCH-CHPE-NEXT: ]
+PATCH-CHPE-NEXT: CodeRangesToEntryPoints [
+PATCH-CHPE-NEXT: 0x2000 - 0x2010 -> 0x2000
+PATCH-CHPE-NEXT: ]
+PATCH-CHPE-NEXT: RedirectionMetadata [
+PATCH-CHPE-NEXT: 0x2000 -> 0x1000
+PATCH-CHPE-NEXT: ]
RUN: lld-link -out:test2.dll -machine:arm64ec arm64ec-alias.obj test-sec.obj loadconfig-arm64ec.obj -dll -noentry
``````````
</details>
https://github.com/llvm/llvm-project/pull/105741
More information about the llvm-commits
mailing list