与push一样的指令序列

时间:2013-02-14 18:01:26

标签: assembly x86 stack x86-16

我想知道是否有可能(如果是这样,如何)编写一系列与push具有相同效果的指令。例如,如果ax的内容为1200,而我执行push ax,我可以使用哪些其他说明来完成push ax的操作?

4 个答案:

答案 0 :(得分:7)

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

那么,您需要做什么:将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将标志加载到lahf中,然后将标记从ah存储到内存中,然后如上所述修改堆栈来解决,然后使用ah通过sahf从内存中恢复标记,最后从内存中恢复ah

修改:要在不更改标记的情况下模拟push axah必须在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修改AFCFOFPFSFZF,而lahf }加载和sahf仅存储AFCFPFSFZF(无OF)。但是,sp永远不会在正常的堆栈使用中溢出。

但是,如果您无法访问内存,并希望使用堆栈来存储bp,那么您可以这样做,但如果您既没有可用的免费寄存器,那么事情会变得复杂。但是,如果您使用的是实模式操作系统,则可以使用cli阻止中断,交换bpsp,使用bp进行堆栈寻址,交换bp再次sp并允许sti再次中断。

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

cli
xchg bp,sp
lea bp,[bp-2]
mov [bp],ax
xchg bp,sp
sti

答案 1 :(得分:2)

至少如果内存服务,它大致相当于:

sub sp, 2
mov [sp], ax

答案 2 :(得分:1)

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

答案 3 :(得分:1)

如果我没有忘记英特尔语法:

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

我使用了lea来避免触及FLAGSpush也不movlea触摸它们,但是sub和{ {1}}做)。

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