【问题标题】:Why do we need to decrement the stack pointer when calling a function为什么调用函数时需要递减栈指针
【发布时间】:2014-11-25 23:13:53
【问题描述】:

我学习汇编已经有一段时间了,我开始掌握它的窍门,但是我似乎无法理解的一件事是为什么我们需要递减堆栈指针才能离开漫游对于局部变量,看看这段代码:(使用 64 位 GNU 编译器编译的代码,AT&T 语法)

pushq   %rbp

movq    %rsp, %rbp

subq    $48, %rsp

call    __main
movl    $0, -4(%rbp)
movl    $4, -8(%rbp)
movl    -8(%rbp), %edx
movl    -4(%rbp), %eax
addl    %edx, %eax
movl    %eax, -12(%rbp)
movl    -4(%rbp), %edx
movl    -12(%rbp), %eax
addl    %eax, %edx
movl    -8(%rbp), %eax
addl    %edx, %eax
movl    %eax, -16(%rbp)
addq    $48, %rsp
popq    %rbp
ret

在这个小程序中,我可以想象在不需要将 esp 递减 48 的情况下完成所有这些操作。我可以使用基指针将值从堆栈移入和移入堆栈,并且只需让 esp 指向相同的位置即可弹出 ebp 并返回。 有人可以澄清为什么有必要为局部变量留出“空间”。 谢谢!! 如果这似乎是一个愚蠢的问题,我深表歉意

【问题讨论】:

    标签: assembly x86 stack stack-pointer


    【解决方案1】:

    您是否希望您的函数调用的每个函数都必须非常清楚您将变量放在堆栈中的什么位置?

    许多函数调用其他函数 - 递减堆栈指针是您的函数说“我正在使用堆栈的这一位”的方式


    “叶”方法 - 从不调用其他函数的方法 - 确实可以按照您建议的样式编写 - 因为没有其他代码会自己使用堆栈。

    【讨论】:

    • 好的,所以减少堆栈指针的全部意义在于为我们省去执行以下操作的麻烦:mov "return address", -52($ebp) 在调用另一个函数时,每次插入局部变量时始终保持递减 ebp对于新功能,并跟踪每帧的开始和结束(通过推送 ebp 和递减 esp),对吗?
    • call __main 看起来像 MinGW,这意味着您没有低于 RSP 的红色区域,可以避免异步破坏。这是 x86-64 System V ABI(Linux、MacOS、其他非 Windows)的一个特性。
    【解决方案2】:

    如果发生中断,地址小于 RSP 的任何东西都是公平的游戏 - 操作系统会在不询问您的情况下擦除它(即用自己的数据替换)。中断总是发生。 Ergo - 您必须将所有您关心的东西保存在 RSP 或以下。

    另外,调用其他函数会推送返回地址。除非 RSP 上方有空格,否则会覆盖您的数据。

    【讨论】:

    • 中断不使用用户空间堆栈。信号处理程序可以,或 Windows SEH 异常处理程序,这可能是 MinGW 代码。因此,没有像 Linux 上那样的红色区域可以让本地人保持在 RSP 以下是安全的。
    【解决方案3】:

    从堆栈指针中减去一个常量就是为局部变量分配空间的方式。编译器或汇编程序程序员会知道这些变量在哪里,或者是相对于 rbp 的负偏移量,或者是相对于 rsp 的正(或零)偏移量。

    你展示的例子有点奇怪,因为它执行了几次加法,将结果存储在堆栈上的局部变量数据中,然后将一个常量添加回堆栈指针,有效地释放所有这些局部变量(它确实在 eax 中留下一个总和)。再看这个例子,使用的“最低”地址是 rbp-16 处的 4 个字节的数据,所以从 esp 中减去 20 就足够了(在这种情况下)。

    如果使用 _alloca() 之类的东西,这可能会变得更加复杂,因为它会从堆栈中分配可变数量的内存。

    另外,rbp 的使用是可选的。它在示例代码中被用作“帧指针”,但一些编译器可以选择禁用帧指针,在这种情况下,编译器仅使用 rsp(或 esp,如果在 32 位模式下)来跟踪局部变量,释放up rbp(或 ebp)用作通用寄存器。

    【讨论】:

      【解决方案4】:

      用于记忆函数,对递归函数调用很有帮助。

      【讨论】:

      • 这不能再模糊或不完整了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 2014-06-05
      • 2019-11-23
      • 2010-12-19
      • 1970-01-01
      • 2012-07-22
      • 2014-01-26
      相关资源
      最近更新 更多