| 22 | }; |
| 23 | |
| 24 | JalResolutionResult resolve_jal(const N64Recomp::Context& context, size_t cur_section_index, uint32_t target_func_vram, size_t& matched_function_index) { |
| 25 | // Skip resolution if all function calls should use lookup and just return Ambiguous. |
| 26 | if (context.use_lookup_for_all_function_calls) { |
| 27 | return JalResolutionResult::Ambiguous; |
| 28 | } |
| 29 | |
| 30 | // Look for symbols with the target vram address |
| 31 | const N64Recomp::Section& cur_section = context.sections[cur_section_index]; |
| 32 | const auto matching_funcs_find = context.functions_by_vram.find(target_func_vram); |
| 33 | uint32_t section_vram_start = cur_section.ram_addr; |
| 34 | uint32_t section_vram_end = cur_section.ram_addr + cur_section.size; |
| 35 | bool in_current_section = target_func_vram >= section_vram_start && target_func_vram < section_vram_end; |
| 36 | bool exact_match_found = false; |
| 37 | |
| 38 | // Use a thread local to prevent reallocation across runs and to allow multi-threading in the future. |
| 39 | thread_local std::vector<size_t> matched_funcs{}; |
| 40 | matched_funcs.clear(); |
| 41 | |
| 42 | // Evaluate any functions with the target address to see if they're potential candidates for JAL resolution. |
| 43 | if (matching_funcs_find != context.functions_by_vram.end()) { |
| 44 | for (size_t target_func_index : matching_funcs_find->second) { |
| 45 | const auto& target_func = context.functions[target_func_index]; |
| 46 | |
| 47 | // Zero-sized symbol handling. unless there's only one matching target. |
| 48 | if (target_func.words.empty()) { |
| 49 | if (!N64Recomp::is_manual_patch_symbol(target_func.vram)) { |
| 50 | continue; |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | // Immediately accept a function in the same section as this one, since it must also be loaded if the current function is. |
| 55 | if (target_func.section_index == cur_section_index) { |
| 56 | exact_match_found = true; |
| 57 | matched_funcs.clear(); |
| 58 | matched_funcs.push_back(target_func_index); |
| 59 | break; |
| 60 | } |
| 61 | |
| 62 | // If the function's section isn't relocatable, add the function as a candidate. |
| 63 | const auto& target_func_section = context.sections[target_func.section_index]; |
| 64 | if (!target_func_section.relocatable) { |
| 65 | matched_funcs.push_back(target_func_index); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // If the target vram is in the current section, only allow exact matches. |
| 71 | if (in_current_section) { |
| 72 | // If an exact match was found, use it. |
| 73 | if (exact_match_found) { |
| 74 | matched_function_index = matched_funcs[0]; |
| 75 | return JalResolutionResult::Match; |
| 76 | } |
| 77 | // Otherwise, create a static function at the target address. |
| 78 | else { |
| 79 | return JalResolutionResult::CreateStatic; |
| 80 | } |
| 81 | } |
no test coverage detected