diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index ae5b095fba772..be01ee41c9a2f 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -2548,7 +2548,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0); symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0); - if (isArm64EC(ctx.config.machine)) { + if (symtab.isEC()) { symtab.addAbsolute("__arm64x_extra_rfe_table", 0); symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0); symtab.addAbsolute("__arm64x_redirection_metadata", 0); diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 5946c2944aa21..b3dd5f6cf4926 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -575,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) { // Create a code map for CHPE metadata. void Writer::createECCodeMap() { - if (!isArm64EC(ctx.config.machine)) + if (!ctx.symtabEC) return; // Clear the map in case we were're recomputing the map after adding @@ -611,7 +611,8 @@ void Writer::createECCodeMap() { closeRange(); - Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count"); + Symbol *tableCountSym = + ctx.symtabEC->findUnderscore("__hybrid_code_map_count"); cast(tableCountSym)->setVA(codeMap.size()); } @@ -1229,8 +1230,7 @@ void Writer::createMiscChunks() { // Create /guard:cf tables if requested. createGuardCFTables(); - if (isArm64EC(config->machine)) - createECChunks(); + createECChunks(); if (config->autoImport) createRuntimePseudoRelocs(); @@ -2158,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, // Create CHPE metadata chunks. void Writer::createECChunks() { - for (Symbol *s : ctx.symtab.expSymbols) { + SymbolTable *symtab = ctx.symtabEC; + if (!symtab) + return; + + for (Symbol *s : symtab->expSymbols) { auto sym = dyn_cast(s); if (!sym || !sym->getChunk()) continue; @@ -2177,9 +2181,9 @@ void Writer::createECChunks() { // we should use the #foo$hp_target symbol as the redirection target. // First, try to look up the $hp_target symbol. If it can't be found, // assume it's a regular function and look for #foo instead. - Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str()); + Symbol *targetSym = symtab->find((targetName + "$hp_target").str()); if (!targetSym) - targetSym = ctx.symtab.find(targetName); + targetSym = symtab->find(targetName); Defined *t = dyn_cast_or_null(targetSym); if (t && isArm64EC(t->getChunk()->getMachine())) exportThunks.push_back({chunk, t}); @@ -2188,20 +2192,20 @@ void Writer::createECChunks() { auto codeMapChunk = make(codeMap); rdataSec->addChunk(codeMapChunk); - Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map"); + Symbol *codeMapSym = symtab->findUnderscore("__hybrid_code_map"); replaceSymbol(codeMapSym, codeMapSym->getName(), codeMapChunk); CHPECodeRangesChunk *ranges = make(exportThunks); rdataSec->addChunk(ranges); Symbol *rangesSym = - ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points"); + symtab->findUnderscore("__x64_code_ranges_to_entry_points"); replaceSymbol(rangesSym, rangesSym->getName(), ranges); CHPERedirectionChunk *entryPoints = make(exportThunks); a64xrmSec->addChunk(entryPoints); Symbol *entryPointsSym = - ctx.symtab.findUnderscore("__arm64x_redirection_metadata"); + symtab->findUnderscore("__arm64x_redirection_metadata"); replaceSymbol(entryPointsSym, entryPointsSym->getName(), entryPoints); } @@ -2294,7 +2298,8 @@ void Writer::setSectionPermissions() { // Set symbols used by ARM64EC metadata. void Writer::setECSymbols() { - if (!isArm64EC(ctx.config.machine)) + SymbolTable *symtab = ctx.symtabEC; + if (!symtab) return; llvm::stable_sort(exportThunks, [](const std::pair &a, @@ -2302,45 +2307,45 @@ void Writer::setECSymbols() { return a.first->getRVA() < b.first->getRVA(); }); - Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table"); + Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table"); replaceSymbol(rfeTableSym, "__arm64x_extra_rfe_table", pdata.first); if (pdata.first) { Symbol *rfeSizeSym = - ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size"); + symtab->findUnderscore("__arm64x_extra_rfe_table_size"); cast(rfeSizeSym) ->setVA(pdata.last->getRVA() + pdata.last->getSize() - pdata.first->getRVA()); } Symbol *rangesCountSym = - ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count"); + symtab->findUnderscore("__x64_code_ranges_to_entry_points_count"); cast(rangesCountSym)->setVA(exportThunks.size()); Symbol *entryPointCountSym = - ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count"); + symtab->findUnderscore("__arm64x_redirection_metadata_count"); cast(entryPointCountSym)->setVA(exportThunks.size()); - Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat"); + Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat"); replaceSymbol(iatSym, "__hybrid_auxiliary_iat", idata.auxIat.empty() ? nullptr : idata.auxIat.front()); - Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy"); + Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy"); replaceSymbol( iatCopySym, "__hybrid_auxiliary_iat_copy", idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front()); Symbol *delayIatSym = - ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat"); + symtab->findUnderscore("__hybrid_auxiliary_delayload_iat"); replaceSymbol( delayIatSym, "__hybrid_auxiliary_delayload_iat", delayIdata.getAuxIat().empty() ? nullptr : delayIdata.getAuxIat().front()); Symbol *delayIatCopySym = - ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy"); + symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy"); replaceSymbol( delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy", delayIdata.getAuxIatCopy().empty() ? nullptr @@ -2695,6 +2700,23 @@ void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) { } } + IF_CONTAINS(CHPEMetadataPointer) { + // On ARM64X, only the EC version of the load config contains + // CHPEMetadataPointer. Copy its value to the native load config. + if (ctx.hybridSymtab && !symtab.isEC() && + ctx.hybridSymtab->loadConfigSize >= + offsetof(T, CHPEMetadataPointer) + sizeof(T::CHPEMetadataPointer)) { + OutputSection *sec = + ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk()); + uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff(); + auto hybridLoadConfig = + reinterpret_cast( + secBuf + + (ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA())); + loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer; + } + } + if (ctx.config.guardCF == GuardCFLevel::Off) return; RETURN_IF_NOT_CONTAINS(GuardFlags) diff --git a/lld/test/COFF/Inputs/loadconfig-arm64.s b/lld/test/COFF/Inputs/loadconfig-arm64.s new file mode 100644 index 0000000000000..67d1a0aea50e4 --- /dev/null +++ b/lld/test/COFF/Inputs/loadconfig-arm64.s @@ -0,0 +1,15 @@ + .section .rdata,"dr" + .globl _load_config_used + .p2align 3, 0 +_load_config_used: + .word 0x140 + .fill 0x7c,1,0 + .xword __guard_fids_table + .xword __guard_fids_count + .xword __guard_flags + .xword 0 + .xword __guard_iat_table + .xword __guard_iat_count + .xword __guard_longjmp_table + .xword __guard_longjmp_count + .fill 0x80,1,0 diff --git a/lld/test/COFF/arm64ec-codemap.test b/lld/test/COFF/arm64ec-codemap.test index 2d79538f0a7eb..050261117be2e 100644 --- a/lld/test/COFF/arm64ec-codemap.test +++ b/lld/test/COFF/arm64ec-codemap.test @@ -9,7 +9,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows data-sec2.s -o data-sec2.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows empty-sec.s -o arm64ec-empty-sec.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows empty-sec.s -o x86_64-empty-sec.obj -RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj Link ARM64EC DLL and verify that the code is arranged as expected. diff --git a/lld/test/COFF/arm64ec-entry-thunk.s b/lld/test/COFF/arm64ec-entry-thunk.s index bf5cb42755b62..b31d315eeb7a8 100644 --- a/lld/test/COFF/arm64ec-entry-thunk.s +++ b/lld/test/COFF/arm64ec-entry-thunk.s @@ -27,7 +27,7 @@ thunk: .rva func // RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj -// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o native-loadcfg.obj +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o native-loadcfg.obj // RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj // RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj // RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s diff --git a/lld/test/COFF/arm64ec-lib.test b/lld/test/COFF/arm64ec-lib.test index ea07d28f1a411..8698a5ceccbe7 100644 --- a/lld/test/COFF/arm64ec-lib.test +++ b/lld/test/COFF/arm64ec-lib.test @@ -11,7 +11,7 @@ RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-alias.s -o ref-alias.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-thunk.s -o ref-thunk.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func.s -o func.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows func-x86_64.s -o func-x86_64.obj -RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj RUN: llvm-lib -machine:arm64ec -out:sym-arm64ec.lib sym-arm64ec.obj nsym-aarch64.obj diff --git a/lld/test/COFF/arm64ec-range-thunks.s b/lld/test/COFF/arm64ec-range-thunks.s index 09d9b013f97a5..dcfa6365b4e3a 100644 --- a/lld/test/COFF/arm64ec-range-thunks.s +++ b/lld/test/COFF/arm64ec-range-thunks.s @@ -5,7 +5,7 @@ # RUN: llvm-mc -filetype=obj -triple=aarch64-windows native-funcs.s -o funcs-aarch64.obj # RUN: llvm-mc -filetype=obj -triple=x86_64-windows space.s -o space-x86_64.obj # RUN: llvm-mc -filetype=obj -triple=aarch64-windows space.s -o space-aarch64.obj -# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64.obj +# RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj # RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj diff --git a/lld/test/COFF/arm64x-loadconfig.s b/lld/test/COFF/arm64x-loadconfig.s index 6023828a2746f..8d2ab55554634 100644 --- a/lld/test/COFF/arm64x-loadconfig.s +++ b/lld/test/COFF/arm64x-loadconfig.s @@ -2,13 +2,15 @@ // RUN: split-file %s %t.dir && cd %t.dir // RUN: llvm-mc -filetype=obj -triple=aarch64-windows test.s -o test.obj +// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows chpe.s -o chpe.obj // RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig.s -o loadconfig.obj +// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-ec.s -o loadconfig-ec.obj // RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig-short.s -o loadconfig-short.obj // RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-short.s -o loadconfig-short-arm64ec.obj // RUN: lld-link -machine:arm64x -out:out.dll -dll -noentry loadconfig.obj test.obj -// RUN: llvm-readobj --coff-load-config out.dll | FileCheck -check-prefix=DYNRELOCS %s +// RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=DYNRELOCS %s // DYNRELOCS: DynamicValueRelocTableOffset: 0xC // DYNRELOCS-NEXT: DynamicValueRelocTableSection: 4 // DYNRELOCS: DynamicRelocations [ @@ -35,7 +37,7 @@ // DYNRELOCS-NEXT: ] // DYNRELOCS-NEXT: ] -// RUN: llvm-readobj --headers out.dll | FileCheck -check-prefix=HEADERS %s +// RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=HEADERS %s // HEADERS: BaseRelocationTableRVA: 0x4000 // HEADERS-NEXT: BaseRelocationTableSize: 0xC // HEADERS: LoadConfigTableRVA: 0x1000 @@ -47,6 +49,70 @@ // RUN: lld-link -machine:arm64x -out:out-short.dll -dll -noentry loadconfig-short-arm64ec.obj 2>&1 | FileCheck --check-prefix=WARN-RELOC-SIZE %s // WARN-RELOC-SIZE: lld-link: warning: '_load_config_used' structure too small to include dynamic relocations +// Check that the CHPE metadata pointer is correctly copied from the EC load config to the native load config. + +// RUN: lld-link -machine:arm64x -out:out-hyb.dll -dll -noentry loadconfig.obj loadconfig-ec.obj chpe.obj test.obj + +// RUN: llvm-readobj --coff-load-config out-hyb.dll | FileCheck --check-prefix=LOADCFG %s +// LOADCFG: Format: COFF-ARM64X +// LOADCFG-NEXT: Arch: aarch64 +// LOADCFG-NEXT: AddressSize: 64bit +// LOADCFG-NEXT: LoadConfig [ +// LOADCFG-NEXT: Size: 0x140 +// LOADCFG: CHPEMetadata [ +// LOADCFG-NEXT: Version: 0x2 +// LOADCFG: RedirectionMetadata: 12288 +// LOADCFG: AlternateEntryPoint: 0x0 +// LOADCFG-NEXT: AuxiliaryIAT: 0x0 +// LOADCFG-NEXT: GetX64InformationFunctionPointer: 0x0 +// LOADCFG-NEXT: SetX64InformationFunctionPointer: 0x0 +// LOADCFG-NEXT: ExtraRFETable: 0x0 +// LOADCFG-NEXT: ExtraRFETableSize: 0x0 +// LOADCFG-NEXT: __os_arm64x_dispatch_fptr: 0x0 +// LOADCFG-NEXT: AuxiliaryIATCopy: 0x0 +// LOADCFG-NEXT: AuxiliaryDelayloadIAT: 0x0 +// LOADCFG-NEXT: AuxiliaryDelayloadIATCopy: 0x0 +// LOADCFG-NEXT: HybridImageInfoBitfield: 0x0 +// LOADCFG: ] +// LOADCFG-NEXT: DynamicRelocations [ +// LOADCFG-NEXT: Version: 0x1 +// LOADCFG-NEXT: Arm64X [ +// LOADCFG-NEXT: Entry [ +// LOADCFG-NEXT: RVA: 0x7C +// LOADCFG-NEXT: Type: VALUE +// LOADCFG-NEXT: Size: 0x2 +// LOADCFG-NEXT: Value: 0x8664 +// LOADCFG-NEXT: ] +// LOADCFG-NEXT: Entry [ +// LOADCFG-NEXT: RVA: 0x150 +// LOADCFG-NEXT: Type: VALUE +// LOADCFG-NEXT: Size: 0x4 +// LOADCFG-NEXT: Value: 0x0 +// LOADCFG-NEXT: ] +// LOADCFG-NEXT: Entry [ +// LOADCFG-NEXT: RVA: 0x154 +// LOADCFG-NEXT: Type: VALUE +// LOADCFG-NEXT: Size: 0x4 +// LOADCFG-NEXT: Value: 0x0 +// LOADCFG-NEXT: ] +// LOADCFG-NEXT: ] +// LOADCFG-NEXT: ] +// LOADCFG-NEXT: HybridObject { +// LOADCFG-NEXT: Format: COFF-x86-64 +// LOADCFG-NEXT: Arch: x86_64 +// LOADCFG-NEXT: AddressSize: 64bit + +// RUN: llvm-readobj --coff-basereloc out-hyb.dll | FileCheck --check-prefix=BASERELOC %s +// BASERELOC: BaseReloc [ +// BASERELOC-NEXT: Entry { +// BASERELOC-NEXT: Type: DIR64 +// BASERELOC-NEXT: Address: 0x1208 +// BASERELOC-NEXT: } +// BASERELOC-NEXT: Entry { +// BASERELOC: Type: DIR64 +// BASERELOC-NEXT: Address: 0x2074 +// BASERELOC-NEXT: } + #--- test.s .data sym: @@ -61,6 +127,16 @@ _load_config_used: .word 0x140 .fill 0x13c,1,0 +#--- loadconfig-ec.s + .section .rdata,"dr" + .globl _load_config_used + .p2align 3, 0 +_load_config_used: + .word 0x140 + .fill 0xc4,1,0 + .xword __chpe_metadata + .fill 0x70,1,0 + #--- loadconfig-short.s .section .rdata,"dr" .globl _load_config_used @@ -68,3 +144,38 @@ _load_config_used: _load_config_used: .word 0xe4 .fill 0xe0,1,0 + +#--- chpe.s + .data + .globl __chpe_metadata + .p2align 3, 0 +__chpe_metadata: + .word 2 + .rva __hybrid_code_map + .word __hybrid_code_map_count + .rva __x64_code_ranges_to_entry_points + .rva __arm64x_redirection_metadata + .word 0 // __os_arm64x_dispatch_call_no_redirect + .word 0 // __os_arm64x_dispatch_ret + .word 0 // __os_arm64x_check_call + .word 0 // __os_arm64x_check_icall + .word 0 // __os_arm64x_check_icall_cfg + .rva __arm64x_native_entrypoint + .rva __hybrid_auxiliary_iat + .word __x64_code_ranges_to_entry_points_count + .word __arm64x_redirection_metadata_count + .word 0 // __os_arm64x_get_x64_information + .word 0 // __os_arm64x_set_x64_information + .rva __arm64x_extra_rfe_table + .word __arm64x_extra_rfe_table_size + .word 0 // __os_arm64x_dispatch_fptr + .rva __hybrid_auxiliary_iat_copy + .rva __hybrid_auxiliary_delayload_iat + .rva __hybrid_auxiliary_delayload_iat_copy + .word __hybrid_image_info_bitfield + .word 0 // __os_arm64x_helper3 + .word 0 // __os_arm64x_helper4 + .word 0 // __os_arm64x_helper5 + .word 0 // __os_arm64x_helper6 + .word 0 // __os_arm64x_helper7 + .word 0 // __os_arm64x_helper8