diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index be44950a1720e3..4e3a564ebacd87 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -1078,4 +1078,17 @@ void ECExportThunkChunk::writeTo(uint8_t *buf) const { write32le(buf + 10, target->getRVA() - rva - 14); } +size_t CHPERedirectionChunk::getSize() const { + return exportThunks.size() * sizeof(chpe_redirection_entry); +} + +void CHPERedirectionChunk::writeTo(uint8_t *buf) const { + auto entries = reinterpret_cast(buf); + + for (uint32_t i = 0; i < exportThunks.size(); i++) { + entries[i].Source = exportThunks[i].first->getRVA(); + entries[i].Destination = exportThunks[i].second->getRVA(); + } +} + } // namespace lld::coff diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 5443d4619a977e..015df41b04c67d 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -749,6 +749,17 @@ class ECCodeMapChunk : public NonSectionChunk { std::vector ↦ }; +class CHPERedirectionChunk : public NonSectionChunk { +public: + CHPERedirectionChunk(std::vector> &exportThunks) + : exportThunks(exportThunks) {} + size_t getSize() const override; + void writeTo(uint8_t *buf) const override; + +private: + std::vector> &exportThunks; +}; + static const uint8_t ECExportThunkCode[] = { 0x48, 0x8b, 0xc4, // movq %rsp, %rax 0x48, 0x89, 0x58, 0x20, // movq %rbx, 0x20(%rax) diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index c09c91fe4b1719..472f5074ba8b8c 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -2440,6 +2440,8 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (isArm64EC(config->machine)) { ctx.symtab.addAbsolute("__arm64x_extra_rfe_table", 0); ctx.symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0); + ctx.symtab.addAbsolute("__arm64x_redirection_metadata", 0); + ctx.symtab.addAbsolute("__arm64x_redirection_metadata_count", 0); ctx.symtab.addAbsolute("__hybrid_code_map", 0); ctx.symtab.addAbsolute("__hybrid_code_map_count", 0); } diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 776595d98c391d..358d16fe330cea 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -298,6 +298,9 @@ class Writer { CVDebugRecordChunk *buildId = nullptr; ArrayRef sectionTable; + // List of Arm64EC export thunks. + std::vector> exportThunks; + uint64_t fileSize; uint32_t pointerToSymbolTable = 0; uint64_t sizeOfImage; @@ -312,6 +315,7 @@ class Writer { OutputSection *idataSec; OutputSection *edataSec; OutputSection *didatSec; + OutputSection *a64xrmSec; OutputSection *rsrcSec; OutputSection *relocSec; OutputSection *ctorsSec; @@ -995,6 +999,8 @@ void Writer::createSections() { idataSec = createSection(".idata", data | r); edataSec = createSection(".edata", data | r); didatSec = createSection(".didat", data | r); + if (isArm64EC(ctx.config.machine)) + a64xrmSec = createSection(".a64xrm", data | r); rsrcSec = createSection(".rsrc", data | r); relocSec = createSection(".reloc", data | discardable | r); ctorsSec = createSection(".ctors", data | r | w); @@ -2053,8 +2059,10 @@ void Writer::createECChunks() { auto sym = dyn_cast(s); if (!sym || !sym->getChunk()) continue; - if (auto thunk = dyn_cast(sym->getChunk())) + if (auto thunk = dyn_cast(sym->getChunk())) { hexpthkSec->addChunk(thunk); + exportThunks.push_back({thunk, thunk->target}); + } } auto codeMapChunk = make(codeMap); @@ -2062,6 +2070,13 @@ void Writer::createECChunks() { Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map"); replaceSymbol(codeMapSym, codeMapSym->getName(), codeMapChunk); + + CHPERedirectionChunk *entryPoints = make(exportThunks); + a64xrmSec->addChunk(entryPoints); + Symbol *entryPointsSym = + ctx.symtab.findUnderscore("__arm64x_redirection_metadata"); + replaceSymbol(entryPointsSym, entryPointsSym->getName(), + entryPoints); } // MinGW specific. Gather all relocations that are imported from a DLL even @@ -2154,6 +2169,11 @@ void Writer::setECSymbols() { if (!isArm64EC(ctx.config.machine)) return; + llvm::stable_sort(exportThunks, [](const std::pair &a, + const std::pair &b) { + return a.first->getRVA() < b.first->getRVA(); + }); + Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table"); replaceSymbol(rfeTableSym, "__arm64x_extra_rfe_table", pdata.first); @@ -2165,6 +2185,10 @@ void Writer::setECSymbols() { ->setVA(pdata.last->getRVA() + pdata.last->getSize() - pdata.first->getRVA()); } + + Symbol *entryPointCountSym = + ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count"); + cast(entryPointCountSym)->setVA(exportThunks.size()); } // Write section contents to a mmap'ed file. diff --git a/lld/test/COFF/Inputs/loadconfig-arm64ec.s b/lld/test/COFF/Inputs/loadconfig-arm64ec.s index a270d281095dd6..62a6d0cab642e9 100644 --- a/lld/test/COFF/Inputs/loadconfig-arm64ec.s +++ b/lld/test/COFF/Inputs/loadconfig-arm64ec.s @@ -67,7 +67,7 @@ __chpe_metadata: .rva __hybrid_code_map .word __hybrid_code_map_count .word 0 // __x64_code_ranges_to_entry_points - .word 0 //__arm64x_redirection_metadata + .rva __arm64x_redirection_metadata .rva __os_arm64x_dispatch_call_no_redirect .rva __os_arm64x_dispatch_ret .rva __os_arm64x_check_call @@ -76,7 +76,7 @@ __chpe_metadata: .word 0 // __arm64x_native_entrypoint .word 0 // __hybrid_auxiliary_iat .word 0 // __x64_code_ranges_to_entry_points_count - .word 0 // __arm64x_redirection_metadata_count + .word __arm64x_redirection_metadata_count .rva __os_arm64x_get_x64_information .rva __os_arm64x_set_x64_information .rva __arm64x_extra_rfe_table diff --git a/lld/test/COFF/arm64ec-export-thunks.test b/lld/test/COFF/arm64ec-export-thunks.test index 6ed0514d4b17f3..2e4cfd6203b751 100644 --- a/lld/test/COFF/arm64ec-export-thunks.test +++ b/lld/test/COFF/arm64ec-export-thunks.test @@ -49,7 +49,7 @@ EXP-DISASM-NEXT: 18000301f: cc int3 RUN: llvm-objdump -p exports.dll | FileCheck -check-prefix=EXP-EXPORT %s EXP-EXPORT: Ordinal RVA Name EXP-EXPORT-NEXT: 1 0x3010 arm64ec_func -EXP-EXPORT-NEXT: 2 0x6000 data_sym +EXP-EXPORT-NEXT: 2 0x7000 data_sym EXP-EXPORT-NEXT: 3 0x3000 func EXP-EXPORT-NEXT: 4 0x2000 x86_64_func @@ -58,9 +58,30 @@ EXP-CHPE: CodeMap [ EXP-CHPE-NEXT: 0x1000 - 0x100C ARM64EC EXP-CHPE-NEXT: 0x2000 - 0x3020 X64 EXP-CHPE-NEXT: ] +EXP-CHPE-NEXT: CodeRangesToEntryPoints: 0 +EXP-CHPE-NEXT: RedirectionMetadata [ +EXP-CHPE-NEXT: 0x3000 -> 0x1000 +EXP-CHPE-NEXT: 0x3010 -> 0x1000 +EXP-CHPE-NEXT: ] + +RUN: llvm-readobj --sections exports.dll | FileCheck --check-prefix=A64XRM %s + +A64XRM: Name: .a64xrm (2E 61 36 34 78 72 6D 00) +A64XRM-NEXT: VirtualSize: 0x10 +A64XRM-NEXT: VirtualAddress: 0x6000 +A64XRM-NEXT: RawDataSize: 512 +A64XRM-NEXT: PointerToRawData: +A64XRM-NEXT: PointerToRelocations: 0x0 +A64XRM-NEXT: PointerToLineNumbers: 0x0 +A64XRM-NEXT: RelocationCount: 0 +A64XRM-NEXT: LineNumberCount: 0 +A64XRM-NEXT: Characteristics [ (0x40000040) +A64XRM-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) +A64XRM-NEXT: IMAGE_SCN_MEM_READ (0x40000000) +A64XRM-NEXT: ] RUN: llvm-objdump -s --section=.test exports.dll | FileCheck --check-prefix=EXP-DATA %s -EXP-DATA: 180006000 00300000 10300000 +EXP-DATA: 180007000 00300000 10300000 RUN: lld-link -out:exports2.dll -machine:arm64ec antidep-func.obj x86_64-func.obj loadconfig-arm64ec.obj \ RUN: arm64ec-data.obj -dll -noentry -export:arm64ec_func -export:func=arm64ec_func \ @@ -100,6 +121,10 @@ ENTRY-CHPE: CodeMap [ ENTRY-CHPE-NEXT: 0x1000 - 0x100C ARM64EC ENTRY-CHPE-NEXT: 0x2000 - 0x2010 X64 ENTRY-CHPE-NEXT: ] +ENTRY-CHPE-NEXT: CodeRangesToEntryPoints: 0 +ENTRY-CHPE-NEXT: RedirectionMetadata [ +ENTRY-CHPE-NEXT: 0x2000 -> 0x1000 +ENTRY-CHPE-NEXT: ] Test exporting data symbol as a function: diff --git a/lld/test/COFF/arm64ec-patchable-thunks.test b/lld/test/COFF/arm64ec-patchable-thunks.test index cccd42eebfd367..044f3c7cebdf8e 100644 --- a/lld/test/COFF/arm64ec-patchable-thunks.test +++ b/lld/test/COFF/arm64ec-patchable-thunks.test @@ -27,13 +27,17 @@ PATCH-DISASM-NEXT: 18000200e: cc int3 PATCH-DISASM-NEXT: 18000200f: cc int3 RUN: llvm-readobj --hex-dump=.test test.dll | FileCheck -check-prefix=RVA %s -RVA: 0x180005000 00200000 +RVA: 0x180006000 00200000 RUN: llvm-readobj --coff-load-config test.dll | FileCheck -check-prefix=PATCH-CHPE %s PATCH-CHPE: CodeMap [ PATCH-CHPE-NEXT: 0x1000 - 0x1008 ARM64EC PATCH-CHPE-NEXT: 0x2000 - 0x2010 X64 PATCH-CHPE-NEXT: ] +PATCH-CHPE-NEXT: CodeRangesToEntryPoints: 0 +PATCH-CHPE-NEXT: RedirectionMetadata [ +PATCH-CHPE-NEXT: 0x2000 -> 0x1000 +PATCH-CHPE-NEXT: ] RUN: lld-link -out:test2.dll -machine:arm64ec arm64ec-alias.obj test-sec.obj loadconfig-arm64ec.obj -dll -noentry