为什么这个函数将 RAX 压入堆栈作为第一个操作? [英] Why does this function push RAX to the stack as the first operation?
问题描述
在下面的 C++ 源代码的汇编中.为什么 RAX 被压入堆栈?
In the assembly of the C++ source below. Why is RAX pushed to the stack?
RAX,正如我从 ABI 理解的那样,它可以包含来自调用函数的任何内容.但是我们将它保存在这里,然后将堆栈向后移动 8 个字节.所以堆栈上的 RAX,我认为只与 std::__throw_bad_function_call()
操作相关......?
RAX, as I understand it from the ABI could contain anything from the calling function. But we save it here, and then later move the stack back by 8 bytes. So the RAX on the stack is, I think only relevant for the std::__throw_bad_function_call()
operation ... ?
代码:-
#include <functional>
void f(std::function<void()> a)
{
a();
}
输出,来自 gcc.godbolt.org
,使用 Clang 3.7.1 -O3:
Output, from gcc.godbolt.org
, using Clang 3.7.1 -O3:
f(std::function<void ()>): # @f(std::function<void ()>)
push rax
cmp qword ptr [rdi + 16], 0
je .LBB0_1
add rsp, 8
jmp qword ptr [rdi + 24] # TAILCALL
.LBB0_1:
call std::__throw_bad_function_call()
我确定原因很明显,但我正在努力弄清楚.
I'm sure the reason is obvious, but I'm struggling to figure it out.
这是一个没有 std::function
包装器的尾调用,用于比较:
Here's a tailcall without the std::function<void()>
wrapper for comparison:
void g(void(*a)())
{
a();
}
琐碎:
g(void (*)()): # @g(void (*)())
jmp rdi # TAILCALL
推荐答案
64 位 ABI 要求堆栈在 call
指令之前对齐到 16 个字节.
The 64-bit ABI requires that the stack is aligned to 16 bytes before a call
instruction.
call
将一个 8 字节的返回地址压入栈中,这打破了对齐方式,因此编译器需要在下一个 之前做一些事情将栈再次对齐到 16 的倍数调用
.
call
pushes an 8-byte return address on the stack, which breaks the alignment, so the compiler needs to do something to align the stack again to a multiple of 16 before the next call
.
(要求在 call
之前而不是之后对齐的 ABI 设计选择有一个次要的优势,即如果在堆栈上传递了任何 args,则此选择会使第一个 arg 与 16B 对齐.)
(The ABI design choice of requiring alignment before a call
instead of after has the minor advantage that if any args were passed on the stack, this choice makes the first arg 16B-aligned.)
推送一个不关心的值效果很好,并且可以比 sub rsp, 8
在 具有堆栈引擎的 CPU.(见评论).
Pushing a don't-care value works well, and can be more efficient than sub rsp, 8
on CPUs with a stack engine. (See the comments).
这篇关于为什么这个函数将 RAX 压入堆栈作为第一个操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!