为啥 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 上非常流行……

你可以看看enterleave做了什么。

【讨论】:

以上是关于为啥 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头?的主要内容,如果未能解决你的问题,请参考以下文章

课程学习总结报告

递归工作栈

Linux内核及分析 第二周 操作系统是如何工作的?

20169217 《Linux内核原理与分析》 第十一周作业

分配的堆栈空间没用?

过早重置堆栈指针?令人困惑的汇编代码