Skip to content

Commit a16adaf

Browse files
authored
[LLD][COFF] Add support for alternate entry point in CHPE metadata on ARM64X (#123346)
Includes handling for ARM64X relocations relative to a symbol.
1 parent 5a7a324 commit a16adaf

File tree

5 files changed

+131
-20
lines changed

5 files changed

+131
-20
lines changed

lld/COFF/Chunks.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ size_t Arm64XDynamicRelocEntry::getSize() const {
11831183

11841184
void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const {
11851185
auto out = reinterpret_cast<ulittle16_t *>(buf);
1186-
*out = (offset & 0xfff) | (type << 12);
1186+
*out = (offset.get() & 0xfff) | (type << 12);
11871187

11881188
switch (type) {
11891189
case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:
@@ -1211,14 +1211,19 @@ void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const {
12111211
void DynamicRelocsChunk::finalize() {
12121212
llvm::stable_sort(arm64xRelocs, [=](const Arm64XDynamicRelocEntry &a,
12131213
const Arm64XDynamicRelocEntry &b) {
1214-
return a.offset < b.offset;
1214+
return a.offset.get() < b.offset.get();
12151215
});
12161216

1217-
size = sizeof(coff_dynamic_reloc_table) + sizeof(coff_dynamic_relocation64) +
1218-
sizeof(coff_base_reloc_block_header);
1217+
size = sizeof(coff_dynamic_reloc_table) + sizeof(coff_dynamic_relocation64);
1218+
uint32_t prevPage = 0xfff;
12191219

12201220
for (const Arm64XDynamicRelocEntry &entry : arm64xRelocs) {
1221-
assert(!(entry.offset & ~0xfff)); // Not yet supported.
1221+
uint32_t page = entry.offset.get() & ~0xfff;
1222+
if (page != prevPage) {
1223+
size = alignTo(size, sizeof(uint32_t)) +
1224+
sizeof(coff_base_reloc_block_header);
1225+
prevPage = page;
1226+
}
12221227
size += entry.getSize();
12231228
}
12241229

@@ -1235,17 +1240,31 @@ void DynamicRelocsChunk::writeTo(uint8_t *buf) const {
12351240
header->Symbol = IMAGE_DYNAMIC_RELOCATION_ARM64X;
12361241
buf += sizeof(*header);
12371242

1238-
auto pageHeader = reinterpret_cast<coff_base_reloc_block_header *>(buf);
1239-
pageHeader->BlockSize = sizeof(*pageHeader);
1243+
coff_base_reloc_block_header *pageHeader = nullptr;
1244+
size_t relocSize = 0;
12401245
for (const Arm64XDynamicRelocEntry &entry : arm64xRelocs) {
1241-
entry.writeTo(buf + pageHeader->BlockSize);
1242-
pageHeader->BlockSize += entry.getSize();
1246+
uint32_t page = entry.offset.get() & ~0xfff;
1247+
if (!pageHeader || page != pageHeader->PageRVA) {
1248+
relocSize = alignTo(relocSize, sizeof(uint32_t));
1249+
if (pageHeader)
1250+
pageHeader->BlockSize =
1251+
buf + relocSize - reinterpret_cast<uint8_t *>(pageHeader);
1252+
pageHeader =
1253+
reinterpret_cast<coff_base_reloc_block_header *>(buf + relocSize);
1254+
pageHeader->PageRVA = page;
1255+
relocSize += sizeof(*pageHeader);
1256+
}
1257+
1258+
entry.writeTo(buf + relocSize);
1259+
relocSize += entry.getSize();
12431260
}
1244-
pageHeader->BlockSize = alignTo(pageHeader->BlockSize, sizeof(uint32_t));
1261+
relocSize = alignTo(relocSize, sizeof(uint32_t));
1262+
pageHeader->BlockSize =
1263+
buf + relocSize - reinterpret_cast<uint8_t *>(pageHeader);
12451264

1246-
header->BaseRelocSize = pageHeader->BlockSize;
1247-
table->Size += header->BaseRelocSize;
1248-
assert(size == sizeof(*table) + sizeof(*header) + header->BaseRelocSize);
1265+
header->BaseRelocSize = relocSize;
1266+
table->Size += relocSize;
1267+
assert(size == sizeof(*table) + sizeof(*header) + relocSize);
12491268
}
12501269

12511270
} // namespace lld::coff

lld/COFF/Chunks.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -851,13 +851,13 @@ class Arm64XRelocVal {
851851
class Arm64XDynamicRelocEntry {
852852
public:
853853
Arm64XDynamicRelocEntry(llvm::COFF::Arm64XFixupType type, uint8_t size,
854-
uint32_t offset, Arm64XRelocVal value)
854+
Arm64XRelocVal offset, Arm64XRelocVal value)
855855
: offset(offset), value(value), type(type), size(size) {}
856856

857857
size_t getSize() const;
858858
void writeTo(uint8_t *buf) const;
859859

860-
uint32_t offset;
860+
Arm64XRelocVal offset;
861861
Arm64XRelocVal value;
862862

863863
private:
@@ -873,8 +873,8 @@ class DynamicRelocsChunk : public NonSectionChunk {
873873
void writeTo(uint8_t *buf) const override;
874874
void finalize();
875875

876-
void add(llvm::COFF::Arm64XFixupType type, uint8_t size, uint32_t offset,
877-
Arm64XRelocVal value) {
876+
void add(llvm::COFF::Arm64XFixupType type, uint8_t size,
877+
Arm64XRelocVal offset, Arm64XRelocVal value) {
878878
arm64xRelocs.emplace_back(type, size, offset, value);
879879
}
880880

lld/COFF/Symbols.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ bool Symbol::isLive() const {
100100
return true;
101101
}
102102

103-
// MinGW specific.
104103
void Symbol::replaceKeepingName(Symbol *other, size_t size) {
105104
StringRef origName = getName();
106105
memcpy(this, other, size);

lld/COFF/Writer.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,20 @@ void Writer::setECSymbols() {
23522352
delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",
23532353
delayIdata.getAuxIatCopy().empty() ? nullptr
23542354
: delayIdata.getAuxIatCopy().front());
2355+
2356+
if (ctx.hybridSymtab) {
2357+
// For the hybrid image, set the alternate entry point to the EC entry
2358+
// point. In the hybrid view, it is swapped to the native entry point
2359+
// using ARM64X relocations.
2360+
if (auto altEntrySym = cast_or_null<Defined>(ctx.hybridSymtab->entry)) {
2361+
// If the entry is an EC export thunk, use its target instead.
2362+
if (auto thunkChunk =
2363+
dyn_cast<ECExportThunkChunk>(altEntrySym->getChunk()))
2364+
altEntrySym = thunkChunk->target;
2365+
symtab->findUnderscore("__arm64x_native_entrypoint")
2366+
->replaceKeepingName(altEntrySym, sizeof(SymbolUnion));
2367+
}
2368+
}
23552369
}
23562370

23572371
// Write section contents to a mmap'ed file.
@@ -2586,12 +2600,23 @@ void Writer::createDynamicRelocs() {
25862600
coffHeaderOffset + offsetof(coff_file_header, Machine),
25872601
AMD64);
25882602

2589-
if (ctx.symtab.entry != ctx.hybridSymtab->entry)
2603+
if (ctx.symtab.entry != ctx.hybridSymtab->entry) {
25902604
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
25912605
peHeaderOffset +
25922606
offsetof(pe32plus_header, AddressOfEntryPoint),
25932607
cast_or_null<Defined>(ctx.hybridSymtab->entry));
25942608

2609+
// Swap the alternate entry point in the CHPE metadata.
2610+
Symbol *s = ctx.hybridSymtab->findUnderscore("__chpe_metadata");
2611+
if (auto chpeSym = cast_or_null<DefinedRegular>(s))
2612+
ctx.dynamicRelocs->add(
2613+
IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
2614+
Arm64XRelocVal(chpeSym, offsetof(chpe_metadata, AlternateEntryPoint)),
2615+
cast_or_null<Defined>(ctx.symtab.entry));
2616+
else
2617+
Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target";
2618+
}
2619+
25952620
// Set the hybrid load config to the EC load config.
25962621
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
25972622
dataDirOffset64 +

lld/test/COFF/arm64x-entry.test

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ RUN: split-file %s %t.dir && cd %t.dir
33

44
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj
55
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj
6+
RUN: llvm-mc -filetype=obj -triple=x86_64-windows amd64-dllmain.s -o amd64-dllmain.obj
67
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj
78
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
89
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj
910
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj
1011
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
1112
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
13+
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-min.s -o loadconfig-min.obj
1214

1315
RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \
1416
RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
@@ -34,10 +36,12 @@ DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+
3436
DISASM-NEXT: 18000300e: cc int3
3537
DISASM-NEXT: 18000300f: cc int3
3638

37-
RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s
39+
RUN: llvm-readobj --headers --coff-load-config out.dll | FileCheck --check-prefix=READOBJ %s
3840
READOBJ: AddressOfEntryPoint: 0x1000
41+
READOBJ: AlternateEntryPoint: 0x2000
3942
READOBJ: HybridObject {
4043
READOBJ: AddressOfEntryPoint: 0x3000
44+
READOBJ: AlternateEntryPoint: 0x1000
4145
READOBJ: }
4246

4347
RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \
@@ -55,6 +59,20 @@ RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func
5559
RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
5660
RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s
5761

62+
RUN: lld-link -machine:arm64x -dll -out:out-x86.dll amd64-dllmain.obj arm64-dllmain.obj \
63+
RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
64+
RUN: llvm-readobj --headers --coff-load-config out-x86.dll | FileCheck --check-prefix=READOBJ-X86 %s
65+
READOBJ-X86: AddressOfEntryPoint: 0x1000
66+
READOBJ-X86: AlternateEntryPoint: 0x2000
67+
READOBJ-X86: HybridObject {
68+
READOBJ-X86: AddressOfEntryPoint: 0x2000
69+
READOBJ-X86: AlternateEntryPoint: 0x1000
70+
READOBJ-X86: }
71+
72+
RUN: lld-link -machine:arm64x -dll -out:out-warn.dll arm64ec-dllmain.obj arm64-dllmain.obj \
73+
RUN: loadconfig-arm64.obj loadconfig-min.obj 2>&1 | FileCheck --check-prefix=WARN %s
74+
WARN: lld-link: warning: '__chpe_metadata' is missing for ARM64X target
75+
5876
#--- arm64-dllmain.s
5977
.section .text,"xr",discard,_DllMainCRTStartup
6078
.globl _DllMainCRTStartup
@@ -87,6 +105,56 @@ func:
87105
mov w0, #2
88106
ret
89107

108+
#--- amd64-dllmain.s
109+
.section .text,"xr",discard,_DllMainCRTStartup
110+
.globl _DllMainCRTStartup
111+
.p2align 2
112+
_DllMainCRTStartup:
113+
movl $3, %eax
114+
retq
115+
90116
#--- arm64-drectve.s
91117
.section .drectve
92118
.ascii "-entry:func"
119+
120+
#--- loadconfig-min.s
121+
.section .rdata,"dr"
122+
.globl _load_config_used
123+
.p2align 3, 0
124+
_load_config_used:
125+
.word 0x140
126+
.fill 0xc4,1,0
127+
.xword chpe_metadata
128+
.fill 0x70,1,0
129+
130+
.p2align 3, 0
131+
chpe_metadata:
132+
.word 2
133+
.rva __hybrid_code_map
134+
.word __hybrid_code_map_count
135+
.rva __x64_code_ranges_to_entry_points
136+
.rva __arm64x_redirection_metadata
137+
.word 0 // __os_arm64x_dispatch_call_no_redirect
138+
.word 0 // __os_arm64x_dispatch_ret
139+
.word 0 // __os_arm64x_check_call
140+
.word 0 // __os_arm64x_check_icall
141+
.word 0 // __os_arm64x_check_icall_cfg
142+
.rva __arm64x_native_entrypoint
143+
.rva __hybrid_auxiliary_iat
144+
.word __x64_code_ranges_to_entry_points_count
145+
.word __arm64x_redirection_metadata_count
146+
.word 0 // __os_arm64x_get_x64_information
147+
.word 0 // __os_arm64x_set_x64_information
148+
.rva __arm64x_extra_rfe_table
149+
.word __arm64x_extra_rfe_table_size
150+
.word 0 // __os_arm64x_dispatch_fptr
151+
.rva __hybrid_auxiliary_iat_copy
152+
.rva __hybrid_auxiliary_delayload_iat
153+
.rva __hybrid_auxiliary_delayload_iat_copy
154+
.word __hybrid_image_info_bitfield
155+
.word 0 // __os_arm64x_helper3
156+
.word 0 // __os_arm64x_helper4
157+
.word 0 // __os_arm64x_helper5
158+
.word 0 // __os_arm64x_helper6
159+
.word 0 // __os_arm64x_helper7
160+
.word 0 // __os_arm64x_helper8

0 commit comments

Comments
 (0)