0

If I setup the stack like this

push rbp;
mov rbp, rsp;
sub rsp, 64;

do I need to

mov rsp, rbp;
pop rbp;
ret 64;

or only

mov rsp, rbp;
pop rbp;
ret;

?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
alexandernst
  • 14,352
  • 22
  • 97
  • 197
  • The first one (with `ret 64`) is deallocating stack space set up by the caller. That's how `stdcall` gets rid of arguments on the stack. But here it would just be destroying something. – harold Dec 21 '13 at 14:29
  • @harold How can I reserve some space without destroying arguments on the stack? – alexandernst Dec 21 '13 at 14:30
  • @harold Or maybe a better question is: Can I use [rbp - from-8-to-64] without worrying? – alexandernst Dec 21 '13 at 19:24
  • Generally yes, unless you're writing something bigger than 8 bytes of course – harold Dec 21 '13 at 19:30
  • Isn't that 64 bytes of reserved stack? Or its 64 bits? – alexandernst Dec 21 '13 at 19:32
  • 64 bytes, and you can use all 64 of them, the problem with something larger than 8 bytes is that if you wrote it at, say `rbp - 8`, it would extend past the area you allocated. Similarly, for things that are less wide, there are slightly more places you could use, for example you can use `rbp - 64` through `rbp - 1` as places to store bytes. – harold Dec 21 '13 at 19:47
  • @harold So when I write ```mov [rbp - 8], rax;```, I'm moving the value of RAX into my first 8-bytes stack variable. That instruction isn't taking any more space than 8 bytes on the stack, right? – alexandernst Dec 22 '13 at 02:41
  • Right, that's perfectly fine – harold Dec 22 '13 at 07:03

2 Answers2

2

It is enough to do:

mov rsp, rbp;
pop rbp;
ret;

As it will restore the old value of rsp ( regardless of how much was decreased in the sub instruction ).

MByD
  • 135,866
  • 28
  • 264
  • 277
2

The second one, if you are going to use the C calling convention (caller removes the arguments).

mov rsp, rbp;
pop rbp;
ret;

If you would use the first epilog, this is what happens with your stack:

push rbp;     ;RSP = RSP - 8  (1)  |
mov rbp, rsp; ;Keep RSP (2)        | Your prologue. Nothing wrong here.
sub rsp, 64;  ;RSP = RSP - 64      |
...
...
mov rsp, rbp; ;Retrieve RSP from (2)
pop rbp;      ;RSP = RSP + 8. Now it's at the same address as before (1)
ret 64;       ;Return, but after that, add 64 to RSP

So when this function returns to its caller, the stack pointer is 64 bytes ahead of its position just before the CALL to this function. This is fine, if your function is defined with the STD calling convention (callee removes the arguments). I think that this is not what you want, as you seem to think that the ret 64 is for restoring the 64 bytes the stack allocated for automatic variables.

mcleod_ideafix
  • 11,128
  • 2
  • 24
  • 32
  • In fact, this code will replace a syscall in the Linux kernel. What are the assumptions there? Who must care about the parameters? – alexandernst Dec 21 '13 at 14:34
  • You may want to check the chosen answer to this question: http://stackoverflow.com/questions/20520778/why-doesnt-linux-follow-unix-syscall-conventions – mcleod_ideafix Dec 21 '13 at 15:11