add unself tool

This commit is contained in:
DH 2024-11-13 21:59:36 +03:00
parent 1497d01fed
commit 245bc31b6d
4 changed files with 126 additions and 2 deletions

View file

@ -1,2 +1,3 @@
add_subdirectory(shader-tool)
add_subdirectory(spv-gen)
add_subdirectory(unself)

View file

@ -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);
}

View file

@ -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)

118
tools/unself/unself.cpp Normal file
View file

@ -0,0 +1,118 @@
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <elf.h>
#include <fstream>
#include <vector>
static std::vector<std::byte> 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<Header *>(image);
auto segments = std::bit_cast<Segment *>(image + sizeof(Header));
auto elfOffset = sizeof(Header) + sizeof(Segment) * header->segmentCount;
std::vector<std::byte> result;
result.reserve(header->fileSize);
result.resize(sizeof(Elf64_Ehdr));
auto ehdr = std::bit_cast<Elf64_Ehdr *>(image + elfOffset);
auto phdrs = std::bit_cast<Elf64_Phdr *>(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<std::byte> 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;
}