我想知道是否可以(如果可以,如何)编写一系列与push
. 例如,如果 的内容ax
是 1200 ,而我做了 a push ax
,我可以使用什么其他指令来完成什么push ax
?
4 回答
其他一些答案[sp]
用于堆栈寻址,但在 16 位模式下是不可能的,在 32 位或 64 位模式下也是不可能的。但是,在 32 位模式下可以使用[esp]
,在 x86-64 中可以[rsp]
用于内存寻址,但在 16 位模式下,没有使用sp
. 有关16 位模式下可能的内存寻址模式,请参见此处。
所以,你需要做的是:将 的值存储在bp
某处,复制sp
到bp
中,然后bp
用于寻址堆栈,最后恢复 的原始值bp
。
如果您有存储的地方bp
,那很容易(这是在 YASM/NASM 语法中):
mov [bp_storage], bp
sub sp,2
mov bp,sp
mov [bp],ax
mov bp,[bp_storage]
...
bp_storage dw 0
使用寄存器而不是像bp_storage
这里这样的内存地址也很简单。
编辑:添加了不修改标志的版本(如下),因为push
也不修改标志。
上面的代码修改了标志,而push ax
没有修改任何标志。这可以通过首先存储ah
到内存中来解决,然后将标志加载到ah
withlahf
中,然后将标志存储ah
到内存中,然后如上所述修改堆栈,然后ah
通过 using从内存中恢复标志sahf
,最后ah
从内存中恢复。
编辑:push ax
要在不更改标志的情况下进行模拟,ah
必须在之前保存lahf
并在之前加载mov [bp],ax
。固定的。
mov [ah_storage],ah
lahf
mov [flags_storage],ah
mov [bp_storage],bp
sub sp,2
mov bp,sp
mov ah,[ah_storage]
mov [bp],ax
mov bp,[bp_storage]
mov ah,[flags_storage]
sahf
mov ah,[ah_storage]
...
bp_storage dw 0
ah_storage db 0
flags_storage db 0
sub
修改AF
, CF
, OF
, PF
, SF
, ZF
, 而仅lahf
加载和sahf
存储AF
, CF
, PF
, SF
, ZF
(no OF
)。但是,sp
在正常的堆栈使用中永远不应该溢出。
但是,如果你不能访问内存,并且想使用堆栈来存储bp
你可以这样做,但是如果你没有可用的寄存器可以使用,事情就会变得复杂。但是,如果您使用的是实模式操作系统,您可以使用cli
、交换bp
和来阻止中断sp
,bp
用于堆栈寻址、再次交换bp
和 并sp
再次使用 允许中断sti
。
编辑:sp
需要减去 2 来模拟的值push ax
。固定的。此版本不修改标志(中断标志除外)。
cli
xchg bp,sp
lea bp,[bp-2]
mov [bp],ax
xchg bp,sp
sti
至少如果记忆有用,它大致相当于:
sub sp, 2
mov [sp], ax
从 sp 中减去一个等于所需数据写入大小的值,然后在堆栈上移动/写入所需的对象。编译器一直在做这种事情。查看 -S 输出示例。如果您这样做,请注意原子/线程问题...
如果我没有忘记 Intel 语法:
lea sp, [sp-2]
mov [sp], ax
我过去常常lea
避免触摸FLAGS
(既不push
也不触摸它们,但是mov
并且这样做)。lea
sub
dec
编辑:事实证明我忘记了更重要的事情:没有[sp]
寻址模式。正确的答案是@nrz 的答案,我的答案可以应用于80386esp
及更高版本eax
(将是lea esp,[esp-4]
)。