【问题标题】:rsp doesn't move when entering new function [duplicate]输入新功能时rsp不动[重复]
【发布时间】:2018-04-17 03:42:21
【问题描述】:

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

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

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

【问题讨论】:

标签: assembly stack x86-64 red-zone


【解决方案1】:

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

看起来您编译 int foo{ int x = 4; return 0; } 时使用了 gcc -O0(优化已禁用),而 gcc 选择将 x 保留在 中,而不是将 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 以下内存的东西)。 red-zone 让编译器可以利用它,而无需特殊的编译选项(对于 SysV ABI 未定义 red-zone 的 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 也没有使用地址大小前缀。

【讨论】:

    猜你喜欢
    • 2016-02-24
    • 2014-11-03
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    • 2019-11-27
    • 1970-01-01
    相关资源
    最近更新 更多