From 26a05439c2215ea9e1c0b0d572b46b3584a90a4f Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 9 Sep 2024 02:00:28 -0400 Subject: [PATCH] Implement mip32 relocs for mod loading and add mod functions to function lookup table --- librecomp/include/librecomp/overlays.hpp | 2 + librecomp/src/mods.cpp | 58 ++++++++++++++++++++++-- librecomp/src/overlays.cpp | 5 ++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/librecomp/include/librecomp/overlays.hpp b/librecomp/include/librecomp/overlays.hpp index 8defccc..33a1859 100644 --- a/librecomp/include/librecomp/overlays.hpp +++ b/librecomp/include/librecomp/overlays.hpp @@ -33,6 +33,8 @@ namespace recomp { recomp_func_t* get_base_export(const std::string& export_name); size_t get_base_event_index(const std::string& event_name); size_t num_base_events(); + + void add_loaded_function(int32_t ram_addr, recomp_func_t* func); } }; diff --git a/librecomp/src/mods.cpp b/librecomp/src/mods.cpp index 8fa688b..f66797a 100644 --- a/librecomp/src/mods.cpp +++ b/librecomp/src/mods.cpp @@ -424,17 +424,48 @@ recomp::mods::ModLoadError recomp::mods::ModContext::load_mod(uint8_t* rdram, co return ModLoadError::FailedToParseSyms; } - handle.section_load_addresses.resize(handle.recompiler_context->sections.size()); + const std::vector& mod_sections = handle.recompiler_context->sections; + handle.section_load_addresses.resize(mod_sections.size()); // Copy each section's binary into rdram, leaving room for the section's bss before the next one. int32_t cur_section_addr = load_address; - for (size_t section_index = 0; section_index < handle.recompiler_context->sections.size(); section_index++) { - const auto& section = handle.recompiler_context->sections[section_index]; + for (size_t section_index = 0; section_index < mod_sections.size(); section_index++) { + const auto& section = mod_sections[section_index]; for (size_t i = 0; i < section.size; i++) { MEM_B(i, (gpr)cur_section_addr) = binary_data[section.rom_addr + i]; } handle.section_load_addresses[section_index] = cur_section_addr; cur_section_addr += section.size + section.bss_size; + + } + + // Iterate over each section again after loading them to perform R_MIPS_32 relocations. + for (size_t section_index = 0; section_index < mod_sections.size(); section_index++) { + const auto& section = mod_sections[section_index]; + uint32_t cur_section_original_vram = section.ram_addr; + uint32_t cur_section_loaded_vram = handle.section_load_addresses[section_index]; + + // Perform mips32 relocations for this section. + for (const auto& reloc : section.relocs) { + if (reloc.type == N64Recomp::RelocType::R_MIPS_32 && !reloc.reference_symbol) { + if (reloc.target_section >= mod_sections.size()) { + return ModLoadError::FailedToParseSyms; + } + // Get the ram address of the word that's being relocated and read its original value. + int32_t reloc_word_addr = reloc.address - cur_section_original_vram + cur_section_loaded_vram; + uint32_t reloc_word = MEM_W(0, reloc_word_addr); + + // Determine the original and loaded addresses of the section that the relocation points to. + uint32_t target_section_original_vram = mod_sections[reloc.target_section].ram_addr; + uint32_t target_section_loaded_vram = handle.section_load_addresses[reloc.target_section]; + + uint32_t reloc_word_old = reloc_word; + + // Recalculate the word and write it back into ram. + reloc_word += (target_section_loaded_vram - target_section_original_vram); + MEM_W(0, reloc_word_addr) = reloc_word; + } + } } ram_used = cur_section_addr - load_address; @@ -710,6 +741,25 @@ recomp::mods::ModLoadError recomp::mods::ModContext::load_mod_code(recomp::mods: // Allocate the event indices used by the mod. num_events += mod.num_events(); + // Add each function from the mod into the function lookup table. + const std::vector& mod_sections = mod.recompiler_context->sections; + for (size_t func_index = 0; func_index < mod.recompiler_context->functions.size(); func_index++) { + const auto& func = mod.recompiler_context->functions[func_index]; + if (func.section_index >= mod_sections.size()) { + return ModLoadError::FailedToParseSyms; + } + // Calculate the loaded address of this function. + int32_t func_address = func.vram - mod_sections[func.section_index].ram_addr + mod.section_load_addresses[func.section_index]; + + // Get the handle to the function and add it to the lookup table based on its type. + recomp::mods::GenericFunction func_handle = mod.code_handle->get_function_handle(func_index); + std::visit(overloaded{ + [func_address](recomp_func_t* native_func) { + recomp::overlays::add_loaded_function(func_address, native_func); + } + }, func_handle); + } + return ModLoadError::Good; } @@ -849,8 +899,6 @@ recomp::mods::ModLoadError recomp::mods::ModContext::resolve_dependencies(recomp patch_func(to_replace, mod.code_handle->get_function_handle(replacement.func_index)); } - // TODO perform mips32 relocations - return ModLoadError::Good; } diff --git a/librecomp/src/overlays.cpp b/librecomp/src/overlays.cpp index b0d15ec..e546467 100644 --- a/librecomp/src/overlays.cpp +++ b/librecomp/src/overlays.cpp @@ -108,6 +108,10 @@ const std::unordered_map& recomp::overlays::get_vrom_to_sect return code_sections_by_rom; } +void recomp::overlays::add_loaded_function(int32_t ram, recomp_func_t* func) { + func_map[ram] = func; +} + void load_overlay(size_t section_table_index, int32_t ram) { const SectionTableEntry& section = sections_info.code_sections[section_table_index]; @@ -230,6 +234,7 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) { } void recomp::overlays::init_overlays() { + func_map.clear(); section_addresses = (int32_t *)calloc(sections_info.total_num_sections, sizeof(int32_t)); // Sort the executable sections by rom address