2
votes

The pushl Y86 instruction both decrements the stack pointer by 4 and writes a register value to memory. So it's not clear what the processor should do when it executes the instruction pushl %esp, since the register being pushed is being changed by the same instruction. Two possible events can occur:

(1) push the original value of %esp, or (2) push the decremented value of %esp.

In light of this, how could we modify this code-equivalent of pushl REG to account for, and accomdate, these ambiguities (being that REG can be %esp as well as any other register)?:

subl $4,%esp                   Decrement stack pointer
movl REG,(%esp)                Store REG on stack

Similarly, the instruction popl %esp could either set %esp to the value read from memory or to the incremented stack pointer. How could this code be changed to accommodate for these ambiguities?:

movl (%esp),REG                Read REG from stack
addl $4,%esp                   Increment stack pointer
1
I recall that this changed between steppings of the 8086, not relevant to y86 though.fuz

1 Answers

1
votes

y86 is based on x86. The x86 instruction-set reference manual entry for push says (correctly):

The PUSH ESP instruction pushes the value of the ESP register as it existed before the instruction was executed.

And pop:

The POP ESP instruction increments the stack pointer (ESP) before data at the old top of stack is written into the destination.

So in the pop %esp case, the increment is lost. This sequence has the same effect, although most real CPUs probably load into temporary internal storage instead of actually using an updated ESP value in the addressing mode.

add   $4, %esp
movl  -4(%esp), %esp

But pop %esp does that without updating FLAGS, and without a possibility of an interrupt or signal-handler between the add and mov. (The separate add/mov sequence isn't safe in contexts where anything below the current %esp can be asynchronously overwritten by an interrupt handler.)


Presumably y86 does the same thing as x86. You can easily (and should) check with a debugger to see how your favourite y86 simulator handles this corner case. push %esp is easy to test by looking at memory (or adding a pop %eax after it).

Testing both at once would get confusing, and if the value you pop is the same as the old stack pointer, you can't tell the difference. Probably push a 0 (or store a 0 to (%esp)), then pop %esp and see what value is in the register with a debugger. (It doesn't matter if your code crashes afterwards, you're just using a debugger.)

I didn't check if y86 supports push $0 or movl $0, (%esp) like x86. I guess it would be immovl $0, (%esp) if it's supported (immediate to memory). If not, then zero a register and push that.