2014-10-01 70 views
1

我已经学习了一会儿的程序集,现在我已经开始掌握它了,但是我似乎无法理解的一件事就是为什么我们需要递减堆栈指针离开漫游本地变量,来看看下面的代码:在这个小程序(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 

我可以想象做所有这些,而不需要减少48。我可以使用基指针来将值从堆栈中移出,并且只需要指向相同的位置以准备好弹出ebp并返回。 有人可以澄清为什么有必要为局部变量留下“空间”。 谢谢!! 如果这看起来像一个愚蠢的问题,我很抱歉

回答

2

你想让你的函数调用的每个函数都必须知道你已经把变量放在堆栈上的位置吗?

大量的函数调用等功能 - 递减堆栈指针是你的函数说:“我使用的堆栈此位”的方式


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

+0

好吧,所以递减堆栈指针的全部意义在于,当我们调用另一个函数时总是保持递减ebp,从而为我们节省了执行如下操作的麻烦:'mov“返回地址”,-52($ ebp)'我们为新函数插入一个局部变量,并且保持跟踪每帧的beginig和end(通过推送ebp和递减esp),是吗? – user3769877 2014-10-01 07:22:44

-2

它用于记忆功能,它在递归函数调用中非常有用。

+2

这不能再模糊或不完整。 – 2014-10-01 07:53:24

0

从堆栈指针中减去一个常量是如何为局部变量分配空间。编译器或汇编程序员将知道这些变量的位置,或者是来自rbp的负偏移量,或者是来自rsp的正偏移量(或零偏移量)。你显示的例子有点奇怪,因为它执行了多次添加,将结果存储在堆栈中的局部变量数据中,然后将一个常量返回到堆栈指针,从而有效地释放了所有这些局部变量(它在eax中留下了一笔款项)。同样看例子,使用的“最低”地址是rbp-16的4个字节的数据,所以从esp中减去20就足够了(在这种情况下)。

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

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

2

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

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

相关问题