1

When a call happens, it is my understanding that the address of the caller is pushed onto the stack, and when a ret is executed, it jumps to the popped value from the stack.

What happens if I push a value and forget to pop it? Wouldn't ret simply pop what it expects to be the return address from the stack and be sorely mistaken by whatever value was actually at the top of the stack? E.g:

Function:
    mov ax, "A"
    push ax
    ret

call Function

Additionally, I wonder the same thing about pusha and popa. If I push a value after a pusha does the popa now use that value when it pops however many registers it uses, leaving the original first register on the stack and restoring every register to the register + 1's value?

Jester
  • 56,577
  • 4
  • 81
  • 125
jellies
  • 639
  • 1
  • 5
  • 17
  • 2
    It's exactly as you say. Note you can try such things in a debugger. – Jester Mar 25 '20 at 19:40
  • 3
    You're exactly right. FYI, that's why calling conventions typically use both a "stack pointer" (e.g. "esp") *AND* a [frame pointer](https://softwareengineering.stackexchange.com/questions/194339/frame-pointer-explanation) (e.g. "ebp"). You can read more here: [What is the purpose of the EBP frame pointer register?](https://stackoverflow.com/questions/579262/what-is-the-purpose-of-the-ebp-frame-pointer-register) – FoggyDay Mar 25 '20 at 19:44

1 Answers1

3

Stack is just a memory, it is not "typed" anyhow, you can always push one register and pop another.

ret is just a pop into the ip register so push/ret is an inefficient way to jmp. There's no magic that matches up with the previous call.

You can even change data on stack without using push, just change it using esp or ebp pointer. And sure you can accidentally overwrite return address. And causing your program to accidentally overwrite return address is a well known technique used by malware.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79