From f300b6dcccdf7b0d699264d49b0fb6be58fd6569 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sun, 18 Aug 2024 14:11:03 -0400 Subject: [PATCH] Some cleanup by making some Context members private --- OfflineModRecomp/main.cpp | 14 ++-- RecompModTool/main.cpp | 63 ++++++----------- include/n64recomp.h | 141 +++++++++++++++++++++++++++++++++++--- src/config.cpp | 38 +++------- src/elf.cpp | 17 +++-- src/main.cpp | 7 +- src/mod_symbols.cpp | 20 ++---- src/recompilation.cpp | 17 ++--- 8 files changed, 191 insertions(+), 126 deletions(-) diff --git a/OfflineModRecomp/main.cpp b/OfflineModRecomp/main.cpp index ff4b70f..5733eb7 100644 --- a/OfflineModRecomp/main.cpp +++ b/OfflineModRecomp/main.cpp @@ -81,14 +81,12 @@ int main(int argc, const char** argv) { // Populate R_MIPS_26 reloc symbol indices. Start by building a map of vram address to matching reference symbols. std::unordered_map> reference_symbols_by_vram{}; - for (size_t reference_symbol_index = 0; reference_symbol_index < mod_context.reference_symbols.size(); reference_symbol_index++) { - const auto& sym = mod_context.reference_symbols[reference_symbol_index]; + for (size_t reference_symbol_index = 0; reference_symbol_index < mod_context.num_regular_reference_symbols(); reference_symbol_index++) { + const auto& sym = mod_context.get_regular_reference_symbol(reference_symbol_index); uint16_t section_index = sym.section_index; if (section_index != N64Recomp::SectionAbsolute && section_index != N64Recomp::SectionSelf) { - const auto& section = mod_context.reference_sections[section_index]; - - uint32_t vram = section.ram_addr + sym.section_offset; - reference_symbols_by_vram[vram].push_back(reference_symbol_index); + uint32_t section_vram = mod_context.get_reference_section_vram(section_index); + reference_symbols_by_vram[section_vram + sym.section_offset].push_back(reference_symbol_index); } } @@ -97,8 +95,8 @@ int main(int argc, const char** argv) { for (auto& reloc : section.relocs) { if (reloc.type == N64Recomp::RelocType::R_MIPS_26 && reloc.reference_symbol) { if (mod_context.is_regular_reference_section(reloc.target_section)) { - const auto& target_section = mod_context.reference_sections[reloc.target_section]; - uint32_t target_vram = target_section.ram_addr + reloc.target_section_offset; + uint32_t section_vram = mod_context.get_reference_section_vram(reloc.target_section); + uint32_t target_vram = section_vram + reloc.target_section_offset; auto find_funcs_it = reference_symbols_by_vram.find(target_vram); bool found = false; diff --git a/RecompModTool/main.cpp b/RecompModTool/main.cpp index 32b1ded..7c748f4 100644 --- a/RecompModTool/main.cpp +++ b/RecompModTool/main.cpp @@ -113,21 +113,9 @@ static bool read_dependency_file(const std::filesystem::path& dependency_path, N throw toml::parse_error("Invalid dependency function", function_node.source()); } const std::string& function_name = function_node.ref(); - context.reference_symbols_by_name[function_name] = N64Recomp::SymbolReference { - .section_index = N64Recomp::SectionImport, - .symbol_index = import_symbol_dependency_indices.size() - }; - context.import_symbols.emplace_back( - N64Recomp::ImportSymbol { - .base = N64Recomp::ReferenceSymbol { - .name = function_name, - .section_index = N64Recomp::SectionImport, - .section_offset = 0, - .is_function = true - }, - .dependency_index = dependency_index, - } - ); + size_t symbol_index = import_symbol_dependency_indices.size(); + + context.add_import_symbol(function_name, dependency_index, symbol_index); import_symbol_dependency_indices.emplace_back(dependency_index); } } @@ -328,22 +316,8 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st // If this is the patch section, create a replacement for this function. if (patch_section || force_patch_section) { // Find the corresponding symbol in the reference symbols. - bool original_func_exists = false; - auto find_sym_it = input_context.reference_symbols_by_name.find(cur_func.name); - - // Check if the function was found. - if (find_sym_it == input_context.reference_symbols_by_name.end()) { - original_func_exists = false; - } - // Ignore reference symbols in the import section, as those are imports and not original symbols. - else if ( - find_sym_it->second.section_index == N64Recomp::SectionImport || - find_sym_it->second.section_index == N64Recomp::SectionHook) { - original_func_exists = false; - } - else { - original_func_exists = true; - } + N64Recomp::SymbolReference cur_reference; + bool original_func_exists = input_context.find_regular_reference_symbol(cur_func.name, cur_reference); // Check that the function being patched exists in the original reference symbols. if (!original_func_exists) { @@ -352,20 +326,21 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st } // Check that the reference symbol is actually a function. - const auto& reference_symbol = input_context.get_reference_symbol(find_sym_it->second.section_index, find_sym_it->second.symbol_index); + const auto& reference_symbol = input_context.get_reference_symbol(cur_reference); if (!reference_symbol.is_function) { fmt::print("Function {0} is marked as a patch, but {0} was a variable in the original ROM!\n", cur_func.name); return {}; } - const auto& reference_section = input_context.reference_sections[reference_symbol.section_index]; + uint32_t reference_section_vram = input_context.get_reference_section_vram(reference_symbol.section_index); + uint32_t reference_section_rom = input_context.get_reference_section_rom(reference_symbol.section_index); // Add a replacement for this function to the output context. ret.replacements.emplace_back( N64Recomp::FunctionReplacement { .func_index = (uint32_t)output_func_index, - .original_section_vrom = reference_section.rom_addr, - .original_vram = reference_section.ram_addr + reference_symbol.section_offset, + .original_section_vrom = reference_section_rom, + .original_vram = reference_section_vram + reference_symbol.section_offset, .flags = force_patch_section ? N64Recomp::ReplacementFlags::Force : N64Recomp::ReplacementFlags{} } ); @@ -405,16 +380,17 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st if (cur_reloc.type == N64Recomp::RelocType::R_MIPS_NONE) { continue; } - // Reloc to an imported symbol. - if (cur_reloc.target_section == N64Recomp::SectionImport) { + // Reloc to a special section symbol. + if (!input_context.is_regular_reference_section(cur_reloc.target_section)) { section_out.relocs.emplace_back(cur_reloc); } // Reloc to a reference symbol. else if (cur_reloc.reference_symbol) { - const auto& reloc_section = input_context.reference_sections[cur_reloc.target_section]; + bool is_relocatable = input_context.is_reference_section_relocatable(cur_reloc.target_section); + uint32_t section_vram = input_context.get_reference_section_vram(cur_reloc.target_section); // Patch relocations to non-relocatable reference sections. - if (!reloc_section.relocatable) { - uint32_t reloc_target_address = reloc_section.ram_addr + cur_reloc.target_section_offset; + if (!is_relocatable) { + uint32_t reloc_target_address = section_vram + cur_reloc.target_section_offset; uint32_t reloc_rom_address = cur_reloc.address - cur_section.ram_addr + cur_section.rom_addr; uint32_t* reloc_word_ptr = reinterpret_cast(ret.rom.data() + reloc_rom_address); @@ -477,7 +453,7 @@ N64Recomp::Context build_mod_context(const N64Recomp::Context& input_context, st ret.import_symbols = input_context.import_symbols; // Copy the reference sections from the input context as-is for resolving reference symbol relocations. - ret.reference_sections = input_context.reference_sections; + ret.copy_reference_sections_from(input_context); good = true; return ret; @@ -510,7 +486,10 @@ int main(int argc, const char** argv) { } // Use the reference context to build a reference symbol list for the actual context. - context.import_reference_context(reference_context); + if (!context.import_reference_context(reference_context)) { + fmt::print(stderr, "Internal error: failed to import reference context\n"); + return EXIT_FAILURE; + } } for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) { diff --git a/include/n64recomp.h b/include/n64recomp.h index 857e3b0..bfe57a2 100644 --- a/include/n64recomp.h +++ b/include/n64recomp.h @@ -154,7 +154,16 @@ namespace N64Recomp { ReplacementFlags flags; }; - struct Context { + class Context { + private: + //// Reference symbols (used for populating relocations for patches) + // A list of the sections that contain the reference symbols. + std::vector reference_sections; + // A list of the reference symbols. + std::vector reference_symbols; + // Mapping of symbol name to reference symbol index. + std::unordered_map reference_symbols_by_name; + public: std::vector
sections; std::vector functions; // A list of the list of each function (by index in `functions`) in a given section @@ -169,14 +178,6 @@ namespace N64Recomp { // A mapping of function name to index in the functions vector std::unordered_map functions_by_name; - //// Reference symbols (used for populating relocations for patches) - // A list of the sections that contain the reference symbols. - std::vector reference_sections; - // A list of the reference symbols. - std::vector reference_symbols; - // Mapping of symbol name to reference symbol index. - std::unordered_map reference_symbols_by_name; - //// Mod dependencies and their symbols std::vector dependencies; std::vector import_symbols; @@ -187,7 +188,7 @@ namespace N64Recomp { std::vector replacements; // Imports sections and function symbols from a provided context into this context's reference sections and reference functions. - void 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. bool read_data_reference_syms(const std::filesystem::path& data_syms_file_path); @@ -204,6 +205,38 @@ namespace N64Recomp { return section_index != SectionImport && section_index != SectionHook; } + bool find_reference_symbol(const std::string& symbol_name, SymbolReference& ref_out) const { + auto find_sym_it = reference_symbols_by_name.find(symbol_name); + + // Check if the symbol was found. + if (find_sym_it == reference_symbols_by_name.end()) { + return false; + } + + ref_out = find_sym_it->second; + return true; + } + + bool reference_symbol_exists(const std::string& symbol_name) const { + SymbolReference dummy_ref; + return find_reference_symbol(symbol_name, dummy_ref); + } + + bool find_regular_reference_symbol(const std::string& symbol_name, SymbolReference& ref_out) const { + SymbolReference ref_found; + if (!find_reference_symbol(symbol_name, ref_found)) { + return false; + } + + // Ignore reference symbols in special sections. + if (!is_regular_reference_section(ref_found.section_index)) { + return false; + } + + ref_out = ref_found; + return true; + } + const ReferenceSymbol& get_reference_symbol(uint16_t section_index, size_t symbol_index) const { if (section_index == SectionImport) { return import_symbols[symbol_index].base; @@ -214,16 +247,102 @@ namespace N64Recomp { return reference_symbols[symbol_index]; } + size_t num_regular_reference_symbols() { + return reference_symbols.size(); + } + + const ReferenceSymbol& get_regular_reference_symbol(size_t index) const { + return reference_symbols[index]; + } + const ReferenceSymbol& get_reference_symbol(const SymbolReference& ref) const { return get_reference_symbol(ref.section_index, ref.symbol_index); } bool is_reference_section_relocatable(uint16_t section_index) const { - if (section_index == SectionImport || section_index == SectionHook) { + if (section_index == SectionAbsolute) { + return false; + } + else if (section_index == SectionImport || section_index == SectionHook) { return true; } return reference_sections[section_index].relocatable; } + + bool add_reference_symbol(const std::string& symbol_name, uint16_t section_index, uint32_t vram, bool is_function) { + uint32_t section_vram; + + if (section_index == SectionAbsolute) { + section_vram = 0; + } + else if (section_index < reference_sections.size()) { + section_vram = reference_sections[section_index].ram_addr; + } + // Invalid section index. + else { + return false; + } + + // TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so. + reference_symbols_by_name.emplace(symbol_name, N64Recomp::SymbolReference{ + .section_index = section_index, + .symbol_index = reference_symbols.size() + }); + + reference_symbols.emplace_back(N64Recomp::ReferenceSymbol{ + .name = symbol_name, + .section_index = section_index, + .section_offset = vram - section_vram, + .is_function = is_function + }); + return true; + } + + void add_import_symbol(const std::string& symbol_name, size_t dependency_index, size_t symbol_index) { + reference_symbols_by_name[symbol_name] = N64Recomp::SymbolReference { + .section_index = N64Recomp::SectionImport, + .symbol_index = symbol_index + }; + import_symbols.emplace_back( + N64Recomp::ImportSymbol { + .base = N64Recomp::ReferenceSymbol { + .name = symbol_name, + .section_index = N64Recomp::SectionImport, + .section_offset = 0, + .is_function = true + }, + .dependency_index = dependency_index, + } + ); + } + + uint32_t get_reference_section_vram(uint16_t section_index) const { + if (section_index == N64Recomp::SectionAbsolute) { + return 0; + } + else if (!is_regular_reference_section(section_index)) { + return 0; + } + else { + return reference_sections[section_index].ram_addr; + } + } + + uint32_t get_reference_section_rom(uint16_t section_index) const { + if (section_index == N64Recomp::SectionAbsolute) { + return (uint32_t)-1; + } + else if (!is_regular_reference_section(section_index)) { + return (uint32_t)-1; + } + else { + return reference_sections[section_index].rom_addr; + } + } + + void copy_reference_sections_from(const Context& rhs) { + reference_sections = rhs.reference_sections; + } }; bool recompile_function(const Context& context, const Function& func, const std::string& recomp_include, std::ofstream& output_file, std::span> static_funcs, bool write_header); diff --git a/src/config.cpp b/src/config.cpp index 397260b..e32217b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -611,7 +611,7 @@ bool N64Recomp::Context::from_symbol_file(const std::filesystem::path& symbol_fi return true; } -void N64Recomp::Context::import_reference_context(const N64Recomp::Context& reference_context) { +bool N64Recomp::Context::import_reference_context(const N64Recomp::Context& reference_context) { reference_sections.resize(reference_context.sections.size()); reference_symbols.reserve(reference_context.functions.size()); @@ -628,21 +628,12 @@ void N64Recomp::Context::import_reference_context(const N64Recomp::Context& refe // Copy the functions from the reference context into the reference context's function map. for (const N64Recomp::Function& func_in: reference_context.functions) { - const N64Recomp::Section& func_section = reference_context.sections[func_in.section_index]; - - // TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so. - reference_symbols_by_name.emplace(func_in.name, N64Recomp::SymbolReference{ - .section_index = func_in.section_index, - .symbol_index = reference_symbols.size() - }); - - reference_symbols.emplace_back(N64Recomp::ReferenceSymbol{ - .name = func_in.name, - .section_index = func_in.section_index, - .section_offset = func_in.vram - static_cast(func_section.ram_addr), - .is_function = true - }); + if (!add_reference_symbol(func_in.name, func_in.section_index, func_in.vram, true)) { + return false; + } } + + return true; } // Reads a data symbol file and adds its contents into this context's reference data symbols. @@ -730,20 +721,9 @@ bool N64Recomp::Context::read_data_reference_syms(const std::filesystem::path& d throw toml::parse_error("Reference data symbol entry is missing required field(s)", data_sym_el.source()); } - // TODO Check if reference_symbols_by_name already contains the name and show a conflict error if so. - this->reference_symbols_by_name.emplace(name.value(), SymbolReference { - .section_index = ref_section_index, - .symbol_index = reference_symbols.size() - }); - - this->reference_symbols.emplace_back( - ReferenceSymbol { - .name = name.value(), - .section_index = ref_section_index, - .section_offset = vram_addr.value() - ref_section_vram, - .is_function = false - } - ); + if (!this->add_reference_symbol(name.value(), ref_section_index, vram_addr.value(), false)) { + throw toml::parse_error("Internal error: Failed to add reference symbol to context", data_sym_el.source()); + } } else { throw toml::parse_error("Invalid data symbol entry", data_sym_el.source()); diff --git a/src/elf.cpp b/src/elf.cpp index f993660..8f6e068 100644 --- a/src/elf.cpp +++ b/src/elf.cpp @@ -213,6 +213,7 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP ELFIO::section* symtab_section = nullptr; std::vector segments{}; segments.resize(elf_file.segments.size()); + bool has_reference_symbols = context.has_reference_symbols(); // Copy the data for each segment into the segment entry list for (size_t segment_index = 0; segment_index < elf_file.segments.size(); segment_index++) { @@ -263,7 +264,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP // If this reloc section is for a section that has been marked as relocatable, record it in the reloc section lookup. // Alternatively, if this recompilation uses reference symbols then record all reloc sections. - if (elf_config.all_sections_relocatable || !context.reference_sections.empty() || elf_config.relocatable_sections.contains(reloc_target_section)) { + bool section_is_relocatable = elf_config.all_sections_relocatable || elf_config.relocatable_sections.contains(reloc_target_section); + if (has_reference_symbols || section_is_relocatable) { reloc_sections_by_name[reloc_target_section] = section.get(); } } @@ -396,8 +398,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP // Check if the symbol is undefined and to know whether to look for it in the reference symbols. if (rel_symbol_section_index == ELFIO::SHN_UNDEF) { // Undefined sym, check the reference symbols. - auto sym_find_it = context.reference_symbols_by_name.find(rel_symbol_name); - if (sym_find_it == context.reference_symbols_by_name.end()) { + N64Recomp::SymbolReference sym_ref; + if (!context.find_reference_symbol(rel_symbol_name, sym_ref)) { fmt::print(stderr, "Undefined symbol: {}, not found in input or reference symbols!\n", rel_symbol_name); return nullptr; @@ -406,8 +408,8 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP reloc_out.reference_symbol = true; // Replace the reloc's symbol index with the index into the reference symbol array. rel_section_vram = 0; - reloc_out.target_section = sym_find_it->second.section_index; - reloc_out.symbol_index = sym_find_it->second.symbol_index; + reloc_out.target_section = sym_ref.section_index; + reloc_out.symbol_index = sym_ref.symbol_index; const auto& reference_symbol = context.get_reference_symbol(reloc_out.target_section, reloc_out.symbol_index); rel_symbol_offset = reference_symbol.section_offset; @@ -504,10 +506,7 @@ ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::ElfP // TODO set section_out.has_mips32_relocs to true if this section should emit its mips32 relocs (mainly for TLB mapping). if (reloc_out.reference_symbol) { - uint32_t reloc_target_section_addr = 0; - if (reloc_out.target_section != N64Recomp::SectionAbsolute) { - reloc_target_section_addr = context.reference_sections[reloc_out.target_section].ram_addr; - } + uint32_t reloc_target_section_addr = context.get_reference_section_vram(reloc_out.target_section); // Patch the word in the ROM to incorporate the symbol's value. uint32_t updated_reloc_word = reloc_rom_word + reloc_target_section_addr + reloc_out.target_section_offset; *reinterpret_cast(context.rom.data() + reloc_rom_addr) = byteswap(updated_reloc_word); diff --git a/src/main.cpp b/src/main.cpp index 72e152e..59a2d0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -320,7 +320,9 @@ int main(int argc, char** argv) { } // Use the reference context to build a reference symbol list for the actual context. - context.import_reference_context(reference_context); + if (!context.import_reference_context(reference_context)) { + exit_failure("Internal error: Failed to import reference context\n"); + } } for (const std::filesystem::path& cur_data_sym_path : config.data_reference_syms_file_paths) { @@ -586,7 +588,8 @@ int main(int argc, char** argv) { bool in_normal_patch_section = func_section.name == N64Recomp::PatchSectionName; bool in_force_patch_section = func_section.name == N64Recomp::ForcedPatchSectionName; bool in_patch_section = in_normal_patch_section || in_force_patch_section; - bool reference_symbol_found = context.reference_symbols_by_name.contains(func.name); + N64Recomp::SymbolReference dummy_ref; + bool reference_symbol_found = context.reference_symbol_exists(func.name); // This is a patch function, but no corresponding symbol was found in the original symbol list. if (in_patch_section && !reference_symbol_found) { diff --git a/src/mod_symbols.cpp b/src/mod_symbols.cpp index fdb8dbf..3de5d87 100644 --- a/src/mod_symbols.cpp +++ b/src/mod_symbols.cpp @@ -116,11 +116,14 @@ bool parse_v1(std::span data, const std::unordered_map(data, offset); if (section_header == nullptr) { @@ -304,18 +307,7 @@ bool parse_v1(std::span data, const std::unordered_map N64Recomp::symbols_to_bin_v1(const N64Recomp::Context& cont target_section_offset_or_index = cur_reloc.symbol_index; } else if (cur_reloc.reference_symbol) { - target_section_vrom = context.reference_sections[cur_reloc.target_section].rom_addr; + target_section_vrom = context.get_reference_section_rom(cur_reloc.target_section); } else { target_section_vrom = context.sections[cur_reloc.target_section].rom_addr; diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 474fbb0..d3f01bc 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -171,18 +171,13 @@ bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Fun if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16 || reloc_type == N64Recomp::RelocType::R_MIPS_26) { if (reloc.reference_symbol) { reloc_reference_symbol = reloc.symbol_index; - static N64Recomp::ReferenceSection dummy_section{ - .rom_addr = 0, - .ram_addr = 0, - .size = 0, - .relocatable = false - }; - // Don't try to relocate import symbols. - if (reloc.target_section != N64Recomp::SectionImport) { - const auto& reloc_reference_section = reloc.target_section == N64Recomp::SectionAbsolute ? dummy_section : context.reference_sections[reloc.target_section]; + // Don't try to relocate special section symbols. + if (context.is_regular_reference_section(reloc.target_section)) { + bool ref_section_relocatable = context.is_reference_section_relocatable(reloc.target_section); + uint32_t ref_section_vram = context.get_reference_section_vram(reloc.target_section); // Resolve HI16 and LO16 reference symbol relocs to non-relocatable sections by patching the instruction immediate. - if (!reloc_reference_section.relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) { - uint32_t full_immediate = reloc.target_section_offset + reloc_reference_section.ram_addr; + if (!ref_section_relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) { + uint32_t full_immediate = reloc.target_section_offset + ref_section_vram; if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16) { imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1);