diff --git a/PowerAnalyse/function.cpp b/PowerAnalyse/function.cpp index bc06b15..0737a2c 100644 --- a/PowerAnalyse/function.cpp +++ b/PowerAnalyse/function.cpp @@ -40,6 +40,13 @@ size_t Function::SearchBlock(size_t address) const Function Function::Analyze(const void* code, size_t size, size_t base) { Function fn{ base, 0 }; + + if (*((uint32_t*)code + 1) == 0x04000048) // shifted ptr tail call + { + fn.size = 0x8; + return fn; + } + auto& blocks = fn.blocks; blocks.reserve(8); blocks.emplace_back(); diff --git a/PowerRecomp/CMakeLists.txt b/PowerRecomp/CMakeLists.txt index 0e749ce..53c04e5 100644 --- a/PowerRecomp/CMakeLists.txt +++ b/PowerRecomp/CMakeLists.txt @@ -4,6 +4,6 @@ project("PowerRecomp") BIN2H(SOURCE_FILE ${POWERUTILS_ROOT}/ppc_context.h HEADER_FILE "generated/ppc_context.gen.h" VARIABLE_NAME "gPPCContextText") -add_executable(PowerRecomp "main.cpp" "pch.h" "recompiler.cpp" "recompiler.h" "swa_recompiler.cpp" "swa_recompiler.h" "test_recompiler.cpp" "test_recompiler.h") +add_executable(PowerRecomp "main.cpp" "pch.h" "recompiler.cpp" "recompiler.h" "test_recompiler.cpp" "test_recompiler.h" "recompiler_config.h" "recompiler_config.cpp") target_precompile_headers(PowerRecomp PUBLIC "pch.h") target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse tomlplusplus::tomlplusplus xxHash::xxhash) diff --git a/PowerRecomp/main.cpp b/PowerRecomp/main.cpp index db0e4b5..f172546 100644 --- a/PowerRecomp/main.cpp +++ b/PowerRecomp/main.cpp @@ -1,32 +1,20 @@ #include "pch.h" -#include "swa_recompiler.h" #include "test_recompiler.h" -// argv 1: xex file path -// argv 2: switches toml file path -// argv 3: output directory path - int main(int argc, char* argv[]) { - if (strstr(argv[1], ".xex") != nullptr) + const char* path = + #ifdef CONFIG_FILE_PATH + CONFIG_FILE_PATH + #else + argv[1] + #endif + ; + + if (std::filesystem::is_regular_file(path)) { - SWARecompiler recompiler; - //recompiler.config.skipLr = true; - recompiler.config.ctrAsLocalVariable = true; - recompiler.config.xerAsLocalVariable = true; - recompiler.config.reservedRegisterAsLocalVariable = true; - recompiler.config.skipMsr = true; - recompiler.config.crRegistersAsLocalVariables = true; - recompiler.config.nonArgumentRegistersAsLocalVariables = true; - recompiler.config.nonVolatileRegistersAsLocalVariables = true; - - std::println("Loading executable..."); - recompiler.LoadExecutable(argv[1]); - - std::println("Loading switch tables..."); - recompiler.LoadSwitchTables(argv[2]); - - std::println("Analysing functions..."); + Recompiler recompiler; + recompiler.LoadConfig(path); recompiler.Analyse(); auto entry = recompiler.image.symbols.find(recompiler.image.entry_point); @@ -35,11 +23,11 @@ int main(int argc, char* argv[]) entry->name = "_xstart"; } - recompiler.Recompile(argv[3]); + recompiler.Recompile(); } else { - TestRecompiler::RecompileTests(argv[1], argv[2]); + TestRecompiler::RecompileTests(path, argv[2]); } return 0; diff --git a/PowerRecomp/recompiler.cpp b/PowerRecomp/recompiler.cpp index ca6f909..c0ca801 100644 --- a/PowerRecomp/recompiler.cpp +++ b/PowerRecomp/recompiler.cpp @@ -9,33 +9,156 @@ static uint64_t ComputeMask(uint32_t mstart, uint32_t mstop) return mstart <= mstop ? value : ~value; } -void Recompiler::LoadSwitchTables(const char* filePath) +void Recompiler::LoadConfig(const std::string_view& configFilePath) { - toml::table toml = toml::parse_file(filePath); - for (auto& entry : *toml["switch"].as_array()) - { - auto& table = *entry.as_table(); + config.Load(configFilePath); - SwitchTable switchTable; - switchTable.r = *table["r"].value(); - for (auto& array : *table["labels"].as_array()) - switchTable.labels.push_back(*array.value()); - - switchTables.emplace(*table["base"].value(), std::move(switchTable)); - } + const auto file = LoadFile((config.directoryPath + config.filePath).c_str()).value(); + image = Image::ParseImage(file.data(), file.size()).value(); } -void Recompiler::LoadExecutable(const char* filePath) +void Recompiler::Analyse() { - const auto file = LoadFile(filePath).value(); - image = Image::ParseImage(file.data(), file.size()).value(); + for (size_t i = 14; i < 128; i++) + { + if (i < 32) + { + auto& restgpr = functions.emplace_back(); + restgpr.base = config.restGpr14Address + (i - 14) * 4; + restgpr.size = (32 - i) * 4 + 12; + image.symbols.emplace(std::format("__restgprlr_{}", i), restgpr.base, restgpr.size, Symbol_Function); + + auto& savegpr = functions.emplace_back(); + savegpr.base = config.saveGpr14Address + (i - 14) * 4; + savegpr.size = (32 - i) * 4 + 8; + image.symbols.emplace(std::format("__savegprlr_{}", i), savegpr.base, savegpr.size, Symbol_Function); + + auto& restfpr = functions.emplace_back(); + restfpr.base = config.restFpr14Address + (i - 14) * 4; + restfpr.size = (32 - i) * 4 + 4; + image.symbols.emplace(std::format("__restfpr_{}", i), restfpr.base, restfpr.size, Symbol_Function); + + auto& savefpr = functions.emplace_back(); + savefpr.base = config.saveFpr14Address + (i - 14) * 4; + savefpr.size = (32 - i) * 4 + 4; + image.symbols.emplace(std::format("__savefpr_{}", i), savefpr.base, savefpr.size, Symbol_Function); + + auto& restvmx = functions.emplace_back(); + restvmx.base = config.restVmx14Address + (i - 14) * 8; + restvmx.size = (32 - i) * 8 + 4; + image.symbols.emplace(std::format("__restvmx_{}", i), restvmx.base, restvmx.size, Symbol_Function); + + auto& savevmx = functions.emplace_back(); + savevmx.base = config.saveVmx14Address + (i - 14) * 8; + savevmx.size = (32 - i) * 8 + 4; + image.symbols.emplace(std::format("__savevmx_{}", i), savevmx.base, savevmx.size, Symbol_Function); + } + + if (i >= 64) + { + auto& restvmx = functions.emplace_back(); + restvmx.base = config.restVmx64Address + (i - 64) * 8; + restvmx.size = (128 - i) * 8 + 4; + image.symbols.emplace(std::format("__restvmx_{}", i), restvmx.base, restvmx.size, Symbol_Function); + + auto& savevmx = functions.emplace_back(); + savevmx.base = config.saveVmx64Address + (i - 64) * 8; + savevmx.size = (128 - i) * 8 + 4; + image.symbols.emplace(std::format("__savevmx_{}", i), savevmx.base, savevmx.size, Symbol_Function); + } + } + + for (auto& [address, size] : config.functions) + { + functions.emplace_back(address, size); + image.symbols.emplace(std::format("sub_{:X}", address), address, size, Symbol_Function); + } + + auto& pdata = *image.Find(".pdata"); + size_t count = pdata.size / sizeof(IMAGE_CE_RUNTIME_FUNCTION); + auto* pf = (IMAGE_CE_RUNTIME_FUNCTION*)pdata.data; + for (size_t i = 0; i < count; i++) + { + auto fn = pf[i]; + fn.BeginAddress = std::byteswap(fn.BeginAddress); + fn.Data = std::byteswap(fn.Data); + + if (image.symbols.find(fn.BeginAddress) == image.symbols.end()) + { + auto& f = functions.emplace_back(); + f.base = fn.BeginAddress; + f.size = fn.FunctionLength * 4; + + image.symbols.emplace(std::format("sub_{:X}", f.base), f.base, f.size, Symbol_Function); + } + } + + 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) + { + uint32_t insn = std::byteswap(*(uint32_t*)data); + if (PPC_OP(insn) == PPC_OP_B && PPC_BL(insn)) + { + size_t address = base + (data - section.data) + PPC_BI(insn); + + if (address >= section.base && address < section.base + section.size && image.symbols.find(address) == image.symbols.end()) + { + auto data = section.data + address - section.base; + auto& fn = functions.emplace_back(Function::Analyze(data, section.base + section.size - address, address)); + image.symbols.emplace(std::format("sub_{:X}", fn.base), fn.base, fn.size, Symbol_Function); + } + } + data += 4; + } + + data = section.data; + + while (data < dataEnd) + { + auto invalidInstr = config.invalidInstructions.find(std::byteswap(*(uint32_t*)data)); + if (invalidInstr != config.invalidInstructions.end()) + { + base += invalidInstr->second; + data += invalidInstr->second; + continue; + } + + auto fnSymbol = image.symbols.find(base); + if (fnSymbol != image.symbols.end() && fnSymbol->address == base && fnSymbol->type == Symbol_Function) + { + assert(fnSymbol->address == base); + + base += fnSymbol->size; + data += fnSymbol->size; + } + else + { + auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); + image.symbols.emplace(std::format("sub_{:X}", fn.base), fn.base, fn.size, Symbol_Function); + + base += fn.size; + data += fn.size; + } + } + } + + std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; }); } bool Recompiler::Recompile( const Function& fn, uint32_t base, const ppc_insn& insn, - std::unordered_map::iterator& switchTable, + std::unordered_map::iterator& switchTable, RecompilerLocalVariables& localVariables, CSRState& csrState) { @@ -141,11 +264,11 @@ bool Recompiler::Recompile( auto printFunctionCall = [&](uint32_t address) { - if (address == longJmpAddress) + if (address == config.longJmpAddress) { println("\tlongjmp(*reinterpret_cast(base + {}.u32), {}.s32);", r(3), r(4)); } - else if (address == setJmpAddress) + else if (address == config.setJmpAddress) { println("\t{} = ctx;", env()); println("\t{}.s64 = setjmp(*reinterpret_cast(base + {}.u32));", r(3), r(3)); @@ -292,7 +415,7 @@ bool Recompiler::Recompile( break; case PPC_INST_BCTR: - if (switchTable != switchTables.end()) + if (switchTable != config.switchTables.end()) { println("\tswitch ({}.u64) {{", r(switchTable->second.r)); @@ -316,7 +439,7 @@ bool Recompiler::Recompile( println("\t\t__builtin_unreachable();"); println("\t}}"); - switchTable = switchTables.end(); + switchTable = config.switchTables.end(); } else { @@ -1963,8 +2086,8 @@ bool Recompiler::Recompile(const Function& fn) labels.emplace(addr + PPC_BD(instruction)); } - auto switchTable = switchTables.find(addr); - if (switchTable != switchTables.end()) + auto switchTable = config.switchTables.find(addr); + if (switchTable != config.switchTables.end()) { for (auto label : switchTable->second.labels) labels.emplace(label); @@ -1986,7 +2109,7 @@ bool Recompiler::Recompile(const Function& fn) println("PPC_FUNC_IMPL(__imp__{}) {{", name); println("\tPPC_FUNC_PROLOGUE();"); - auto switchTable = switchTables.end(); + auto switchTable = config.switchTables.end(); bool allRecompiled = true; CSRState csrState = CSRState::Unknown; @@ -2010,8 +2133,8 @@ bool Recompiler::Recompile(const Function& fn) csrState = CSRState::Unknown; } - if (switchTable == switchTables.end()) - switchTable = switchTables.find(base); + if (switchTable == config.switchTables.end()) + switchTable = config.switchTables.find(base); ppc::Disassemble(data, 4, base, insn); @@ -2025,7 +2148,7 @@ bool Recompiler::Recompile(const Function& fn) } else { - if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == switchTables.end()) + if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == config.switchTables.end()) std::println("Found a switch jump table at {:X} with no switch table entry present", base); if (!Recompile(fn, base, insn, switchTable, localVariables, csrState)) @@ -2095,7 +2218,7 @@ bool Recompiler::Recompile(const Function& fn) return allRecompiled; } -void Recompiler::Recompile(const char* directoryPath) +void Recompiler::Recompile() { out.reserve(10 * 1024 * 1024); @@ -2124,16 +2247,16 @@ void Recompiler::Recompile(const char* directoryPath) println("\n#endif"); - SaveCurrentOutData(directoryPath, "ppc_config.h"); + SaveCurrentOutData("ppc_config.h"); } { println("#pragma once"); - println("#include \"ppc_config.h\""); + println("#include \"ppc_config.h\"\n"); println("{}", std::string_view{gPPCContextText, gPPCContextText_SIZE}); - SaveCurrentOutData(directoryPath, "ppc_context.h"); + SaveCurrentOutData("ppc_context.h"); } { @@ -2144,7 +2267,7 @@ void Recompiler::Recompile(const char* directoryPath) for (auto& symbol : image.symbols) println("PPC_EXTERN_FUNC({});", symbol.name); - SaveCurrentOutData(directoryPath, "ppc_recomp_shared.h"); + SaveCurrentOutData("ppc_recomp_shared.h"); } { @@ -2157,14 +2280,14 @@ void Recompiler::Recompile(const char* directoryPath) println("\t{{ 0, nullptr }}"); println("}};"); - SaveCurrentOutData(directoryPath, "ppc_func_mapping.cpp"); + SaveCurrentOutData("ppc_func_mapping.cpp"); } for (size_t i = 0; i < functions.size(); i++) { if ((i % 256) == 0) { - SaveCurrentOutData(directoryPath); + SaveCurrentOutData(); println("#include \"ppc_recomp_shared.h\"\n"); } @@ -2174,10 +2297,10 @@ void Recompiler::Recompile(const char* directoryPath) Recompile(functions[i]); } - SaveCurrentOutData(directoryPath); + SaveCurrentOutData(); } -void Recompiler::SaveCurrentOutData(const char* directoryPath, const std::string_view& name) +void Recompiler::SaveCurrentOutData(const std::string_view& name) { if (!out.empty()) { @@ -2192,7 +2315,7 @@ void Recompiler::SaveCurrentOutData(const char* directoryPath, const std::string bool shouldWrite = true; // Check if an identical file already exists first to not trigger recompilation - std::string filePath = std::format("{}/{}", directoryPath, name.empty() ? cppName : name); + std::string filePath = std::format("{}/{}/{}", config.directoryPath, config.outDirectoryPath, name.empty() ? cppName : name); FILE* f = fopen(filePath.c_str(), "rb"); if (f) { diff --git a/PowerRecomp/recompiler.h b/PowerRecomp/recompiler.h index 4cdc741..5fbfaf3 100644 --- a/PowerRecomp/recompiler.h +++ b/PowerRecomp/recompiler.h @@ -1,11 +1,7 @@ #pragma once -#include "pch.h" -struct SwitchTable -{ - size_t r; - std::vector labels; -}; +#include "pch.h" +#include "recompiler_config.h" struct RecompilerLocalVariables { @@ -22,18 +18,6 @@ struct RecompilerLocalVariables bool ea{}; }; -struct RecompilerConfig -{ - bool skipLr = false; - bool ctrAsLocalVariable = false; - bool xerAsLocalVariable = false; - bool reservedRegisterAsLocalVariable = false; - bool skipMsr = false; - bool crRegistersAsLocalVariables = false; - bool nonArgumentRegistersAsLocalVariables = false; - bool nonVolatileRegistersAsLocalVariables = false; -}; - enum class CSRState { Unknown, @@ -45,15 +29,11 @@ struct Recompiler { Image image; std::vector functions; - std::unordered_map switchTables; std::string out; size_t cppFileIndex = 0; - uint32_t setJmpAddress = 0; - uint32_t longJmpAddress = 0; RecompilerConfig config; - void LoadSwitchTables(const char* filePath); - void LoadExecutable(const char* filePath); + void LoadConfig(const std::string_view& configFilePath); template void print(std::format_string fmt, Args&&... args) @@ -68,18 +48,20 @@ struct Recompiler out += '\n'; } + void Analyse(); + // TODO: make a RecompileArgs struct instead this is getting messy bool Recompile( const Function& fn, uint32_t base, const ppc_insn& insn, - std::unordered_map::iterator& switchTable, + std::unordered_map::iterator& switchTable, RecompilerLocalVariables& localVariables, CSRState& csrState); bool Recompile(const Function& fn); - void Recompile(const char* directoryPath); + void Recompile(); - void SaveCurrentOutData(const char* directoryPath, const std::string_view& name = std::string_view()); + void SaveCurrentOutData(const std::string_view& name = std::string_view()); }; diff --git a/PowerRecomp/recompiler_config.cpp b/PowerRecomp/recompiler_config.cpp new file mode 100644 index 0000000..69485f4 --- /dev/null +++ b/PowerRecomp/recompiler_config.cpp @@ -0,0 +1,76 @@ +#include "recompiler_config.h" + +void RecompilerConfig::Load(const std::string_view& configFilePath) +{ + directoryPath = configFilePath.substr(0, configFilePath.find_last_of("\\/") + 1); + toml::table toml = toml::parse_file(configFilePath); + + if (auto mainPtr = toml["main"].as_table()) + { + const auto& main = *mainPtr; + filePath = main["file_path"].value_or(""); + outDirectoryPath = main["out_directory_path"].value_or(""); + switchTableFilePath = main["switch_table_file_path"].value_or(""); + + skipLr = main["skip_lr"].value_or(false); + skipMsr = main["skip_msr"].value_or(false); + ctrAsLocalVariable = main["ctr_as_local"].value_or(false); + xerAsLocalVariable = main["xer_as_local"].value_or(false); + reservedRegisterAsLocalVariable = main["reserved_as_local"].value_or(false); + crRegistersAsLocalVariables = main["cr_as_local"].value_or(false); + nonArgumentRegistersAsLocalVariables = main["non_argument_as_local"].value_or(false); + nonVolatileRegistersAsLocalVariables = main["non_volatile_as_local"].value_or(false); + + restGpr14Address = main["restgprlr_14_address"].value_or(0u); + saveGpr14Address = main["savegprlr_14_address"].value_or(0u); + restFpr14Address = main["restfpr_14_address"].value_or(0u); + saveFpr14Address = main["savefpr_14_address"].value_or(0u); + restVmx14Address = main["restvmx_14_address"].value_or(0u); + saveVmx14Address = main["savevmx_14_address"].value_or(0u); + restVmx64Address = main["restvmx_64_address"].value_or(0u); + saveVmx64Address = main["savevmx_64_address"].value_or(0u); + longJmpAddress = main["longjmp_address"].value_or(0u); + setJmpAddress = main["setjmp_address"].value_or(0u); + + if (auto functionsArray = main["functions"].as_array()) + { + for (auto& func : *functionsArray) + { + auto& funcTable = *func.as_table(); + uint32_t address = *funcTable["address"].value(); + uint32_t size = *funcTable["size"].value(); + functions.emplace(address, size); + } + } + + if (auto invalidArray = main["invalid_instructions"].as_array()) + { + for (auto& instr : *invalidArray) + { + auto& instrTable = *instr.as_table(); + uint32_t data = *instrTable["data"].value(); + uint32_t size = *instrTable["size"].value(); + invalidInstructions.emplace(data, size); + } + } + + if (!switchTableFilePath.empty()) + { + toml::table switchToml = toml::parse_file(directoryPath + switchTableFilePath); + if (auto switchArray = switchToml["switch"].as_array()) + { + for (auto& entry : *switchArray) + { + auto& table = *entry.as_table(); + RecompilerSwitchTable switchTable; + switchTable.r = *table["r"].value(); + for (auto& label : *table["labels"].as_array()) + { + switchTable.labels.push_back(*label.value()); + } + switchTables.emplace(*table["base"].value(), std::move(switchTable)); + } + } + } + } +} diff --git a/PowerRecomp/recompiler_config.h b/PowerRecomp/recompiler_config.h new file mode 100644 index 0000000..3a4b7a7 --- /dev/null +++ b/PowerRecomp/recompiler_config.h @@ -0,0 +1,38 @@ +#pragma once + +struct RecompilerSwitchTable +{ + uint32_t r; + std::vector labels; +}; + +struct RecompilerConfig +{ + std::string directoryPath; + std::string filePath; + std::string outDirectoryPath; + std::string switchTableFilePath; + std::unordered_map switchTables; + bool skipLr = false; + bool ctrAsLocalVariable = false; + bool xerAsLocalVariable = false; + bool reservedRegisterAsLocalVariable = false; + bool skipMsr = false; + bool crRegistersAsLocalVariables = false; + bool nonArgumentRegistersAsLocalVariables = false; + bool nonVolatileRegistersAsLocalVariables = false; + uint32_t restGpr14Address = 0; + uint32_t saveGpr14Address = 0; + uint32_t restFpr14Address = 0; + uint32_t saveFpr14Address = 0; + uint32_t restVmx14Address = 0; + uint32_t saveVmx14Address = 0; + uint32_t restVmx64Address = 0; + uint32_t saveVmx64Address = 0; + uint32_t longJmpAddress = 0; + uint32_t setJmpAddress = 0; + std::unordered_map functions; + std::unordered_map invalidInstructions; + + void Load(const std::string_view& configFilePath); +}; diff --git a/PowerRecomp/swa_recompiler.cpp b/PowerRecomp/swa_recompiler.cpp deleted file mode 100644 index 3c815a1..0000000 --- a/PowerRecomp/swa_recompiler.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "pch.h" -#include "swa_recompiler.h" - -void SWARecompiler::Analyse() -{ - constexpr uint32_t cxxFrameHandler = std::byteswap(0x831B1C90); - constexpr uint32_t cSpecificFrameHandler = std::byteswap(0x8324B3BC); - constexpr uint32_t yetAnotherFrameHandler = std::byteswap(0x831C8B50); - - auto& pdata = *image.Find(".pdata"); - size_t count = pdata.size / sizeof(IMAGE_CE_RUNTIME_FUNCTION); - auto* pf = (IMAGE_CE_RUNTIME_FUNCTION*)pdata.data; - for (size_t i = 0; i < count; i++) - { - auto fn = pf[i]; - fn.BeginAddress = std::byteswap(fn.BeginAddress); - fn.Data = std::byteswap(fn.Data); - - auto& f = functions.emplace_back(); - f.base = fn.BeginAddress; - f.size = fn.FunctionLength * 4; - - std::string name; - if (f.base == 0x831B0B40) name = "__restgprlr_14"; - else if (f.base == 0x831B0AF0) name = "__savegprlr_14"; - else if (f.base == 0x831B144C) name = "__restfpr_14"; - else if (f.base == 0x831B1400) name = "__savefpr_14"; - else if (f.base == 0x831B36E8) name = "__restvmx_14"; - else if (f.base == 0x831B3450) name = "__savevmx_14"; - else if (f.base == 0x831B377C) name = "__restvmx_64"; - else if (f.base == 0x831B34E4) name = "__savevmx_64"; - else name = std::format("sub_{:X}", f.base); - - image.symbols.emplace(name, f.base, f.size, Symbol_Function); - } - - for (size_t i = 15; i < 128; i++) - { - if (i < 32) - { - auto& restgpr = functions.emplace_back(); - restgpr.base = 0x831B0B40 + (i - 14) * 4; - restgpr.size = 0x831B0B94 - restgpr.base; - image.symbols.emplace(std::format("__restgprlr_{}", i), restgpr.base, restgpr.size, Symbol_Function); - - auto& savegpr = functions.emplace_back(); - savegpr.base = 0x831B0AF0 + (i - 14) * 4; - savegpr.size = 0x831B0B40 - savegpr.base; - image.symbols.emplace(std::format("__savegprlr_{}", i), savegpr.base, savegpr.size, Symbol_Function); - - auto& restfpr = functions.emplace_back(); - restfpr.base = 0x831B144C + (i - 14) * 4; - restfpr.size = 0x831B1498 - restfpr.base; - image.symbols.emplace(std::format("__restfpr_{}", i), restfpr.base, restfpr.size, Symbol_Function); - - auto& savefpr = functions.emplace_back(); - savefpr.base = 0x831B1400 + (i - 14) * 4; - savefpr.size = 0x831B144C - savefpr.base; - image.symbols.emplace(std::format("__savefpr_{}", i), savefpr.base, savefpr.size, Symbol_Function); - - auto& restvmx = functions.emplace_back(); - restvmx.base = 0x831B36E8 + (i - 14) * 8; - restvmx.size = 0x831B377C - restvmx.base; - image.symbols.emplace(std::format("__restvmx_{}", i), restvmx.base, restvmx.size, Symbol_Function); - - auto& savevmx = functions.emplace_back(); - savevmx.base = 0x831B3450 + (i - 14) * 8; - savevmx.size = 0x831B34E4 - savevmx.base; - image.symbols.emplace(std::format("__savevmx_{}", i), savevmx.base, savevmx.size, Symbol_Function); - } - - if (i >= 64) - { - auto& restvmx = functions.emplace_back(); - restvmx.base = 0x831B377C + (i - 64) * 8; - restvmx.size = 0x831B3980 - restvmx.base; - image.symbols.emplace(std::format("__restvmx_{}", i), restvmx.base, restvmx.size, Symbol_Function); - - auto& savevmx = functions.emplace_back(); - savevmx.base = 0x831B34E4 + (i - 64) * 8; - savevmx.size = 0x831B36E8 - savevmx.base; - image.symbols.emplace(std::format("__savevmx_{}", i), savevmx.base, savevmx.size, Symbol_Function); - } - } - - auto hardcodedFuncCheck = [&](uint8_t* data, Function& f) - { - if (*(uint32_t*)(data + 4) == 0x04000048) f.size = 0x8; // shifted ptr tail call - else if (f.base == 0x824E7EF0) f.size = 0x98; - else if (f.base == 0x824E7F28) f.size = 0x60; - else if (f.base == 0x82C980E8) f.size = 0x110; - else if (f.base == 0x82CF7080) f.size = 0x80; - else if (f.base == 0x82D9AC08) f.size = 0x78; - else if (f.base == 0x82E86770) f.size = 0x98; - else if (f.base == 0x82E97E50) f.size = 0x84; - else if (f.base == 0x82EE2D08) f.size = 0x154; - else if (f.base == 0x82EF5C38) f.size = 0x64; - else if (f.base == 0x82EF5D78) f.size = 0x3F8; - else if (f.base == 0x82F08730) f.size = 0x2B0; - else if (f.base == 0x82F098C0) f.size = 0x19C; - else if (f.base == 0x82F13980) f.size = 0xF4; - else if (f.base == 0x82F1D668) f.size = 0x1E8; - else if (f.base == 0x82F22908) f.size = 0x20C; - else if (f.base == 0x82F25FD8) f.size = 0x240; - else if (f.base == 0x82F852A0) f.size = 0xCC; - else if (f.base == 0x830DADA0) f.size = 0x150; - else if (f.base == 0x831487D0) f.size = 0xD4; - else if (f.base == 0x831530C8) f.size = 0x258; - else if (f.base == 0x831539E0) f.size = 0xD0; - else if (f.base == 0x83168940) f.size = 0x100; - else if (f.base == 0x83168A48) f.size = 0x11C; - else if (f.base == 0x83168B70) f.size = 0x128; - else if (f.base == 0x83168F18) f.size = 0x254; - else if (f.base == 0x8316C678) f.size = 0x78; - else if (f.base == 0x8317CD30) f.size = 0x50; - else if (f.base == 0x83180700) f.size = 0x74; - else if (f.base == 0x8319ED58) f.size = 0x98; - else if (f.base == 0x82455E70) f.size = 0x84; - else if (f.base == 0x82456DC8) f.size = 0xD4; - else if (f.base == 0x826ABB70) f.size = 0x70; - else if (f.base == 0x82893088) f.size = 0x45C; - else if (f.base == 0x82C49540) f.size = 0x114; - else if (f.base == 0x82DE35D8) f.size = 0x68; - else if (f.base == 0x82DE3640) f.size = 0x64; - else if (f.base == 0x82DE36A8) f.size = 0x5C; - else if (f.base == 0x82DE3708) f.size = 0x198; - else if (f.base == 0x82DE38A0) f.size = 0x16C; - else if (f.base == 0x830B7DD0) f.size = 0x74; - else if (f.base == 0x831B0BA0) f.size = 0xA0; - else if (f.base == 0x8305D168) f.size = 0x278; - }; - - 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) - { - uint32_t insn = std::byteswap(*(uint32_t*)data); - if (PPC_OP(insn) == PPC_OP_B && PPC_BL(insn)) - { - size_t address = base + (data - section.data) + PPC_BI(insn); - - if (address >= section.base && address < section.base + section.size && image.symbols.find(address) == image.symbols.end()) - { - auto data = section.data + address - section.base; - auto& fn = functions.emplace_back(Function::Analyze(data, section.base + section.size - address, address)); - hardcodedFuncCheck(data, fn); - image.symbols.emplace(std::format("sub_{:X}", fn.base), fn.base, fn.size, Symbol_Function); - } - } - data += 4; - } - - data = section.data; - - while (data < dataEnd) - { - if (*(uint32_t*)data == 0) - { - data += 4; - base += 4; - continue; - } - - if (*(uint32_t*)data == cxxFrameHandler || *(uint32_t*)data == cSpecificFrameHandler || *(uint32_t*)data == yetAnotherFrameHandler) - { - data += 8; - base += 8; - continue; - } - - if (*(uint32_t*)data == 0x45564800) - { - break; - } - - auto fnSymbol = image.symbols.find(base); - if (fnSymbol != image.symbols.end() && fnSymbol->address == base && fnSymbol->type == Symbol_Function) - { - assert(fnSymbol->address == base); - - base += fnSymbol->size; - data += fnSymbol->size; - } - else - { - auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); - hardcodedFuncCheck(data, fn); - image.symbols.emplace(std::format("sub_{:X}", fn.base), fn.base, fn.size, Symbol_Function); - - base += fn.size; - data += fn.size; - } - } - } - - std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; }); - - setJmpAddress = 0x831B6AB0; - longJmpAddress = 0x831B6790; -} diff --git a/PowerRecomp/swa_recompiler.h b/PowerRecomp/swa_recompiler.h deleted file mode 100644 index 77b93da..0000000 --- a/PowerRecomp/swa_recompiler.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "recompiler.h" - -struct SWARecompiler : Recompiler -{ - void Analyse(); -}; diff --git a/PowerRecomp/test_recompiler.cpp b/PowerRecomp/test_recompiler.cpp index 18e47eb..b70759f 100644 --- a/PowerRecomp/test_recompiler.cpp +++ b/PowerRecomp/test_recompiler.cpp @@ -40,8 +40,12 @@ void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* ds { if (file.path().extension() == ".o") { + const auto exeFile = LoadFile(file.path().string().c_str()).value(); + TestRecompiler recompiler; - recompiler.LoadExecutable(file.path().string().c_str()); + recompiler.config.outDirectoryPath = dstDirectoryPath; + recompiler.image = Image::ParseImage(exeFile.data(), exeFile.size()).value(); + auto stem = file.path().stem().string(); recompiler.Analyse(stem); @@ -61,7 +65,7 @@ void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* ds } } stem += ".cpp"; - recompiler.SaveCurrentOutData(dstDirectoryPath, stem); + recompiler.SaveCurrentOutData(stem); } } diff --git a/PowerSample/CMakeLists.txt b/PowerSample/CMakeLists.txt index 60c1cc8..d207650 100644 --- a/PowerSample/CMakeLists.txt +++ b/PowerSample/CMakeLists.txt @@ -5,12 +5,10 @@ add_compile_options( "/fp:strict" "/GS-" "/EHa-" - "-march=haswell" + "-march=sandybridge" "-fno-strict-aliasing") file(GLOB RecompiledFiles *.cpp) add_library(PowerSample ${RecompiledFiles}) target_precompile_headers(PowerSample PUBLIC "ppc_recomp_shared.h") - -target_link_libraries(PowerSample PUBLIC PowerUtils)