Skip to content

[LLD][COFF] Use EC symbol table for CHPE metadata #120328

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
Dec 29, 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
2 changes: 1 addition & 1 deletion lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2548,7 +2548,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);

if (isArm64EC(ctx.config.machine)) {
if (symtab.isEC()) {
symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
symtab.addAbsolute("__arm64x_redirection_metadata", 0);
Expand Down
60 changes: 41 additions & 19 deletions lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) {

// Create a code map for CHPE metadata.
void Writer::createECCodeMap() {
if (!isArm64EC(ctx.config.machine))
if (!ctx.symtabEC)
return;

// Clear the map in case we were're recomputing the map after adding
Expand Down Expand Up @@ -611,7 +611,8 @@ void Writer::createECCodeMap() {

closeRange();

Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");
Symbol *tableCountSym =
ctx.symtabEC->findUnderscore("__hybrid_code_map_count");
cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());
}

Expand Down Expand Up @@ -1229,8 +1230,7 @@ void Writer::createMiscChunks() {
// Create /guard:cf tables if requested.
createGuardCFTables();

if (isArm64EC(config->machine))
createECChunks();
createECChunks();

if (config->autoImport)
createRuntimePseudoRelocs();
Expand Down Expand Up @@ -2158,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,

// Create CHPE metadata chunks.
void Writer::createECChunks() {
for (Symbol *s : ctx.symtab.expSymbols) {
SymbolTable *symtab = ctx.symtabEC;
if (!symtab)
return;

for (Symbol *s : symtab->expSymbols) {
auto sym = dyn_cast<Defined>(s);
if (!sym || !sym->getChunk())
continue;
Expand All @@ -2177,9 +2181,9 @@ void Writer::createECChunks() {
// we should use the #foo$hp_target symbol as the redirection target.
// First, try to look up the $hp_target symbol. If it can't be found,
// assume it's a regular function and look for #foo instead.
Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str());
Symbol *targetSym = symtab->find((targetName + "$hp_target").str());
if (!targetSym)
targetSym = ctx.symtab.find(targetName);
targetSym = symtab->find(targetName);
Defined *t = dyn_cast_or_null<Defined>(targetSym);
if (t && isArm64EC(t->getChunk()->getMachine()))
exportThunks.push_back({chunk, t});
Expand All @@ -2188,20 +2192,20 @@ void Writer::createECChunks() {

auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
rdataSec->addChunk(codeMapChunk);
Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
Symbol *codeMapSym = 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");
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");
symtab->findUnderscore("__arm64x_redirection_metadata");
replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
entryPoints);
}
Expand Down Expand Up @@ -2294,53 +2298,54 @@ void Writer::setSectionPermissions() {

// Set symbols used by ARM64EC metadata.
void Writer::setECSymbols() {
if (!isArm64EC(ctx.config.machine))
SymbolTable *symtab = ctx.symtabEC;
if (!symtab)
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");
Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table");
replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
pdata.first);

if (pdata.first) {
Symbol *rfeSizeSym =
ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");
symtab->findUnderscore("__arm64x_extra_rfe_table_size");
cast<DefinedAbsolute>(rfeSizeSym)
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
pdata.first->getRVA());
}

Symbol *rangesCountSym =
ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
symtab->findUnderscore("__x64_code_ranges_to_entry_points_count");
cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());

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

Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat");
Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat");
replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat",
idata.auxIat.empty() ? nullptr
: idata.auxIat.front());

Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy");
Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy");
replaceSymbol<DefinedSynthetic>(
iatCopySym, "__hybrid_auxiliary_iat_copy",
idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front());

Symbol *delayIatSym =
ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat");
symtab->findUnderscore("__hybrid_auxiliary_delayload_iat");
replaceSymbol<DefinedSynthetic>(
delayIatSym, "__hybrid_auxiliary_delayload_iat",
delayIdata.getAuxIat().empty() ? nullptr
: delayIdata.getAuxIat().front());

Symbol *delayIatCopySym =
ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
replaceSymbol<DefinedSynthetic>(
delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",
delayIdata.getAuxIatCopy().empty() ? nullptr
Expand Down Expand Up @@ -2695,6 +2700,23 @@ void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
}
}

IF_CONTAINS(CHPEMetadataPointer) {
// On ARM64X, only the EC version of the load config contains
// CHPEMetadataPointer. Copy its value to the native load config.
if (ctx.hybridSymtab && !symtab.isEC() &&
ctx.hybridSymtab->loadConfigSize >=
offsetof(T, CHPEMetadataPointer) + sizeof(T::CHPEMetadataPointer)) {
OutputSection *sec =
ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk());
uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
auto hybridLoadConfig =
reinterpret_cast<const coff_load_configuration64 *>(
secBuf +
(ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA()));
loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer;
}
}

if (ctx.config.guardCF == GuardCFLevel::Off)
return;
RETURN_IF_NOT_CONTAINS(GuardFlags)
Expand Down
15 changes: 15 additions & 0 deletions lld/test/COFF/Inputs/loadconfig-arm64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.section .rdata,"dr"
.globl _load_config_used
.p2align 3, 0
_load_config_used:
.word 0x140
.fill 0x7c,1,0
.xword __guard_fids_table
.xword __guard_fids_count
.xword __guard_flags
.xword 0
.xword __guard_iat_table
.xword __guard_iat_count
.xword __guard_longjmp_table
.xword __guard_longjmp_count
.fill 0x80,1,0
2 changes: 1 addition & 1 deletion lld/test/COFF/arm64ec-codemap.test
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.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=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj

Link ARM64EC DLL and verify that the code is arranged as expected.
Expand Down
2 changes: 1 addition & 1 deletion lld/test/COFF/arm64ec-entry-thunk.s
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ thunk:
.rva func

// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o native-loadcfg.obj
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o native-loadcfg.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj
// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj
// RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s
Expand Down
2 changes: 1 addition & 1 deletion lld/test/COFF/arm64ec-lib.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-alias.s -o ref-alias.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-thunk.s -o ref-thunk.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func.s -o func.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows func-x86_64.s -o func-x86_64.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj

RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64.obj
Expand Down
2 changes: 1 addition & 1 deletion lld/test/COFF/arm64ec-range-thunks.s
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows native-funcs.s -o funcs-aarch64.obj
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows space.s -o space-x86_64.obj
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows space.s -o space-aarch64.obj
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.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 %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj


Expand Down
115 changes: 113 additions & 2 deletions lld/test/COFF/arm64x-loadconfig.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
// RUN: split-file %s %t.dir && cd %t.dir

// RUN: llvm-mc -filetype=obj -triple=aarch64-windows test.s -o test.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows chpe.s -o chpe.obj
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig.s -o loadconfig.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-ec.s -o loadconfig-ec.obj
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig-short.s -o loadconfig-short.obj
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-short.s -o loadconfig-short-arm64ec.obj

// RUN: lld-link -machine:arm64x -out:out.dll -dll -noentry loadconfig.obj test.obj

// RUN: llvm-readobj --coff-load-config out.dll | FileCheck -check-prefix=DYNRELOCS %s
// RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=DYNRELOCS %s
// DYNRELOCS: DynamicValueRelocTableOffset: 0xC
// DYNRELOCS-NEXT: DynamicValueRelocTableSection: 4
// DYNRELOCS: DynamicRelocations [
Expand All @@ -35,7 +37,7 @@
// DYNRELOCS-NEXT: ]
// DYNRELOCS-NEXT: ]

// RUN: llvm-readobj --headers out.dll | FileCheck -check-prefix=HEADERS %s
// RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=HEADERS %s
// HEADERS: BaseRelocationTableRVA: 0x4000
// HEADERS-NEXT: BaseRelocationTableSize: 0xC
// HEADERS: LoadConfigTableRVA: 0x1000
Expand All @@ -47,6 +49,70 @@
// RUN: lld-link -machine:arm64x -out:out-short.dll -dll -noentry loadconfig-short-arm64ec.obj 2>&1 | FileCheck --check-prefix=WARN-RELOC-SIZE %s
// WARN-RELOC-SIZE: lld-link: warning: '_load_config_used' structure too small to include dynamic relocations

// Check that the CHPE metadata pointer is correctly copied from the EC load config to the native load config.

// RUN: lld-link -machine:arm64x -out:out-hyb.dll -dll -noentry loadconfig.obj loadconfig-ec.obj chpe.obj test.obj

// RUN: llvm-readobj --coff-load-config out-hyb.dll | FileCheck --check-prefix=LOADCFG %s
// LOADCFG: Format: COFF-ARM64X
// LOADCFG-NEXT: Arch: aarch64
// LOADCFG-NEXT: AddressSize: 64bit
// LOADCFG-NEXT: LoadConfig [
// LOADCFG-NEXT: Size: 0x140
// LOADCFG: CHPEMetadata [
// LOADCFG-NEXT: Version: 0x2
// LOADCFG: RedirectionMetadata: 12288
// LOADCFG: AlternateEntryPoint: 0x0
// LOADCFG-NEXT: AuxiliaryIAT: 0x0
// LOADCFG-NEXT: GetX64InformationFunctionPointer: 0x0
// LOADCFG-NEXT: SetX64InformationFunctionPointer: 0x0
// LOADCFG-NEXT: ExtraRFETable: 0x0
// LOADCFG-NEXT: ExtraRFETableSize: 0x0
// LOADCFG-NEXT: __os_arm64x_dispatch_fptr: 0x0
// LOADCFG-NEXT: AuxiliaryIATCopy: 0x0
// LOADCFG-NEXT: AuxiliaryDelayloadIAT: 0x0
// LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x0
// LOADCFG-NEXT: HybridImageInfoBitfield: 0x0
// LOADCFG: ]
// LOADCFG-NEXT: DynamicRelocations [
// LOADCFG-NEXT: Version: 0x1
// LOADCFG-NEXT: Arm64X [
// LOADCFG-NEXT: Entry [
// LOADCFG-NEXT: RVA: 0x7C
// LOADCFG-NEXT: Type: VALUE
// LOADCFG-NEXT: Size: 0x2
// LOADCFG-NEXT: Value: 0x8664
// LOADCFG-NEXT: ]
// LOADCFG-NEXT: Entry [
// LOADCFG-NEXT: RVA: 0x150
// LOADCFG-NEXT: Type: VALUE
// LOADCFG-NEXT: Size: 0x4
// LOADCFG-NEXT: Value: 0x0
// LOADCFG-NEXT: ]
// LOADCFG-NEXT: Entry [
// LOADCFG-NEXT: RVA: 0x154
// LOADCFG-NEXT: Type: VALUE
// LOADCFG-NEXT: Size: 0x4
// LOADCFG-NEXT: Value: 0x0
// LOADCFG-NEXT: ]
// LOADCFG-NEXT: ]
// LOADCFG-NEXT: ]
// LOADCFG-NEXT: HybridObject {
// LOADCFG-NEXT: Format: COFF-x86-64
// LOADCFG-NEXT: Arch: x86_64
// LOADCFG-NEXT: AddressSize: 64bit

// RUN: llvm-readobj --coff-basereloc out-hyb.dll | FileCheck --check-prefix=BASERELOC %s
// BASERELOC: BaseReloc [
// BASERELOC-NEXT: Entry {
// BASERELOC-NEXT: Type: DIR64
// BASERELOC-NEXT: Address: 0x1208
// BASERELOC-NEXT: }
// BASERELOC-NEXT: Entry {
// BASERELOC: Type: DIR64
// BASERELOC-NEXT: Address: 0x2074
// BASERELOC-NEXT: }

#--- test.s
.data
sym:
Expand All @@ -61,10 +127,55 @@ _load_config_used:
.word 0x140
.fill 0x13c,1,0

#--- loadconfig-ec.s
.section .rdata,"dr"
.globl _load_config_used
.p2align 3, 0
_load_config_used:
.word 0x140
.fill 0xc4,1,0
.xword __chpe_metadata
.fill 0x70,1,0

#--- loadconfig-short.s
.section .rdata,"dr"
.globl _load_config_used
.p2align 3, 0
_load_config_used:
.word 0xe4
.fill 0xe0,1,0

#--- chpe.s
.data
.globl __chpe_metadata
.p2align 3, 0
__chpe_metadata:
.word 2
.rva __hybrid_code_map
.word __hybrid_code_map_count
.rva __x64_code_ranges_to_entry_points
.rva __arm64x_redirection_metadata
.word 0 // __os_arm64x_dispatch_call_no_redirect
.word 0 // __os_arm64x_dispatch_ret
.word 0 // __os_arm64x_check_call
.word 0 // __os_arm64x_check_icall
.word 0 // __os_arm64x_check_icall_cfg
.rva __arm64x_native_entrypoint
.rva __hybrid_auxiliary_iat
.word __x64_code_ranges_to_entry_points_count
.word __arm64x_redirection_metadata_count
.word 0 // __os_arm64x_get_x64_information
.word 0 // __os_arm64x_set_x64_information
.rva __arm64x_extra_rfe_table
.word __arm64x_extra_rfe_table_size
.word 0 // __os_arm64x_dispatch_fptr
.rva __hybrid_auxiliary_iat_copy
.rva __hybrid_auxiliary_delayload_iat
.rva __hybrid_auxiliary_delayload_iat_copy
.word __hybrid_image_info_bitfield
.word 0 // __os_arm64x_helper3
.word 0 // __os_arm64x_helper4
.word 0 // __os_arm64x_helper5
.word 0 // __os_arm64x_helper6
.word 0 // __os_arm64x_helper7
.word 0 // __os_arm64x_helper8
Loading