From cbfcdc3ebc97111ca298d20cdea996bb14c2283f Mon Sep 17 00:00:00 2001 From: Sajid Date: Mon, 9 Sep 2024 23:23:04 +0600 Subject: [PATCH] Move C emit code to PowerRecomp --- PowerAnalyse/CMakeLists.txt | 5 ++ PowerAnalyse/function.cpp | 1 + PowerAnalyse/main.cpp | 96 +------------------------ PowerRecomp/CMakeLists.txt | 4 +- PowerRecomp/main.cpp | 136 ++++++++++++++++++++++++++++++++++++ PowerUtils/file.h | 7 +- 6 files changed, 149 insertions(+), 100 deletions(-) diff --git a/PowerAnalyse/CMakeLists.txt b/PowerAnalyse/CMakeLists.txt index d928e2d..78499dc 100644 --- a/PowerAnalyse/CMakeLists.txt +++ b/PowerAnalyse/CMakeLists.txt @@ -3,4 +3,9 @@ project("PowerAnalyse") add_executable(PowerAnalyse "main.cpp" "function.h" "function.cpp") +add_library(LibPowerAnalyse "function.h" "function.cpp") + +target_include_directories(LibPowerAnalyse PUBLIC .) +target_link_libraries(LibPowerAnalyse PUBLIC PowerUtils) + target_link_libraries(PowerAnalyse PRIVATE PowerUtils) diff --git a/PowerAnalyse/function.cpp b/PowerAnalyse/function.cpp index 91d94c7..7eb154e 100644 --- a/PowerAnalyse/function.cpp +++ b/PowerAnalyse/function.cpp @@ -131,6 +131,7 @@ Function Function::Analyze(const void* code, size_t size, size_t base) const auto branchBase = insn.operands[0] - base; const auto branchBlock = fn.SearchBlock(insn.operands[0]); + // carry over our projection if blocks are next to each other const auto isContinious = branchBase == curBlock.base + curBlock.size; auto sizeProjection = (size_t)-1; diff --git a/PowerAnalyse/main.cpp b/PowerAnalyse/main.cpp index 88feef6..a31d11d 100644 --- a/PowerAnalyse/main.cpp +++ b/PowerAnalyse/main.cpp @@ -7,7 +7,7 @@ int main() { - const auto file = LoadFile("cond-fall.elf"); + const auto file = LoadFile("cond-fall.elf").value(); auto image = Image::ParseImage(file.data(), file.size()).value(); for (const auto& section : image.sections) @@ -72,99 +72,5 @@ int main() } std::println(""); - - FILE* f = fopen("add.elf.cpp", "w"); - for (const auto& fn : functions) - { - auto base = fn.base; - auto end = base + fn.size; - auto* data = (uint32_t*)image.Find(base); - - std::string name = ""; - auto symbol = image.symbols.find(base); - if (symbol != image.symbols.end()) - { - name = symbol->name; - } - else - { - name = std::format("sub_{:X}", base); - } - - std::println(f, "void {}() {{", name); - - ppc_insn insn; - while (base < end) - { - ppc::Disassemble(data, 4, base, insn); - - base += 4; - ++data; - if (insn.opcode == nullptr) - { - std::println(f, "\t// {:x} {}", base - 4, insn.op_str); - } - else - { - std::println(f, "\t// {:x} {} {}", base - 4, insn.opcode->name, insn.op_str); - switch (insn.opcode->id) - { - case PPC_INST_ADD: - std::println(f, "\tr{} = r{} + r{};", insn.operands[0], insn.operands[1], insn.operands[2]); - break; - case PPC_INST_ADDI: - std::println(f, "\tr{} = r{} + {};", insn.operands[0], insn.operands[1], insn.operands[2]); - break; - case PPC_INST_STWU: - std::println(f, "\tea = r{} + {};", insn.operands[2], static_cast(insn.operands[1])); - std::println(f, "\t*ea = byteswap(r{});", insn.operands[0]); - std::println(f, "\tr{} = ea;", insn.operands[2]); - break; - case PPC_INST_STW: - std::println(f, "\t*(r{} + {}) = byteswap(r{});", insn.operands[2], static_cast(insn.operands[1]), insn.operands[0]); - break; - case PPC_INST_MR: - std::println(f, "\tr{} = r{};", insn.operands[0], insn.operands[1]); - break; - case PPC_INST_LWZ: - std::println(f, "\tr{} = *(r{} + {});", insn.operands[0], insn.operands[2], insn.operands[1]); - break; - case PPC_INST_LI: - std::println(f, "\tr{} = {};", insn.operands[0], insn.operands[1]); - break; - case PPC_INST_MFLR: - std::println(f, "\tr{} = lr;", insn.operands[0]); - break; - case PPC_INST_MTLR: - std::println(f, "\tlr = r{};", insn.operands[0]); - break; - case PPC_INST_BLR: - std::println(f, "\treturn;"); - break; - case PPC_INST_BL: - { - std::string targetName = ""; - auto targetSymbol = image.symbols.find(insn.operands[0]); - if (targetSymbol != image.symbols.end() && targetSymbol->type == Symbol_Function) - { - targetName = targetSymbol->name; - } - else - { - targetName = std::format("sub_{:X}", insn.operands[0]); - } - std::println(f, "\tlr = 0x{:x};", base); - std::println(f, "\t{}();", targetName); - break; - } - } - } - } - - std::println(f, "}}\n"); - } - - fclose(f); - return 0; } diff --git a/PowerRecomp/CMakeLists.txt b/PowerRecomp/CMakeLists.txt index 0205a7f..f80739b 100644 --- a/PowerRecomp/CMakeLists.txt +++ b/PowerRecomp/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.8) project("PowerRecomp") -add_executable(PowerRecomp "main.cpp") -set_property(TARGET PowerRecomp PROPERTY CXX_STANDARD 20) \ No newline at end of file +add_executable(PowerRecomp "main.cpp") +target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse) diff --git a/PowerRecomp/main.cpp b/PowerRecomp/main.cpp index 905869d..22727b4 100644 --- a/PowerRecomp/main.cpp +++ b/PowerRecomp/main.cpp @@ -1,4 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#define TEST_FILE "add.elf" + int main() { + const auto file = LoadFile(TEST_FILE).value(); + auto image = Image::ParseImage(file.data(), file.size()).value(); + + // TODO: Load functions from an existing database + std::vector functions; + for (const auto& section : image.sections) + { + if (!(section.flags & SectionFlags_Code)) + { + continue; + } + + size_t base = section.base; + uint8_t* data = section.data; + uint8_t* dataEnd = section.data + section.size; + while (data < dataEnd) + { + if (*(uint32_t*)data == 0) + { + data += 4; + base += 4; + continue; + } + + const auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); + data += fn.size; + base += fn.size; + + image.symbols.emplace(std::format("sub_{:X}", fn.base), fn.base, fn.size, Symbol_Function); + } + } + + std::filesystem::create_directory("out"); + FILE* f = fopen("out/" TEST_FILE ".cpp", "w"); + for (const auto& fn : functions) + { + auto base = fn.base; + auto end = base + fn.size; + auto* data = (uint32_t*)image.Find(base); + + std::string name = ""; + auto symbol = image.symbols.find(base); + if (symbol != image.symbols.end()) + { + name = symbol->name; + } + else + { + name = std::format("sub_{:X}", base); + } + + std::println(f, "void {}() {{", name); + + ppc_insn insn; + while (base < end) + { + ppc::Disassemble(data, 4, base, insn); + + base += 4; + ++data; + if (insn.opcode == nullptr) + { + std::println(f, "\t// {:x} {}", base - 4, insn.op_str); + } + else + { + std::println(f, "\t// {:x} {} {}", base - 4, insn.opcode->name, insn.op_str); + switch (insn.opcode->id) + { + case PPC_INST_ADD: + std::println(f, "\tr{} = r{} + r{};", insn.operands[0], insn.operands[1], insn.operands[2]); + break; + case PPC_INST_ADDI: + std::println(f, "\tr{} = r{} + {};", insn.operands[0], insn.operands[1], insn.operands[2]); + break; + case PPC_INST_STWU: + std::println(f, "\tea = r{} + {};", insn.operands[2], static_cast(insn.operands[1])); + std::println(f, "\t*ea = byteswap(r{});", insn.operands[0]); + std::println(f, "\tr{} = ea;", insn.operands[2]); + break; + case PPC_INST_STW: + std::println(f, "\t*(r{} + {}) = byteswap(r{});", insn.operands[2], static_cast(insn.operands[1]), insn.operands[0]); + break; + case PPC_INST_MR: + std::println(f, "\tr{} = r{};", insn.operands[0], insn.operands[1]); + break; + case PPC_INST_LWZ: + std::println(f, "\tr{} = *(r{} + {});", insn.operands[0], insn.operands[2], insn.operands[1]); + break; + case PPC_INST_LI: + std::println(f, "\tr{} = {};", insn.operands[0], insn.operands[1]); + break; + case PPC_INST_MFLR: + std::println(f, "\tr{} = lr;", insn.operands[0]); + break; + case PPC_INST_MTLR: + std::println(f, "\tlr = r{};", insn.operands[0]); + break; + case PPC_INST_BLR: + std::println(f, "\treturn;"); + break; + case PPC_INST_BL: + { + std::string targetName = ""; + auto targetSymbol = image.symbols.find(insn.operands[0]); + if (targetSymbol != image.symbols.end() && targetSymbol->type == Symbol_Function) + { + targetName = targetSymbol->name; + } + else + { + targetName = std::format("sub_{:X}", insn.operands[0]); + } + std::println(f, "\tlr = 0x{:x};", base); + std::println(f, "\t{}();", targetName); + break; + } + } + } + } + + std::println(f, "}}\n"); + } + + fclose(f); + return 0; } diff --git a/PowerUtils/file.h b/PowerUtils/file.h index 145fe4f..473086b 100644 --- a/PowerUtils/file.h +++ b/PowerUtils/file.h @@ -1,13 +1,14 @@ #pragma once +#include #include -inline static std::vector LoadFile(const char* path) +inline static std::expected, int> LoadFile(const char* path) { std::vector data{}; auto* stream = fopen(path, "rb"); if (stream == nullptr) { - return data; + return std::unexpected(1); } fseek(stream, 0, SEEK_END); @@ -22,4 +23,4 @@ inline static std::vector LoadFile(const char* path) fclose(stream); return data; -} \ No newline at end of file +}