perfect_dark/src/lib/getra.s

46 lines
1.2 KiB
ArmAsm

#include "macros.inc"
.set noat
.set noreorder
/**
* Get the return address ($ra) that the caller would return to.
*
* For example, a C function could use:
*
* osSyncPrintf("Called from %u\n", getReturnAddress());
*
* It follows the current $ra to get to the function that called
* getReturnAddress, then steps backwards through that function's bytecode until
* it finds either `addiu $sp` or `sw $ra, 0xnn($sp)`.
*
* If it finds `addiu $sp` first then it's reached the top of the function and
* $ra wasn't saved to the stack. In this case something is massively wrong and
* the function returns -1.
*
* If it finds `sw $ra, 0xnn($sp)` first then it reads the stack offset out of
* the instruction, then reads the value out of the stack using that offset.
*/
glabel getReturnAddress
or $a0, $ra, $zero
addiu $v0, $zero, -1
.loop:
lw $t0, 0($a0)
addiu $t2, $zero, 0x27bd
srl $t1, $t0, 16
beq $t1, $t2, .foundtop
nop
dli $t2, 0xafbf
beql $t1, $t2, .foundstore
sll $t2, $t0, 16
j .loop
addiu $a0, $a0, -4
sll $t2, $t0, 16
.foundstore:
sra $t2, $t2, 16
add $t2, $t2, $sp
lw $v0, 0($t2)
.foundtop:
jr $ra
nop