4

我想知道是否可以(如果可以,如何)编写一系列与push. 例如,如果 的内容ax是 1200 ,而我做了 a push ax,我可以使用什么其他指令来完成什么push ax

4

4 回答 4

7

其他一些答案[sp]用于堆栈寻址,但在 16 位模式下是不可能的,在 32 位或 64 位模式下也是不可能的。但是,在 32 位模式下可以使用[esp],在 x86-64 中可以[rsp]用于内存寻址,但在 16 位模式下,没有使用sp. 有关16 位模式下可能的内存寻址模式,请参见此处。

所以,你需要做的是:将 的值存储在bp某处,复制spbp中,然后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和来阻止中断spbp用于堆栈寻址、再次交换bp和 并sp再次使用 允许中断sti

编辑:sp需要减去 2 来模拟的值push ax。固定的。此版本不修改标志(中断标志除外)。

cli
xchg bp,sp
lea bp,[bp-2]
mov [bp],ax
xchg bp,sp
sti
于 2013-02-14T18:39:31.790 回答
2

至少如果记忆有用,它大致相当于:

sub sp, 2
mov [sp], ax
于 2013-02-14T18:05:19.950 回答
1

从 sp 中减去一个等于所需数据写入大小的值,然后在堆栈上移动/写入所需的对象。编译器一直在做这种事情。查看 -S 输出示例。如果您这样做,请注意原子/线程问题...

于 2013-02-14T18:08:11.670 回答
1

如果我没有忘记 Intel 语法:

lea sp, [sp-2]
mov [sp], ax

我过去常常lea避免触摸FLAGS(既不push也不触摸它们,但是mov并且这样做)。leasubdec

编辑:事实证明我忘记了更重要的事情:没有[sp]寻址模式。正确的答案是@nrz 的答案,我的答案可以应用于80386esp及更高版本eax(将是lea esp,[esp-4])。

于 2013-02-14T18:09:52.177 回答