Skip to content

Commit d004947

Browse files
authored
[LLD][COFF] Add support for hybrid ARM64X entry points (#123096)
Store the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables.
1 parent b7e2014 commit d004947

File tree

6 files changed

+128
-23
lines changed

6 files changed

+128
-23
lines changed

lld/COFF/Config.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ struct Configuration {
120120
size_t wordsize;
121121
bool verbose = false;
122122
WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
123-
Symbol *entry = nullptr;
124123
bool noEntry = false;
125124
std::string outputFile;
126125
std::string importName;

lld/COFF/Driver.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
491491
case OPT_entry:
492492
if (!arg->getValue()[0])
493493
Fatal(ctx) << "missing entry point symbol name";
494-
ctx.config.entry =
495-
file->symtab.addGCRoot(file->symtab.mangle(arg->getValue()), true);
494+
ctx.forEachSymtab([&](SymbolTable &symtab) {
495+
symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
496+
});
496497
break;
497498
case OPT_failifmismatch:
498499
checkFailIfMismatch(arg->getValue(), file);
@@ -1394,8 +1395,9 @@ void LinkerDriver::createECExportThunks() {
13941395
}
13951396
}
13961397

1397-
if (ctx.config.entry)
1398-
maybeCreateECExportThunk(ctx.config.entry->getName(), ctx.config.entry);
1398+
if (ctx.symtabEC->entry)
1399+
maybeCreateECExportThunk(ctx.symtabEC->entry->getName(),
1400+
ctx.symtabEC->entry);
13991401
for (Export &e : ctx.config.exports) {
14001402
if (!e.data)
14011403
maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym);
@@ -2357,33 +2359,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
23572359
}
23582360

23592361
// Handle /entry and /dll
2360-
{
2362+
ctx.forEachSymtab([&](SymbolTable &symtab) {
23612363
llvm::TimeTraceScope timeScope("Entry point");
23622364
if (auto *arg = args.getLastArg(OPT_entry)) {
23632365
if (!arg->getValue()[0])
23642366
Fatal(ctx) << "missing entry point symbol name";
2365-
config->entry =
2366-
ctx.symtab.addGCRoot(ctx.symtab.mangle(arg->getValue()), true);
2367-
} else if (!config->entry && !config->noEntry) {
2367+
symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
2368+
} else if (!symtab.entry && !config->noEntry) {
23682369
if (args.hasArg(OPT_dll)) {
23692370
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
23702371
: "_DllMainCRTStartup";
2371-
config->entry = ctx.symtab.addGCRoot(s, true);
2372+
symtab.entry = symtab.addGCRoot(s, true);
23722373
} else if (config->driverWdm) {
23732374
// /driver:wdm implies /entry:_NtProcessStartup
2374-
config->entry =
2375-
ctx.symtab.addGCRoot(ctx.symtab.mangle("_NtProcessStartup"), true);
2375+
symtab.entry =
2376+
symtab.addGCRoot(symtab.mangle("_NtProcessStartup"), true);
23762377
} else {
23772378
// Windows specific -- If entry point name is not given, we need to
23782379
// infer that from user-defined entry name.
2379-
StringRef s = ctx.symtab.findDefaultEntry();
2380+
StringRef s = symtab.findDefaultEntry();
23802381
if (s.empty())
23812382
Fatal(ctx) << "entry point must be defined";
2382-
config->entry = ctx.symtab.addGCRoot(s, true);
2383+
symtab.entry = symtab.addGCRoot(s, true);
23832384
Log(ctx) << "Entry name inferred: " << s;
23842385
}
23852386
}
2386-
}
2387+
});
23872388

