Skip to content

[LLD][COFF] Add support for CHPE code ranges metadata. #105741

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

Merged
merged 1 commit into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions lld/COFF/Chunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,22 @@ 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is a similar list as #105739, with the same start RVAs, but containing the size and not the destination? And the EntryPoint value seems pointless at this point, I presume it will seem more useful after some more future patches.

(I.e. I'm not questioning this patch, I'm questioning the usefulness of this data structure - but I guess it makes more sense when more complete.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid it doesn't make more sense even when it's more complete. I've never seen StartRva and EntryPoint differ, even with some unusual synthetic inputs that I experimented with for custom export thunks. I’m not sure why it’s structured this way. Instead of duplicating the value in EntryPoint, I imagine it could store the redirection destination here and use a single structure instead of separate ones for redirection and code ranges.

As for how these structures are used, I can only speculate, so please keep in mind that this is just a guess. I think it might be useful for auxiliary IAT handling. The loader needs to populate the auxiliary IAT with addresses of actual ARM64EC functions, where something like redirection metadata could be used. It would also need to detect runtime patching of x86 thunks to know when to revert the auxiliary IAT to go through the call checker. For that, it would additionally need to know the thunks' sizes, which is what the code ranges metadata provides.

}
}

size_t CHPERedirectionChunk::getSize() const {
return exportThunks.size() * sizeof(chpe_redirection_entry);
}
Expand Down
11 changes: 11 additions & 0 deletions lld/COFF/Chunks.h
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,17 @@ class ECCodeMapChunk : public NonSectionChunk {
std::vector<ECCodeMapEntry> &map;
};

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)
Expand Down
2 changes: 2 additions & 0 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
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) {
Expand Down
10 changes: 10 additions & 0 deletions lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2071,6 +2071,12 @@ void Writer::createECChunks() {
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 =
Expand Down Expand Up @@ -2186,6 +2192,10 @@ void Writer::setECSymbols() {
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());
Expand Down
4 changes: 2 additions & 2 deletions lld/test/COFF/Inputs/loadconfig-arm64ec.s
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ __chpe_metadata:
.word 1
.rva __hybrid_code_map
.word __hybrid_code_map_count
.word 0 // __x64_code_ranges_to_entry_points
.rva __x64_code_ranges_to_entry_points
.rva __arm64x_redirection_metadata
.rva __os_arm64x_dispatch_call_no_redirect
.rva __os_arm64x_dispatch_ret
Expand All @@ -75,7 +75,7 @@ __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 __x64_code_ranges_to_entry_points_count
.word __arm64x_redirection_metadata_count
.rva __os_arm64x_get_x64_information
.rva __os_arm64x_set_x64_information
Expand Down
9 changes: 7 additions & 2 deletions lld/test/COFF/arm64ec-export-thunks.test
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ EXP-CHPE: CodeMap [
EXP-CHPE-NEXT: 0x1000 - 0x100C ARM64EC
EXP-CHPE-NEXT: 0x2000 - 0x3020 X64
EXP-CHPE-NEXT: ]
EXP-CHPE-NEXT: CodeRangesToEntryPoints: 0
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
Expand Down Expand Up @@ -121,7 +124,9 @@ ENTRY-CHPE: CodeMap [
ENTRY-CHPE-NEXT: 0x1000 - 0x100C ARM64EC
ENTRY-CHPE-NEXT: 0x2000 - 0x2010 X64
ENTRY-CHPE-NEXT: ]
ENTRY-CHPE-NEXT: CodeRangesToEntryPoints: 0
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: ]
Expand Down
4 changes: 3 additions & 1 deletion lld/test/COFF/arm64ec-patchable-thunks.test
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ PATCH-CHPE: CodeMap [
PATCH-CHPE-NEXT: 0x1000 - 0x1008 ARM64EC
PATCH-CHPE-NEXT: 0x2000 - 0x2010 X64
PATCH-CHPE-NEXT: ]
PATCH-CHPE-NEXT: CodeRangesToEntryPoints: 0
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: ]
Expand Down
Loading