diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 9e6b17e87c9e7..924560fef0231 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 beb135f08fa3b..0de4c8ff5b250 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 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 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 e3531c04e7747..af87587d143d5 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(ctx.config.entry); + Defined *entry = dyn_cast_or_null(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 1de0b3e1deac3..809b5d9dfea30 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 localImportChunks; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index eb82a9cc01593..1fb5b7292f055 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -1748,7 +1748,7 @@ template void Writer::writeHeader() { pe->SizeOfImage = sizeOfImage; pe->SizeOfHeaders = sizeOfHeaders; if (!config->noEntry) { - Defined *entry = cast(config->entry); + Defined *entry = cast(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,12 @@ void Writer::createDynamicRelocs() { coffHeaderOffset + offsetof(coff_file_header, Machine), AMD64); + if (ctx.symtab.entry != ctx.hybridSymtab->entry) + ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + peHeaderOffset + + offsetof(pe32plus_header, AddressOfEntryPoint), + cast_or_null(ctx.hybridSymtab->entry)); + // 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 0000000000000..d5363c66544a5 --- /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"