diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h --- a/llvm/include/llvm/Object/COFF.h +++ b/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: diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -753,6 +753,54 @@ return E; LoadConfig = (const void *)IntPtr; + + if (is64()) { + auto Config = getLoadConfig64(); + if (Config->Size >= + offsetof(coff_load_configuration64, CHPEMetadataPointer) + + sizeof(Config->CHPEMetadataPointer) && + Config->CHPEMetadataPointer) { + uint64_t ChpeOff = Config->CHPEMetadataPointer; + 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(); } diff --git a/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml b/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml @@ -0,0 +1,49 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj --coff-load-config %t | FileCheck %s + +# CHECK: CHPEMetadataPointer: 0x180005000 +# 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: 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: ] + +--- !COFF +OptionalHeader: + ImageBase: 0x180000000 + SectionAlignment: 4096 + FileAlignment: 512 + DLLCharacteristics: [ ] + LoadConfigTable: + RelativeVirtualAddress: 0x4000 + Size: 320 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 0x1000 + VirtualSize: 0x2050 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 0x4000 + VirtualSize: 328 + SectionData: '40010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 0x5000 + VirtualSize: 144 + SectionData: '010000005050000003000000685000008050000000000000000000000000000000000000000000000000000000000000020000000200000000000000000000000000000000000000000000000000000001100000300000000020000040000000023000005000000000100000201000000010000020100000401000000020000000100000002000002010000030200000' +symbols: [] +... diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -842,6 +842,93 @@ 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); + } + + 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.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 +1008,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);