| 265 | } |
| 266 | |
| 267 | bool N64Recomp::analyze_function(const N64Recomp::Context& context, const N64Recomp::Function& func, |
| 268 | const std::vector<rabbitizer::InstructionCpu>& instructions, N64Recomp::FunctionStats& stats) { |
| 269 | const Section* section = &context.sections[func.section_index]; |
| 270 | std::optional<uint32_t> got_ram_addr = section->got_ram_addr; |
| 271 | |
| 272 | // Create a state to track each register (r0 won't be used) |
| 273 | RegState reg_states[32] {}; |
| 274 | std::vector<RegState> stack_states{}; |
| 275 | |
| 276 | // Look for jump tables |
| 277 | // A linear search through the func won't be accurate due to not taking control flow into account, but it'll work for finding jtables |
| 278 | for (const auto& instr : instructions) { |
| 279 | if (!analyze_instruction(instr, func, stats, reg_states, stack_states, got_ram_addr.has_value())) { |
| 280 | return false; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | // Calculate absolute addresses for position-independent jump tables |
| 285 | if (got_ram_addr.has_value()) { |
| 286 | uint32_t got_rom_addr = got_ram_addr.value() + func.rom - func.vram; |
| 287 | |
| 288 | for (size_t i = 0; i < stats.jump_tables.size(); i++) { |
| 289 | JumpTable& cur_jtbl = stats.jump_tables[i]; |
| 290 | |
| 291 | if (cur_jtbl.got_offset.has_value()) { |
| 292 | uint32_t got_word = byteswap(*reinterpret_cast<const uint32_t*>(&context.rom[got_rom_addr + cur_jtbl.got_offset.value()])); |
| 293 | |
| 294 | cur_jtbl.vram += (section->ram_addr + got_word); |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | // Sort jump tables by their address |
| 300 | std::sort(stats.jump_tables.begin(), stats.jump_tables.end(), |
| 301 | [](const JumpTable& a, const JumpTable& b) |
| 302 | { |
| 303 | return a.vram < b.vram; |
| 304 | }); |
| 305 | |
| 306 | // Determine jump table sizes |
| 307 | for (size_t i = 0; i < stats.jump_tables.size(); i++) { |
| 308 | JumpTable& cur_jtbl = stats.jump_tables[i]; |
| 309 | uint32_t end_address = (uint32_t)-1; |
| 310 | uint32_t entry_count = 0; |
| 311 | uint32_t vram = cur_jtbl.vram; |
| 312 | |
| 313 | if (i < stats.jump_tables.size() - 1) { |
| 314 | end_address = stats.jump_tables[i + 1].vram; |
| 315 | } |
| 316 | |
| 317 | // TODO this assumes that the jump table is in the same section as the function itself |
| 318 | cur_jtbl.rom = cur_jtbl.vram + func.rom - func.vram; |
| 319 | cur_jtbl.section_index = func.section_index; |
| 320 | |
| 321 | while (vram < end_address) { |
| 322 | // Retrieve the current entry of the jump table |
| 323 | // TODO same as above |
| 324 | uint32_t rom_addr = vram + func.rom - func.vram; |
nothing calls this directly
no test coverage detected