【问题标题】:decrementing ESP during a function call在函数调用期间递减 ESP
【发布时间】:2015-05-06 03:25:47
【问题描述】:

我反汇编了一个小程序,询问用户姓名,然后输出“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); 

}

【问题讨论】:

    标签: c assembly intel


    【解决方案1】:

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

    这与将某个虚拟值重复多次推入堆栈基本相同。

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

    【讨论】:

    • 对,正如我们所看到的,这里也确实发生了这种情况。
    • 最好补充一点,您有时会这样做以对齐堆栈。例如,ABI 需要一个 16 字节对齐的堆栈,用于对系统库的所有函数调用。
    • 这是正确的,但我认为这并不是 OP 在这里真正要求的。我猜可能与 AND 指令对齐,这不是这里发生的事情。但是任何阅读你评论的人现在也会知道这些东西。 :-)
    • 其实我很欣赏这个信息,我以前不知道。 “... ABI 需要 16 字节对齐的堆栈用于对 sys-libraries 的所有函数调用。这实际上是否意味着(比如说 linux)每个系统调用(例如,execve)也期望堆栈对齐16 字节?
    • 我只是更仔细地查看了代码,我承认有些事情我不明白(比如为什么 rax 中的返回值在从未使用时被保存) .但是您说“仅减少 ESP 电阻器并不意味着将局部变量值复制到堆栈中”。好吧,在 C 中,本地值是未分配的,因此不必进行复制。只有分配,减少 ESP 会做得很好。
    【解决方案2】:

    堆栈是通过指向堆栈段的堆栈指针来“实现”的。每次将某些东西压入堆栈(通过 pushl、call 或类似的堆栈操作码)时,都会将其写入堆栈指针指向的地址,并且堆栈指针会递减(堆栈正在增长向下,即较小的地址)。当你从栈中弹出一些东西(popl, ret)时,栈指针会递增并且从栈中读取值。

    对于不同的函数调用,我们在栈中为局部变量预留空间,所以我们将其递减并获取空间。这通常使用prologue and epilogue 完成。

    序幕

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

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

    结语

    函数尾声反转函数序言的动作并将控制权返回给调用函数。它通常执行以下操作(此过程可能因一种架构而异):

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

    【讨论】:

      【解决方案3】:

      据我所知,此类递减主要用于“保留”堆栈上的位置或保证内存对齐。

      What does it mean to align the stack?

      【讨论】:

      • 我认为这个答案是有道理的。但是,根据您的链接,内存对齐是使用 AND1 指令完成的。为什么这里使用子指令来完成?
      • 你记错了。减量是为了给当地人腾出空间。 sub rsp, 0x10 将堆栈指针递减 16。这永远不会将未对齐的地址更改为 x64 上的对齐地址。如果在减法之前它是未对齐的,它仍然是未对齐的。
      • 我说过。如果你阅读正确。我的回答中也有一个 OR。
      猜你喜欢
      • 1970-01-01
      • 2016-12-17
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多