当进入C函数时,我希望在反汇编中看到堆栈指针如何被减去足以为变量腾出空间,但是没有;我只看到变量的地址如何通过ebp直接访问,当esp仍然指向ebp时。
push %rbp
mov %rsp,%rbp
movl $0x4,-0x4(%rbp)
mov $0x0,%eax
pop %rbp
retq
我必须创建很多变量并初始化它们才能被计算机认真对待,看看是否有很多不必要的空间。差异真的是使用的空间量还是其他什么?如果是这样, 如果我要求大量的空间,只需要移动rsp来腾出空间吗?
答案 0 :(得分:1)
x86-64 System V ABI在RSP下面有一个128字节的红色区域,可以防止异步破坏,即拥有"拥有"通过功能。
看起来您使用int foo{ int x = 4; return 0; }
编译了gcc -O0
(已禁用优化),gcc选择将x
保留在red-zone中,而不是将rsp
调整为sub
"储备" /"分配"堆栈空间。 (有关更多链接/信息,请参阅red-zone tag wiki。)
这是红区的重点:在叶子函数中保存那些add
/ -O1
指令。
-O2
至少更具可读性,-O3
/ rsp
与您应该关注的代码相关。另请参阅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,信号处理程序是ebp
以下异步破坏内存的唯一因素。红区让编译器可以利用它而无需特殊的编译选项(并且对于32位模式没有这样的选项,其中SysV ABI没有定义红区)。即使使用整个程序优化,证明没有信号处理程序也是不可行的。
不,你不是。通过我只看到变量的地址如何通过ebp直接访问
rbp
访问会导致64位代码出错,因为堆栈超出了低4GB的地址空间(默认情况下至少在Linux上)。指针是64位的,因此gcc使用movl $0x4,-0x4(%ebp)
来访问它们。
使用地址大小前缀在64位模式下对esp
进行编码将会浪费代码大小,即使它没有发生错误。
有趣的事实:在指针为32位的x32 ABI(长模式下的ILP32)中,gcc经常使用地址大小前缀而不是额外的指令来截断寄存器中可能的高垃圾,并确保寻址模式换行为2 ^ 32而不是超出4GB(例如有一个带符号的位移)。它不是以最佳方式执行此操作,而是默认使用显式内存操作数在每条指令上使用地址大小前缀。但是a recent patch gets it to always use 64-bit rsp
而不是使用地址大小的前缀,即使是{{1}}。