我想知道是否可以(如果可以,如何)编写一系列与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到内存中来解决,然后将标志加载到ahwithlahf中,然后将标志存储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并且这样做)。leasubdec
编辑:事实证明我忘记了更重要的事情:没有[sp]寻址模式。正确的答案是@nrz 的答案,我的答案可以应用于80386esp及更高版本eax(将是lea esp,[esp-4])。