在函数调用期间递减 ESP

decrementing ESP during a function call

我反汇编了一个小程序,询问用户他们的名字然后输出 "Hello + [user's_name]"

这是反汇编的输出:

主要功能:

问候功能:

我注意到对于 main() 函数,ESP 寄存器递减了 Ox10,而对于 say_hello() 函数,ESP 寄存器递减了 Ox20。为什么会这样?

仅供参考:我的处理器是 1.4 GHz Intel Core i5,我 运行 OSX

原始 C 代码:

void say_hello (void);

int main (){

    printf("Enter your name\n");
    say_hello();
    return 0;
}

void say_hello (void) { 

    char name[5]; 
    gets(name); //this is a unsafe function to use. Results in stack overflow
    printf("Hello %s\n", name); 

}

据我所知,这样的递减主要用于"reserve"放置在堆栈上或保证内存对齐。

What does it mean to align the stack?

它在堆栈上为局部变量分配space。首先将 BP 设置为 SP 的当前值,然后递减 SP 以为函数使用的局部变量腾出空间。可以看到,后面的[ss:rbp+???]用于访问这个reservedspace.

的部分内存

这与将一些虚拟值重复多次压入堆栈基本相同。

在函数离开之前,将准确的数量加回SP是至关重要的,否则RET指令将使用错误的return地址,程序很可能会崩溃。

堆栈是"implemented"通过堆栈指针,指向堆栈段。每次将某些东西压入堆栈(通过 pushl、call 或类似的堆栈操作码)时,它都会写入堆栈指针指向的地址,并且堆栈指针递减 (堆栈向下增长,即更小的地址)。当您从堆栈中弹出某些内容时 (popl, ret),堆栈指针会递增并从堆栈中读取值。

对于不同的函数调用,我们在栈中为局部变量预留space,所以我们将其递减得到space。这通常使用 prologue and epilogue.

来完成

序言

如果架构具有基指针(也称为帧指针)和堆栈指针(以下操作可能不适用于缺少基指针或堆栈的架构,则函数序言通常会执行以下操作指针):

  • 将旧的基指针压入堆栈,以便稍后恢复(通过获取在下一步中设置并始终指向该位置的新基指针值)。
  • 将堆栈指针(指向保存的基指针和旧堆栈帧的顶部)的值分配给基指针,以便在旧堆栈帧的顶部创建一个新的堆栈帧(即旧堆栈帧的顶部将成为新堆栈帧的底部。
  • 根据堆栈向下或向上增长,通过减小或增大其值来进一步移动堆栈指针。在 x86 上,减少堆栈指针以为变量(即函数的局部变量)腾出空间。

结语

函数尾声将函数序言和returns控制权的操作反转为调用函数。它通常执行以下操作(此过程可能因架构而异):

  • 用当前基(或帧)指针替换堆栈指针,因此堆栈指针恢复到它在序言之前的值
  • 将基指针从堆栈中弹出,使其恢复到序言之前的值
  • Returns 到调用函数,通过从堆栈中弹出前一帧的程序计数器并跳转到它