MIPS32函数调用实例汇编分析

我们首先来看函数的调用过程,下面的代码属于调用者。

la      $t9, cgibin_parse_request
lui     $a0, 0x41  # 'A'
lui     $a2, 2
li      $a0, sub_409A6C
jalr    $t9 ; cgibin_parse_request
move    $a1, $zero

lui用于向一个寄存器的高位存储数,且其低位会被清0,因此lui $a0, 0x41li $a0, sub_409A6C共同完成了$a0参数的传递。被调用函数cgibin_parse_request被保存在了寄存器$t9中,然后通过jalr $t9完成跳转。由于流水线效应,$a1参数传递指令的取指在jalr指令取指之后。
我们再来看被调用函数的开头部分

lui     $gp, 0x43  # 'C'
addiu   $sp, -0x50
li      $gp, 0x4346D0
sw      $ra, 0x30+var_s1C($sp)
sw      $s6, 0x30+var_s18($sp)
sw      $s5, 0x30+var_s14($sp)
sw      $s4, 0x30+var_s10($sp)
sw      $s3, 0x30+var_sC($sp)
sw      $s2, 0x30+var_s8($sp)
sw      $s1, 0x30+var_s4($sp)
sw      $s0, 0x30+var_s0($sp)
sw      $gp, 0x30+var_20($sp)

首当其冲的就是$gp全局寄存器,这个寄存器是为了简化数据的访问的,访问一段区域内的数据,只需要通过该寄存器做小范围的加减即可。这里通过luili$gp赋值,同样因为流水线的原因,两条指令被错开了。
紧接着延伸了栈顶,$ra保存在离$sp最远的地方$sp+0x4C$gp保存在离$sp最近的地方$sp+0x10$sp+0x10$sp+0x30被空了出来。
接下来是被调用函数的结束部分

lw      $ra, 0x30+var_s1C($sp)
move    $v0, $s0
lw      $s6, 0x30+var_s18($sp)
lw      $s5, 0x30+var_s14($sp)
lw      $s4, 0x30+var_s10($sp)
lw      $s3, 0x30+var_sC($sp)
lw      $s2, 0x30+var_s8($sp)
lw      $s1, 0x30+var_s4($sp)
lw      $s0, 0x30+var_s0($sp)
jr      $ra
addiu   $sp, 0x50

可以观察到$s0~$s6以及$ra都成功的重原位恢复,跳转到返回地址$ra,并将$sp回缩。还剩一个$gp,在函数返回之后可以找到lw $gp, 0x4C0+var_4B0($sp),即将$sp+0x10恢复给$gp,可能会有疑惑返回之后$sp不是已经+0x50了吗,这里应该还是因为流水线吧,执行恢复$gp指令时,$sp还未加上。
本来还想找一个叶子函数的,结果没有找到,挖个坑

posted @ 2023-01-08 01:31  benoqtr  阅读(108)  评论(0编辑  收藏  举报