POP in various architectures?

CTho9305

Elite Member
Jul 26, 2000
9,214
1
81
What is the behavior of the POP instruction? After testing some stuff last night, I get the impression that on x86, POP reads the data at SS:SP, writes back junk, and increments SP by 2.

The code I used:
MOV AX, ABCD
MOV BX, 1234
PUSH AX
NOP
POP AX
NOP
DEC SP
NOP
DEC SP
NOP
POP BX
NOP
NOP

trace:
AX=ABCD BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0103 NV UP EI PL NZ NA PO NC
0B1D:0103 BB3412 MOV BX,1234
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0106 NV UP EI PL NZ NA PO NC
0B1D:0106 50 PUSH AX
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0107 NV UP EI PL NZ NA PO NC
0B1D:0107 90 NOP
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0108 NV UP EI PL NZ NA PO NC
0B1D:0108 58 POP AX
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0109 NV UP EI PL NZ NA PO NC
0B1D:0109 90 NOP

-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010A NV UP EI PL NZ NA PO NC
0B1D:010A 4C DEC SP
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFED BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010B NV UP EI NG NZ NA PE NC
0B1D:010B 90 NOP
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFED BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010C NV UP EI NG NZ NA PE NC
0B1D:010C 4C DEC SP
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010D NV UP EI NG NZ NA PO NC
0B1D:010D 90 NOP
-T

AX=ABCD BX=1234 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010E NV UP EI NG NZ NA PO NC
0B1D:010E 5B POP BX
-T

AX=ABCD BX=3333 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=010F NV UP EI NG NZ NA PO NC
0B1D:010F 90 NOP
-T

AX=ABCD BX=3333 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B1D ES=0B1D SS=0B1D CS=0B1D IP=0110 NV UP EI NG NZ NA PO NC
0B1D:0110 90 NOP
-

I did it with slightly different orders a few times, and BX seems to come back with different numbers pretty much every time. I can't find any information on what happens to the memory location where AX was popped from after a pop (probably because you're not supposed to do things like this ;)).

What would other architectures do in a situation like this? (If it matters, I tested this on an pre-tbird Athlon)
 

Peter

Elite Member
Oct 15, 1999
9,640
1
0
That's because on x86, the stack grows DOWNWARD inside SS. Look at your capture, after the PUSH AX instruction SP is two less than before. Now if you decrease SP further before POPing BX, you'll read from a previously unused location with random content. If you want to remove the top word from the stack, do an ADD SP, 2.
 

CTho9305

Elite Member
Jul 26, 2000
9,214
1
81
Originally posted by: Peter
That's because on x86, the stack grows DOWNWARD inside SS. Look at your capture, after the PUSH AX instruction SP is two less than before. Now if you decrease SP further before POPing BX, you'll read from a previously unused location with random content. If you want to remove the top word from the stack, do an ADD SP, 2.

SS is constant throughout this.

SP starts at FFEE. After the PUSH AX, it is FFEC. Before the POP BX, it is again FFEC. The stack grows down from FFFF, so decrementing it and poping should put ABCD in AX. Right?

edit: from what you said, it looks like you missed the fact that immediately after PUSH AX, I POP AX back out.
 

Peter

Elite Member
Oct 15, 1999
9,640
1
0
Right, I missed that. You missed something too, namely the fact that the debugger itself uses stack too, meaning that the storage that said ABCD right before will not necessarily still have that data a moment later. Moving the stack pointer into un-occupied territory is no good kung fu, while moving it up to quickly dispose of no longer needed data on the stack is a common and well working technique.

If you really want a headache, examine the results of PUSH SP. :)
 

CTho9305

Elite Member
Jul 26, 2000
9,214
1
81
Originally posted by: Peter
Right, I missed that. You missed something too, namely the fact that the debugger itself uses stack too, meaning that the storage that said ABCD right before will not necessarily still have that data a moment later. Moving the stack pointer into un-occupied territory is no good kung fu, while moving it up to quickly dispose of no longer needed data on the stack is a common and well working technique.

If you really want a headache, examine the results of PUSH SP. :)

Ah :) So if I run that program all at once and add some calls to print out bx (whatever int 21h call that would be in windows), I should see ABCD?

 

Peter

Elite Member
Oct 15, 1999
9,640
1
0
Possibly ... if you don't happen to get interrupted by some hardware event, whose handler uses stack as well. As I said, do not rely on the contents of the stack outside of the stuff you PUSHed yourself.
 

CTho9305

Elite Member
Jul 26, 2000
9,214
1
81
Originally posted by: Peter
Possibly ... if you don't happen to get interrupted by some hardware event, whose handler uses stack as well. As I said, do not rely on the contents of the stack outside of the stuff you PUSHed yourself.

Is the stack properly protected in protected mode? ;)
edit: actually, I better start a new thread about protected mode.