Skip to content

Commit

Permalink
[LLD][COFF] Add support for CHPE redirection metadata. (llvm#105739)
Browse files Browse the repository at this point in the history
This is part of CHPE metadata containing a sorted list of x86_64 export
thunks RVAs and RVAs of ARM64EC functions associated with them. It's
stored in a dedicated .a64xrm section.
  • Loading branch information
cjacek committed Aug 23, 2024
1 parent 57b89fd commit caa844e
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 6 deletions.
13 changes: 13 additions & 0 deletions lld/COFF/Chunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,4 +1078,17 @@ void ECExportThunkChunk::writeTo(uint8_t *buf) const {
write32le(buf + 10, target->getRVA() - rva - 14);
}

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
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 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)
Expand Down
2 changes: 2 additions & 0 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2440,6 +2440,8 @@ 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);
}
Expand Down
26 changes: 25 additions & 1 deletion lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -312,6 +315,7 @@ class Writer {
OutputSection *idataSec;
OutputSection *edataSec;
OutputSection *didatSec;
OutputSection *a64xrmSec;
OutputSection *rsrcSec;
OutputSection *relocSec;
OutputSection *ctorsSec;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2053,15 +2059,24 @@ 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);
rdataSec->addChunk(codeMapChunk);
Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),
codeMapChunk);

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
Expand Down Expand Up @@ -2154,6 +2169,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);
Expand All @@ -2165,6 +2185,10 @@ void Writer::setECSymbols() {
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
pdata.first->getRVA());
}

Symbol *entryPointCountSym =
ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
}

// Write section contents to a mmap'ed file.
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 @@ -67,7 +67,7 @@ __chpe_metadata:
.rva __hybrid_code_map
.word __hybrid_code_map_count
.word 0 // __x64_code_ranges_to_entry_points
.word 0 //__arm64x_redirection_metadata
.rva __arm64x_redirection_metadata
.rva __os_arm64x_dispatch_call_no_redirect
.rva __os_arm64x_dispatch_ret
.rva __os_arm64x_check_call
Expand All @@ -76,7 +76,7 @@ __chpe_metadata:
.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 __arm64x_redirection_metadata_count
.rva __os_arm64x_get_x64_information
.rva __os_arm64x_set_x64_information
.rva __arm64x_extra_rfe_table
Expand Down
29 changes: 27 additions & 2 deletions lld/test/COFF/arm64ec-export-thunks.test
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -58,9 +58,30 @@ 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: 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 \
Expand Down Expand Up @@ -100,6 +121,10 @@ 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: RedirectionMetadata [
ENTRY-CHPE-NEXT: 0x2000 -> 0x1000
ENTRY-CHPE-NEXT: ]


Test exporting data symbol as a function:
Expand Down
6 changes: 5 additions & 1 deletion lld/test/COFF/arm64ec-patchable-thunks.test
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ 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: 0
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
Expand Down

0 comments on commit caa844e

Please sign in to comment.