-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLD][COFF] Add support for hybrid ARM64X entry points #123096
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
Conversation
Store the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables.
@llvm/pr-subscribers-lld Author: Jacek Caban (cjacek) ChangesStore the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables. Full diff: https://github.com/llvm/llvm-project/pull/123096.diff 6 Files Affected:
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 9e6b17e87c9e70..924560fef0231d 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -120,7 +120,6 @@ struct Configuration {
size_t wordsize;
bool verbose = false;
WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
- Symbol *entry = nullptr;
bool noEntry = false;
std::string outputFile;
std::string importName;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index beb135f08fa3b1..0de4c8ff5b250d 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -491,8 +491,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_entry:
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- ctx.config.entry =
- file->symtab.addGCRoot(file->symtab.mangle(arg->getValue()), true);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ });
break;
case OPT_failifmismatch:
checkFailIfMismatch(arg->getValue(), file);
@@ -1394,8 +1395,9 @@ void LinkerDriver::createECExportThunks() {
}
}
- if (ctx.config.entry)
- maybeCreateECExportThunk(ctx.config.entry->getName(), ctx.config.entry);
+ if (ctx.symtabEC->entry)
+ maybeCreateECExportThunk(ctx.symtabEC->entry->getName(),
+ ctx.symtabEC->entry);
for (Export &e : ctx.config.exports) {
if (!e.data)
maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym);
@@ -2357,33 +2359,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
// Handle /entry and /dll
- {
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
llvm::TimeTraceScope timeScope("Entry point");
if (auto *arg = args.getLastArg(OPT_entry)) {
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle(arg->getValue()), true);
- } else if (!config->entry && !config->noEntry) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ } else if (!symtab.entry && !config->noEntry) {
if (args.hasArg(OPT_dll)) {
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
} else if (config->driverWdm) {
// /driver:wdm implies /entry:_NtProcessStartup
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle("_NtProcessStartup"), true);
+ symtab.entry =
+ symtab.addGCRoot(symtab.mangle("_NtProcessStartup"), true);
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
- StringRef s = ctx.symtab.findDefaultEntry();
+ StringRef s = symtab.findDefaultEntry();
if (s.empty())
Fatal(ctx) << "entry point must be defined";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
Log(ctx) << "Entry name inferred: " << s;
}
}
- }
+ });
// Handle /delayload
{
@@ -2522,10 +2523,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
{
llvm::TimeTraceScope timeScope("Add unresolved symbols");
do {
- // Windows specific -- if entry point is not found,
- // search for its mangled names.
- if (config->entry)
- ctx.symtab.mangleMaybe(config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ // Windows specific -- if entry point is not found,
+ // search for its mangled names.
+ if (symtab.entry)
+ symtab.mangleMaybe(symtab.entry);
+ });
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : config->exports) {
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index e3531c04e77473..af87587d143d56 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -301,7 +301,7 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
uint64_t entryAddress = 0;
if (!ctx.config.noEntry) {
- Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
+ Defined *entry = dyn_cast_or_null<Defined>(ctx.symtab.entry);
if (entry) {
Chunk *chunk = entry->getChunk();
entrySecIndex = chunk->getOutputSectionIdx();
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 1de0b3e1deac3e..809b5d9dfea307 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -143,6 +143,9 @@ class SymbolTable {
bool isEC() const { return machine == ARM64EC; }
+ // An entry point symbol.
+ Symbol *entry = nullptr;
+
// A list of chunks which to be added to .rdata.
std::vector<Chunk *> localImportChunks;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index eb82a9cc015933..a839f400f7a882 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1748,7 +1748,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
pe->SizeOfImage = sizeOfImage;
pe->SizeOfHeaders = sizeOfHeaders;
if (!config->noEntry) {
- Defined *entry = cast<Defined>(config->entry);
+ Defined *entry = cast<Defined>(ctx.symtab.entry);
pe->AddressOfEntryPoint = entry->getRVA();
// Pointer to thumb code must have the LSB set, so adjust it.
if (config->machine == ARMNT)
@@ -2031,8 +2031,10 @@ void Writer::createGuardCFTables() {
}
// Mark the image entry as address-taken.
- if (config->entry)
- maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.entry)
+ maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry);
+ });
// Mark exported symbols in executable sections as address-taken.
for (Export &e : config->exports)
@@ -2584,6 +2586,16 @@ void Writer::createDynamicRelocs() {
coffHeaderOffset + offsetof(coff_file_header, Machine),
AMD64);
+ if (ctx.symtab.entry || ctx.hybridSymtab->entry) {
+ Defined *entrySym = ctx.hybridSymtab->entry
+ ? dyn_cast<Defined>(ctx.hybridSymtab->entry)
+ : nullptr;
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ peHeaderOffset +
+ offsetof(pe32plus_header, AddressOfEntryPoint),
+ entrySym);
+ }
+
// Set the hybrid load config to the EC load config.
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
dataDirOffset64 +
diff --git a/lld/test/COFF/arm64x-entry.test b/lld/test/COFF/arm64x-entry.test
new file mode 100644
index 00000000000000..d5363c66544a5f
--- /dev/null
+++ b/lld/test/COFF/arm64x-entry.test
@@ -0,0 +1,92 @@
+REQUIRES: aarch64, x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
+
+RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
+
+RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
+DISASM: Disassembly of section .text:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180001000 <.text>:
+DISASM-NEXT: 180001000: 52800020 mov w0, #0x1 // =1
+DISASM-NEXT: 180001004: d65f03c0 ret
+DISASM-NEXT: ...
+DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+DISASM-NEXT: 180002004: d65f03c0 ret
+DISASM-EMPTY:
+DISASM-NEXT: Disassembly of section .hexpthk:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180003000 <.hexpthk>:
+DISASM-NEXT: 180003000: 48 8b c4 movq %rsp, %rax
+DISASM-NEXT: 180003003: 48 89 58 20 movq %rbx, 0x20(%rax)
+DISASM-NEXT: 180003007: 55 pushq %rbp
+DISASM-NEXT: 180003008: 5d popq %rbp
+DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+0x1000>
+DISASM-NEXT: 18000300e: cc int3
+DISASM-NEXT: 18000300f: cc int3
+
+RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s
+READOBJ: AddressOfEntryPoint: 0x1000
+READOBJ: HybridObject {
+READOBJ: AddressOfEntryPoint: 0x3000
+READOBJ: }
+
+RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64ec-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out2.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out3.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out3.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out3.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out4.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func
+RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s
+
+#--- arm64-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #1
+ ret
+
+#--- arm64ec-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #2
+ ret
+
+#--- arm64-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+#--- arm64ec-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #2
+ ret
+
+#--- arm64-drectve.s
+.section .drectve
+ .ascii "-entry:func"
|
@llvm/pr-subscribers-lld-coff Author: Jacek Caban (cjacek) ChangesStore the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables. Full diff: https://github.com/llvm/llvm-project/pull/123096.diff 6 Files Affected:
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 9e6b17e87c9e70..924560fef0231d 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -120,7 +120,6 @@ struct Configuration {
size_t wordsize;
bool verbose = false;
WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
- Symbol *entry = nullptr;
bool noEntry = false;
std::string outputFile;
std::string importName;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index beb135f08fa3b1..0de4c8ff5b250d 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -491,8 +491,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_entry:
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- ctx.config.entry =
- file->symtab.addGCRoot(file->symtab.mangle(arg->getValue()), true);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ });
break;
case OPT_failifmismatch:
checkFailIfMismatch(arg->getValue(), file);
@@ -1394,8 +1395,9 @@ void LinkerDriver::createECExportThunks() {
}
}
- if (ctx.config.entry)
- maybeCreateECExportThunk(ctx.config.entry->getName(), ctx.config.entry);
+ if (ctx.symtabEC->entry)
+ maybeCreateECExportThunk(ctx.symtabEC->entry->getName(),
+ ctx.symtabEC->entry);
for (Export &e : ctx.config.exports) {
if (!e.data)
maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym);
@@ -2357,33 +2359,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
// Handle /entry and /dll
- {
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
llvm::TimeTraceScope timeScope("Entry point");
if (auto *arg = args.getLastArg(OPT_entry)) {
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle(arg->getValue()), true);
- } else if (!config->entry && !config->noEntry) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ } else if (!symtab.entry && !config->noEntry) {
if (args.hasArg(OPT_dll)) {
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
} else if (config->driverWdm) {
// /driver:wdm implies /entry:_NtProcessStartup
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle("_NtProcessStartup"), true);
+ symtab.entry =
+ symtab.addGCRoot(symtab.mangle("_NtProcessStartup"), true);
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
- StringRef s = ctx.symtab.findDefaultEntry();
+ StringRef s = symtab.findDefaultEntry();
if (s.empty())
Fatal(ctx) << "entry point must be defined";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
Log(ctx) << "Entry name inferred: " << s;
}
}
- }
+ });
// Handle /delayload
{
@@ -2522,10 +2523,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
{
llvm::TimeTraceScope timeScope("Add unresolved symbols");
do {
- // Windows specific -- if entry point is not found,
- // search for its mangled names.
- if (config->entry)
- ctx.symtab.mangleMaybe(config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ // Windows specific -- if entry point is not found,
+ // search for its mangled names.
+ if (symtab.entry)
+ symtab.mangleMaybe(symtab.entry);
+ });
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : config->exports) {
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index e3531c04e77473..af87587d143d56 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -301,7 +301,7 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
uint64_t entryAddress = 0;
if (!ctx.config.noEntry) {
- Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
+ Defined *entry = dyn_cast_or_null<Defined>(ctx.symtab.entry);
if (entry) {
Chunk *chunk = entry->getChunk();
entrySecIndex = chunk->getOutputSectionIdx();
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 1de0b3e1deac3e..809b5d9dfea307 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -143,6 +143,9 @@ class SymbolTable {
bool isEC() const { return machine == ARM64EC; }
+ // An entry point symbol.
+ Symbol *entry = nullptr;
+
// A list of chunks which to be added to .rdata.
std::vector<Chunk *> localImportChunks;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index eb82a9cc015933..a839f400f7a882 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1748,7 +1748,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
pe->SizeOfImage = sizeOfImage;
pe->SizeOfHeaders = sizeOfHeaders;
if (!config->noEntry) {
- Defined *entry = cast<Defined>(config->entry);
+ Defined *entry = cast<Defined>(ctx.symtab.entry);
pe->AddressOfEntryPoint = entry->getRVA();
// Pointer to thumb code must have the LSB set, so adjust it.
if (config->machine == ARMNT)
@@ -2031,8 +2031,10 @@ void Writer::createGuardCFTables() {
}
// Mark the image entry as address-taken.
- if (config->entry)
- maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.entry)
+ maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry);
+ });
// Mark exported symbols in executable sections as address-taken.
for (Export &e : config->exports)
@@ -2584,6 +2586,16 @@ void Writer::createDynamicRelocs() {
coffHeaderOffset + offsetof(coff_file_header, Machine),
AMD64);
+ if (ctx.symtab.entry || ctx.hybridSymtab->entry) {
+ Defined *entrySym = ctx.hybridSymtab->entry
+ ? dyn_cast<Defined>(ctx.hybridSymtab->entry)
+ : nullptr;
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ peHeaderOffset +
+ offsetof(pe32plus_header, AddressOfEntryPoint),
+ entrySym);
+ }
+
// Set the hybrid load config to the EC load config.
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
dataDirOffset64 +
diff --git a/lld/test/COFF/arm64x-entry.test b/lld/test/COFF/arm64x-entry.test
new file mode 100644
index 00000000000000..d5363c66544a5f
--- /dev/null
+++ b/lld/test/COFF/arm64x-entry.test
@@ -0,0 +1,92 @@
+REQUIRES: aarch64, x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
+
+RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
+
+RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
+DISASM: Disassembly of section .text:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180001000 <.text>:
+DISASM-NEXT: 180001000: 52800020 mov w0, #0x1 // =1
+DISASM-NEXT: 180001004: d65f03c0 ret
+DISASM-NEXT: ...
+DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+DISASM-NEXT: 180002004: d65f03c0 ret
+DISASM-EMPTY:
+DISASM-NEXT: Disassembly of section .hexpthk:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180003000 <.hexpthk>:
+DISASM-NEXT: 180003000: 48 8b c4 movq %rsp, %rax
+DISASM-NEXT: 180003003: 48 89 58 20 movq %rbx, 0x20(%rax)
+DISASM-NEXT: 180003007: 55 pushq %rbp
+DISASM-NEXT: 180003008: 5d popq %rbp
+DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+0x1000>
+DISASM-NEXT: 18000300e: cc int3
+DISASM-NEXT: 18000300f: cc int3
+
+RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s
+READOBJ: AddressOfEntryPoint: 0x1000
+READOBJ: HybridObject {
+READOBJ: AddressOfEntryPoint: 0x3000
+READOBJ: }
+
+RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64ec-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out2.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out3.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out3.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out3.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out4.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func
+RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s
+
+#--- arm64-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #1
+ ret
+
+#--- arm64ec-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #2
+ ret
+
+#--- arm64-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+#--- arm64ec-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #2
+ ret
+
+#--- arm64-drectve.s
+.section .drectve
+ .ascii "-entry:func"
|
@llvm/pr-subscribers-platform-windows Author: Jacek Caban (cjacek) ChangesStore the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables. Full diff: https://github.com/llvm/llvm-project/pull/123096.diff 6 Files Affected:
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 9e6b17e87c9e70..924560fef0231d 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -120,7 +120,6 @@ struct Configuration {
size_t wordsize;
bool verbose = false;
WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
- Symbol *entry = nullptr;
bool noEntry = false;
std::string outputFile;
std::string importName;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index beb135f08fa3b1..0de4c8ff5b250d 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -491,8 +491,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_entry:
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- ctx.config.entry =
- file->symtab.addGCRoot(file->symtab.mangle(arg->getValue()), true);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ });
break;
case OPT_failifmismatch:
checkFailIfMismatch(arg->getValue(), file);
@@ -1394,8 +1395,9 @@ void LinkerDriver::createECExportThunks() {
}
}
- if (ctx.config.entry)
- maybeCreateECExportThunk(ctx.config.entry->getName(), ctx.config.entry);
+ if (ctx.symtabEC->entry)
+ maybeCreateECExportThunk(ctx.symtabEC->entry->getName(),
+ ctx.symtabEC->entry);
for (Export &e : ctx.config.exports) {
if (!e.data)
maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym);
@@ -2357,33 +2359,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
// Handle /entry and /dll
- {
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
llvm::TimeTraceScope timeScope("Entry point");
if (auto *arg = args.getLastArg(OPT_entry)) {
if (!arg->getValue()[0])
Fatal(ctx) << "missing entry point symbol name";
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle(arg->getValue()), true);
- } else if (!config->entry && !config->noEntry) {
+ symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true);
+ } else if (!symtab.entry && !config->noEntry) {
if (args.hasArg(OPT_dll)) {
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
} else if (config->driverWdm) {
// /driver:wdm implies /entry:_NtProcessStartup
- config->entry =
- ctx.symtab.addGCRoot(ctx.symtab.mangle("_NtProcessStartup"), true);
+ symtab.entry =
+ symtab.addGCRoot(symtab.mangle("_NtProcessStartup"), true);
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
- StringRef s = ctx.symtab.findDefaultEntry();
+ StringRef s = symtab.findDefaultEntry();
if (s.empty())
Fatal(ctx) << "entry point must be defined";
- config->entry = ctx.symtab.addGCRoot(s, true);
+ symtab.entry = symtab.addGCRoot(s, true);
Log(ctx) << "Entry name inferred: " << s;
}
}
- }
+ });
// Handle /delayload
{
@@ -2522,10 +2523,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
{
llvm::TimeTraceScope timeScope("Add unresolved symbols");
do {
- // Windows specific -- if entry point is not found,
- // search for its mangled names.
- if (config->entry)
- ctx.symtab.mangleMaybe(config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ // Windows specific -- if entry point is not found,
+ // search for its mangled names.
+ if (symtab.entry)
+ symtab.mangleMaybe(symtab.entry);
+ });
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : config->exports) {
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index e3531c04e77473..af87587d143d56 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -301,7 +301,7 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
uint64_t entryAddress = 0;
if (!ctx.config.noEntry) {
- Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
+ Defined *entry = dyn_cast_or_null<Defined>(ctx.symtab.entry);
if (entry) {
Chunk *chunk = entry->getChunk();
entrySecIndex = chunk->getOutputSectionIdx();
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 1de0b3e1deac3e..809b5d9dfea307 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -143,6 +143,9 @@ class SymbolTable {
bool isEC() const { return machine == ARM64EC; }
+ // An entry point symbol.
+ Symbol *entry = nullptr;
+
// A list of chunks which to be added to .rdata.
std::vector<Chunk *> localImportChunks;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index eb82a9cc015933..a839f400f7a882 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1748,7 +1748,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
pe->SizeOfImage = sizeOfImage;
pe->SizeOfHeaders = sizeOfHeaders;
if (!config->noEntry) {
- Defined *entry = cast<Defined>(config->entry);
+ Defined *entry = cast<Defined>(ctx.symtab.entry);
pe->AddressOfEntryPoint = entry->getRVA();
// Pointer to thumb code must have the LSB set, so adjust it.
if (config->machine == ARMNT)
@@ -2031,8 +2031,10 @@ void Writer::createGuardCFTables() {
}
// Mark the image entry as address-taken.
- if (config->entry)
- maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ if (symtab.entry)
+ maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry);
+ });
// Mark exported symbols in executable sections as address-taken.
for (Export &e : config->exports)
@@ -2584,6 +2586,16 @@ void Writer::createDynamicRelocs() {
coffHeaderOffset + offsetof(coff_file_header, Machine),
AMD64);
+ if (ctx.symtab.entry || ctx.hybridSymtab->entry) {
+ Defined *entrySym = ctx.hybridSymtab->entry
+ ? dyn_cast<Defined>(ctx.hybridSymtab->entry)
+ : nullptr;
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ peHeaderOffset +
+ offsetof(pe32plus_header, AddressOfEntryPoint),
+ entrySym);
+ }
+
// Set the hybrid load config to the EC load config.
ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
dataDirOffset64 +
diff --git a/lld/test/COFF/arm64x-entry.test b/lld/test/COFF/arm64x-entry.test
new file mode 100644
index 00000000000000..d5363c66544a5f
--- /dev/null
+++ b/lld/test/COFF/arm64x-entry.test
@@ -0,0 +1,92 @@
+REQUIRES: aarch64, x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
+
+RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj
+
+RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
+DISASM: Disassembly of section .text:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180001000 <.text>:
+DISASM-NEXT: 180001000: 52800020 mov w0, #0x1 // =1
+DISASM-NEXT: 180001004: d65f03c0 ret
+DISASM-NEXT: ...
+DISASM-NEXT: 180002000: 52800040 mov w0, #0x2 // =2
+DISASM-NEXT: 180002004: d65f03c0 ret
+DISASM-EMPTY:
+DISASM-NEXT: Disassembly of section .hexpthk:
+DISASM-EMPTY:
+DISASM-NEXT: 0000000180003000 <.hexpthk>:
+DISASM-NEXT: 180003000: 48 8b c4 movq %rsp, %rax
+DISASM-NEXT: 180003003: 48 89 58 20 movq %rbx, 0x20(%rax)
+DISASM-NEXT: 180003007: 55 pushq %rbp
+DISASM-NEXT: 180003008: 5d popq %rbp
+DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+0x1000>
+DISASM-NEXT: 18000300e: cc int3
+DISASM-NEXT: 18000300f: cc int3
+
+RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s
+READOBJ: AddressOfEntryPoint: 0x1000
+READOBJ: HybridObject {
+READOBJ: AddressOfEntryPoint: 0x3000
+READOBJ: }
+
+RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64ec-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out2.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out3.dll arm64ec-func.obj arm64-func.obj \
+RUN: arm64-drectve.obj loadconfig-arm64.obj loadconfig-arm64ec.obj
+RUN: llvm-objdump -d out3.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out3.dll | FileCheck --check-prefix=READOBJ %s
+
+RUN: lld-link -machine:arm64x -dll -out:out4.dll arm64ec-func.obj arm64-func.obj \
+RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func
+RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s
+
+#--- arm64-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #1
+ ret
+
+#--- arm64ec-dllmain.s
+ .section .text,"xr",discard,_DllMainCRTStartup
+ .globl _DllMainCRTStartup
+ .p2align 2
+_DllMainCRTStartup:
+ mov w0, #2
+ ret
+
+#--- arm64-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+#--- arm64ec-func.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #2
+ ret
+
+#--- arm64-drectve.s
+.section .drectve
+ .ascii "-entry:func"
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly LGTM, a couple minor points.
lld/COFF/Writer.cpp
Outdated
if (ctx.symtab.entry || ctx.hybridSymtab->entry) { | ||
Defined *entrySym = ctx.hybridSymtab->entry | ||
? dyn_cast<Defined>(ctx.hybridSymtab->entry) | ||
: nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't a dyn_cast_or_null<Defined>(ctx.hybridSymtab->entry)
be equivalent to this whole ternary expression?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, it could even be cast_or_null
.
lld/COFF/Writer.cpp
Outdated
@@ -2584,6 +2586,16 @@ void Writer::createDynamicRelocs() { | |||
coffHeaderOffset + offsetof(coff_file_header, Machine), | |||
AMD64); | |||
|
|||
if (ctx.symtab.entry || ctx.hybridSymtab->entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, a different way of expressing this condition would be if (ctx.symtab.entry != ctx.hybridSymtab->entry)
, right? (Not a strong opinion though.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it expresses the actual reason for the reloc, I will change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Store the entry symbol in SymbolTable instead of Configuration, as it differs between symbol tables.