Why does push EBX result in pop ESI

4.2k views Asked by At

I picked up the book "Practical reverse engineering" and i have the following example on page 14 (x86 assembly):

mov eax, 0AAAAAAAh
mov ebx, 0BBBBBBBh
push eax
push ebx
pop esi
pop edi

Now, I push eax and ebx on to the stack, but i pop esi and edi of the stack. Why is that? I thought I would push and pop the same registers.

3

There are 3 answers

0
Mike On

push — Push on stack

The push instruction places its operand onto the top of the hardware supported stack in memory. Specifically, push first decrements ESP by 4, then places its operand into the contents of the 32-bit location at address (%esp). ESP (the stack pointer) is decremented by push since the x86 stack grows down — i.e. the stack grows from high addresses to lower addresses.

pop — Pop from stack

The pop instruction removes the 4-byte data element from the top of the hardware-supported stack into the specified operand (i.e. register or memory location). It first moves the 4 bytes located at memory location (%esp) into the specified register or memory location, and then increments ESP by 4.

look for more details: push / pop explanation

0
Rudy Velthuis On

You don't push registers, you push the values held in these registers. In this case, the values come from registers eax and ebx. The registers themselves remain where they were (somewhere inside the CPU).

You can pop these values into any registers, like esi and edi here. It simply depends on where in your code and in which registers you need these values.

Sometimes you only want to clear a few values from the stack. Then you could do

pop esi   ; or whatever register is not in use at the moment
pop esi    

That would not affect any other register. (Of course, you could also simply change the stack pointer, but that is another topic.)

0
Govind Parmar On

When you pop the stack, the register operand just receives the value that was on the top of the stack. As long as the same number of bytes are pushed and popped, the stack is balanced, regardless of where the bytes go. You do not necessarily need to pop back into the same location that was the source of your earlier pushed value.

For example, this code loads the register ecx with whatever was currently in eax, without misaligning the stack:

push eax
pop ecx

You can also perform an effective "operand-less" pop by manually adjusting the stack pointer:

push eax
...
add esp, 4 ; Discard 32-bits on top of stack 
; Stack is now balanced (assuming the intermediate instructions did not misalign the stack)