I'm using at&t ordering I came across this a little while ago and while i understand why we want to push a stack frame when we call a new routine I don't see why it was done here: (for the example i'm looking at static code and the jmp address is just an example and arbritrary)

pushq %rbp
movq %rsp, %rbp
pop %rbp
jmp $0x10002135a
nopw(%rax, %rax)

so It turns out the next instruction after the nop is a new function entry so I surmise the nop stuff was done to achieve some sort of alignment. When I go and look at the jumped address I get a real stack frame (standard series of pushes, register saves, etc and at the end of the function standard pops and does the retq.

What did we gain by doing the push/pop sequence?

The only thing i can think of is because it does the pop before the jump is that when the other does the retq it might be returning to the rbp prior to this little bit of code. It's as if this little bit of jmp code never existed? if so why have this little bit of code here in the first place? Or perhaps at runtime the jmp address will occupy more bytes and spill into the nopw area? just guessing.

It almost looks like its a template or a macro that is doing nothing since the pop is restoring the original base pointer that was saved. Or is this more along the lines of the compiler trying to get things aligned?

We got to this point via a jmp.

up vote 3 down vote accepted

This is most likely an optimized tail call. The original code probably looked similar to this:

int f1()
{
//some code which was optimized out
  return f2();// &f2=0x10002135a
}

Since there is no code after calling f2, there is no need to perform any additional actions, so the compiler restored the original stack pointer and jumped to f2 instead of performing the call. Since the stack was restored, the address of return from f1 is at the top of the stack, so when f2 returns, it will return to the place f1 was called from. This trick saves a few instructions compared to the non-optimized "call f2 then return" sequence.

Now, the compiler could also just remove all stack manipulation completely and leave just the jump, but possibly some other considerations prevented that (e.g. frame pointer omission optimization was turned off which made it insert ebp initialization in all functions, even those not using it).

  • I don't actually have the source code but this makes the most sense, the code I'm look at seems to be littered with this construct and your answer seems to make a lot of sense. I took a look at the wiki reference and indeed it does describe the idea of using the current base pointer as the return point when we eventually return somewhere, so it does make sense. – Div Apr 28 '17 at 21:14

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.