Add runtime-driven fields to offline mod recompiler, fix event symbol relocs using the wrong section in the mod tool

This commit is contained in:
Mr-Wiseguy 2024-08-22 00:23:23 -04:00
parent 21504041b9
commit ad0e38dde7
3 changed files with 95 additions and 46 deletions

View file

@ -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;

View file

@ -222,6 +222,12 @@ bool parse_v1(std::span<const char> data, const std::unordered_map<uint32_t, uin
reloc_symbol_index = reloc_in.target_section_offset_or_index;
cur_reloc.reference_symbol = true;
}
else if (target_section_vrom == SectionEventVromV1) {
reloc_target_section = N64Recomp::SectionEvent;
reloc_target_section_offset = 0; // Not used for event symbols.
reloc_symbol_index = reloc_in.target_section_offset_or_index;
cur_reloc.reference_symbol = true;
}
else {
// TODO lookup by section index by original vrom
auto find_section_it = sections_by_vrom.find(target_section_vrom);
@ -597,6 +603,10 @@ std::vector<uint8_t> 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);
}

View file

@ -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, &section, &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;
};