2

The first 6 arguments go in registers rdi, rsi, rdx, rcx, r8, r9 respectively. My understanding is that if there's a seventh argument or more, they should be pushed onto the stack. The following code works:

mov rdi, format_string
mov rsi, 1
mov rdx, 2
mov rcx, 3
mov r8, 4
mov r9, 5
call printf

But when I add a seventh argument:

mov rdi, format_string
mov rsi, 1
mov rdx, 2
mov rcx, 3
mov r8, 4
mov r9, 5
push 6
call printf
add rsp, 8

The code generates a segmentation fault. What am I doing wrong?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Mayer Goldberg
  • 1,378
  • 11
  • 23
  • It's been forever since I've used assembly, but is there a value in 6 you are trying to push? – Benjamin Commet May 26 '17 at 17:32
  • 4
    Likeliest of problems is that you don't zero out _RAX_ for the call to `printf` . RAX needs setting for variadic functions (like `printf` that take an unspecified # of args). Per the 64-bit Linux calling convention RAX needs to contain the # of vector registers used to pass arguments.Your case the number is zero so you need to set _RAX_ to zero (you can do that with `xor eax, eax`. One other requirement is that the stack be 16 (or 32-bytes) aligned at the point a function call is done. This includes _C_ library functions. You may not see problems with alignment unless you start passing floats. – Michael Petch May 26 '17 at 17:35
  • 2
    Technically speaking the number of vector registers is in _AL_ (the lower 8 bts of _RAX_). If you want to read the latest Linux System V ABI you can find a copy here: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI . The 64-bit one is at the link in the first list item. – Michael Petch May 26 '17 at 17:52
  • What is the content of `format_string`? – fuz May 26 '17 at 18:45
  • When first learning to call C from assembly I found it useful to write what it was I wanted to do in C, then [compile it to output asm](https://stackoverflow.com/q/137038/17300). Then I could look at how _that_ used the registers and handled the stack. – Stephen P May 26 '17 at 20:08
  • I wasn't aware of how rax is used in this context. I'll study the ABI document for linux. Thanks! – Mayer Goldberg May 26 '17 at 20:30
  • Did you find setting _RAX_ (in thiscase to 0) solved your problem? (Just curious) – Michael Petch May 26 '17 at 21:33
  • It solved it completely. I was using a document that was clearly derived from the ABI, but somehow didn't manage the use of RAX to specify how many vector registers are passed to a variadic function, so I was just unaware. – Mayer Goldberg May 27 '17 at 19:54
  • 2
    Now that you've solved the problem, please feel free to submit an answer to your own question, explaining what the problem was and how you fixed it. You might also want to include a link to the ABI that Michael referred you to. It is encouraged to answer your own question (you get a badge for it), although you do have to wait a bit before the system will let you accept (checkmark) your own answer. – Cody Gray - on strike May 28 '17 at 07:35
  • @MayerGoldberg Please also note what @MichaelPetch said: You need to call `printf` with the proper stack alignment, so you probably need to push 16 bytes (not just 8). glibc compiled with newer GCC versions will enforcement stack alignment more aggressively even if floating point arguments are not used. – Florian Weimer Jul 17 '17 at 11:31

0 Answers0