【问题标题】:Why am I getting "popq %rbp" instead of "leave"? [duplicate]为什么我得到“popq %rbp”而不是“leave”? [复制]
【发布时间】:2015-04-04 03:02:18
【问题描述】:

我看不出我做错了什么,这是我的 C 代码:

main() {
    int i = 0;
    if (i == 0) i++;
    return 0;
}

使用 gcc -S test.c 编译

我期待的是“leave”而不是“popq %rbp”。

.L2:
movl $0, %eax
popq %rbp
ret

【问题讨论】:

  • main() 应该是int main(void)
  • 编译时添加-fomit-frame-pointer并观察输出。
  • %rsp 仍然指向正确的位置时,不需要leavemov %rbp, %rsp 部分,因此pop %rbp 更快。如果gcc 需要一个帧指针并且它必须保留一些额外的堆栈空间,它仍将使用leave(具有大多数调整选项)。

标签: c assembly


【解决方案1】:

我看不出我做错了什么

由 GCC 决定是否使用 ENTER/LEAVE。
由于即使是 INTEL 也不赞成使用 ENTER/LEAVE,所以 GCC 不再使用它也就不足为奇了。
这里也不需要movq %rbp,%rsp,所以你只找到了popq %rbp

【讨论】:

  • gcc-4.8 确实偶尔会发出leave。可能与对齐或函数大小有关。
  • @EOF:如果 RSP 已经指向正确的位置,它只会使用 POP。否则它使用 LEAVE,例如在具有 C99 可变长度数组的函数的末尾。 (gcc6.2 仍然这样做,就像在这个例子中:godbolt.org/g/xRsk0m)。 clang 使用 mov / pop。 Agner Fog 说 LEAVE 是 3 uops,但我想知道他的测量方法是否考虑了额外的堆栈引擎 uops。 (例如,mov %rbp, %rsp / pop %rbp 的序列也将是每对 3 uop)。
【解决方案2】:

Intel64 和 IA-32 架构软件开发人员手册说:

LEAVE 指令没有任何操作数,它反转前面ENTER 指令的操作。 LEAVE 指令将EBP 寄存器的内容复制到ESP 寄存器中,以释放分配给该过程的所有堆栈空间。然后它从堆栈中恢复EBP 寄存器的旧值。这同时将ESP 寄存器恢复为其原始值。随后的RET 指令可以删除调用程序压入堆栈以供过程使用的所有参数和返回地址。

和 gcc 手动执行此操作。

【讨论】:

    猜你喜欢
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    相关资源
    最近更新 更多