Skip to content

Commit db7123f

Browse files
authored
[LLD][COFF] Use EC symbol table for CHPE metadata (#120328)
Copy CHPE metadata pointer from EC load config to native configuration.
1 parent 7144325 commit db7123f

8 files changed

+174
-26
lines changed

lld/COFF/Driver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2548,7 +2548,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
25482548
symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
25492549
symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
25502550

2551-
if (isArm64EC(ctx.config.machine)) {
2551+
if (symtab.isEC()) {
25522552
symtab.addAbsolute("__arm64x_extra_rfe_table", 0);
25532553
symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0);
25542554
symtab.addAbsolute("__arm64x_redirection_metadata", 0);

lld/COFF/Writer.cpp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) {
575575

576576
// Create a code map for CHPE metadata.
577577
void Writer::createECCodeMap() {
578-
if (!isArm64EC(ctx.config.machine))
578+
if (!ctx.symtabEC)
579579
return;
580580

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

612612
closeRange();
613613

614-
Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");
614+
Symbol *tableCountSym =
615+
ctx.symtabEC->findUnderscore("__hybrid_code_map_count");
615616
cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());
616617
}
617618

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

1232-
if (isArm64EC(config->machine))
1233-
createECChunks();
1233+
createECChunks();
12341234

12351235
if (config->autoImport)
12361236
createRuntimePseudoRelocs();
@@ -2158,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
21582158

21592159
// Create CHPE metadata chunks.
21602160
void Writer::createECChunks() {
2161-
for (Symbol *s : ctx.symtab.expSymbols) {
2161+
SymbolTable *symtab = ctx.symtabEC;
2162+
if (!symtab)
2163+
return;
2164+
2165+
for (Symbol *s : symtab->expSymbols) {
21622166
auto sym = dyn_cast<Defined>(s);
21632167
if (!sym || !sym->getChunk())
21642168
continue;
@@ -2177,9 +2181,9 @@ void Writer::createECChunks() {
21772181
// we should use the #foo$hp_target symbol as the redirection target.
21782182
// First, try to look up the $hp_target symbol. If it can't be found,
21792183
// assume it's a regular function and look for #foo instead.
2180-
Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str());
2184+
Symbol *targetSym = symtab->find((targetName + "$hp_target").str());
21812185
if (!targetSym)
2182-
targetSym = ctx.symtab.find(targetName);
2186+
targetSym = symtab->find(targetName);
21832187
Defined *t = dyn_cast_or_null<Defined>(targetSym);
21842188
if (t && isArm64EC(t->getChunk()->getMachine()))
21852189
exportThunks.push_back({chunk, t});
@@ -2188,20 +2192,20 @@ void Writer::createECChunks() {
21882192

21892193
auto codeMapChunk = make<ECCodeMapChunk>(codeMap);
21902194
rdataSec->addChunk(codeMapChunk);
2191-
Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");
2195+
Symbol *codeMapSym = symtab->findUnderscore("__hybrid_code_map");
21922196
replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),
21932197
codeMapChunk);
21942198

21952199
CHPECodeRangesChunk *ranges = make<CHPECodeRangesChunk>(exportThunks);
21962200
rdataSec->addChunk(ranges);
21972201
Symbol *rangesSym =
2198-
ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points");
2202+
symtab->findUnderscore("__x64_code_ranges_to_entry_points");
21992203
replaceSymbol<DefinedSynthetic>(rangesSym, rangesSym->getName(), ranges);
22002204

22012205
CHPERedirectionChunk *entryPoints = make<CHPERedirectionChunk>(exportThunks);
22022206
a64xrmSec->addChunk(entryPoints);
22032207
Symbol *entryPointsSym =
2204-
ctx.symtab.findUnderscore("__arm64x_redirection_metadata");
2208+
symtab->findUnderscore("__arm64x_redirection_metadata");
22052209
replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
22062210
entryPoints);
22072211
}
@@ -2294,53 +2298,54 @@ void Writer::setSectionPermissions() {
22942298

22952299
// Set symbols used by ARM64EC metadata.
22962300
void Writer::setECSymbols() {
2297-
if (!isArm64EC(ctx.config.machine))
2301+
SymbolTable *symtab = ctx.symtabEC;
2302+
if (!symtab)
22982303
return;
22992304

23002305
llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,
23012306
const std::pair<Chunk *, Defined *> &b) {
23022307
return a.first->getRVA() < b.first->getRVA();
23032308
});
23042309

2305-
Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");
2310+
Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table");
23062311
replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",
23072312
pdata.first);
23082313

