指定函数参数的寄存器?

发布于 2025-02-05 04:12:30 字数 1568 浏览 3 评论 0原文

旧的GCC或EGC说,一些编译器对单个文件中的静态功能应用ABIB-BROKING优化,例如传递参数或使用任意寄存器返回结果。

考虑一些源代码:

// 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();

    // ...
}

// ...

问题是:

  1. GCC / Clang是否支持某些特定功能的自定义呼叫约定?
  2. 有什么方法可以更优雅地处理非标准的ABI电话吗?

Some compilers, says old gcc or egcs, apply ABI-breaking optimization for static functions within single file, like passing arguments or returning results with arbitrary registers.

Consider some source code like:

// 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();

    // ...
}

// ...

The question is:

  1. Does gcc / clang supports customize calling convention for some specific functions?
  2. Are there any way to deal with non-standard ABI calls more elegantly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

等数载,海棠开 2025-02-12 04:12:30
  1. GCC / Clang是否支持某些特定功能的自定义呼叫约定?< / li>

您能做的最好的方法是选择参加特定的呼叫惯例之一,例如,其中之一用于x86 。如果静态所讨论的功能不符合其中的任何一个,那么您就会卡住。

  1. 有什么方法可以更优雅地处理非标准的ABI呼叫?

没有什么真正优雅的。如果不适用受支持的呼叫约定,则您会陷入以下:

  1. 反向&amp;重建整个过程(以便它可以正常编译而不依赖原始二进制文件),或者至少足够多,您可以完全替换ABI符合功能及其所有依赖项,或者
  2. 是从组装中呼吁的,明确地通过参数通过编译功能的非标准呼叫约定。

#2是最优雅的解决方案的基础,基本上是在汇编中编写包装器功能,该功能接收参数并根据ABI返回值,否则除了重新安排它们以传递到非标准函数外,其他什么也没做包装(如果不根据正常规则返回,则可能会修复返回值)。您一次编写包装器,现在可以用C编写代码的其余部分,称其为粘附在ABI上的包装器功能,并幸福地不知道封面下的怪异性。

同样,如果您试图用另一个替换现有的非标准功能,则在汇编中编写不合格的包装器,然后将您的替换功能写在普通C中,并将包装器称为称呼,然后在包装器中交换。在您被黑的原始二进制和新代码的混合物中。

  1. Does gcc / clang supports customize calling convention for some specific functions?

The best you can do is opt in to one of the specific supported calling conventions, e.g. one of these for x86. If the static function in question does not conform to any of them, then you're stuck.

  1. Are there any way to deal with non-standard ABI calls more elegantly?

Nothing truly elegant. If none of the supported calling conventions apply, you're stuck with either:

  1. Reversing & rebuilding the whole thing (so it can compile as normal without relying on original binaries), or at least enough of it that you're replacing ABI conforming functions and all their dependencies completely, or
  2. Calling it from assembly, explicitly passing the arguments per the non-standard calling conventions of the compiled function.

#2 is the basis for the most elegant solution, which is basically to write a wrapper function in assembly that receives the arguments and returns the values according to the ABI, and otherwise does nothing but rearrange them to pass to the non-standard function it wraps (and possibly fix up the return value if it's not returning according to normal rules). You write the wrapper(s) once, and now the rest of your code can be written in C, calling the wrapper functions which adhere to the ABI and being blissfully unaware of the weirdness under the covers.

Similarly, if you're trying to replace the existing non-standard function with another, you'd write the non-conforming wrapper in assembly, then write your replacement function in plain C and have the wrapper call it, and swap in your wrapper in your hacked together mix of the original binary and the new code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文