x86_64:强制gcc在堆栈上传递参数

ilp*_*lle 9 c gcc x86-64 parameter-passing calling-convention

我正在为x86-64系统开发setjmp/ longjmp自定义实现,它保存了CPU的整个上下文(即所有xmm,fpu堆栈等;不仅是callee-save寄存器).这是直接在汇编中编写的.

代码在最小的示例中工作正常(直接从汇编源调用它时).由于参数传递给自制程序setjmp/ longjmp函数的方式,在使用C代码时会出现问题.实际上,x64_64系统的SysV ABI规定参数应该通过寄存器传递(如果它们最多为6).我的职能签名是:

long long set_jmp(exec_context_t *env);
__attribute__ ((__noreturn__)) void long_jmp(exec_context_t *env, long long val);

当然,这不能正常工作.事实上,当我进入set_jmp,rdirsi已经被破坏,以保持指针envval.这同样适用long_jmprdi.

有没有办法强制GCC,例如依靠某些属性,强制通过堆栈传递参数?这将比包装set_jmplong_jmp使用某些定义更加优雅,这些定义手动将堆栈寄存器压入堆栈,以便稍后检索它们.

小智 1

您可以通过使用内联汇编调用函数来避免覆盖寄存器。

#include <stdio.h>

static void foo(void)
{
        int i;
        asm volatile ("mov 16(%%rbp), %0" : "=g" (i));
        printf("%d\n", i);
}

#define foo(x) ({ int _i = (x); \
        asm ("push %0\ncall %P1\nadd $8, %%rsp\n" : : "g"(_i), "i"(foo)); })

int main(int argc, char *argv[])
{
        foo(argc-1);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

这里,一个整数被压入堆栈,并调用函数 foo。foo 使其值在其局部变量 i 中可用。返回后,堆栈指针调整回原来的值。