23092314
if (pdata.first) {
23102315
Symbol *rfeSizeSym =
2311-
ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");
2316+
symtab->findUnderscore("__arm64x_extra_rfe_table_size");
23122317
cast<DefinedAbsolute>(rfeSizeSym)
23132318
->setVA(pdata.last->getRVA() + pdata.last->getSize() -
23142319
pdata.first->getRVA());
23152320
}
23162321

23172322
Symbol *rangesCountSym =
2318-
ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");
2323+
symtab->findUnderscore("__x64_code_ranges_to_entry_points_count");
23192324
cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());
23202325

23212326
Symbol *entryPointCountSym =
2322-
ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");
2327+
symtab->findUnderscore("__arm64x_redirection_metadata_count");
23232328
cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());
23242329

2325-
Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat");
2330+
Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat");
23262331
replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat",
23272332
idata.auxIat.empty() ? nullptr
23282333
: idata.auxIat.front());
23292334

2330-
Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy");
2335+
Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy");
23312336
replaceSymbol<DefinedSynthetic>(
23322337
iatCopySym, "__hybrid_auxiliary_iat_copy",
23332338
idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front());
23342339

23352340
Symbol *delayIatSym =
2336-
ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat");
2341+
symtab->findUnderscore("__hybrid_auxiliary_delayload_iat");
23372342
replaceSymbol<DefinedSynthetic>(
23382343
delayIatSym, "__hybrid_auxiliary_delayload_iat",
23392344
delayIdata.getAuxIat().empty() ? nullptr
23402345
: delayIdata.getAuxIat().front());
23412346

23422347
Symbol *delayIatCopySym =
2343-
ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
2348+
symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy");
23442349
replaceSymbol<DefinedSynthetic>(
23452350
delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",
23462351
delayIdata.getAuxIatCopy().empty() ? nullptr
@@ -2695,6 +2700,23 @@ void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
26952700
}
26962701
}
26972702

2703+
IF_CONTAINS(CHPEMetadataPointer) {
2704+
// On ARM64X, only the EC version of the load config contains
2705+
// CHPEMetadataPointer. Copy its value to the native load config.
2706+
if (ctx.hybridSymtab && !symtab.isEC() &&
2707+
ctx.hybridSymtab->loadConfigSize >=
2708+
offsetof(T, CHPEMetadataPointer) + sizeof(T::CHPEMetadataPointer)) {
2709+
OutputSection *sec =
2710+
ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk());
2711+
uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
2712+
auto hybridLoadConfig =
2713+
reinterpret_cast<const coff_load_configuration64 *>(
2714+
secBuf +
2715+
(ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA()));
2716+
loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer;
2717+
}
2718+
}
2719+
26982720
if (ctx.config.guardCF == GuardCFLevel::Off)
26992721
return;
27002722
RETURN_IF_NOT_CONTAINS(GuardFlags)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.section .rdata,"dr"
2+
.globl _load_config_used
3+
.p2align 3, 0
4+
_load_config_used:
5+
.word 0x140
6+
.fill 0x7c,1,0
7+
.xword __guard_fids_table
8+
.xword __guard_fids_count
9+
.xword __guard_flags
10+
.xword 0
11+
.xword __guard_iat_table
12+
.xword __guard_iat_count
13+
.xword __guard_longjmp_table
14+
.xword __guard_longjmp_count
15+
.fill 0x80,1,0

lld/test/COFF/arm64ec-codemap.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj
99
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.obj
1010
RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj
1111
RUN: llvm-mc -filetype=obj -triple=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj
12-
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj
12+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
1313
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
1414

1515
Link ARM64EC DLL and verify that the code is arranged as expected.

lld/test/COFF/arm64ec-entry-thunk.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ thunk:
2727
.rva func
2828

