为什么我们在装配中的CALLEE中"推动EBP"和"MOV EBP,ESP"?

Art*_*gio 8 x86 assembly x86-64 cpu-registers

为什么我们push ebp作为装配函的Callee中的第一个动作?

我知道然后我们mov edi, [ebp+8]用来获取传入的变量,但是我们esp已经指向了调用函数的返回地址.我们可以轻松访问传入的变量,mov edi, [esp+4]或者如果我们按下Callee寄存器,那么mov edi, [esp+16].

那么,为什么在cpu(the ebp)中有额外的寄存器,以后你必须在函数中管理?即

push ebp
mov ebp, esp

...

mov esp, ebp
pop ebp
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 9

它在被调用者中建立一个新的堆栈帧,同时保留调用者的堆栈帧.堆栈帧允许使用相对于EBP函数中任何位置的固定偏移量对传递的参数和局部变量进行一致访问,同时ESP可以在函数运行时根据需要继续进行修改.ESP是一个移动目标,因此使用动态偏移相对于访问参数和变量ESP可能是棘手的,如果不是不可能的话,取决于函数如何使用堆栈.创建堆栈帧通常更安全,代价是使用几个字节的堆栈空间来保留指向调用者堆栈帧的指针.

  • @RemyLebeau重点是,`[r/e] bp`**是一个完全正常的通用寄存器. (4认同)
  • 保持帧指针的成本不在单个`push [r/e] bp`中,它放弃了在寄存器缺乏时使用调用者保存的寄存器(或者*非常*寄存器饥饿,32位) )建筑. (2认同)
  • @EOF:“ enter”和“ leave”指令为该约定提供了ISA支持,但是除非优化代码大小而不是速度,否则它们不值得使用。(即使没有索引寄存器,使用堆栈帧也可以节省代码大小,即使它需要花费insns来设置和拆除,因为使用`[e / rsp(+ disp8 / disp32)]`的寻址模式也必须使用SIB字节。表示“ [rsp]”的编码反而意味着“有一个SIB字节”。)因此,这种约定在某种程度上已经渗透到ISA中。幸运的是,并没有真正执行它。 (2认同)