Implemented function stubbing

This commit is contained in:
Mr-Wiseguy 2023-03-24 18:04:21 -04:00
parent fba0085946
commit 7df3e28c76
4 changed files with 99 additions and 78 deletions

View file

@ -70,6 +70,7 @@ namespace RecompPort {
ELFIO::Elf_Half section_index; ELFIO::Elf_Half section_index;
bool ignored; bool ignored;
bool reimplemented; bool reimplemented;
bool stubbed;
}; };
enum class RelocType : uint8_t { enum class RelocType : uint8_t {
@ -113,6 +114,8 @@ namespace RecompPort {
std::vector<Section> sections; std::vector<Section> sections;
std::vector<Function> functions; std::vector<Function> functions;
std::unordered_map<uint32_t, std::vector<size_t>> functions_by_vram; std::unordered_map<uint32_t, std::vector<size_t>> functions_by_vram;
// A mapping of function name to index in the functions vector
std::unordered_map<std::string, size_t> functions_by_name;
std::vector<uint8_t> rom; std::vector<uint8_t> rom;
// A list of the list of each function (by index in `functions`) in a given section // A list of the list of each function (by index in `functions`) in a given section
std::vector<std::vector<size_t>> section_functions; std::vector<std::vector<size_t>> section_functions;
@ -124,7 +127,8 @@ namespace RecompPort {
sections.resize(elf_file.sections.size()); sections.resize(elf_file.sections.size());
section_functions.resize(elf_file.sections.size()); section_functions.resize(elf_file.sections.size());
functions.reserve(1024); functions.reserve(1024);
functions_by_vram.reserve(1024); functions_by_vram.reserve(functions.capacity());
functions_by_name.reserve(functions.capacity());
rom.reserve(8 * 1024 * 1024); rom.reserve(8 * 1024 * 1024);
executable_section_count = 0; executable_section_count = 0;
} }

View file

@ -100,7 +100,7 @@ RecompPort::Config::Config(const char* path) {
// Patches section (optional) // Patches section (optional)
const toml::value& patches_data = toml::find_or<toml::value>(config_data, "patches", toml::value{}); const toml::value& patches_data = toml::find_or<toml::value>(config_data, "patches", toml::value{});
if (patches_data.type() == toml::value_t::empty) { if (patches_data.type() != toml::value_t::empty) {
// Stubs array (optional) // Stubs array (optional)
get_stubbed_funcs(stubbed_funcs, patches_data); get_stubbed_funcs(stubbed_funcs, patches_data);

View file

@ -665,6 +665,7 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
if (num_instructions > 0) { if (num_instructions > 0) {
context.section_functions[section_index].push_back(context.functions.size()); context.section_functions[section_index].push_back(context.functions.size());
} }
context.functions_by_name[name] = context.functions.size();
context.functions.emplace_back( context.functions.emplace_back(
vram, vram,
rom_address, rom_address,
@ -1069,6 +1070,19 @@ int main(int argc, char** argv) {
fmt::print("Working dir: {}\n", std::filesystem::current_path().string()); fmt::print("Working dir: {}\n", std::filesystem::current_path().string());
// Stub out any functions specified in the config file.
for (const std::string& stubbed_func : config.stubbed_funcs) {
// Check if the specified function exists.
auto func_find = context.functions_by_name.find(stubbed_func);
if (func_find == context.functions_by_name.end()) {
// Function doesn't exist, present an error to the user instead of silently failing to stub it out.
// This helps prevent typos in the config file or functions renamed between versions from causing issues.
exit_failure(fmt::format("Function {} is stubbed out in the config file but does not exist!", stubbed_func));
}
// Mark the function as stubbed.
context.functions[func_find->second].stubbed = true;
}
//#pragma omp parallel for //#pragma omp parallel for
for (size_t i = 0; i < context.functions.size(); i++) { for (size_t i = 0; i < context.functions.size(); i++) {
const auto& func = context.functions[i]; const auto& func = context.functions[i];

View file

@ -997,6 +997,8 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
" int c1cs = 0; \n", // cop1 conditional signal " int c1cs = 0; \n", // cop1 conditional signal
func.name); func.name);
// Skip analysis and recompilation of this function is stubbed.
if (!func.stubbed) {
// Use a set to sort and deduplicate labels // Use a set to sort and deduplicate labels
std::set<uint32_t> branch_labels; std::set<uint32_t> branch_labels;
instructions.reserve(func.words.size()); instructions.reserve(func.words.size());
@ -1065,7 +1067,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
// Process the current instruction and check for errors // Process the current instruction and check for errors
if (process_instruction(context, func, stats, skipped_insns, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, reloc_index, needs_link_branch, is_branch_likely, static_funcs_out) == false) { if (process_instruction(context, func, stats, skipped_insns, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, reloc_index, needs_link_branch, is_branch_likely, static_funcs_out) == false) {
fmt::print(stderr, "Error in recompilation, clearing {}\n", output_path.string() ); fmt::print(stderr, "Error in recompilation, clearing {}\n", output_path.string());
output_file.clear(); output_file.clear();
return false; return false;
} }
@ -1083,6 +1085,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
// Advance the vram address by the size of one instruction // Advance the vram address by the size of one instruction
vram += 4; vram += 4;
} }
}
// Terminate the function // Terminate the function
fmt::print(output_file, ";}}\n"); fmt::print(output_file, ";}}\n");