23882389
// Handle /delayload
23892390
{
@@ -2522,10 +2523,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
25222523
{
25232524
llvm::TimeTraceScope timeScope("Add unresolved symbols");
25242525
do {
2525-
// Windows specific -- if entry point is not found,
2526-
// search for its mangled names.
2527-
if (config->entry)
2528-
ctx.symtab.mangleMaybe(config->entry);
2526+
ctx.forEachSymtab([&](SymbolTable &symtab) {
2527+
// Windows specific -- if entry point is not found,
2528+
// search for its mangled names.
2529+
if (symtab.entry)
2530+
symtab.mangleMaybe(symtab.entry);
2531+
});
25292532

25302533
// Windows specific -- Make sure we resolve all dllexported symbols.
25312534
for (Export &e : config->exports) {

lld/COFF/MapFile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
301301
uint64_t entryAddress = 0;
302302

303303
if (!ctx.config.noEntry) {
304-
Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
304+
Defined *entry = dyn_cast_or_null<Defined>(ctx.symtab.entry);
305305
if (entry) {
306306
Chunk *chunk = entry->getChunk();
307307
entrySecIndex = chunk->getOutputSectionIdx();

lld/COFF/SymbolTable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ class SymbolTable {
143143

144144
bool isEC() const { return machine == ARM64EC; }
145145

146+
// An entry point symbol.
147+
Symbol *entry = nullptr;
148+
146149
// A list of chunks which to be added to .rdata.
147150
std::vector<Chunk *> localImportChunks;
148151

lld/COFF/Writer.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
17481748
pe->SizeOfImage = sizeOfImage;
17491749
pe->SizeOfHeaders = sizeOfHeaders;
17501750
if (!config->noEntry) {
1751-
Defined *entry = cast<Defined>(config->entry);
1751+
Defined *entry = cast<Defined>(ctx.symtab.entry);
17521752
pe->AddressOfEntryPoint = entry->getRVA();
17531753
// Pointer to thumb code must have the LSB set, so adjust it.
17541754
if (config->machine == ARMNT)
@@ -2031,8 +2031,10 @@ void Writer::createGuardCFTables() {
20312031
}
20322032

20332033
// Mark the image entry as address-taken.
2034-
if (config->entry)
2035-
maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
2034+
ctx.forEachSymtab([&](SymbolTable &symtab) {
2035+
if (symtab.entry)
2036+
maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry);
2037+
});
20362038

20372039
// Mark exported symbols in executable sections as address-taken.
20382040
for (Export &e : config->exports)
@@ -2584,6 +2586,12 @@ void Writer::createDynamicRelocs() {
25842586
coffHeaderOffset + offsetof(coff_file_header, Machine),
25852587
AMD64);
25862588

2589+
if (ctx.symtab.entry != ctx.hybridSymtab->entry)
2590+
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
2591+
peHeaderOffset +
2592+
offsetof(pe32plus_header, AddressOfEntryPoint),
2593+
cast_or_null<Defined>(ctx.hybridSymtab->entry));
2594+
25872595
// Set the hybrid load config to the EC load config.
25882596
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
25892597
dataDirOffset64 +

lld/test/COFF/arm64x-entry.test

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
REQUIRES: aarch64, x86
2+
RUN: split-file %s %t.dir && cd %t.dir
3+
4+
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj
5+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj
6+
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj
7+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
8+
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj
9+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj
10+
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
11+
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
12+
13+
RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \
14+
RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
15+
16+
RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
17+
DISASM: Disassembly of section .text:
18+
DISASM-EMPTY:
19+
DISASM-NEXT: 0000000180001000 <.text>:
20+
DISASM-NEXT: 180001000: 52800020 mov w0, #0x1 // =1
21+
DISASM-NEXT: 180001004: d65f03c0 ret
22+
DISASM-NEXT: ...
23+
DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
24+
DISASM-NEXT: 180002004: d65f03c0 ret
25+
DISASM-EMPTY:
26+
DISASM-NEXT: Disassembly of section .hexpthk:
27+
DISASM-EMPTY:
28+
DISASM-NEXT: 0000000180003000 <.hexpthk>:
29+
DISASM-NEXT: 180003000: 48 8b c4 movq %rsp, %rax
30+
DISASM-NEXT: 180003003: 48 89 58 20 movq %rbx, 0x20(%rax)
31+
DISASM-NEXT: 180003007: 55 pushq %rbp
32+
DISASM-NEXT: 180003008: 5d popq %rbp
33+
DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+0x1000>
34+
DISASM-NEXT: 18000300e: cc int3
35+
DISASM-NEXT: 18000300f: cc int3
36+
37+
RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s
38+
READOBJ: AddressOfEntryPoint: 0x1000
39+
READOBJ: HybridObject {
40+
READOBJ: AddressOfEntryPoint: 0x3000
41+
READOBJ: }
42+
43+
RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \
44+
RUN: arm64ec-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
45+
RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
46+
RUN: llvm-readobj --headers --coff-load-config out2.dll | FileCheck --check-prefix=READOBJ %s
47+
48+
RUN: lld-link -machine:arm64x -dll -out:out3.dll arm64ec-func.obj arm64-func.obj \
49+
RUN: arm64-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
50+
RUN: llvm-objdump -d out3.dll | FileCheck --check-prefix=DISASM %s
51+
RUN: llvm-readobj --headers --coff-load-config out3.dll | FileCheck --check-prefix=READOBJ %s
52+
53+
RUN: lld-link -machine:arm64x -dll -out:out4.dll arm64ec-func.obj arm64-func.obj \
54+
RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func
55+
RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
56+
RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s
57+
58+
#--- arm64-dllmain.s
59+
.section .text,"xr",discard,_DllMainCRTStartup
60+
.globl _DllMainCRTStartup
61+
.p2align 2
62+
_DllMainCRTStartup:
63+
mov w0, #1
64+
ret
65+
66+
#--- arm64ec-dllmain.s
67+
.section .text,"xr",discard,_DllMainCRTStartup
68+
.globl _DllMainCRTStartup
69+
.p2align 2
70+
_DllMainCRTStartup:
71+
mov w0, #2
72+
ret
73+
74+
#--- arm64-func.s
75+
.section .text,"xr",discard,func
76+
.globl func
77+
.p2align 2
78+
func:
79+
mov w0, #1
80+
ret
81+
82+
#--- arm64ec-func.s
83+
.section .text,"xr",discard,func
84+
.globl func
85+
.p2align 2
86+
func:
87+
mov w0, #2
88+
ret
89+
90+
#--- arm64-drectve.s
91+
.section .drectve
92+
.ascii "-entry:func"

0 commit comments

Comments
 (0)