mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-22 03:14:59 +00:00
add renaming and re mode
This commit is contained in:
parent
2632d435b0
commit
0cc8edcf40
7 changed files with 79 additions and 9 deletions
|
@ -216,6 +216,9 @@ namespace N64Recomp {
|
||||||
// List of symbols from events, which contains the names of events that this context provides.
|
// List of symbols from events, which contains the names of events that this context provides.
|
||||||
std::vector<EventSymbol> event_symbols;
|
std::vector<EventSymbol> 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.
|
// 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);
|
bool import_reference_context(const Context& reference_context);
|
||||||
// Reads a data symbol file and adds its contents into this context's reference data symbols.
|
// Reads a data symbol file and adds its contents into this context's reference data symbols.
|
||||||
|
|
|
@ -93,7 +93,7 @@ std::vector<std::string> get_ignored_funcs(const toml::table* patches_data) {
|
||||||
// Make room for all the ignored funcs in the array.
|
// Make room for all the ignored funcs in the array.
|
||||||
ignored_funcs.reserve(ignored_funcs_array->size());
|
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) {
|
ignored_funcs_array->for_each([&ignored_funcs](auto&& el) {
|
||||||
if constexpr (toml::is_string<decltype(el)>) {
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
ignored_funcs.push_back(*el);
|
ignored_funcs.push_back(*el);
|
||||||
|
@ -104,6 +104,29 @@ std::vector<std::string> get_ignored_funcs(const toml::table* patches_data) {
|
||||||
return ignored_funcs;
|
return ignored_funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> get_renamed_funcs(const toml::table* patches_data) {
|
||||||
|
std::vector<std::string> 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<decltype(el)>) {
|
||||||
|
renamed_funcs.push_back(*el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return renamed_funcs;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<N64Recomp::FunctionSize> get_func_sizes(const toml::table* patches_data) {
|
std::vector<N64Recomp::FunctionSize> get_func_sizes(const toml::table* patches_data) {
|
||||||
std::vector<N64Recomp::FunctionSize> func_sizes{};
|
std::vector<N64Recomp::FunctionSize> func_sizes{};
|
||||||
|
|
||||||
|
@ -377,6 +400,9 @@ N64Recomp::Config::Config(const char* path) {
|
||||||
// Ignored funcs array (optional)
|
// Ignored funcs array (optional)
|
||||||
ignored_funcs = get_ignored_funcs(table);
|
ignored_funcs = get_ignored_funcs(table);
|
||||||
|
|
||||||
|
// Renamed funcs array (optional)
|
||||||
|
renamed_funcs = get_renamed_funcs(table);
|
||||||
|
|
||||||
// Single-instruction patches (optional)
|
// Single-instruction patches (optional)
|
||||||
instruction_patches = get_instruction_patches(table);
|
instruction_patches = get_instruction_patches(table);
|
||||||
|
|
||||||
|
@ -387,6 +413,18 @@ N64Recomp::Config::Config(const char* path) {
|
||||||
function_hooks = get_function_hooks(table);
|
function_hooks = get_function_hooks(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use RE mode if enabled (optional)
|
||||||
|
std::optional<bool> re_mode_opt = input_data["re_mode"].value<bool>();
|
||||||
|
if (re_mode_opt.has_value()) {
|
||||||
|
re_mode = re_mode_opt.value();
|
||||||
|
if (re_mode) {
|
||||||
|
recomp_include += "\n#include <stdio.h>\n#include <stdlib.h>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
re_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Function reference symbols file (optional)
|
// Function reference symbols file (optional)
|
||||||
std::optional<std::string> func_reference_syms_file_opt = input_data["func_reference_syms_file"].value<std::string>();
|
std::optional<std::string> func_reference_syms_file_opt = input_data["func_reference_syms_file"].value<std::string>();
|
||||||
if (func_reference_syms_file_opt.has_value()) {
|
if (func_reference_syms_file_opt.has_value()) {
|
||||||
|
|
|
@ -42,6 +42,7 @@ namespace N64Recomp {
|
||||||
bool single_file_output;
|
bool single_file_output;
|
||||||
bool use_absolute_symbols;
|
bool use_absolute_symbols;
|
||||||
bool unpaired_lo16_warnings;
|
bool unpaired_lo16_warnings;
|
||||||
|
bool re_mode;
|
||||||
bool allow_exports;
|
bool allow_exports;
|
||||||
bool strict_patch_mode;
|
bool strict_patch_mode;
|
||||||
std::filesystem::path elf_path;
|
std::filesystem::path elf_path;
|
||||||
|
@ -54,6 +55,7 @@ namespace N64Recomp {
|
||||||
std::filesystem::path output_binary_path;
|
std::filesystem::path output_binary_path;
|
||||||
std::vector<std::string> stubbed_funcs;
|
std::vector<std::string> stubbed_funcs;
|
||||||
std::vector<std::string> ignored_funcs;
|
std::vector<std::string> ignored_funcs;
|
||||||
|
std::vector<std::string> renamed_funcs;
|
||||||
std::vector<InstructionPatch> instruction_patches;
|
std::vector<InstructionPatch> instruction_patches;
|
||||||
std::vector<FunctionHook> function_hooks;
|
std::vector<FunctionHook> function_hooks;
|
||||||
std::vector<FunctionSize> manual_func_sizes;
|
std::vector<FunctionSize> manual_func_sizes;
|
||||||
|
|
|
@ -60,7 +60,7 @@ bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELF
|
||||||
|
|
||||||
if (section_index < context.sections.size()) {
|
if (section_index < context.sections.size()) {
|
||||||
// Check if this symbol is the entrypoint
|
// 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) {
|
if (found_entrypoint_func) {
|
||||||
fmt::print(stderr, "Ambiguous entrypoint: {}\n", name);
|
fmt::print(stderr, "Ambiguous entrypoint: {}\n", name);
|
||||||
return false;
|
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();
|
auto section_offset = value - elf_file.sections[section_index]->get_address();
|
||||||
const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
|
const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
|
||||||
uint32_t vram = static_cast<uint32_t>(value);
|
uint32_t vram = static_cast<uint32_t>(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<uint32_t>(section_offset + section.rom_addr);
|
uint32_t rom_address = static_cast<uint32_t>(section_offset + section.rom_addr);
|
||||||
|
|
||||||
section.function_addrs.push_back(vram);
|
section.function_addrs.push_back(vram);
|
||||||
|
|
25
src/main.cpp
25
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.
|
// TODO expose a way to dump the context from the command line.
|
||||||
bool dumping_context = false;
|
bool dumping_context = argc > 2;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc > 3) {
|
||||||
fmt::print("Usage: {} [config file]\n", argv[0]);
|
fmt::print("Usage: {} [config file] (should-dump)\n", argv[0]);
|
||||||
std::exit(EXIT_SUCCESS);
|
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.
|
// 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));
|
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;
|
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.
|
// Apply any single-instruction patches.
|
||||||
for (const N64Recomp::InstructionPatch& patch : config.instruction_patches) {
|
for (const N64Recomp::InstructionPatch& patch : config.instruction_patches) {
|
||||||
// Check if the specified function exists.
|
// Check if the specified function exists.
|
||||||
|
|
|
@ -745,6 +745,16 @@ bool N64Recomp::recompile_function(const N64Recomp::Context& context, const N64R
|
||||||
" int c1cs = 0;\n", // cop1 conditional signal
|
" int c1cs = 0;\n", // cop1 conditional signal
|
||||||
func.name);
|
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.
|
// Skip analysis and recompilation of this function is stubbed.
|
||||||
if (!func.stubbed) {
|
if (!func.stubbed) {
|
||||||
// Use a set to sort and deduplicate labels
|
// Use a set to sort and deduplicate labels
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "n64recomp.h"
|
#include "n64recomp.h"
|
||||||
|
|
||||||
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs{
|
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs {
|
||||||
// OS initialize functions
|
// OS initialize functions
|
||||||
"__osInitialize_common",
|
"__osInitialize_common",
|
||||||
"osInitialize",
|
"osInitialize",
|
||||||
|
@ -557,7 +557,7 @@ const std::unordered_set<std::string> N64Recomp::ignored_funcs {
|
||||||
"kdebugserver",
|
"kdebugserver",
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::unordered_set<std::string> N64Recomp::renamed_funcs{
|
const std::unordered_set<std::string> N64Recomp::renamed_funcs {
|
||||||
// Math
|
// Math
|
||||||
"sincosf",
|
"sincosf",
|
||||||
"sinf",
|
"sinf",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue