Fix populating reference symbol pointers and add missing runtime function pointers in offline compiled mod loading (#61)

* Fixed reference symbol pointers not being populated in offline compiled mods

* Add populating missing runtime function pointers in offline compiled mods

* Update N64Recomp after merge
This commit is contained in:
Wiseguy 2024-09-12 19:00:02 -04:00 committed by GitHub
parent 45e9f7a6cb
commit 356b9f901e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 75 additions and 37 deletions

@ -1 +1 @@
Subproject commit cc71b31b09a927f558e142598ffcca7d146b454b
Subproject commit d5ab74220da3d8468d6873ed29afbcad03b890f5

View file

@ -212,6 +212,10 @@ namespace recomp {
virtual uint32_t get_base_event_index() = 0;
virtual void set_recomp_trigger_event_pointer(void (*ptr)(uint8_t* rdram, recomp_context* ctx, uint32_t index)) = 0;
virtual void set_get_function_pointer(recomp_func_t* (*ptr)(int32_t)) = 0;
virtual void set_cop0_status_write_pointer(void (*ptr)(recomp_context* ctx, gpr value)) = 0;
virtual void set_cop0_status_read_pointer(gpr (*ptr)(recomp_context* ctx)) = 0;
virtual void set_switch_error_pointer(void (*ptr)(const char* func, uint32_t vram, uint32_t jtbl)) = 0;
virtual void set_do_break_pointer(void (*ptr)(uint32_t vram)) = 0;
virtual void set_reference_section_addresses_pointer(int32_t* ptr) = 0;
virtual void set_local_section_address(size_t section_index, int32_t address) = 0;
virtual GenericFunction get_function_handle(size_t func_index) = 0;
@ -281,6 +285,18 @@ namespace recomp {
void set_get_function_pointer(recomp_func_t* (*ptr)(int32_t)) final {
*get_function = ptr;
};
void set_cop0_status_write_pointer(void (*ptr)(recomp_context* ctx, gpr value)) final {
*cop0_status_write = ptr;
}
void set_cop0_status_read_pointer(gpr (*ptr)(recomp_context* ctx)) final {
*cop0_status_read = ptr;
}
void set_switch_error_pointer(void (*ptr)(const char* func, uint32_t vram, uint32_t jtbl)) final {
*switch_error = ptr;
}
void set_do_break_pointer(void (*ptr)(uint32_t vram)) final {
*do_break = ptr;
}
void set_reference_section_addresses_pointer(int32_t* ptr) final {
*reference_section_addresses = ptr;
};
@ -300,6 +316,10 @@ namespace recomp {
uint32_t* base_event_index;
void (**recomp_trigger_event)(uint8_t* rdram, recomp_context* ctx, uint32_t index);
recomp_func_t* (**get_function)(int32_t vram);
void (**cop0_status_write)(recomp_context* ctx, gpr value);
gpr (**cop0_status_read)(recomp_context* ctx);
void (**switch_error)(const char* func, uint32_t vram, uint32_t jtbl);
void (**do_break)(uint32_t vram);
int32_t** reference_section_addresses;
int32_t* section_addresses;
};

View file

@ -29,7 +29,8 @@ namespace recomp {
void init_overlays();
const std::unordered_map<uint32_t, uint16_t>& get_vrom_to_section_map();
recomp_func_t* get_func_by_section_ram(uint32_t section_rom, uint32_t function_vram);
recomp_func_t* get_func_by_section_rom_function_vram(uint32_t section_rom, uint32_t function_vram);
recomp_func_t* get_func_by_section_index_function_offset(uint16_t code_section_index, uint32_t function_offset);
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();

View file

@ -347,6 +347,10 @@ recomp::mods::NativeCodeHandle::NativeCodeHandle(const std::filesystem::path& dl
is_good &= dynamic_lib->get_dll_symbol(base_event_index, "base_event_index");
is_good &= dynamic_lib->get_dll_symbol(recomp_trigger_event, "recomp_trigger_event");
is_good &= dynamic_lib->get_dll_symbol(get_function, "get_function");
is_good &= dynamic_lib->get_dll_symbol(cop0_status_write, "cop0_status_write");
is_good &= dynamic_lib->get_dll_symbol(cop0_status_read, "cop0_status_read");
is_good &= dynamic_lib->get_dll_symbol(switch_error, "switch_error");
is_good &= dynamic_lib->get_dll_symbol(do_break, "do_break");
is_good &= dynamic_lib->get_dll_symbol(reference_section_addresses, "reference_section_addresses");
is_good &= dynamic_lib->get_dll_symbol(section_addresses, "section_addresses");
}
@ -483,8 +487,6 @@ recomp::mods::ModLoadError recomp::mods::ModContext::load_mod(uint8_t* rdram, co
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;
@ -788,25 +790,25 @@ recomp::mods::ModLoadError recomp::mods::ModContext::load_mod_code(recomp::mods:
}
recomp::mods::ModLoadError recomp::mods::ModContext::resolve_dependencies(recomp::mods::ModHandle& mod, std::string& error_param) {
// Reference symbols from the base recomp.
for (size_t reference_sym_index = 0; reference_sym_index < mod.recompiler_context->num_regular_reference_symbols(); reference_sym_index++) {
const N64Recomp::ReferenceSymbol& reference_sym = mod.recompiler_context->get_regular_reference_symbol(reference_sym_index);
uint32_t reference_section_vrom = mod.recompiler_context->get_reference_section_rom(reference_sym.section_index);
uint32_t reference_section_vram = mod.recompiler_context->get_reference_section_vram(reference_sym.section_index);
uint32_t reference_symbol_vram = reference_section_vram + reference_sym.section_offset;
recomp_func_t* found_func = recomp::overlays::get_func_by_section_ram(reference_section_vrom, reference_symbol_vram);
if (found_func == nullptr) {
std::stringstream error_param_stream{};
error_param_stream << std::hex <<
"section: 0x" << reference_section_vrom <<
" func: 0x" << std::setfill('0') << std::setw(8) << reference_symbol_vram;
error_param = error_param_stream.str();
return ModLoadError::InvalidReferenceSymbol;
// Reference symbols from the base recomp.1:1 with relocs for offline mods.
// TODO this won't be needed for LuaJIT recompilation, so move this logic into the code handle.
size_t reference_symbol_index = 0;
for (const auto& section : mod.recompiler_context->sections) {
for (const auto& reloc : section.relocs) {
if (reloc.type == N64Recomp::RelocType::R_MIPS_26 && reloc.reference_symbol && mod.recompiler_context->is_regular_reference_section(reloc.target_section)) {
recomp_func_t* cur_func = recomp::overlays::get_func_by_section_index_function_offset(reloc.target_section, reloc.target_section_offset);
if (cur_func == nullptr) {
std::stringstream error_param_stream{};
error_param_stream << std::hex <<
"section: " << reloc.target_section <<
" func offset: 0x" << reloc.target_section_offset;
error_param = error_param_stream.str();
return ModLoadError::InvalidReferenceSymbol;
}
mod.code_handle->set_reference_symbol_pointer(reference_symbol_index, cur_func);
reference_symbol_index++;
}
}
mod.code_handle->set_reference_symbol_pointer(reference_sym_index, found_func);
}
// Create a list of dependencies ordered by their index in the recompiler context.
@ -889,6 +891,10 @@ recomp::mods::ModLoadError recomp::mods::ModContext::resolve_dependencies(recomp
// Populate the mod's state fields.
mod.code_handle->set_recomp_trigger_event_pointer(recomp_trigger_event);
mod.code_handle->set_get_function_pointer(get_function);
mod.code_handle->set_cop0_status_write_pointer(cop0_status_write);
mod.code_handle->set_cop0_status_read_pointer(cop0_status_read);
mod.code_handle->set_switch_error_pointer(switch_error);
mod.code_handle->set_do_break_pointer(do_break);
mod.code_handle->set_reference_section_addresses_pointer(section_addresses);
for (size_t section_index = 0; section_index < mod.section_load_addresses.size(); section_index++) {
mod.code_handle->set_local_section_address(section_index, mod.section_load_addresses[section_index]);
@ -896,7 +902,7 @@ recomp::mods::ModLoadError recomp::mods::ModContext::resolve_dependencies(recomp
// Apply all the function replacements in the mod.
for (const auto& replacement : mod.recompiler_context->replacements) {
recomp_func_t* to_replace = recomp::overlays::get_func_by_section_ram(replacement.original_section_vrom, replacement.original_vram);
recomp_func_t* to_replace = recomp::overlays::get_func_by_section_rom_function_vram(replacement.original_section_vrom, replacement.original_vram);
if (to_replace == nullptr) {
std::stringstream error_param_stream{};

View file

@ -254,26 +254,37 @@ void recomp::overlays::init_overlays() {
load_patch_functions();
}
recomp_func_t* recomp::overlays::get_func_by_section_ram(uint32_t section_rom, uint32_t function_vram) {
// Finds a function given a section's index and the function's offset into the section.
recomp_func_t* recomp::overlays::get_func_by_section_index_function_offset(uint16_t code_section_index, uint32_t function_offset) {
if (code_section_index >= sections_info.num_code_sections) {
return nullptr;
}
SectionTableEntry* section = &sections_info.code_sections[code_section_index];
if (function_offset >= section->size) {
return nullptr;
}
for (size_t func_index = 0; func_index < section->num_funcs; func_index++) {
if (section->funcs[func_index].offset == function_offset) {
return section->funcs[func_index].func;
}
}
return nullptr;
}
// Finds a function given a section's rom address and the function's vram address.
recomp_func_t* recomp::overlays::get_func_by_section_rom_function_vram(uint32_t section_rom, uint32_t function_vram) {
auto find_section_it = code_sections_by_rom.find(section_rom);
if (find_section_it == code_sections_by_rom.end()) {
return nullptr;
}
SectionTableEntry* section = &sections_info.code_sections[find_section_it->second];
if (function_vram < section->ram_addr || function_vram >= section->ram_addr + section->size) {
return nullptr;
}
uint32_t func_offset = function_vram - section->ram_addr;
for (size_t func_index = 0; func_index < section->num_funcs; func_index++) {
if (section->funcs[func_index].offset == func_offset) {
return section->funcs[func_index].func;
}
}
return nullptr;
int32_t func_offset = function_vram - section->ram_addr;
return get_func_by_section_index_function_offset(find_section_it->second, func_offset);
}
extern "C" recomp_func_t * get_function(int32_t addr) {