MIPS堆栈帧(和“addiu”指令混淆)

时间:2011-07-26 19:52:03

标签: assembly mips disassembly opcode

我是MIPS的新手,正在尝试理解函数的反汇编 (编辑:它动态链接到/lib/ld-uClib.so.0并使用一些常用的libc函数,所以我假设它是使用uClibc工具链用C编写的,因此应该有调用过程和堆栈框架等)。

在功能开始时

00400824 <practice_crackme>:
  400824:   3c1c0fc0    lui gp,0xfc0        ; ???
  400828:   279c673c    addiu   gp,gp,26428 ; ???
  40082c:   0399e021    addu    gp,gp,t9    ; ???

  400830:   27bd8020    addiu   sp,sp,-32736  ; sp -= 0x7fe0 (-32736=0xffff8020)
  400834:   34038670    li  v1,0x8670
  400838:   afbf7fdc    sw  ra,32732(sp)
  40083c:   afbe7fd8    sw  s8,32728(sp)
  400840:   afb77fd4    sw  s7,32724(sp)
  400844:   afb67fd0    sw  s6,32720(sp)
  400848:   afb57fcc    sw  s5,32716(sp)
  40084c:   afb47fc8    sw  s4,32712(sp)
  400850:   afb37fc4    sw  s3,32708(sp)
  400854:   afb27fc0    sw  s2,32704(sp)
  400858:   afb17fbc    sw  s1,32700(sp)
  40085c:   afb07fb8    sw  s0,32696(sp)
  400860:   03a3e823    subu    sp,sp,v1  ; sp-=0x8670 (local space=0x8670 bytes)
  400864:   afbc0018    sw  gp,24(sp)

然后在函数结束时:

  4009e0:   8fbc0018    lw  gp,24(sp)
  4009e4:   34088670    li  t0,0x8670
  4009e8:   03a8e821    addu    sp,sp,t0    ; sp+=0x8670; //remove local space
  4009ec:   8fbf7fdc    lw  ra,32732(sp)
  4009f0:   8fbe7fd8    lw  s8,32728(sp)
  4009f4:   8fb77fd4    lw  s7,32724(sp)
  4009f8:   8fb67fd0    lw  s6,32720(sp)
  4009fc:   8fb57fcc    lw  s5,32716(sp)
  400a00:   8fb47fc8    lw  s4,32712(sp)
  400a04:   8fb37fc4    lw  s3,32708(sp)
  400a08:   8fb27fc0    lw  s2,32704(sp)
  400a0c:   8fb17fbc    lw  s1,32700(sp)
  400a10:   8fb07fb8    lw  s0,32696(sp)
  400a14:   03e00008    jr  ra
  400a18:   27bd7fe0    addiu   sp,sp,32736 ; sp += 0x7fe0

问题#1:
尽管在互联网上搜索了一段时间,我仍然不太明白如何在堆栈框架中使用gp。

特别是,我读过的文件说调用过程标准是a0-a3用作函数输入,v0-v3用作函数输出,s0-s8用于调用,并且t0-t9不会在任何调用中保留。所以s0-s8的推动和弹出是有道理的。 但是为什么世界上根据t9中的值设置gp!?

问题#2:
我不明白为什么它会将堆栈指针移动两次。它似乎保留了两次当地空间。

最重要的是,addiu指令正在被否定数字反汇编,这个数字没有意义,因为'u'表示无符号,但是代码没有意义,除非我实际上认为它是一个负数。我在en.wikipedia.org/wiki/MIPS_architecture上查看了操作码。它确实是“addiu”而不是“addi”。我在这里很困惑。

1 个答案:

答案 0 :(得分:2)

前三条说明用于支持位置无关代码。有关MIPS上PIC的优秀解释,请参阅this linux-mips paget9保存函数的地址,每次加载支持PIC的库时都会更改该函数的地址,并且该值将添加到gp中已有的常量中。与x86类似:

call __i686.get_pc_thunk.bx
add $0x1b88, %ebx

其中__i686.get_pc_thunk.bx使用下一条指令的地址加载%ebx,后续添加将%ebx转换为将用于访问全局符号的参考点。

<强> ADDIU: MIPS上有符号和无符号加法之间的唯一区别是有符号加法会引发溢出异常,因此使用ADDIU来避免这种情况。

多次堆栈调整:这些可能与MIPS使用16位立即数这一事实有关,因此无法始终在一个ADDIU中调整堆栈。