拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 pusha/popa在函式序言/尾声中的使用?

pusha/popa在函式序言/尾声中的使用?

白鹭 - 2022-02-14 1978 0 0

阅读汇编教程,我看到“功能”序言/结语包括:

push bp
mov bp, sp  
---
pop bp

但我也看到了其他一些使用pushathenpopa来保存暂存器的教程那么为什么除了设定 bp 之外,函式 prologue/epilogue 不执行 pusha/popa 来保存暂存器背景关系?

uj5u.com热心网友回复:

它们不会保存所有暂存器,因为您并不总是需要保存所有暂存器。保存和恢复它们很慢。是的,这是一个很小的单一指令,看起来很节省,但它需要时间和堆栈空间。要了解保存的内容,请查看呼叫约定。

https://en.wikipedia.org/wiki/X86_calling_conventions

PUSHA/PUSHAD—压入所有通用暂存器

这些是缓慢的指令。在 Skylake 上,PUSHA 需要 19 uop 和 8 个吞吐量周期。POPA 需要 18 uop 和 8c 的吞吐量。

此外,PUSHA/PUSHAD 在 64 位中无效。当 x86 扩展到 64b 时,它们被 AMD 清除,然后被 Intel 清除。

现代编译器反其道而行之,尽可能避免保存暂存器。LLVM 执行称为收缩包装的分析,其中 prolog 被向前推以允许快速提前退出。

https://llvm.org/doxygen/ShrinkWrap_8cpp_source.html

这些是可怕的,可怕的,没有好的,非常糟糕的指示。

uj5u.com热心网友回复:

对于真正的汇编语言(您不必遵守不同语言的呼叫约定),“函式序言/结尾”一词没有意义。

对于“旨在符合某些其他语言的呼叫约定的汇编语言”;您只需要保存/恢复一些暂存器(可能没有)。

举个例子;对于 CDECL,EAX、ECX 和 EDX 的内容可以被被呼叫者丢弃,永远不需要被被呼叫者保存/恢复(如果他们关心,呼叫者需要保存它们);如果一个函式不使用任何其他暂存器,被呼叫者也不需要保存或恢复任何其他暂存器。还要注意,“EBP 作为帧指标”是过时的垃圾(它存在是因为除错器不是很好,并且在除错信息改进时变得毫无意义——例如 DWARF 除错信息等)。这些东西结合在一起意味着这样的事情对于 CDECL 来说具有可接受的序言和尾声:

    myFunction:
            mov eax,12345      ;eax = returned value
            ret

如果确实需要保存和恢复“大量”暂存器;pusha很慢(微编码),一系列多push条指令也很慢(存盘的地址取决于最近修改的 ESP 中的值)。典型的方法是自己做,例如:

                        ;Don't bother saving EAX, ECX, EDX.
    sub esp,16          ;Create space to save 4 registers (but maybe more for local variables)

    mov [esp],ebx
    mov [esp 4],esi
    mov [esp 8],edi
    mov [esp 12],ebp

然而; 成本是空间。在代码大小极其有限(例如“512 字节的一部分”)的引导加载程序中,聪明的程序员将使用真正的汇编语言(其中“函式序言/结尾”没有意义),初学者可能会使用它pusha来节省空间(没有意识到他们没有理由关心其他编程语言的呼叫约定)。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *