PS2游戏逆向:如何编写C代码让汇编生成dsll32、dsra32指令
如何用C代码复现PS2调试版游戏中的重复移位汇编指令?
我正在逆向一款PS2调试版游戏,已完成部分反编译工作,能使用原编译器Metrowerks CodeWarrior编译出ELF文件。对比原ELF与自行编译的ELF反汇编结果时,发现原汇编中存在频繁使用dsll32和dsra32移位指令的重复模式,但我的编译版本无法复现。
示例1:取反操作的汇编差异
原汇编代码:
dsll32 v1,s1,16 dsra32 v1,v1,16 subu v1,$0,v1 dsll32 v1,v1,16 dsra32 v1,v1,16 dsll32 s1,v1,16 dsra32 s1,s1,16
对应的反编译C代码:
d1 = -d1;
自行编译后的汇编:
subu v1,$0,s1 dsll32 s1,v1,16 dsra32 s1,s1,16
尝试过类型转换、改为d1 = 0 - d1、64位转换等方法,均无法复现原汇编中的移位指令组。
示例2:加法操作的汇编差异
原汇编代码:
lh v0,80(sp) dsll32 v1,v0,16 dsra32 v1,v1,16 lw v0,128(sp) lb v0,0(v0) dsll32 v0,v0,24 dsra32 v0,v0,24 dsll32 v0,v0,16 dsra32 v0,v0,16 addu v0,v1,v0 dsll32 v0,v0,16 dsra32 v0,v0,16 dsll32 s3,v0,16 dsra32 s3,s3,16
对应的反编译C代码:
x = xposi + sprdat->xoff;
自行编译后的汇编:
lh v1,80(sp) lw v0,128(sp) lb v0,0(v0) dsll32 v0,v0,24 dsra32 v0,v0,24 addu v0,v1,v0 dsll32 s3,v0,16 dsra32 s3,s3,16
可行的复现方法
这些dsll32+dsra32组合本质是在MIPS64架构下强制将32位值符号扩展为64位后再截断回32位,调试模式下的编译器通常会生成这类冗余指令,用于保留类型信息或中间计算步骤。
要复现这种行为,可以尝试以下写法:
- 显式嵌套类型转换,模拟编译器调试模式的冗余操作:
// 对应示例1的写法 d1 = (int32_t)(-(int64_t)d1); // 拆分步骤更贴近原汇编的中间操作 int64_t temp = (int64_t)d1; temp = -temp; d1 = (int32_t)temp; - 对每个操作数和结果都进行64位转32位的强制转换:
// 对应示例2的写法 int32_t xposi_ext = (int32_t)(int64_t)xposi; int32_t xoff_ext = (int32_t)(int64_t)((int8_t)sprdat->xoff); int32_t sum_ext = (int32_t)(int64_t)(xposi_ext + xoff_ext); x = (int32_t)(int64_t)sum_ext; - 检查Metrowerks CodeWarrior的编译选项,确保开启禁止优化、保留中间变量等调试模式专属选项,这类选项会让编译器放弃指令精简,生成与原调试版一致的冗余代码。
内容的提问来源于stack exchange,提问作者user16316067
相关产品推荐
相关产品推荐

