You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:24:52