4

当输入一个 C 函数时,我希望在反汇编中看到堆栈指针如何被减去足以为变量腾出空间,但没有;我只看到变量的地址是如何通过ebp直接访问的,当esp仍然指向ebp时。

push   %rbp
mov    %rsp,%rbp
movl   $0x4,-0x4(%rbp)
mov    $0x0,%eax
pop    %rbp
retq   

我必须创建很多变量并初始化它们以让计算机认真对待,看看是如何产生大量不需要的空间的。差异真的是使用的空间量还是其他?如果是这样,仅当我要求大量空间时才需要通过移动 rsp 腾出空间?

4

1 回答 1

2

x86-64 System V ABI 在 RSP 下方有一个 128 字节的红色区域,可防止异步破坏,即由函数“拥有”。

看起来您编译 int foo{ int x = 4; return 0; }时使用gcc -O0(禁用优化),并且 gcc 选择保留x而不是调整rsp为“保留”/“分配”堆栈空间。(有关更多链接/信息,请参阅红色区域标记 wiki。)

这是红色区域的重点:将这些sub/add指令保存在叶函数中。

顺便说一句,查看未优化的代码通常是浪费时间。 -O1至少更具可读性,并且-O2/-O3与您真正应该关心的代码相关。另请参阅如何从 GCC/clang 程序集输出中删除“噪音”?.

在没有信号处理程序的程序中,整个堆栈区域可以有效地用作红色区域。示例:代码高尔夫扩展精度斐波那契使用esp作为数组指针,因为pop它是快速和紧凑的。(AFAIK,信号处理程序是唯一会在下面异步破坏内存的东西rsp)。red-zone 让编译器可以利用它,而无需特殊的编译选项(对于 SysV ABI 未定义 red-zone 的 32 位模式,没有这样的选项)。即使对整个程序进行优化,证明没有信号处理程序也可能是不可行的。

我只看到变量的地址是如何通过ebp直接访问的

不,你没有。在 64 位代码中访问ebp会出错,因为堆栈超出了 4GB 的低地址空间(至少在 Linux 上是默认的)。指针是 64 位的,所以 gccrbp用来访问它们。

使用地址大小前缀movl $0x4,-0x4(%ebp)在 64 位模式下编码会浪费代码大小,即使它没有出错。

有趣的事实:在指针为 32 位的 x32 ABI(长模式下的 ILP32)中,gcc 通常使用地址大小前缀而不是额外指令来截断寄存器中可能存在的高垃圾并确保寻址模式在 2^32 处换行超出 4GB(例如有符号位移)。默认情况下,它不是以最佳方式执行此操作,而是在每条带有显式内存操作数的指令上愚蠢地使用地址大小前缀。但是最近的一个补丁让它始终使用 64 位rsp而不是使用地址大小前缀,即使是esp.

于 2017-11-04T15:36:21.730 回答