【问题标题】:Instruction sequence that does the same thing as push与 push 做同样事情的指令序列
【发布时间】:2013-01-30 15:06:35
【问题描述】:

我想知道是否可以(如果可以,如何)编写与push 具有相同效果的指令序列。比如ax的内容是1200,我做了一个push ax,我还能用什么其他指令来完成push ax做的事情?

【问题讨论】:

    标签: assembly x86 stack x86-16


    【解决方案1】:

    其他一些答案使用[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 存储到内存中来解决,然后使用lahf 将标志加载到ah,然后将ah 中的标志存储到内存中,然后如上所述修改堆栈,然后从内存中恢复标志通过ah 使用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 修改AFCFOFPFSFZF,而lahf 加载和sahf 仅存储CFCFPFSFZF(没有OF)。但是,sp 在正常的堆栈使用中永远不会溢出。

    但是,如果你不能访问内存,并且想使用堆栈来存储bp,你可以这样做,但是如果你没有可用的寄存器来使用,事情就会变得复杂。但是如果您使用的是实模式操作系统,您可以使用cli 阻止中断,交换bpsp,使用bp 进行堆栈寻址,再次交换bpsp,并再次允许中断sti.

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

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

    【讨论】:

      【解决方案2】:

      至少如果有记忆的话,大致相当于:

      sub sp, 2
      mov [sp], ax
      

      【讨论】:

      • 没有对你投反对票,但一个简单的 dec 不会涵盖上述写入的大小。你需要一个减法或类似的东西。
      • 现在好多了,不过ax是一个字,所以dec sp两次
      • mov [sp], ax 无效。 x86 中没有这样的指令。 esprsp 可用于内存寻址,sp 不能。看我的回答。
      【解决方案3】:

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

      【讨论】:

      • 在嵌入式系统上,您以非原子方式使用堆栈指针,事情就变得繁荣起来。 “移动堆栈指针”,中断,推送信息,返回,“写入信息”,繁荣。
      • 顺便说一句,我赞成其他答案,因为它们包含实际的示例代码,而我很懒惰并且没有:)
      • 我认为只要你记得 SP 之上的内存随时可能被丢弃,你在嵌入式系统上也是安全的。只要中断正确保存和恢复SP,我看不到“调整esp保留一个单词在顶部,将数据存储在顶部”的场景可以被打破。
      • 那就叫我多疑吧。我已经被 2 条单独的指令烧得够呛了
      【解决方案4】:

      如果我没有忘记 Intel 语法:

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

      我使用lea 来避免触摸FLAGSpushmovlea 都不会触摸它们,但subdec 会触摸它们)。

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

      【讨论】:

      • mov [sp], ax 无效。 x86 中没有这样的指令。 esprsp 可以用于内存寻址,sp 不能。看我的回答。
      猜你喜欢
      • 2020-09-28
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 2011-03-07
      • 1970-01-01
      相关资源
      最近更新 更多