5

我正在查看一个非常可疑的 C 应用程序的反汇编 MIPS 代码

80019B90                 jal     loc_80032EB4

loc_80032EB4 位于另一个函数主体的中间,我特别检查了运行时没有在此地址加载其他代码,并且以这种方式调用该函数(在开头传递一些代码)可能很有用。但是在 C 中怎么可能呢?这不是 goto,因为您无法转到另一个函数,并且正常的函数调用将始终“jal”到开头。这可以是一些手动优化吗?

更新:

两个函数的简化布局,被调用者:

sub_80032E88 (lz77_decode)
... save registers ...
80032E90                 addiu   $sp, -8
... allocate memory for decompressed data ...
80032EB0                 move    DECOMPRESSED_DATA_POINTER_A1, $v0
loc_80032EB4:
80032EB4                 lw      $t7, 0(PACKED_DATA_POINTER_A0)
... actual data decompression ...
80032F4C                 jr      $ra

呼叫者:

80019ACC                 addiu   $sp, -0x30
... some not related code ...
80019B88                 lw      $a1, off_80018084   // A predefined buffer is used instead of allocating it for decompressed data
80019B90                 jal     loc_80032EB4
80019B94                 move    $a0, $s0
... some other code and function epilogue ...

更新 2: 我检查了这是否可能是使用 setjmp/longjmp 的情况,但在我的测试中,我总是可以在反汇编代码中看到对 setjmp 和 longjmp 函数的调用,而不是直接跳转。

更新 3: 我尝试使用 GCC 特定的功能来获取标签指针并将这个指针转换为函数,结果接近我想要的但反汇编代码仍然不同,而不是使用带有 exaxct 地址的 jal 它计算它的运行时,也许由于范围问题,我无法强制编译器将此值视为常量。

4

1 回答 1

2

由于是来自游戏系统的数据解压功能,因此该功能很可能是多入口的手工优化组装。多个入口点不常用,因此很难找到公开可用的示例,但这里有一个来自 gcc 邮件列表的旧线程,它暗示了这种技术的可能用途。

要点是,如果您有两个函数,其中一个函数F1的代码是另一个函数F2的代码的子集,那么 F2 的代码可以落入F1的代码中。在您的情况下,F2为解压缩的数据分配内存,F1假设内存分配已经完成。我很确定 GCC 2.9x 不能生成这样的代码。

不可能直接将此构造从汇编程序转换为标准 C,因为您不能goto在 C 中使用另一个函数,但这在汇编程序代码中是完全合法的。gcc 邮件列表线程建议了一些解决方法来在 C 中表达相同的想法。

如果您查看用于解压缩的反汇编代码,它可能具有与编译器生成的代码不同的样式。甚至可能会使用一些操作码,例如查找编译器无法从 C 生成的第一个设置位。

于 2012-09-03T19:29:39.850 回答