【问题标题】:Changing calling convention in gcc/g++ abi更改 gcc/g++ abi 中的调用约定
【发布时间】:2020-02-27 20:31:58
【问题描述】:

我如何强制 gcc/g++ 不使用寄存器而只使用 x86_64 中的堆栈 将参数传递给函数, 就像在 32 位版本中一样 (并且可能以这种方式获取函数结果)。 我知道它破坏了官方 ABI 以及调用方和被调用方 必须以这种方式编译才能正常工作。我不在乎是 push/pop 还是 mov/sub 方式 用来。我希望编译器应该有一个可以强制执行它的标志 但我没找到。

【问题讨论】:

  • 作为一种解决方法,如果它是您自己的代码,您可以在超过 32 个字节的结构中传递参数,因为这些参数根据 sysv abi 在堆栈上传递。

标签: gcc assembly x86-64 calling-convention abi


【解决方案1】:

看来你不能不破解 GCC 的源代码。

没有使用低效堆栈参数的标准 x86-64 调用约定。

GCC 只知道如何使用标准调用约定,在本例中为 x86-64 SysV 和 MS Windows fastcall 和 vectorcall。 (例如__attribute__((ms_abi))vectorcall)。通常没有人想要这个; MS 的调用约定对于包装器或可变参数函数已经足够友好了。即使在为 Linux、MacOS、*BSD 等编译时,您也可以将其用于某些功能(由 __attribute__ 控制),如果有帮助的话。很难想象纯堆栈参数的用例。


GCC 允许您将寄存器指定为固定(GCC 从未接触过,如-ffixed-rdi)、调用破坏或调用保留。 但是使用带有参数传递寄存器的那些只会创建错误的代码,而不是你想要的。

例如

int foo(int a, int b, int c);

void caller(int x) {
    foo(1,2,3);
    //foo(4,x,6);
}

compiled by gcc9.2 -O3 -fcall-saved-rdi

caller:
        push    rdi
        mov     edx, 3
        mov     esi, 2
        pop     rdi
        jmp     foo

它保存/恢复 RDI,但在调用 foo 之前不会在其中放入 1

并且它不会将 RDI 排除在 arg 传递序列之外并在以后碰撞其他 args。 (我在想你也许可以发明一个调用约定,其中所有传递 arg 的寄存器都是 fixedcall-saved,也许让 GCC 回退到堆栈 args。但不是。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2016-05-05
    • 2017-03-12
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多