C 为什么在函数序言/尾声中使用ebp?

C 为什么在函数序言/尾声中使用ebp?,c,optimization,assembly,x86,C,Optimization,Assembly,X86,不久前,我正在试验编写汇编程序 例程并将其与C程序链接,我发现 我可以跳过标准的C-call开场白 push ebp mov ebp, esp (sub esp, 4 ... mov esp, ebp) pop ebp 只需跳过所有内容,通过esp进行寻址,就像 mov eax, [esp+4] ;; take argument mov [esp-4], eax ;; use some loca

不久前,我正在试验编写汇编程序 例程并将其与C程序链接,我发现 我可以跳过标准的C-call开场白

    push ebp
    mov ebp, esp
    (sub esp, 4
    ...
    mov esp, ebp)
    pop ebp
只需跳过所有内容,通过
esp
进行寻址,就像

    mov eax, [esp+4]          ;; take argument
    mov [esp-4], eax          ;; use some local variable storage
它似乎很管用。为什么使用ebp-可能是
通过ebp进行寻址更快还是怎样?

它可以工作,但是,一旦出现中断,处理器会将其所有寄存器和标志推入堆栈,覆盖您的值。
堆栈存在是有原因的,请使用它…

在调试代码时,使用EBP非常有帮助,因为它允许调试器遍历调用链中的堆栈帧

它[创建]一个单链表,将每个调用方的帧指针链接到一个函数。从例程的EBP中,可以恢复函数的整个调用堆栈



特别是它所链接的页面,其中包含您的问题:

不需要使用堆栈框架,但肯定有一些优点:

首先,如果每个函数都使用相同的过程,我们可以利用这些知识通过反转过程轻松确定调用序列(调用堆栈)。我们知道,在执行
call
指令后,
ESP
指向返回地址,被调用函数将做的第一件事是
推送当前
EBP
,然后将
ESP
复制到
EBP
。因此,在任何时候,我们都可以查看
EBP
指向的数据,它将是前一个
EBP
,而
EBP+4
将是最后一个函数调用的返回地址。因此,我们可以使用如下方式打印调用堆栈(假设为32位):

这将打印出整个调用序列(以及它们的返回地址),直到该点

此外,由于
EBP
不会更改,除非您明确更新它(不像
ESP
,当您
push
/
pop
时会更改),因此相对于
EBP
,而不是相对于
ESP
,通常更容易参考堆栈上的数据,因为后者,您必须了解在函数开始和引用之间可能调用的任何
push
/
pop
指令

正如其他人所提到的,您应该避免使用
ESP
下面的堆栈地址,因为您对其他函数进行的任何
调用都可能覆盖这些地址处的数据。相反,您应该在堆栈上保留空间,以供您的函数使用:

sub esp, [number of bytes to reserve]
在此之后,可以安全使用初始
ESP
ESP-[保留字节数]
之间的堆栈区域。 在退出函数之前,您必须使用以下匹配项释放保留的堆栈空间:

add esp, [number of bytes reserved]

嗯,你确定吗?我用了这个,没有经历过一个错误,这只是运气的问题吗?如果是这样,我知道我可以使用它,但不应该只使用[esp-X]值?或者我可以用另一种方法把esp减到20,然后再加上20?你确定这是系统的过度使用吗?上面有文字吗?@Iridium它可能是一个异步信号,而不是真正的中断,不管是哪一个。esp
esp
下面的所有内容都不受保护,可能会被某些事件破坏。“mov[esp-4],eax”-非常危险,是的。即使堆栈切换通过中断门发生,我也对访问堆栈指针下面的位置没有信心。例如,我不确定如果访问产生了页面错误,会发生什么。更确切地说,关于fpu的这一页确实是对这一点的回答——但mellowcandla说的事情也很有趣,尽管我可以补充一点,我不理解这个链表是如何工作的,而且,似乎没有ebp,这个信息也可以被检索到——如果函数可以返回(并且返回并返回),那么您也可以跟踪这个路径——而不需要ebp@user2214913:函数可以返回其调用者,因为返回地址存储在堆栈中推送参数旁边。但是,调试器无法将返回地址与堆栈上的任何其他值区分开来,因此它无法扫描堆栈以找到之后的下一个返回地址。调试器也无法可靠地确定该函数在本地使用了多少堆栈空间并跳过它。说真的,读链接页面。哈哈:)这很好(我的意思是特别是LogStack示例)很抱歉我能接受所有三个答案,因为它们都很好:)至于这件事,我个人喜欢成为一个操作狂(我想写尽可能快的asm例程)所以,线索是,如果esp-4过度疲劳没有发生,或者真的发生了?(可能会有一些文字?有人?)如果是这样,我可以跳过我写的所有开场白,但不要使用esp-4,而是使用一个本地静态缓冲区-它应该是最高速度:uye?@user2214913:你进入了过早的优化。在一个非平凡的程序中,您的代码所做的任何有意义的工作都会使您通过这种方式缩短周期。需要调试代码的人不会欣赏这一点。@user2214913正如DCoder所说,在汇编中编写代码可能不会产生更快的代码,我认为,在使用前省略堆栈帧和不保留堆栈空间所带来的任何速度增益都会因您引入的低效率而相形见绌。您提出这个非常基本的问题的事实表明,编写代码可能不是为了避免缓存未命中造成的速度减慢,也不是为了利用特定于CPU的指令顺序来实现并行执行。一个好的编译器会意识到这些事情,并且通常会产生比手工汇编快得多的代码。使用C/C++代码库进行实验是很容易的,因为编译器不使用框架指针(
-fomit frame pointer
等等)和gcc st
add esp, [number of bytes reserved]