0

I tried to use inline assembly to call the function with three arguments, but it fails with Segmentation fault.

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <assert.h>
#include <stdlib.h>

void callee_test3(char* dest, char* src, size_t srclen)
{
    printf("%s %s %li\n", dest, src, srclen);
};

int main()
{
    char* dest = "test";
    char* src = "src";
    size_t srclen = 4;

    asm(
        "movq %[arg1], %%rdi\n\t"
        "movq %[arg2], %%rsi\n\t"
        "movq %[arg3], %%rdx\n\t"
        "call *%[callee]"
        :
        :[arg1]"r"((u_int64_t)(dest)),
         [arg2]"r"((u_int64_t)(src)),
         [arg3]"r"((u_int64_t)(srclen)),
         [callee]"r"(callee_test3)
        :"cc"
    );

    return 0;
}

I can call a function with two arguments, but when I added into three arguments, it just failed. Tried to use gdb to trace where the code break it shows :

Breakpoint 1, main () at test.c:24
24      char* dest = "test";
(gdb) next
25      char* src = "src";
(gdb) 
26      size_t srclen = 4;
(gdb) 
34          :[arg1]"r"((u_int64_t)(dest)),
(gdb) 
35           [arg2]"r"((u_int64_t)(src)),
(gdb) 
28      asm(
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
0x0000555555554872 in ?? ()

For some reasons, the third argument didn't store into the register. My assumption is I'm calling the wrong register to store the third argument. But I couldn't find the resource about that.

Kyle
  • 154
  • 3
  • 9
  • 4
    You didn't declare any clobbers so this is totally unsafe. Look at the compiler-generated asm (`disas` or `layout reg` in GDB); I wouldn't be surprised if one of the inputs picked RSI or RDX which you're overwriting without telling the compiler about it. Also the red-zone below RSP, which `call` itself clobbers. It's very inconvenient to make function calls from inside inline asm safely, seriously just don't do that. – Peter Cordes May 19 '20 at 18:51
  • 4
    Besides what @PeterCordes said: in addition to the registers you used explicitly, called functions are not required to preserve RAX, RCX, R8-R11, or any of the floating-point registers, so you'd need all of those on your clobber list too. Moreover, functions have to be called with the stack aligned to 16 bytes, and the compiler won't guarantee whether or not this has been done at the start of the asm block, so you'll have to do it yourself and then clean it up afterwards. As Peter says, it seems unlikely to be worth the trouble. – Nate Eldredge May 19 '20 at 19:22
  • 1
    Avoid inline assembly for this. Add an Assembly file to your project and assemble it to an object file and link it to your program. Some of the problems being described are mentioned in this SO answer: https://stackoverflow.com/a/37503773/3857942 – Michael Petch May 19 '20 at 19:57
  • 1
    Why are you using assembly at all to call a function with a normal calling convention? Is it just to learn assembly? If so, then do it in a .S file. Inline assembly is the worst way to learn assembly. – Joseph Sible-Reinstate Monica May 19 '20 at 20:34

0 Answers0