为啥 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头?
Posted
技术标签:
【中文标题】为啥 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头?【英文标题】:Why pushl %ebp and movl %esp, %ebp at the start of every ASM function?为什么 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头? 【发布时间】:2014-05-15 16:25:33 【问题描述】:我正在学习 Uni 的计算机体系结构和汇编编程课程。前段时间我们学习了如何在 ASM 中编写函数并从 C 中调用它们。不过有一点我不明白——在每个 ASM 函数的开头,讲师总是做两条指令;
pushl %ebp
movl %esp, %ebp
我不明白他为什么这样做,以及调用时它对函数有什么影响。在我的 Intel Mac 上,当为 IA32 编写程序集时,我是否包含这些指令或只是跳过它似乎根本没有区别。
谁能告诉我在调用这些指令时实际发生了什么,以及为什么它们总是在 ASM 函数的开头被调用?最好在 GNU ASM 中,虽然 Intel ASM 也可以。
【问题讨论】:
我们昨天刚刚讨论了这个话题...... What is the use of "push %ebp; movl %esp, %ebp" generated by GCC for x86?的可能重复 注意在函数的末尾应该有一个匹配的popl %ebp
,就在retl
之前
【参考方案1】:
这是正确展开堆栈所必需的约定的一部分。 %ebp 基指针指向调用者的栈帧。调用约定是通过将调用者的基指针压入堆栈来保存它。请参阅 Agner Fog 的综合调用约定文档中的第 9 章异常处理和堆栈展开
http://www.agner.org/optimize/calling_conventions.pdf.
如果您想使用调试器(例如 gdb
)来调试您的程序,并且希望它向您显示 backtrace
,那么您需要遵循该调用约定。
http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_node/gdb_42.html
回溯是对您的程序如何到达当前位置的总结。它每帧显示一行,对于许多帧,从当前执行的帧(第 0 帧)开始,然后是其调用者(第 1 帧),并在堆栈上。
【讨论】:
你能不能告诉我为什么我有时会得到:“0xbffff8a8: aam $-0x8”,当我在函数顶部有说明时,当函数正常工作时说指令? @HenrikHillestadLøvold,您能否提供一个示例,说明您在哪里看到了aam
指令?我的猜测是函数条目有意对齐在 8 字节边界,反汇编程序已将“填充”字节解释为代码。【参考方案2】:
根据编译器的不同,帧指针是可选的(您可以使用 Microsoft 编译器省略帧指针)。在这种情况下,局部变量和参数作为 ESP 的偏移量而不是 EBP 被访问,并且 EBP 被释放以用作通用寄存器(尽管使用 EBP 作为地址的一部分默认使用 ss 而不是 ds 段寄存器)。
【讨论】:
【参考方案3】:原因很简单:
上面提到的函数prolog保存前一帧指针,并为新帧建立一个新指针。无框代码在 16 位/32 位 x86 上非常流行……
你可以看看enter
和leave
做了什么。
【讨论】:
以上是关于为啥 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头?的主要内容,如果未能解决你的问题,请参考以下文章