From 0cc8edcf4096d4f2232226f4666733ef0fd718be Mon Sep 17 00:00:00 2001 From: LittleCube Date: Mon, 23 Dec 2024 16:11:22 -0500 Subject: [PATCH] add renaming and re mode --- include/n64recomp.h | 3 +++ src/config.cpp | 40 +++++++++++++++++++++++++++++++++++++++- src/config.h | 2 ++ src/elf.cpp | 4 ++-- src/main.cpp | 25 +++++++++++++++++++++---- src/recompilation.cpp | 10 ++++++++++ src/symbol_lists.cpp | 4 ++-- 7 files changed, 79 insertions(+), 9 deletions(-) diff --git a/include/n64recomp.h b/include/n64recomp.h index 66ce06b..40ce449 100644 --- a/include/n64recomp.h +++ b/include/n64recomp.h @@ -216,6 +216,9 @@ namespace N64Recomp { // List of symbols from events, which contains the names of events that this context provides. std::vector event_symbols; + // Causes functions to print their name to the console the first time they're called. + bool re_mode; + // Imports sections and function symbols from a provided context into this context's reference sections and reference functions. bool import_reference_context(const Context& reference_context); // Reads a data symbol file and adds its contents into this context's reference data symbols. diff --git a/src/config.cpp b/src/config.cpp index 4471923..6a1e415 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -93,7 +93,7 @@ std::vector get_ignored_funcs(const toml::table* patches_data) { // Make room for all the ignored funcs in the array. ignored_funcs.reserve(ignored_funcs_array->size()); - // Gather the stubs and place them into the array. + // Gather the ignored and place them into the array. ignored_funcs_array->for_each([&ignored_funcs](auto&& el) { if constexpr (toml::is_string) { ignored_funcs.push_back(*el); @@ -104,6 +104,29 @@ std::vector get_ignored_funcs(const toml::table* patches_data) { return ignored_funcs; } +std::vector get_renamed_funcs(const toml::table* patches_data) { + std::vector renamed_funcs{}; + + // Check if the renamed funcs array exists. + const toml::node_view renamed_funcs_data = (*patches_data)["renamed"]; + + if (renamed_funcs_data.is_array()) { + const toml::array* renamed_funcs_array = renamed_funcs_data.as_array(); + + // Make room for all the renamed funcs in the array. + renamed_funcs.reserve(renamed_funcs_array->size()); + + // Gather the renamed and place them into the array. + renamed_funcs_array->for_each([&renamed_funcs](auto&& el) { + if constexpr (toml::is_string) { + renamed_funcs.push_back(*el); + } + }); + } + + return renamed_funcs; +} + std::vector get_func_sizes(const toml::table* patches_data) { std::vector func_sizes{}; @@ -377,6 +400,9 @@ N64Recomp::Config::Config(const char* path) { // Ignored funcs array (optional) ignored_funcs = get_ignored_funcs(table); + // Renamed funcs array (optional) + renamed_funcs = get_renamed_funcs(table); + // Single-instruction patches (optional) instruction_patches = get_instruction_patches(table); @@ -387,6 +413,18 @@ N64Recomp::Config::Config(const char* path) { function_hooks = get_function_hooks(table); } + // Use RE mode if enabled (optional) + std::optional re_mode_opt = input_data["re_mode"].value(); + if (re_mode_opt.has_value()) { + re_mode = re_mode_opt.value(); + if (re_mode) { + recomp_include += "\n#include \n#include "; + } + } + else { + re_mode = false; + } + // Function reference symbols file (optional) std::optional func_reference_syms_file_opt = input_data["func_reference_syms_file"].value(); if (func_reference_syms_file_opt.has_value()) { diff --git a/src/config.h b/src/config.h index 70bf0fa..836c0f4 100644 --- a/src/config.h +++ b/src/config.h @@ -42,6 +42,7 @@ namespace N64Recomp { bool single_file_output; bool use_absolute_symbols; bool unpaired_lo16_warnings; + bool re_mode; bool allow_exports; bool strict_patch_mode; std::filesystem::path elf_path; @@ -54,6 +55,7 @@ namespace N64Recomp { std::filesystem::path output_binary_path; std::vector stubbed_funcs; std::vector ignored_funcs; + std::vector renamed_funcs; std::vector instruction_patches; std::vector function_hooks; std::vector manual_func_sizes; diff --git a/src/elf.cpp b/src/elf.cpp index 8c11a5d..f37754a 100644 --- a/src/elf.cpp +++ b/src/elf.cpp @@ -60,7 +60,7 @@ bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELF if (section_index < context.sections.size()) { // Check if this symbol is the entrypoint - if (elf_config.has_entrypoint && value == elf_config.entrypoint_address && type == ELFIO::STT_FUNC) { + if (elf_config.has_entrypoint && (uint32_t) value == (uint32_t) elf_config.entrypoint_address && (type == ELFIO::STT_FUNC || type == ELFIO::STT_NOTYPE)) { if (found_entrypoint_func) { fmt::print(stderr, "Ambiguous entrypoint: {}\n", name); return false; @@ -105,7 +105,7 @@ bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELF auto section_offset = value - elf_file.sections[section_index]->get_address(); const uint32_t* words = reinterpret_cast(elf_file.sections[section_index]->get_data() + section_offset); uint32_t vram = static_cast(value); - uint32_t num_instructions = type == ELFIO::STT_FUNC ? size / 4 : 0; + uint32_t num_instructions = (type == ELFIO::STT_FUNC || type == ELFIO::STT_NOTYPE) ? size / 4 : 0; uint32_t rom_address = static_cast(section_offset + section.rom_addr); section.function_addrs.push_back(vram); diff --git a/src/main.cpp b/src/main.cpp index 05b79aa..bceba31 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -273,10 +273,10 @@ int main(int argc, char** argv) { }; // TODO expose a way to dump the context from the command line. - bool dumping_context = false; + bool dumping_context = argc > 2; - if (argc != 2) { - fmt::print("Usage: {} [config file]\n", argv[0]); + if (argc > 3) { + fmt::print("Usage: {} [config file] (should-dump)\n", argv[0]); std::exit(EXIT_SUCCESS); } @@ -485,10 +485,27 @@ int main(int argc, char** argv) { // This helps prevent typos in the config file or functions renamed between versions from causing issues. exit_failure(fmt::format("Function {} is set as ignored in the config file but does not exist!", ignored_func)); } - // Mark the function as . + // Mark the function as ignored. context.functions[func_find->second].ignored = true; } + // Rename any functions specified in the config file. + for (const std::string& renamed_func : config.renamed_funcs) { + // Check if the specified function exists. + auto func_find = context.functions_by_name.find(renamed_func); + if (func_find == context.functions_by_name.end()) { + // Function doesn't exist, present an error to the user instead of silently failing to mark it as ignored. + // This helps prevent typos in the config file or functions renamed between versions from causing issues. + exit_failure(fmt::format("Function {} is set as renamed in the config file but does not exist!", renamed_func)); + } + // Rename the function. + N64Recomp::Function* func = &context.functions[func_find->second]; + func->name = func->name + "_recomp"; + } + + // Propogate the re_mode parameter. + context.re_mode = config.re_mode; + // Apply any single-instruction patches. for (const N64Recomp::InstructionPatch& patch : config.instruction_patches) { // Check if the specified function exists. diff --git a/src/recompilation.cpp b/src/recompilation.cpp index ca66ae6..09b8d2d 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -745,6 +745,16 @@ bool N64Recomp::recompile_function(const N64Recomp::Context& context, const N64R " int c1cs = 0;\n", // cop1 conditional signal func.name); + if (context.re_mode) { + fmt::print(output_file, + " static int {0}_was_called = 0;\n" + " if ({0}_was_called == 0) {{\n" + " fprintf(stderr, \"new function: {0}\\n\");\n" + " {0}_was_called = 1;\n" + " }}\n", + func.name); + } + // Skip analysis and recompilation of this function is stubbed. if (!func.stubbed) { // Use a set to sort and deduplicate labels diff --git a/src/symbol_lists.cpp b/src/symbol_lists.cpp index 182ccde..4b4eff9 100644 --- a/src/symbol_lists.cpp +++ b/src/symbol_lists.cpp @@ -1,6 +1,6 @@ #include "n64recomp.h" -const std::unordered_set N64Recomp::reimplemented_funcs{ +const std::unordered_set N64Recomp::reimplemented_funcs { // OS initialize functions "__osInitialize_common", "osInitialize", @@ -557,7 +557,7 @@ const std::unordered_set N64Recomp::ignored_funcs { "kdebugserver", }; -const std::unordered_set N64Recomp::renamed_funcs{ +const std::unordered_set N64Recomp::renamed_funcs { // Math "sincosf", "sinf",