我正在Professional Assembly Language Richard Blum阅读,当您输入电话时,您应该将ESP
注册的值复制到EBP
,他还提供了以下模板:
function_label:
pushl %ebp
movl %esp, %ebp
< normal function code goes here>
movl %ebp, %esp
popl %ebp
ret
我不明白为什么这是必要的。当您在函数内部推送某些内容时,您显然打算将其弹回,从而将ESP
恢复为原始值。
为什么要有这个模板呢?
那么EBP
寄存器的用途是什么?
我显然错过了什么,但它是什么?
答案 0 :(得分:2)
当你在函数内部推送某些内容时,你显然打算将其弹回
这只是使用堆栈的部分原因。更常见的用法是你的代码片段中缺少的一个,存储局部变量。在设置EBP之后看到的下一个常见代码是ESP上的减法,相当于本地变量存储所需的空间量。这当然也很容易平衡,只需在功能结尾添加相同的数量。当代码也使用诸如C99可变长度数组或非标准但通常可用的_alloca()函数之类的东西时,它变得更加困难。能够从EBP恢复ESP使这很简单。
或许更重要的是,像这样设置堆栈帧是而不是。大多数x86编译器都支持称为“帧指针省略”的优化选项。在MSVC上使用GCC的-fomit-frame-pointer / Oy打开。这使得EBP寄存器可用于一般用途,这对x86非常有用,因为它缺乏cpu寄存器。
但优化有一个非常严重的缺点。如果EBP寄存器指向堆栈帧的开头,则执行堆栈遍历变得非常困难。当您需要调试代码时,这很重要。堆栈跟踪对于了解代码如何最终崩溃非常重要。当您从客户那里获得崩溃的“核心转储”时,这是非常宝贵的。如此有价值的微软同意{2}在Windows二进制文件上为客户提供了诊断崩溃的机会。