旧的gcc或egcs表示,一些编译器对单个文件中的静态函数应用了ABI中断优化,例如传递参数或使用任意寄存器返回结果.
考虑一些源代码,如:
// Original foobar.c
// This example targets MIPS o32 ABI.
// Shared subroutine
// Compiler decided to use $16, $17 to pass a0 and a1 to minimize stack usage and move between registers.
static void __bar(int a0, int a1) {
// Something very complicated
}
// ...
void foo(int a0, int a1) {
// ...
/*
This call was compiled to something like:
ori $16, $0, 0x1
jal __bar
ori $17, $0, 0x1
*/
__bar(1, 1);
// ...
}
// ...
Suppose someone want to restore / reimplement foobar.c from the compiled assembly without access to the original source.
One would probably like to decompile / rewrite some part first, says start from foo() or other standard functions. However, in order to test the correctness of the implementation, one must deal with calls to non-standard ABI routines.
A trivial way is to workaround with global register variables provided by gcc / clang:
// Restoration of foobar.c
// void __bar(int asm("s0"), int asm("s1"))
// External function in assembly, says foobar.s, which is from compiled original foobar.c.
void __bar();
volatile register int s0 asm ("s0"); // $16 = s0
volatile register int s1 asm ("s1"); // $17 = s1
// ...
void foo(int a0, int a1) {
// ...
// __bar(1, 1);
s0 = 1; s1 = 1;
__bar();
// ...
}
// ...
问题是:
- gcc/clang是否支持为某些特定函数自定义调用约定?
- 有没有办法更优雅地处理非标准ABI呼叫?