Missing jump label in decompile output
lizardman0 opened this issue · comments
Hi, I'm trying out this tool by recompiling a demo from the official SDK (seemed like a better idea than a full blown commercial game)
[input]
entrypoint = 0x80200060
elf_path = "teapot.elf"
output_func_path = "RecompiledFuncs"
[patches]
ignored = ["gspF3DEX2_xbusTextStart"] # ucode should be ignored
I got some ambiguity warnings, but the expected functions were found.
Sections
Num symbols: 903
Found entrypoint, original name: boot
Function count: 766
Working dir: /home/lizardman/projects/n64
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206570
sqrtf_recomp
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206EA0
gcc2_compiled._80206EA0
gcc2_compiled._80206EA0
guNormalize
[Warn] Potential jal resolution ambiguity
gcc2_compiled._80206EA0
gcc2_compiled._80206EA0
gcc2_compiled._80206EA0
guNormalize
The main problem is that the recomp_entrypoint is missing some things:
#include "recomp.h"
#include "disable_warnings.h"
void recomp_entrypoint(uint8_t* rdram, recomp_context* ctx) {
uint64_t hi = 0, lo = 0, result = 0;
unsigned int rounding_mode = DEFAULT_ROUNDING_MODE;
int c1cs = 0;
// addiu $sp, $sp, -0x20
ctx->r29 = ADD32(ctx->r29, -0X20);
// sw $ra, 0x1C($sp)
MEM_W(0X1C, ctx->r29) = ctx->r31;
// jal 0x802051D8
// sw $s0, 0x18($sp)
MEM_W(0X18, ctx->r29) = ctx->r16;
__osInitialize_common_recomp(rdram, ctx);
goto after_0;
// sw $s0, 0x18($sp)
MEM_W(0X18, ctx->r29) = ctx->r16;
after_0:
// jal 0x802015B0
// nop
osCartRomInit_recomp(rdram, ctx);
goto after_1;
// nop
after_1:
// lui $s0, 0x8021
ctx->r16 = S32(0X8021 << 16);
// addiu $s0, $s0, -0x4570
ctx->r16 = ADD32(ctx->r16, -0X4570);
// addu $a0, $s0, $zero
ctx->r4 = ADD32(ctx->r16, 0);
// lui $at, 0x8022
ctx->r1 = S32(0X8022 << 16);
// sw $v0, -0x14F4($at)
MEM_W(-0X14F4, ctx->r1) = ctx->r2;
// lui $v0, 0x8021
ctx->r2 = S32(0X8021 << 16);
// addiu $v0, $v0, -0x23C0
ctx->r2 = ADD32(ctx->r2, -0X23C0);
// sw $v0, 0x10($sp)
MEM_W(0X10, ctx->r29) = ctx->r2;
// addiu $v0, $zero, 0xA
ctx->r2 = ADD32(0, 0XA);
// addiu $a1, $zero, 0x1
ctx->r5 = ADD32(0, 0X1);
// lui $a2, 0x8020
ctx->r6 = S32(0X8020 << 16);
// addiu $a2, $a2, 0xCC
ctx->r6 = ADD32(ctx->r6, 0XCC);
// addu $a3, $zero, $zero
ctx->r7 = ADD32(0, 0);
// jal 0x802039E0
osCreateThread_recomp(rdram, ctx);
goto after_2;
;}
it's trying to jump to a undefined label after_2
, but the the disassembly shows that it was supposed to call osStartThread with the idle thread address:
80200060 <boot> (File Offset: 0x50060):
80200060: 27bdffe0 addiu sp,sp,-32
80200064: afbf001c sw ra,28(sp)
80200068: 0c081476 jal 802051d8 <__osInitialize_common> (File Offset: 0x551d8)
8020006c: afb00018 sw s0,24(sp)
80200070: 0c08056c jal 802015b0 <osCartRomInit> (File Offset: 0x515b0)
80200074: 00000000 nop
80200078: 3c108021 lui s0,0x8021
8020007c: 2610ba90 addiu s0,s0,-17776
80200080: 02002021 move a0,s0
80200084: 3c018022 lui at,0x8022
80200088: ac22eb0c sw v0,-5364(at)
8020008c: 3c028021 lui v0,0x8021
80200090: 2442dc40 addiu v0,v0,-9152
80200094: afa20010 sw v0,16(sp)
80200098: 2402000a li v0,10
8020009c: 24050001 li a1,1
802000a0: 3c068020 lui a2,0x8020
802000a4: 24c600cc addiu a2,a2,204
802000a8: 00003821 move a3,zero
802000ac: 0c080e78 jal 802039e0 <osCreateThread> (File Offset: 0x539e0)
802000b0: afa20014 sw v0,20(sp)
802000b4: 0c080ee8 jal 80203ba0 <osStartThread> (File Offset: 0x53ba0)
802000b8: 02002021 move a0,s0
802000bc: 8fbf001c lw ra,28(sp)
802000c0: 8fb00018 lw s0,24(sp)
802000c4: 03e00008 jr ra
802000c8: 27bd0020 addiu sp,sp,32
I'm not really sure if this is really a bug (it's probably my fault). Should I set the entrypoint to something else? I wasn't sure if boot should be bypassed (it felt important because some functions are not stubbed in the mm runtime)
This doesn't seem to be the entrypoint, as the entrypoint will be a handwritten asm function and is generally the value at offset 0x8 in the ROM header. Generally it's just a loop that clears the boot segment's BSS and jumps to the bootproc (the one you marked as the entrypoint). In this case I'd guess it's probably 0x80200000
.
Thanks! That makes sense. The linker in the official SDK (mild.exe right?) didn't include the actual boot in the elf file and that tripped me up. Instead of doing some elf magic and injecting the boot in the original elf, I decided to just reverse my own demo ROM and it was a pretty good learning experience. Anyways, I finally got it to run
I had to patch the msgqueue logic
diff --git a/ultramodern/mesgqueue.cpp b/ultramodern/mesgqueue.cpp
index 2821c87..6d99979 100644
--- a/ultramodern/mesgqueue.cpp
+++ b/ultramodern/mesgqueue.cpp
@@ -15,7 +15,9 @@ struct QueuedMessage {
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam) {
- external_messages.enqueue({mq, msg, jam});
+ if (mq != 0) {
+ external_messages.enqueue({mq, msg, jam});
+ }
}
bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block);
the idle thread was segfaulting due to a NULL mq being enqueued. Please let me know if you need more info
That's awesome to see, congratulations! Good catch on the message queue issue, I'm guessing the game doesn't have an event handler set up for every event message so one of them was still zero. We're working on moving the recomp runtime into a separate repo currently, so we can add this change or fix the root cause there.