反编译PS2游戏MIPS汇编:先加载立即数再移位的代码功能咨询
解析PS2 MIPS汇编中的有符号数向零取整除法模式
你遇到的这段重复出现的汇编代码,是实现有符号数除以2的幂时的向零取整操作,对应C语言标准的整数除法行为,并非abs取绝对值函数。
第一个示例(除以2)
这段汇编:
li v1,2 sra v1,s1,1 bgez s1,*+16 nop addiu v1,s1,1 sra v1,v1,1 daddu s1,v1,$0
对应的C代码逻辑为:
s1 = (s1 >= 0) ? (s1 >> 1) : ((s1 + 1) >> 1);
完全等价于C语言中的:
s1 = s1 / 2;
这么实现的原因是:MIPS的sra(算术右移)指令对负数执行的是向负无穷取整,但C语言规定有符号整数除法必须是向零取整。比如:
- 当
s1 = -3时,直接sra s1, 1会得到-2(向负无穷取整),但C语言中-3 / 2的结果是-1(向零取整),所以需要先给负数加1再右移,修正结果。 - 正数的算术右移结果和向零取整的除法结果一致,无需调整。
第二个示例(除以256)
移位8位的版本:
li v1,256 sra v1,s1,8 bgez s1,*+16 nop addiu v1,s1,255 sra v1,v1,8 daddu s1,v1,$0
对应的C代码是:
s1 = (s1 >= 0) ? (s1 >> 8) : ((s1 + 255) >> 8);
等价于:
s1 = s1 / 256;
这里的255是2^8 - 1,和第一个例子逻辑完全一致:针对负数,先加上2^n - 1(n为移位位数)再右移,把MIPS算术右移的取整规则修正为C语言要求的向零取整。
为什么不是abs函数?
abs函数的作用是取绝对值,而这段代码本质是除法取整。你最初在数组索引前遇到它,只是因为除法结果恰好被用作非负索引,但它的适用场景是所有需要对有符号整数执行除以2的幂的运算的地方——哪怕结果允许为负,只要是符合C语言整数除法规则的场景,就会生成这段汇编。
内容的提问来源于stack exchange,提问作者user16316067
相关产品推荐
相关产品推荐

