当我输入C函数时,我希望在反汇编中看到如何将堆栈指针减去足够多的空间以容纳变量,但是没有;我只看到当esp仍指向ebp时如何通过ebp直接访问变量的地址。
push %rbp
mov %rsp,%rbp
movl $0x4,-0x4(%rbp)
mov $0x0,%eax
pop %rbp
retq
我必须创建许多变量并将其初始化,以使计算机认真对待它们,并查看产生了多少不必要的空间。差异真的是所使用的空间量还是其他?如果是这样,
仅当我请求大量空间时才需要通过移动rsp腾出空间吗?
最佳答案
x86-64 System V ABI在RSP下方有一个128字节的红色区域,可以防止异步破坏,即该功能“拥有”该区域。
看起来您是在int foo{ int x = 4; return 0; }
的情况下使用gcc -O0
进行编译的(禁用了优化功能),并且gcc选择将x
保留在red-zone中,而不是调整rsp
来“保留” /“分配”堆栈空间。 (有关更多链接/信息,请参见red-zone tag wiki。)
这是红色区域的重点:将这些sub
/ add
指令保存在叶函数中。
顺便说一句,查看未优化的代码通常是浪费时间。至少-O1
更具可读性,并且-O2
/ -O3
与您实际上应该关心的代码有关。另请参见How to remove "noise" from GCC/clang assembly output?。
在没有信号处理程序的程序中,整个堆栈区域都可以有效地用作红色区域。例如:code-golf extended-precision Fibonacci using esp
as an array pointer because pop
is fast and compact。 (AFAIK,信号处理程序是唯一会异步破坏rsp
下的内存的东西)。红区使编译器无需特殊的编译选项即可使用它(对于SysV ABI未定义红区的32位模式,没有这样的选项)。即使没有整个程序优化,证明没有信号处理程序也可能不可行。
我只看到如何通过ebp直接访问变量的地址
不,你没有。通过ebp
的访问将在64位代码中出错,因为堆栈位于低4GB的地址空间之外(至少在Linux上默认为)。指针是64位的,因此gcc使用rbp
来访问它们。
即使没有错误,使用地址大小的前缀在64位模式下对movl $0x4,-0x4(%ebp)
进行编码也会浪费代码大小。
有趣的事实:在指针为32位的x32 ABI(长模式下为ILP32)中,gcc经常使用地址大小前缀而不是额外的指令来截断寄存器中可能存在的高垃圾,并确保寻址模式改写为2 ^ 32超出4GB(例如,带签名的位移)。它不是最佳地执行此操作,而是默认仅在每个带有显式内存操作数的指令上愚蠢地使用地址大小的前缀。但是a recent patch gets it to always use 64-bit rsp
甚至不对esp
使用地址大小前缀。
关于assembly - 输入新功能时rsp不会移动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47112183/