Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

x86_64: forcing gcc to pass arguments on the stack

I'm working on a setjmp/longjmp custom implementation for x86-64 systems which saves the whole context of the CPU (namely, all xmm, fpu stack, etc; not only callee-save registers). This is written directly in assembly.

The code works fine in minimal examples (when calling it directly from an assembly source). The problem arises when using it with C code, due to the way parameters are passed to the homebrew setjmp/longjmp functions. In fact, SysV ABI for x64_64 systems dictates that arguments should be passed via registers (if they are at most 6). The signature of my functions are:

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

Of course, this cannot work as is. In fact, when I enter set_jmp, rdi and rsi have already been clobbered to keep a pointer to env and val. The same applies to long_jmp with respect to rdi.

Is there any way to force GCC, e.g. by relying on some attribute, to force argument passing via stack? This would be much more elegant than wrapping set_jmp and long_jmp with some define which manually pushes the clobbered registers on stack, so as to retrieve them later.

like image 655
ilpelle Avatar asked Dec 11 '15 15:12

ilpelle


1 Answers

You can avoid overwriting the registers by calling the function using inline assembly.

#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;
}

Here, an integer is pushed on the stack, and the function foo is called. foo makes the value available in its local variable i. After returning, the stack pointer is adjusted back to its original value.

like image 194
dan4thewin Avatar answered Sep 17 '22 05:09

dan4thewin