2929
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj
30-
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o native-loadcfg.obj
30+
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o native-loadcfg.obj
3131
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj
3232
// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj
3333
// RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s

lld/test/COFF/arm64ec-lib.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-alias.s -o ref-alias.obj
1111
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-thunk.s -o ref-thunk.obj
1212
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func.s -o func.obj
1313
RUN: llvm-mc -filetype=obj -triple=x86_64-windows func-x86_64.s -o func-x86_64.obj
14-
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj
14+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
1515
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
1616

1717
RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64.obj

lld/test/COFF/arm64ec-range-thunks.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows native-funcs.s -o funcs-aarch64.obj
66
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows space.s -o space-x86_64.obj
77
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows space.s -o space-aarch64.obj
8-
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj
8+
# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
99
# RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
1010

1111

lld/test/COFF/arm64x-loadconfig.s

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
// RUN: split-file %s %t.dir && cd %t.dir
33

44
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows test.s -o test.obj
5+
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows chpe.s -o chpe.obj
56
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig.s -o loadconfig.obj
7+
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-ec.s -o loadconfig-ec.obj
68
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig-short.s -o loadconfig-short.obj
79
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-short.s -o loadconfig-short-arm64ec.obj
810

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

11-
// RUN: llvm-readobj --coff-load-config out.dll | FileCheck -check-prefix=DYNRELOCS %s
13+
// RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=DYNRELOCS %s
1214
// DYNRELOCS: DynamicValueRelocTableOffset: 0xC
1315
// DYNRELOCS-NEXT: DynamicValueRelocTableSection: 4
1416
// DYNRELOCS: DynamicRelocations [
@@ -35,7 +37,7 @@
3537
// DYNRELOCS-NEXT: ]
3638
// DYNRELOCS-NEXT: ]
3739

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

52+
// Check that the CHPE metadata pointer is correctly copied from the EC load config to the native load config.
53+
54+
// RUN: lld-link -machine:arm64x -out:out-hyb.dll -dll -noentry loadconfig.obj loadconfig-ec.obj chpe.obj test.obj
55+
56+
// RUN: llvm-readobj --coff-load-config out-hyb.dll | FileCheck --check-prefix=LOADCFG %s
57+
// LOADCFG: Format: COFF-ARM64X
58+
// LOADCFG-NEXT: Arch: aarch64
59+
// LOADCFG-NEXT: AddressSize: 64bit
60+
// LOADCFG-NEXT: LoadConfig [
61+
// LOADCFG-NEXT: Size: 0x140
62+
// LOADCFG: CHPEMetadata [
63+
// LOADCFG-NEXT: Version: 0x2
64+
// LOADCFG: RedirectionMetadata: 12288
65+
// LOADCFG: AlternateEntryPoint: 0x0
66+
// LOADCFG-NEXT: AuxiliaryIAT: 0x0
67+
// LOADCFG-NEXT: GetX64InformationFunctionPointer: 0x0
68+
// LOADCFG-NEXT: SetX64InformationFunctionPointer: 0x0
69+
// LOADCFG-NEXT: ExtraRFETable: 0x0
70+
// LOADCFG-NEXT: ExtraRFETableSize: 0x0
71+
// LOADCFG-NEXT: __os_arm64x_dispatch_fptr: 0x0
72+
// LOADCFG-NEXT: AuxiliaryIATCopy: 0x0
73+
// LOADCFG-NEXT: AuxiliaryDelayloadIAT: 0x0
74+
// LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x0
75+
// LOADCFG-NEXT: HybridImageInfoBitfield: 0x0
76+
// LOADCFG: ]
77+
// LOADCFG-NEXT: DynamicRelocations [
78+
// LOADCFG-NEXT: Version: 0x1
79+
// LOADCFG-NEXT: Arm64X [
80+
// LOADCFG-NEXT: Entry [
81+
// LOADCFG-NEXT: RVA: 0x7C
82+
// LOADCFG-NEXT: Type: VALUE
83+
// LOADCFG-NEXT: Size: 0x2
84+
// LOADCFG-NEXT: Value: 0x8664
85+
// LOADCFG-NEXT: ]
86+
// LOADCFG-NEXT: Entry [
87+
// LOADCFG-NEXT: RVA: 0x150
88+
// LOADCFG-NEXT: Type: VALUE
89+
// LOADCFG-NEXT: Size: 0x4
90+
// LOADCFG-NEXT: Value: 0x0
91+
// LOADCFG-NEXT: ]
92+
// LOADCFG-NEXT: Entry [
93+
// LOADCFG-NEXT: RVA: 0x154
94+
// LOADCFG-NEXT: Type: VALUE
95+
// LOADCFG-NEXT: Size: 0x4
96+
// LOADCFG-NEXT: Value: 0x0
97+
// LOADCFG-NEXT: ]
98+
// LOADCFG-NEXT: ]
99+
// LOADCFG-NEXT: ]
100+
// LOADCFG-NEXT: HybridObject {
101+
// LOADCFG-NEXT: Format: COFF-x86-64
102+
// LOADCFG-NEXT: Arch: x86_64
103+
// LOADCFG-NEXT: AddressSize: 64bit
104+
105+
// RUN: llvm-readobj --coff-basereloc out-hyb.dll | FileCheck --check-prefix=BASERELOC %s
106+
// BASERELOC: BaseReloc [
107+
// BASERELOC-NEXT: Entry {
108+
// BASERELOC-NEXT: Type: DIR64
109+
// BASERELOC-NEXT: Address: 0x1208
110+
// BASERELOC-NEXT: }
111+
// BASERELOC-NEXT: Entry {
112+
// BASERELOC: Type: DIR64
113+
// BASERELOC-NEXT: Address: 0x2074
114+
// BASERELOC-NEXT: }
115+
50116
#--- test.s
51117
.data
52118
sym:
@@ -61,10 +127,55 @@ _load_config_used:
61127
.word 0x140
62128
.fill 0x13c,1,0
63129

