2011-07-26 104 views
1

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

在它

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”。我在这里很困惑。

回答

2

前三条指令用于支持位置独立代码。请参阅this linux-mips page以获取关于MIPS PIC的极好解释。 t9保存函数的地址,每当您加载一个支持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

+0

因此,ADDIU和ADDI符号都会延长常数吗?所以“addiu a0,a0,0x8020”真的很像说a0 = a0 + 0xFFFF8020?这不符合维基百科,它说addiu的“C是零扩展”。所以我想确保我明白(也许有人知识渊博的人应该改变维基百科页面)。 – CuriousJackie

+0

是的,ADDIU被定义为'GPR [rt] < - GPR [rs] + sign_extend(immed16)'。 – ninjalj

+0

谢谢你谢谢你!由于维基是错误的,是否有一个清晰/简洁(正确)的MIPS操作码指南供您参考? – CuriousJackie