diff --git a/OfflineModRecomp/main.cpp b/OfflineModRecomp/main.cpp index 5733eb7..5a1e0ef 100644 --- a/OfflineModRecomp/main.cpp +++ b/OfflineModRecomp/main.cpp @@ -132,12 +132,31 @@ int main(int argc, const char** argv) { RabbitizerConfig_Cfg.pseudos.pseudoNot = false; RabbitizerConfig_Cfg.pseudos.pseudoBal = false; - std::string recomp_include = "#include \"librecomp/recomp.h\""; + output_file << "#include \"mod_recomp.h\"\n\n"; + + // Write import function pointer array and defines (i.e. `#define testmod_inner_import imported_funcs[0]`) + size_t num_imports = mod_context.import_symbols.size(); + output_file << "// Imported functions\nRECOMP_EXPORT recomp_func_t* imported_funcs[" << num_imports << "] = {};\n"; + for (size_t import_index = 0; import_index < num_imports; import_index++) { + const auto& import = mod_context.import_symbols[import_index]; + output_file << "#define " << import.base.name << " imported_funcs[" << import_index << "]\n"; + } + output_file << "\n"; + + // Write provided event array (maps internal event indices to global ones). + output_file << "RECOMP_EXPORT uint32_t event_indices[" << mod_context.event_symbols.size() <<"] = {};\n\n"; + + // Write the event trigger function pointer. + output_file << "RECOMP_EXPORT void (*recomp_trigger_event)(uint8_t* rdram, recomp_context* ctx, uint32_t);\n\n"; + + // Write the get_function pointer. + output_file << "RECOMP_EXPORT recomp_func_t* (*get_function)(int32_t vram) = NULL;\n\n"; + + // Write the section_addresses pointer. + output_file << "RECOMP_EXPORT int32_t* section_addresses = NULL;\n"; - bool should_write_header = true; for (const auto& func : mod_context.functions) { - N64Recomp::recompile_function(mod_context, func, recomp_include, output_file, static_funcs_by_section, should_write_header); - should_write_header = false; + N64Recomp::recompile_function(mod_context, func, "", output_file, static_funcs_by_section, false); } return EXIT_SUCCESS; diff --git a/src/mod_symbols.cpp b/src/mod_symbols.cpp index 8d17408..8746735 100644 --- a/src/mod_symbols.cpp +++ b/src/mod_symbols.cpp @@ -222,6 +222,12 @@ bool parse_v1(std::span data, const std::unordered_map N64Recomp::symbols_to_bin_v1(const N64Recomp::Context& cont target_section_vrom = SectionImportVromV1; target_section_offset_or_index = cur_reloc.symbol_index; } + else if (cur_reloc.target_section == SectionEvent) { + target_section_vrom = SectionEventVromV1; + target_section_offset_or_index = cur_reloc.symbol_index; + } else if (cur_reloc.reference_symbol) { target_section_vrom = context.get_reference_section_rom(cur_reloc.target_section); } diff --git a/src/recompilation.cpp b/src/recompilation.cpp index b8efd61..580f1e0 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -236,55 +236,75 @@ bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Fun auto print_func_call = [reloc_target_section_offset, reloc_section, reloc_reference_symbol, reloc_type, &context, §ion, &func, &static_funcs_out, &needs_link_branch, &print_unconditional_branch] (uint32_t target_func_vram, bool link_branch = true, bool indent = false) { - std::string jal_target_name{}; - if (reloc_reference_symbol != (size_t)-1) { - const auto& ref_symbol = context.get_reference_symbol(reloc_section, reloc_reference_symbol); - - if (reloc_type != N64Recomp::RelocType::R_MIPS_26) { - fmt::print(stderr, "Unsupported reloc type {} on jal instruction in {}\n", (int)reloc_type, func.name); - return false; + // Event symbol, emit a call to the runtime to trigger this event. + if (reloc_section == N64Recomp::SectionEvent) { + needs_link_branch = link_branch; + if (indent) { + if (!print_unconditional_branch(" recomp_trigger_event(rdram, ctx, event_indices[{}])", reloc_reference_symbol)) { + return false; + } + } else { + if (!print_unconditional_branch("recomp_trigger_event(rdram, ctx, event_indices[{}])", reloc_reference_symbol)) { + return false; + } } - - if (ref_symbol.section_offset != reloc_target_section_offset) { - fmt::print(stderr, "Function {} uses a MIPS_R_26 addend, which is not supported yet\n", func.name); - return false; - } - - jal_target_name = ref_symbol.name; } + // Normal symbol or reference symbol, else { - size_t matched_func_index = 0; - JalResolutionResult jal_result = resolve_jal(context, func.section_index, target_func_vram, matched_func_index); + std::string jal_target_name{}; + if (reloc_reference_symbol != (size_t)-1) { + const auto& ref_symbol = context.get_reference_symbol(reloc_section, reloc_reference_symbol); - switch (jal_result) { - case JalResolutionResult::NoMatch: - fmt::print(stderr, "No function found for jal target: 0x{:08X}\n", target_func_vram); + if (reloc_type != N64Recomp::RelocType::R_MIPS_26) { + fmt::print(stderr, "Unsupported reloc type {} on jal instruction in {}\n", (int)reloc_type, func.name); return false; - case JalResolutionResult::Match: - jal_target_name = context.functions[matched_func_index].name; - break; - case JalResolutionResult::CreateStatic: - // Create a static function add it to the static function list for this section. - jal_target_name = fmt::format("static_{}_{:08X}", func.section_index, target_func_vram); - static_funcs_out[func.section_index].push_back(target_func_vram); - break; - case JalResolutionResult::Ambiguous: - fmt::print(stderr, "[Info] Ambiguous jal target 0x{:08X} in function {}, falling back to function lookup\n", target_func_vram, func.name); - // Relocation isn't necessary for jumps inside a relocatable section, as this code path will never run if the target vram - // is in the current function's section (see the branch for `in_current_section` above). - // If a game ever needs to jump between multiple relocatable sections, relocation will be necessary here. - jal_target_name = fmt::format("LOOKUP_FUNC(0x{:08X})", target_func_vram); - break; - case JalResolutionResult::Error: - fmt::print(stderr, "Internal error when resolving jal to address 0x{:08X} in function {}\n", target_func_vram, func.name); + } + + if (ref_symbol.section_offset != reloc_target_section_offset) { + fmt::print(stderr, "Function {} uses a MIPS_R_26 addend, which is not supported yet\n", func.name); return false; + } + + jal_target_name = ref_symbol.name; + } + else { + size_t matched_func_index = 0; + JalResolutionResult jal_result = resolve_jal(context, func.section_index, target_func_vram, matched_func_index); + + switch (jal_result) { + case JalResolutionResult::NoMatch: + fmt::print(stderr, "No function found for jal target: 0x{:08X}\n", target_func_vram); + return false; + case JalResolutionResult::Match: + jal_target_name = context.functions[matched_func_index].name; + break; + case JalResolutionResult::CreateStatic: + // Create a static function add it to the static function list for this section. + jal_target_name = fmt::format("static_{}_{:08X}", func.section_index, target_func_vram); + static_funcs_out[func.section_index].push_back(target_func_vram); + break; + case JalResolutionResult::Ambiguous: + fmt::print(stderr, "[Info] Ambiguous jal target 0x{:08X} in function {}, falling back to function lookup\n", target_func_vram, func.name); + // Relocation isn't necessary for jumps inside a relocatable section, as this code path will never run if the target vram + // is in the current function's section (see the branch for `in_current_section` above). + // If a game ever needs to jump between multiple relocatable sections, relocation will be necessary here. + jal_target_name = fmt::format("LOOKUP_FUNC(0x{:08X})", target_func_vram); + break; + case JalResolutionResult::Error: + fmt::print(stderr, "Internal error when resolving jal to address 0x{:08X} in function {}\n", target_func_vram, func.name); + return false; + } + } + needs_link_branch = link_branch; + if (indent) { + if (!print_unconditional_branch(" {}(rdram, ctx)", jal_target_name)) { + return false; + } + } else { + if (!print_unconditional_branch("{}(rdram, ctx)", jal_target_name)) { + return false; + } } - } - needs_link_branch = link_branch; - if (indent) { - print_unconditional_branch(" {}(rdram, ctx)", jal_target_name); - } else { - print_unconditional_branch("{}(rdram, ctx)", jal_target_name); } return true; };