2

我已经学习了一段时间的汇编,并且开始掌握它,但是我似乎无法理解的一件事是为什么我们需要递减堆栈指针以离开本地漫游变量,看看这段代码:(使用 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 的相同位置并返回。有人可以澄清为什么有必要为局部变量留出“空间”。谢谢!!如果这似乎是一个愚蠢的问题,我深表歉意

4

4 回答 4

2

您是否希望您的函数调用的每个函数都必须对您将变量放在堆栈上的位置有深入的了解?

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


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

于 2014-10-01T07:10:59.170 回答
2

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

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

于 2014-10-02T20:55:34.190 回答
0

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

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

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

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

于 2014-10-02T20:06:07.747 回答
-3

它用于记忆函数,对递归函数调用非常有帮助。

于 2014-10-01T07:14:59.610 回答