46 lines
1.2 KiB
ArmAsm
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
|