diff --git a/llvm/include/llvm-c/Object.h b/llvm/include/llvm-c/Object.h index 0fc4ebe969a06..f24f768570c5e 100644 --- a/llvm/include/llvm-c/Object.h +++ b/llvm/include/llvm-c/Object.h @@ -55,6 +55,7 @@ typedef enum { LLVMBinaryTypeMachO64B, /**< MachO 64-bit, big endian. */ LLVMBinaryTypeWasm, /**< Web Assembly. */ LLVMBinaryTypeOffload, /**< Offloading fatbinary. */ + LLVMBinaryTypeDXcontainer, /**< DirectX Binary Container. */ } LLVMBinaryType; diff --git a/llvm/include/llvm/Object/Binary.h b/llvm/include/llvm/Object/Binary.h index bd98f40dbc706..a531ba6a812c4 100644 --- a/llvm/include/llvm/Object/Binary.h +++ b/llvm/include/llvm/Object/Binary.h @@ -72,6 +72,7 @@ class LLVM_ABI Binary { ID_GOFF, ID_Wasm, + ID_DXContainer, ID_EndObjects }; @@ -161,6 +162,8 @@ class LLVM_ABI Binary { bool isWinRes() const { return TypeID == ID_WinRes; } + bool isDXContainer() const { return TypeID == ID_DXContainer; } + Triple::ObjectFormatType getTripleObjectFormat() const { if (isCOFF()) return Triple::COFF; diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h index 51f570da6df52..3c8cd174afede 100644 --- a/llvm/include/llvm/Object/DXContainer.h +++ b/llvm/include/llvm/Object/DXContainer.h @@ -20,6 +20,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/DXContainer.h" #include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -499,6 +500,7 @@ class DXContainer { } IteratorState; friend class DXContainer; + friend class DXContainerObjectFile; PartIterator(const DXContainer &C, SmallVectorImpl::const_iterator It) @@ -584,6 +586,79 @@ class DXContainer { } }; +class DXContainerObjectFile : public ObjectFile { +private: + friend class ObjectFile; + DXContainer Container; + + using PartData = DXContainer::PartIterator::PartData; + llvm::SmallVector Parts; + using PartIterator = llvm::SmallVector::iterator; + + DXContainerObjectFile(DXContainer C) + : ObjectFile(ID_DXContainer, MemoryBufferRef(C.getData(), "")), + Container(C) { + for (auto &P : C) + Parts.push_back(P); + } + +public: + static bool classof(const Binary *v) { return v->isDXContainer(); } + + Expected getSymbolName(DataRefImpl) const override; + Expected getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + + Expected getSymbolType(DataRefImpl Symb) const override; + Expected getSymbolSection(DataRefImpl Symb) const override; + void moveSectionNext(DataRefImpl &Sec) const override; + Expected getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + Expected> + getSectionContents(DataRefImpl Sec) const override; + + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl &Result) const override; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + Expected getFeatures() const override; + + void moveSymbolNext(DataRefImpl &Symb) const override {} + Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; + Expected getSymbolFlags(DataRefImpl Symb) const override; + basic_symbol_iterator symbol_begin() const override { + return basic_symbol_iterator(SymbolRef()); + } + basic_symbol_iterator symbol_end() const override { + return basic_symbol_iterator(SymbolRef()); + } + bool is64Bit() const override { return false; } + + bool isRelocatableObject() const override { return false; } +}; + } // namespace object } // namespace llvm diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h index 613c36a6a56d7..289cc770e3466 100644 --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -44,6 +44,7 @@ class SectionRef; class SymbolRef; class symbol_iterator; class WasmObjectFile; +class DXContainerObjectFile; using section_iterator = content_iterator; @@ -401,6 +402,9 @@ class LLVM_ABI ObjectFile : public SymbolicFile { static Expected> createWasmObjectFile(MemoryBufferRef Object); + + static Expected> + createDXContainerObjectFile(MemoryBufferRef Object); }; /// A filtered iterator for SectionRefs that skips sections based on some given diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp index 2dfae8ab5d3c6..da2a7bb0a19da 100644 --- a/llvm/lib/Object/Binary.cpp +++ b/llvm/lib/Object/Binary.cpp @@ -75,6 +75,7 @@ Expected> object::createBinary(MemoryBufferRef Buffer, case file_magic::xcoff_object_32: case file_magic::xcoff_object_64: case file_magic::wasm_object: + case file_magic::dxcontainer_object: return ObjectFile::createSymbolicFile(Buffer, Type, Context, InitContent); case file_magic::macho_universal_binary: return MachOUniversalBinary::create(Buffer); @@ -87,7 +88,6 @@ Expected> object::createBinary(MemoryBufferRef Buffer, case file_magic::clang_ast: case file_magic::cuda_fatbinary: case file_magic::coff_cl_gl_object: - case file_magic::dxcontainer_object: case file_magic::offload_bundle: case file_magic::offload_bundle_compressed: case file_magic::spirv_object: diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp index 0b46ff71240b7..031b9414f4c1a 100644 --- a/llvm/lib/Object/DXContainer.cpp +++ b/llvm/lib/Object/DXContainer.cpp @@ -11,6 +11,7 @@ #include "llvm/Object/Error.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/TargetParser/SubtargetFeature.h" using namespace llvm; using namespace llvm::object; @@ -515,3 +516,183 @@ uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const { return P->SigPatchOrPrimElements; return 0; } + +class DXNotSupportedError : public ErrorInfo { +public: + static char ID; + + DXNotSupportedError(StringRef S) : FeatureString(S) {} + + void log(raw_ostream &OS) const override { + OS << "DXContainer does not support " << FeatureString; + } + + std::error_code convertToErrorCode() const override { + return inconvertibleErrorCode(); + } + +private: + StringRef FeatureString; +}; + +char DXNotSupportedError::ID = 0; + +Expected +DXContainerObjectFile::getSymbolSection(DataRefImpl Symb) const { + return make_error("Symbol sections"); +} + +Expected DXContainerObjectFile::getSymbolName(DataRefImpl) const { + return make_error("Symbol names"); +} + +Expected +DXContainerObjectFile::getSymbolAddress(DataRefImpl Symb) const { + return make_error("Symbol addresses"); +} + +uint64_t DXContainerObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + llvm_unreachable("DXContainer does not support symbols"); +} +uint64_t +DXContainerObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + llvm_unreachable("DXContainer does not support symbols"); +} + +Expected +DXContainerObjectFile::getSymbolType(DataRefImpl Symb) const { + return make_error("Symbol types"); +} + +void DXContainerObjectFile::moveSectionNext(DataRefImpl &Sec) const { + PartIterator It = reinterpret_cast(Sec.p); + if (It == Parts.end()) + return; + + ++It; + Sec.p = reinterpret_cast(It); +} + +Expected +DXContainerObjectFile::getSectionName(DataRefImpl Sec) const { + PartIterator It = reinterpret_cast(Sec.p); + return StringRef(It->Part.getName()); +} + +uint64_t DXContainerObjectFile::getSectionAddress(DataRefImpl Sec) const { + PartIterator It = reinterpret_cast(Sec.p); + return It->Offset; +} + +uint64_t DXContainerObjectFile::getSectionIndex(DataRefImpl Sec) const { + return (Sec.p - reinterpret_cast(Parts.begin())) / + sizeof(PartIterator); +} + +uint64_t DXContainerObjectFile::getSectionSize(DataRefImpl Sec) const { + PartIterator It = reinterpret_cast(Sec.p); + return It->Data.size(); +} +Expected> +DXContainerObjectFile::getSectionContents(DataRefImpl Sec) const { + PartIterator It = reinterpret_cast(Sec.p); + return ArrayRef(It->Data.bytes_begin(), It->Data.size()); +} + +uint64_t DXContainerObjectFile::getSectionAlignment(DataRefImpl Sec) const { + return 1; +} + +bool DXContainerObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return false; +} + +bool DXContainerObjectFile::isSectionText(DataRefImpl Sec) const { + return false; +} + +bool DXContainerObjectFile::isSectionData(DataRefImpl Sec) const { + return false; +} + +bool DXContainerObjectFile::isSectionBSS(DataRefImpl Sec) const { + return false; +} + +bool DXContainerObjectFile::isSectionVirtual(DataRefImpl Sec) const { + return false; +} + +relocation_iterator +DXContainerObjectFile::section_rel_begin(DataRefImpl Sec) const { + return relocation_iterator(RelocationRef()); +} + +relocation_iterator +DXContainerObjectFile::section_rel_end(DataRefImpl Sec) const { + return relocation_iterator(RelocationRef()); +} + +void DXContainerObjectFile::moveRelocationNext(DataRefImpl &Rel) const { + llvm_unreachable("DXContainer does not support relocations"); +} + +uint64_t DXContainerObjectFile::getRelocationOffset(DataRefImpl Rel) const { + llvm_unreachable("DXContainer does not support relocations"); +} + +symbol_iterator +DXContainerObjectFile::getRelocationSymbol(DataRefImpl Rel) const { + return symbol_iterator(SymbolRef()); +} + +uint64_t DXContainerObjectFile::getRelocationType(DataRefImpl Rel) const { + llvm_unreachable("DXContainer does not support relocations"); +} + +void DXContainerObjectFile::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl &Result) const { + llvm_unreachable("DXContainer does not support relocations"); +} + +section_iterator DXContainerObjectFile::section_begin() const { + DataRefImpl Sec; + Sec.p = reinterpret_cast(Parts.begin()); + return section_iterator(SectionRef(Sec, this)); +} +section_iterator DXContainerObjectFile::section_end() const { + DataRefImpl Sec; + Sec.p = reinterpret_cast(Parts.end()); + return section_iterator(SectionRef(Sec, this)); +} + +uint8_t DXContainerObjectFile::getBytesInAddress() const { return 4; } + +StringRef DXContainerObjectFile::getFileFormatName() const { + return "DirectX Container"; +} + +Triple::ArchType DXContainerObjectFile::getArch() const { return Triple::dxil; } + +Expected DXContainerObjectFile::getFeatures() const { + return SubtargetFeatures(); +} + +Error DXContainerObjectFile::printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const { + return make_error("Symbol names"); +} + +Expected +DXContainerObjectFile::getSymbolFlags(DataRefImpl Symb) const { + return make_error("Symbol flags"); +} + +Expected> +ObjectFile::createDXContainerObjectFile(MemoryBufferRef Object) { + auto ExC = DXContainer::create(Object); + if (!ExC) + return ExC.takeError(); + std::unique_ptr Obj(new DXContainerObjectFile(*ExC)); + return std::move(Obj); +} diff --git a/llvm/lib/Object/Object.cpp b/llvm/lib/Object/Object.cpp index c62944ad3eeba..112927ed69e84 100644 --- a/llvm/lib/Object/Object.cpp +++ b/llvm/lib/Object/Object.cpp @@ -124,6 +124,8 @@ LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) { return LLVMBinaryTypeOffload; case ID_Wasm: return LLVMBinaryTypeWasm; + case ID_DXContainer: + return LLVMBinaryTypeDXcontainer; case ID_StartObjects: case ID_EndObjects: llvm_unreachable("Marker types are not valid binary kinds!"); diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp index 6a226a3bbdbca..b0e4ea0a51ba1 100644 --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -15,6 +15,7 @@ #include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/DXContainer.h" #include "llvm/Object/Error.h" #include "llvm/Object/MachO.h" #include "llvm/Object/Wasm.h" @@ -165,7 +166,6 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, case file_magic::goff_object: case file_magic::cuda_fatbinary: case file_magic::offload_binary: - case file_magic::dxcontainer_object: case file_magic::offload_bundle: case file_magic::offload_bundle_compressed: case file_magic::spirv_object: @@ -201,6 +201,8 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, return createXCOFFObjectFile(Object, Binary::ID_XCOFF64); case file_magic::wasm_object: return createWasmObjectFile(Object); + case file_magic::dxcontainer_object: + return createDXContainerObjectFile(Object); } llvm_unreachable("Unexpected Object File Type"); } diff --git a/llvm/lib/Object/SymbolicFile.cpp b/llvm/lib/Object/SymbolicFile.cpp index e87ecb1491090..47295e6027f2c 100644 --- a/llvm/lib/Object/SymbolicFile.cpp +++ b/llvm/lib/Object/SymbolicFile.cpp @@ -68,6 +68,7 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type, case file_magic::xcoff_object_32: case file_magic::xcoff_object_64: case file_magic::wasm_object: + case file_magic::dxcontainer_object: return ObjectFile::createObjectFile(Object, Type, InitContent); case file_magic::coff_import_library: return std::unique_ptr(new COFFImportFile(Object)); @@ -123,6 +124,7 @@ bool SymbolicFile::isSymbolicFile(file_magic Type, const LLVMContext *Context) { case file_magic::elf_relocatable: case file_magic::macho_object: case file_magic::coff_object: + case file_magic::dxcontainer_object: return true; default: return false; diff --git a/llvm/test/tools/llvm-objdump/DXContainer/part-headers.yaml b/llvm/test/tools/llvm-objdump/DXContainer/part-headers.yaml new file mode 100644 index 0000000000000..c989705a1a122 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/DXContainer/part-headers.yaml @@ -0,0 +1,64 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -h %t | FileCheck %s --check-prefix=HEADERS +# RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=CONTENTS + +#HEADERS: Idx Name Size VMA Type +#HEADERS-NEXT: 0 FKE0 00000008 0000003c +#HEADERS-NEXT: 1 FKE1 00000008 0000004c +#HEADERS-NEXT: 2 FKE2 00000008 0000005c +#HEADERS-NEXT: 3 FKE3 00000078 0000006c +#HEADERS-NEXT: 4 FKE4 00000698 000000ec +#HEADERS-NEXT: 5 FKE5 00000014 0000078c +#HEADERS-NEXT: 6 DXIL 0000001c 000007a8 + +#CONTENTS: Contents of section FKE0: +#CONTENTS: 003c 00000000 00000000 ........ +#CONTENTS: Contents of section FKE1: +#CONTENTS: 004c 00000000 00000000 ........ +#CONTENTS: Contents of section FKE2: +#CONTENTS: 005c 00000000 00000000 ........ +#CONTENTS: Contents of section FKE3: +#CONTENTS: 006c 00000000 00000000 00000000 00000000 ................ +#CONTENTS: Contents of section FKE4: +#CONTENTS: 00ec 00000000 00000000 00000000 00000000 ................ +#CONTENTS: Contents of section FKE5: +#CONTENTS: 078c 00000000 00000000 00000000 00000000 ................ +#CONTENTS: Contents of section DXIL: +#CONTENTS-NEXT: 07a8 65000500 08000000 4458494c 05010000 e.......DXIL.... +#CONTENTS-NEXT: 07b8 10000000 04000000 4243c0de ........BC.. + +--- !dxcontainer +Header: + Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ] + Version: + Major: 1 + Minor: 0 + FileSize: 3548 + PartCount: 7 + PartOffsets: [ 60, 76, 92, 108, 236, 1932, 1960 ] +Parts: + - Name: FKE0 + Size: 8 + - Name: FKE1 + Size: 8 + - Name: FKE2 + Size: 8 + - Name: FKE3 + Size: 120 + - Name: FKE4 + Size: 1688 + - Name: FKE5 + Size: 20 + - Name: DXIL + Size: 28 + Program: + MajorVersion: 6 + MinorVersion: 5 + ShaderKind: 5 + Size: 8 + DXILMajorVersion: 1 + DXILMinorVersion: 5 + DXILSize: 4 + DXIL: [ 0x42, 0x43, 0xC0, 0xDE, ] +... diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt index 7e3197f0a0bd3..41d301cd3d77d 100644 --- a/llvm/tools/llvm-objdump/CMakeLists.txt +++ b/llvm/tools/llvm-objdump/CMakeLists.txt @@ -28,6 +28,7 @@ add_llvm_tool(llvm-objdump llvm-objdump.cpp SourcePrinter.cpp COFFDump.cpp + DXContainerDump.cpp ELFDump.cpp MachODump.cpp OffloadDump.cpp diff --git a/llvm/tools/llvm-objdump/DXContainerDump.cpp b/llvm/tools/llvm-objdump/DXContainerDump.cpp new file mode 100644 index 0000000000000..2fb073473de53 --- /dev/null +++ b/llvm/tools/llvm-objdump/DXContainerDump.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the DXContainer-specific dumper for llvm-objdump. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/DXContainer.h" + +using namespace llvm; + +namespace { +class DXContainerDumper : public objdump::Dumper { +public: + DXContainerDumper(const object::DXContainerObjectFile &Obj) + : objdump::Dumper(Obj) {} +}; +} // namespace + +std::unique_ptr llvm::objdump::createDXContainerDumper( + const object::DXContainerObjectFile &Obj) { + return std::make_unique(Obj); +} diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 0316c4ba51da6..60365a698433c 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -50,6 +50,7 @@ #include "llvm/Object/BuildID.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/DXContainer.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Object/FaultMapParser.h" @@ -386,6 +387,8 @@ static Expected> createDumper(const ObjectFile &Obj) { return createWasmDumper(*O); if (const auto *O = dyn_cast(&Obj)) return createXCOFFDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createDXContainerDumper(*O); return createStringError(errc::invalid_argument, "unsupported object file format"); diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h index ce0642950ebdd..3525be9a5314a 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -36,6 +36,7 @@ class ELFObjectFileBase; class MachOObjectFile; class WasmObjectFile; class XCOFFObjectFile; +class DXContainer; } // namespace object namespace objdump { @@ -105,6 +106,8 @@ std::unique_ptr createELFDumper(const object::ELFObjectFileBase &Obj); std::unique_ptr createMachODumper(const object::MachOObjectFile &Obj); std::unique_ptr createWasmDumper(const object::WasmObjectFile &Obj); std::unique_ptr createXCOFFDumper(const object::XCOFFObjectFile &Obj); +std::unique_ptr +createDXContainerDumper(const object::DXContainerObjectFile &Obj); // Various helper functions.