1

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?

4

4 回答 4

6

我认为这应该读

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

即把 ax 的值放入 sp 指向的内存中。

也许您sub sp, 4来自推送 32 位寄存器?堆栈指针总是按压入操作数大小减小。

(请注意,push它不会修改 FLAGS,与 不同sub。此伪代码/等效项并不完全等效,也不适用于这种push sp情况。请参阅Intel 的手册,或此 Q&A以了解即使在这些情况下也有效的伪代码。)

于 2013-07-02T20:53:55.680 回答
1

这不是如何push ax工作的。您“等于”的代码示例应该是:

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

您不会用 AX 覆盖 SP 的值。相反,您将 AX 复制到 SS:SP 指向的内存地址(使用堆栈段,而不是数据段)......但实际上,这甚至不准确。你真正需要的是这样的:

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

基本上,push做一些非常简单的事情,但是围绕这个简单事情的细节使它非常值得自己指导。push word [bp - 4]特别是如果您尚未加载局部变量,则能够使用诸如推送局部变量之类的指令将内存复制到内存。

不需要且不使用[ss:sp]不可编码为 16 位寻址模式的虚构寻址模式的替代代码。

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
于 2013-07-02T20:55:07.753 回答
0

您正在将 的值移动ax到下一个可用的堆栈帧中。堆栈指针是向下构建的(因此,如果您有太多值,它会下溢超过零并引发错误,而不是溢出到重要的地方),因此下一个可用的堆栈帧位置是当前位置之前的一个字(4 个字节)。

于 2013-07-02T20:55:01.827 回答
0

不同之处在于sub esp, 4会设置标志,但 push 不会设置标志。此外,它应该是mov [esp],eax. 您显示的 16 位版本表明您使用的是一本非常旧的书。再也没有人在 16 位机器上编程(可能除了嵌入式微控制器)。

在 x86 上,OF、SF、ZF、ZF、PF 和 CF 标志将通过减法设置,但没有标志受到 a 的影响PUSH

于 2013-07-02T20:55:38.237 回答