diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 50a403c60..00dcc3b9c 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(shader-tool) add_subdirectory(spv-gen) +add_subdirectory(unself) diff --git a/tools/shader-tool/shader-tool.cpp b/tools/shader-tool/shader-tool.cpp index 1b5c04714..21fb5732b 100644 --- a/tools/shader-tool/shader-tool.cpp +++ b/tools/shader-tool/shader-tool.cpp @@ -230,7 +230,7 @@ static bool writeOutput(OutputParam &outputParam, std::ostream &out, } else if (outputParam.type == OutputType::SpirvHeader) { writeSpvHeader(outputParam, out, spv); } else if (outputParam.type == OutputType::SpirvAssembly) { - out << shader::spv::disassembly(spv); + out << shader::spv::disassembly(spv, true); } else if (outputParam.type == OutputType::Glsl) { out << shader::glsl::decompile(spv); } else { @@ -301,7 +301,8 @@ static shader::ir::Region parseIsa(shader::ir::Context &context, } if (auto converted = shader::gcn::convertToSpv( - isaContext, ir, gcnSemanticModuleInfo, *inputParam.gcnStage, env)) { + isaContext, ir, gcnSemanticInfo, gcnSemanticModuleInfo, + *inputParam.gcnStage, env)) { if (auto result = shader::spv::deserialize(context, converted->spv, loc)) { return result->merge(context); } diff --git a/tools/unself/CMakeLists.txt b/tools/unself/CMakeLists.txt new file mode 100644 index 000000000..424cacc07 --- /dev/null +++ b/tools/unself/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(unself unself.cpp) + +set_target_properties(unself PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +install(TARGETS unself RUNTIME DESTINATION bin) diff --git a/tools/unself/unself.cpp b/tools/unself/unself.cpp new file mode 100644 index 000000000..3412fda9f --- /dev/null +++ b/tools/unself/unself.cpp @@ -0,0 +1,118 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +static std::vector unself(const std::byte *image, std::size_t size) { + struct [[gnu::packed]] Header { + std::uint32_t magic; + std::uint32_t unk; + std::uint8_t category; + std::uint8_t programType; + std::uint16_t padding; + std::uint16_t headerSize; + std::uint16_t signSize; + std::uint32_t fileSize; + std::uint32_t padding2; + std::uint16_t segmentCount; + std::uint16_t unk1; + std::uint32_t padding3; + }; + static_assert(sizeof(Header) == 0x20); + + struct [[gnu::packed]] Segment { + std::uint64_t flags; + std::uint64_t offset; + std::uint64_t encryptedSize; + std::uint64_t decryptedSize; + }; + static_assert(sizeof(Segment) == 0x20); + + auto header = std::bit_cast
(image); + auto segments = std::bit_cast(image + sizeof(Header)); + + auto elfOffset = sizeof(Header) + sizeof(Segment) * header->segmentCount; + std::vector result; + result.reserve(header->fileSize); + result.resize(sizeof(Elf64_Ehdr)); + + auto ehdr = std::bit_cast(image + elfOffset); + auto phdrs = std::bit_cast(image + elfOffset + ehdr->e_phoff); + std::memcpy(result.data(), ehdr, sizeof(Elf64_Ehdr)); + + auto phdrEndOffset = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; + if (result.size() < phdrEndOffset) { + result.resize(phdrEndOffset); + } + + for (std::size_t i = 0; i < ehdr->e_phnum; ++i) { + std::memcpy(result.data() + ehdr->e_phoff + ehdr->e_phentsize * i, + image + elfOffset + ehdr->e_phoff + ehdr->e_phentsize * i, + sizeof(Elf64_Phdr)); + } + + for (std::size_t i = 0; i < header->segmentCount; ++i) { + auto &segment = segments[i]; + if ((segment.flags & 0x7fb) != 0 || + segment.decryptedSize != segment.encryptedSize) { + std::fprintf(stderr, "Unsupported self segment (%lx)\n", segment.flags); + std::abort(); + } + + if (~segment.flags & 0x800) { + continue; + } + + auto &phdr = phdrs[segment.flags >> 20]; + + auto endOffset = phdr.p_offset + segment.decryptedSize; + if (result.size() < endOffset) { + result.resize(endOffset); + } + + std::memcpy(result.data() + phdr.p_offset, image + segment.offset, + segment.decryptedSize); + } + + return result; +} + +int main(int argc, const char *argv[]) { + if (argc != 3) { + return 1; + } + + std::vector image; + { + std::ifstream f(argv[1], std::ios::binary | std::ios::ate); + + if (!f) { + return 1; + } + + std::size_t size = f.tellg(); + f.seekg(0, std::ios::beg); + image.resize(size); + f.read((char *)image.data(), image.size()); + if (!f) { + return 1; + } + } + + auto result = unself(image.data(), image.size()); + + { + std::ofstream f(argv[2], std::ios::binary); + f.write((char *)result.data(), result.size()); + if (!f) { + return 1; + } + } + + return 0; +} \ No newline at end of file