Well, how does the stack work? For example the instruction:

push ax

is equal to:

sub sp, 4
mov sp, ax

where sp is a stack pointer. Is that right?

My question is - what's the point of subtracting 4 from the sp register if a moment later I change it to the whole different value?

有帮助吗?

解决方案

I think that's supposed to read

sub  sp, 2       ; AX is only 2 bytes wide, not 4
mov [sp], ax     ; store to memory, not writing the register

That is, put the value of ax into the memory pointed to by sp.

Perhaps your sub sp, 4 came from pushing a 32-bit register? The stack pointer always decreases by the push operand-size.

(Note that push doesn't modify FLAGS, unlike sub. This pseudocode / equivalent isn't exactly equivalent, also not for the push sp case. See Intel's manual, or this Q&A for pseudocode that works even in those cases.)

其他提示

That's not how push ax works. Your code example of what it is "equal to" should be:

sub sp, 2
mov [ss:sp], ax

You don't overwrite the value of SP with AX. You instead copy AX into the memory address pointed to by SS:SP (using the stack segment, rather than the data segment)... But actually, this isn't even accurate. What you really need is something like this:

mov [tmp], sp
pushf          ;push FLAGS
sub [tmp], 2
popf
mov sp, [tmp]
mov [ss:sp], ax

Basically, push does something quite simple, but the details around that simple thing make it very worth making it's own instruction. Especially being able to copy memory-to-memory with instructions like push word [bp - 4] to push a local variable if you didn't already have it loaded.

Alternate code that doesn't need, and doesn't use the imaginary [ss:sp] addressing mode that's not encodeable as a 16-bit addressing mode.

mov internal_tmp, sp
lea internal_tmp, [internal_tmp - 2]   ; sub without FLAGS
mov [internal_tmp], SRC_OPERAND        ; even for a memory source, or for push sp
mov sp, internal_tmp

You're moving the value of ax into the next available stack frame. The stack pointer is built downwards (so that if you have too many values it underflows beyond zero and raises an error instead of overflowing into something important), so the next available stack frame location is one word (4 bytes) before the current location.

The difference is that sub esp, 4 will set flags, but push will not set flags. Also, it should be mov [esp],eax. The 16-bit versions you show indicates you are using a very old book. Nobody programs on a 16-bit machine anymore (except embedded microcontrollers, possibly).

On an x86 the OF, SF, ZF, ZF, PF and CF flags will be set by the subtraction, but no flags are affected by a PUSH.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top