x86' push' pusha'区别

时间:2015-04-19 09:38:41

标签: assembly x86 stack assemblies

我被告知要将有效寄存器放入堆栈中,以便稍后在"子程序"中覆盖它们。对我来说很清楚,每个人都知道。但是当我读到我的伙伴的代码时,我发现了以下代码:

puts: ; display character in ax
        push ax
        push bx
        push cx
        push dx
        mov dx, ax
        mov ah, 9h
        int 21h
        pop dx
        pop cx
        pop bx
        pop ax 
        ret 

然后我看到pushapopa命令。我想可以这样做:

puts: ; display character in ax
        pusha
        mov dx, ax
        mov ah, 9h
        int 21h
        popa
        ret 

pushapush es之间是否存在任何差异? 提前谢谢。

3 个答案:

答案 0 :(得分:3)

pusha操作推送的内容超过axbxcxdx个注册:

  

“在下面将所有通用寄存器压入堆栈   顺序:(E)AX,(E)CX,(E)DX,(E)BX,(E)SP,(E)BP,(E)SI,(E)DI。该   SP的值是实际推送SP之前的值。“

您可以通过使用八个push指令推送寄存器来完成相同的操作,但这会为sp推送不同的值。您可以简单地省略堆栈指针,因为实际上不需要推送它。推送和弹出七个寄存器与pushapopa完全相同,即使它没有做同样的事情:

push ax
push bx
push cx
push dx
push bp
push si
push di
...
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax

答案 1 :(得分:3)

是的,pushapopa在功能上是等效的,只是因为他们推送/弹出所有寄存器。但是,是否有必要对简单的DOS中断调用执行此操作?

  

转移到中断例程
  ...

     

与所有操作一样,尽可能多地执行操作,仅此而已。中断调用必须保留寄存器 - 除了记录的更改之外。常规状态调用会在AX中返回结果,并且可能会更改标志,并且不会更改任何其他内容。如果中断改变了其他任何内容(例如ds:dx),则应在其文档中说明。

在您的代码中,使用ah=09 / int 21,唯一的更改是

  

回程:AL = 24h

因此可以安全地假设所有其他寄存器"存储"。

有一个原因是中断尽可能保留。在全球范围内,当其他代码运行时,中断("真实"那些,而非用户调用的)可能随时发生。

还有一个很好的理由不加区别地使用pusha/popa。您的堆栈大小有限 - 当然,它很大,但可以嵌套的例程数量也是如此。在32位和64位代码中,寄存器也更大。

每个例程都应该只保留那些已知要更改的寄存器,并且镜像它们,你应该只在以后中保存那些之前需要的那些寄存器来调用这样的例程。在示例代码中没有,因此您可以安全地删除所有推送和弹出。

答案 2 :(得分:1)

pusha会在执行spbpsi之前保存更多寄存器,尤其是di的值。除此之外,行为几乎完全相同。