130+
#--- loadconfig-ec.s
131+
.section .rdata,"dr"
132+
.globl _load_config_used
133+
.p2align 3, 0
134+
_load_config_used:
135+
.word 0x140
136+
.fill 0xc4,1,0
137+
.xword __chpe_metadata
138+
.fill 0x70,1,0
139+
64140
#--- loadconfig-short.s
65141
.section .rdata,"dr"
66142
.globl _load_config_used
67143
.p2align 3, 0
68144
_load_config_used:
69145
.word 0xe4
70146
.fill 0xe0,1,0
147+
148+
#--- chpe.s
149+
.data
150+
.globl __chpe_metadata
151+
.p2align 3, 0
152+
__chpe_metadata:
153+
.word 2
154+
.rva __hybrid_code_map
155+
.word __hybrid_code_map_count
156+
.rva __x64_code_ranges_to_entry_points
157+
.rva __arm64x_redirection_metadata
158+
.word 0 // __os_arm64x_dispatch_call_no_redirect
159+
.word 0 // __os_arm64x_dispatch_ret
160+
.word 0 // __os_arm64x_check_call
161+
.word 0 // __os_arm64x_check_icall
162+
.word 0 // __os_arm64x_check_icall_cfg
163+
.rva __arm64x_native_entrypoint
164+
.rva __hybrid_auxiliary_iat
165+
.word __x64_code_ranges_to_entry_points_count
166+
.word __arm64x_redirection_metadata_count
167+
.word 0 // __os_arm64x_get_x64_information
168+
.word 0 // __os_arm64x_set_x64_information
169+
.rva __arm64x_extra_rfe_table
170+
.word __arm64x_extra_rfe_table_size
171+
.word 0 // __os_arm64x_dispatch_fptr
172+
.rva __hybrid_auxiliary_iat_copy
173+
.rva __hybrid_auxiliary_delayload_iat
174+
.rva __hybrid_auxiliary_delayload_iat_copy
175+
.word __hybrid_image_info_bitfield
176+
.word 0 // __os_arm64x_helper3
177+
.word 0 // __os_arm64x_helper4
178+
.word 0 // __os_arm64x_helper5
179+
.word 0 // __os_arm64x_helper6
180+
.word 0 // __os_arm64x_helper7
181+
.word 0 // __os_arm64x_helper8

0 commit comments

Comments
 (0)