15

I'm getting confused on what does pop actually do in assembly. Does pop move the value PUSHed onto the stack last (meaning it doesn't apply if we MOV a value after the the last element PUSHed) or does it just pop whatever value that's last on the stack (thus, applying to both MOV and PUSH), or does it pop what ever value pointed to by the stack pointer? Consider the following code:

push $4
mov $5, -4(%esp)
add $4, %esp (esp pointing to an unknown value)
pop %ebp

So in this code will the value poped into ebp be 4, 5, or the unknown value pointed to by esp?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
GamefanA
  • 1,555
  • 2
  • 16
  • 23
  • Possible duplicate of [Assembler: Push / pop registers?](http://stackoverflow.com/questions/4584089/assembler-push-pop-registers) – Ciro Santilli OurBigBook.com Nov 07 '15 at 11:30
  • Related: [What is an assembly-level representation of pushl/popl %esp?](https://stackoverflow.com/q/14968824) - asm equivalents that match the real behaviour for both `push %esp` and `push` anything else. Intel's pseudo-code *doesn't* reflect what happens in that case, only the text description section covers it. – Peter Cordes Nov 17 '21 at 13:27

2 Answers2

27

The latter

POP EBP

is equivalent to

MOV EBP, [ESP]
ADD ESP, 4           ; but without modifying flags, like  LEA ESP, [ESP+4]

(in Intel syntax - target on the left, source on the right)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • so pop doesn't actually remove the value from the stack, just moves it? – GamefanA Sep 24 '14 at 20:56
  • 3
    That is correct, however the increment of ESP effectively hides it from further access. Theoretically an interrupt could happen immediately afterwards and reuse that area of the stack for storage, but I don't actually believe interrupts use the ring 3 stack anymore. – 500 - Internal Server Error Sep 24 '14 at 20:58
  • 1
    In user-space, signal handlers can asynchronously clobber the stack. In Linux with no signal handlers installed, I think you can count on space below `esp` not to be asynchronously clobbered, but it's still not guaranteed by the ABI. (In x86-64 System V, there's a 128B red-zone below RSP that is guaranteed not to be clobbered, even by signal handlers. But Windows doesn't have that.) – Peter Cordes Oct 14 '17 at 02:06
  • And no, interrupts don't use the user-space stack in any mainstream OS. That wouldn't be secure: another thread could modify that memory while the kernel was using it, and escalate its privileges. Of course, in kernel code, the stack really can be clobbered asynchronously (if it doesn't switch to an interrupt stack separate from the per-thread kernel stack; not sure. x86-64 Linux kernel code doesn't use a red-zone though, I think for this reason.) – Peter Cordes Oct 14 '17 at 02:12
24

PUSH <src> does:

 ESP := ESP-4  ; for x86; -8 for x64
 MEMORY[ESP]:=<operandvalue>

POP <dst> does:

 <operandtarget>:=MEMORY[ESP];
 ESP:=ESP+4    ; for x86; +8 for x64

It is much easier to understand what machine instructions do if you write their descriptions down in pseudo code like this. The Intel reference manuals are full of such pseudo code, and it is worth your time and trouble to get them, and read the details for yourself. (e.g. in the HTML extract https://www.felixcloutier.com/x86/push and https://www.felixcloutier.com/x86/pop)

Regarding your specific question: Your store of $5 into -4(%esp) is a valid machine instruction, and the processor will execute it without complaint, but it is really extremely unsafe programming. If the processor takes a trap or interrupt just after that instruction, the processor state (is usually) saved "on top of the stack", and will overwrite your value. Since interrupts occur asynchronously, the behaviour you will see is that, rarely, the $5 gets lost. That makes for an extremely hard program to debug.

The "add $4" moves the ESP back to the place before the push instruction. So, you cannot say anything about the value popped into ebp except it is "unknown" as you suggested as one of your options.

See Raymond Chen's blog for details of why writing below ESP is unsafe even in user-space under Windows. (Interrupts won't use the user-space stack asynchronously, but a few things can.) On non-Windows, POSIX signal handlers can step on space below the user-space ESP. (Except in x86-64 System V, where the ABI defines a "red zone" of 128 bytes below RSP that's safe to use.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341