1

My system : Ubuntu 22.04.3 running on x86_64. GCC version 11.4.0

I'm asking this because it seems like there are two different representations of the return address as far as the frame it is within ( caller or callee ) is concerned.

This is what "Computer Systems, A Programmer's Perspective" shows :

enter image description here

This is what "System V Application Binary Interface AMD64 Architecture Processor Supplement" shows :

enter image description here

As you can see in the System V ABI document representation we have the return address inside the current frame ( called/callee function ) but in the book representation it is in the caller frame ( caller function ).

Here are my questions :

  1. What representations is right ?

  2. Is the collocation of the return address inside a particular frame ( caller or callee ) just an arbitrary silly matter and not specified by any ABI ?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
alessio solari
  • 313
  • 1
  • 6
  • 2
    Both diagrams show the current frame pointer pointing to the previous frame pointer and the return address in the next “address sized” space above that (four bytes in the 32-bit version, eight bytes in the 64-bit version). So there is no disagreement about where the frame pointer points and where the return address is stored. Those are the facts that matter, since they affect how the machine (the computer) will behave. Whether you call the space where the return address is part of one frame or another is just a matter of names humans use, not facts affecting the machine… – Eric Postpischil Aug 28 '23 at 12:43
  • 2
    … So what the “stack frame” is might not be clearly defined. To the extent it is, the ABI specification is more authoritative than a textbook. – Eric Postpischil Aug 28 '23 at 12:44
  • 2
    I'd say both are correct. You can see that, word size apart, the layouts are identical so it doesn't matter if the return address is formally part of the current or previous frame. Personally, I prefer the SYS V definition because a caller may not use a frame at all yet the callee will have a return address nonetheless. – Margaret Bloom Aug 28 '23 at 12:45
  • 1
    Does the book specify if the diagram is related to a specific ABI? There are architectures that don't put the return address on the stack. For example ARM uses a link register for the latest return address, and a function that wants to call other functions is responsible for saving and restoring this register. – Bodo Aug 28 '23 at 13:02
  • @EricPostpischil https://stackoverflow.com/questions/76993711/does-the-red-zone-still-exist-even-if-we-use-the-mno-red-zone-flag-in-gcc – alessio solari Aug 28 '23 at 14:31
  • @MargaretBloom https://stackoverflow.com/questions/76993711/does-the-red-zone-still-exist-even-if-we-use-the-mno-red-zone-flag-in-gcc – alessio solari Aug 28 '23 at 14:31

1 Answers1

3

The return address is pushed by the caller but popped by the callee upon function completion & return to caller, so that return address on the stack only exists for the duration of the callee's activation.

Because when the callee returns that return address is removed, and the caller doesn't see or use it, I would argue that it is not part of the caller's stack frame.  Therefore I would have to consider it a part of the callee's frame

As others say though, this is just semantics.  What matters is the operations (e.g. who pops) and the values (where addresses point).

However, in general, to answer the question of which frame something belongs to, I would ask: how long does that storage last and who pops it off the stack (i.e. who is really responsible for that storage)?

When a callee returns, what remains on the stack belongs to callers.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • 1
    I agree. It's semantics, but I don't think you can argue that something that is removed by the callee belongs to the caller's stack frame. – 500 - Internal Server Error Aug 28 '23 at 20:33
  • 1
    @500-InternalServerError : I'd agree. Also stack args: the callee "owns" them, i.e. can overwrite them with different values. (GCC often doesn't do this, but will for tail-calls.) You could say the caller hands the stack args off to the callee at the point of the `call` instruction. In a caller-pops convention, the callee hands back the space, but not the values. (That's my initial opinion on the semantics, anyway.) The return address is simpler; it doesn't exist on the stack until the instruction that jumps away from the caller, so no caller code can ever reference it. – Peter Cordes Aug 28 '23 at 20:39
  • Even in a calling convention with a red zone like x86-64 System V, the caller can't assume that `[rsp-8]` upon return is the return address they pushed. An inefficient function could have popped it into a register, stored something else there, and then used `jmp reg` to return. The ABI doesn't IIRC forbid that, just like callees own stack args. So there's never any moment when the caller has any ownership of that stack slot while it's ABI-guaranteed to be holding a return address. – Peter Cordes Aug 28 '23 at 20:41