Index: lld/test/COFF/loadcfg-chpe.s =================================================================== --- /dev/null +++ lld/test/COFF/loadcfg-chpe.s @@ -0,0 +1,76 @@ +# REQUIRES: aarch64 + +# RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %s -o %t.obj +# RUN: lld-link -machine:arm64ec -dll -noentry -out:%t.dll %t.obj +# RUN: llvm-readobj --coff-load-config %t.dll | FileCheck %s + +# CHECK: CHPEMetadataPointer: 0x180002000 +# CHECK: CHPEMetadata [ +# CHECK-NEXT: Version: 0x1 +# CHECK-NEXT: CodeMap [ +# CHECK-NEXT: 0x1000 - 0x1030 ARM64EC +# CHECK-NEXT: 0x2000 - 0x2040 ARM64 +# CHECK-NEXT: 0x3000 - 0x3050 X64 +# CHECK-NEXT: ] +# CHECK-NEXT: CodeMapCount: 3 +# CHECK-NEXT: CodeRangesToEntryPoints [ +# CHECK-NEXT: 0x1000 - 0x1020 -> 0x1000 +# CHECK-NEXT: 0x1020 - 0x1040 -> 0x2000 +# CHECK-NEXT: ] +# CHECK-NEXT: RedirectionMetadata [ +# CHECK-NEXT: 0x1000 -> 0x2000 +# CHECK-NEXT: 0x1020 -> 0x2030 +# CHECK-NEXT: ] + + .section .rdata,"dr" + .globl _load_config_used + .p2align 3, 0 +_load_config_used: + .word 0x140 + .fill 0xc4, 1, 0 + .xword __chpe_metadata + .fill 0x78, 1, 0 + + .data + .globl __chpe_metadata + .p2align 2, 0 +__chpe_metadata: + .word 1 + .rva __code_map + .word 3 + .rva __code_ranges + .rva __redir_metadata + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 2 + .word 2 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 +__code_map: + .word 0x1001 + .word 0x30 + .word 0x2000 + .word 0x40 + .word 0x3002 + .word 0x50 +__code_ranges: + .word 0x1000 + .word 0x1020 + .word 0x1000 + .word 0x1020 + .word 0x1040 + .word 0x2000 +__redir_metadata: + .word 0x1000 + .word 0x2000 + .word 0x1020 + .word 0x2030 Index: llvm/include/llvm/Object/COFF.h =================================================================== --- llvm/include/llvm/Object/COFF.h +++ llvm/include/llvm/Object/COFF.h @@ -722,6 +722,47 @@ support::ulittle64_t CastGuardOsDeterminedFailureMode; }; +struct chpe_metadata { + support::ulittle32_t Version; + support::ulittle32_t CodeMap; + support::ulittle32_t CodeMapCount; + support::ulittle32_t CodeRangesToEntryPoints; + support::ulittle32_t RedirectionMetadata; + support::ulittle32_t __os_arm64x_dispatch_call_no_redirect; + support::ulittle32_t __os_arm64x_dispatch_ret; + support::ulittle32_t __os_arm64x_dispatch_call; + support::ulittle32_t __os_arm64x_dispatch_icall; + support::ulittle32_t __os_arm64x_dispatch_icall_cfg; + support::ulittle32_t AlternateEntryPoint; + support::ulittle32_t AuxiliaryIAT; + support::ulittle32_t CodeRangesToEntryPointsCount; + support::ulittle32_t RedirectionMetadataCount; + support::ulittle32_t GetX64InformationFunctionPointer; + support::ulittle32_t SetX64InformationFunctionPointer; + support::ulittle32_t ExtraRFETable; + support::ulittle32_t ExtraRFETableSize; + support::ulittle32_t __os_arm64x_dispatch_fptr; + support::ulittle32_t AuxiliaryIATCopy; +}; + +struct chpe_range_entry { + support::ulittle32_t StartOffset; + support::ulittle32_t Length; +}; + +enum chpe_range_type { CHPE_RANGE_ARM64, CHPE_RANGE_ARM64EC, CHPE_RANGE_AMD64 }; + +struct chpe_code_range_entry { + support::ulittle32_t StartRva; + support::ulittle32_t EndRva; + support::ulittle32_t EntryPoint; +}; + +struct chpe_redirection_entry { + support::ulittle32_t Source; + support::ulittle32_t Destination; +}; + struct coff_runtime_function_x64 { support::ulittle32_t BeginAddress; support::ulittle32_t EndAddress; @@ -813,6 +854,7 @@ const coff_tls_directory64 *TLSDirectory64; // Either coff_load_configuration32 or coff_load_configuration64. const void *LoadConfig = nullptr; + const chpe_metadata *CHPEMetadata = nullptr; Expected getString(uint32_t offset) const; @@ -927,6 +969,9 @@ assert(is64()); return reinterpret_cast(LoadConfig); } + + const chpe_metadata *getCHPEMetadata() const { return CHPEMetadata; } + StringRef getRelocationTypeName(uint16_t Type) const; protected: Index: llvm/lib/Object/COFFObjectFile.cpp =================================================================== --- llvm/lib/Object/COFFObjectFile.cpp +++ llvm/lib/Object/COFFObjectFile.cpp @@ -753,6 +753,60 @@ return E; LoadConfig = (const void *)IntPtr; + + uintptr_t ChpeOff = 0; + if (is64()) { + auto Config = getLoadConfig64(); + if (Config->Size >= + offsetof(coff_load_configuration64, CHPEMetadataPointer) + + sizeof(Config->CHPEMetadataPointer)) + ChpeOff = Config->CHPEMetadataPointer; + } else { + auto Config = getLoadConfig32(); + if (Config->Size >= + offsetof(coff_load_configuration32, CHPEMetadataPointer) + + sizeof(Config->CHPEMetadataPointer)) + ChpeOff = Config->CHPEMetadataPointer; + } + if (ChpeOff) { + if (Error E = getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata")) + return E; + if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata))) + return E; + + CHPEMetadata = reinterpret_cast(IntPtr); + + // Validate CHPE metadata + if (CHPEMetadata->CodeMapCount) { + if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map")) + return E; + if (Error E = checkOffset(Data, IntPtr, + CHPEMetadata->CodeMapCount * + sizeof(chpe_range_entry))) + return E; + } + + if (CHPEMetadata->CodeRangesToEntryPointsCount) { + if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr, + "CHPE entry point ranges")) + return E; + if (Error E = checkOffset(Data, IntPtr, + CHPEMetadata->CodeRangesToEntryPointsCount * + sizeof(chpe_code_range_entry))) + return E; + } + + if (CHPEMetadata->RedirectionMetadataCount) { + if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr, + "CHPE redirection metadata")) + return E; + if (Error E = checkOffset(Data, IntPtr, + CHPEMetadata->RedirectionMetadataCount * + sizeof(chpe_redirection_entry))) + return E; + } + } + return Error::success(); } Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -842,6 +842,97 @@ else printCOFFLoadConfig(Obj->getLoadConfig32(), Tables); + if (auto CHPE = Obj->getCHPEMetadata()) { + ListScope LS(W, "CHPEMetadata"); + W.printHex("Version", CHPE->Version); + + if (CHPE->CodeMapCount) { + ListScope CMLS(W, "CodeMap"); + + uintptr_t CodeMapInt; + if (Error E = Obj->getRvaPtr(CHPE->CodeMap, CodeMapInt)) + reportError(std::move(E), Obj->getFileName()); + auto CodeMap = reinterpret_cast(CodeMapInt); + for (uint32_t i = 0; i < CHPE->CodeMapCount; i++) { + uint32_t Start = CodeMap[i].StartOffset & ~3; + W.startLine() << W.hex(Start) << " - " + << W.hex(Start + CodeMap[i].Length) << " "; + switch (CodeMap[i].StartOffset & 3) { + case CHPE_RANGE_ARM64: + W.getOStream() << "ARM64\n"; + break; + case CHPE_RANGE_ARM64EC: + W.getOStream() << "ARM64EC\n"; + break; + case CHPE_RANGE_AMD64: + W.getOStream() << "X64\n"; + break; + default: + W.getOStream() << W.hex(CodeMap[i].StartOffset & 3) << "\n"; + break; + } + } + } else { + W.printNumber("CodeMap", CHPE->CodeMap); + } + W.printNumber("CodeMapCount", CHPE->CodeMapCount); + + if (CHPE->CodeRangesToEntryPointsCount) { + ListScope CRLS(W, "CodeRangesToEntryPoints"); + + uintptr_t CodeRangesInt; + if (Error E = + Obj->getRvaPtr(CHPE->CodeRangesToEntryPoints, CodeRangesInt)) + reportError(std::move(E), Obj->getFileName()); + auto CodeRanges = + reinterpret_cast(CodeRangesInt); + for (uint32_t i = 0; i < CHPE->CodeRangesToEntryPointsCount; i++) { + W.startLine() << W.hex(CodeRanges[i].StartRva) << " - " + << W.hex(CodeRanges[i].EndRva) << " -> " + << W.hex(CodeRanges[i].EntryPoint) << "\n"; + } + } else { + W.printNumber("CodeRangesToEntryPoints", CHPE->CodeRangesToEntryPoints); + } + + if (CHPE->RedirectionMetadataCount) { + ListScope RMLS(W, "RedirectionMetadata"); + + uintptr_t RedirMetadataInt; + if (Error E = Obj->getRvaPtr(CHPE->RedirectionMetadata, RedirMetadataInt)) + reportError(std::move(E), Obj->getFileName()); + auto RedirMetadata = + reinterpret_cast(RedirMetadataInt); + for (uint32_t i = 0; i < CHPE->RedirectionMetadataCount; i++) { + W.startLine() << W.hex(RedirMetadata[i].Source) << " -> " + << W.hex(RedirMetadata[i].Destination) << "\n"; + } + } else { + W.printNumber("RedirectionMetadata", CHPE->RedirectionMetadata); + } + + W.printHex("__os_arm64x_dispatch_call_no_redirect", + CHPE->__os_arm64x_dispatch_call_no_redirect); + W.printHex("__os_arm64x_dispatch_ret", CHPE->__os_arm64x_dispatch_ret); + W.printHex("__os_arm64x_dispatch_call", CHPE->__os_arm64x_dispatch_call); + W.printHex("__os_arm64x_dispatch_icall", CHPE->__os_arm64x_dispatch_icall); + W.printHex("__os_arm64x_dispatch_icall_cfg", + CHPE->__os_arm64x_dispatch_icall_cfg); + W.printHex("AlternateEntryPoint", CHPE->AlternateEntryPoint); + W.printHex("AuxiliaryIAT", CHPE->AuxiliaryIAT); + W.printNumber("CodeRangesToEntryPointsCount", + CHPE->CodeRangesToEntryPointsCount); + W.printNumber("RedirectionMetadataCount", CHPE->RedirectionMetadataCount); + W.printHex("GetX64InformationFunctionPointer", + CHPE->GetX64InformationFunctionPointer); + W.printHex("SetX64InformationFunctionPointer", + CHPE->SetX64InformationFunctionPointer); + W.printHex("ExtraRFETable", CHPE->ExtraRFETable); + W.printHex("ExtraRFETableSize", CHPE->ExtraRFETableSize); + W.printHex("__os_arm64x_dispatch_fptr", CHPE->__os_arm64x_dispatch_fptr); + W.printHex("AuxiliaryIATCopy", CHPE->AuxiliaryIATCopy); + } + if (Tables.SEHTableVA) { ListScope LS(W, "SEHTable"); printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4); @@ -921,7 +1012,7 @@ W.printHex("SecurityCookie", Conf->SecurityCookie); // Print the safe SEH table if present. - if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction)) + if (Conf->Size < offsetof(T, GuardCFCheckFunction)) return; W.printHex("SEHandlerTable", Conf->SEHandlerTable); W.printNumber("SEHandlerCount", Conf->SEHandlerCount);