为何编译器选用调用保留寄存器而非栈保存函数调用值?
为什么编译器选择用调用保留寄存器而非栈保存返回值?
C 源代码
void callee(void); long call_and_ret_saved(long ToSave){ callee(); return ToSave; }
为了保存参数ToSave的值(以便调用callee后返回该值),GCC 和 Clang 生成了如下汇编代码:
编译器生成的汇编
call_and_ret_saved: pushq %rbx movq %rdi, %rbx call callee movq %rbx, %rax popq %rbx ret
问题:为何不直接用 push %rdi; call callee; pop %rax; ret; 的实现方式?是因为调用保留寄存器能让返回值更早可用吗?
回答:
核心原因是性能,而非返回值可用时机:
- 寄存器间的读写操作(
movq %rdi, %rbx、movq %rbx, %rax)比内存读写(push %rdi、pop %rax)快得多。寄存器操作的延迟和吞吐量都远优于内存访问,能避免不必要的栈内存读写开销。 - 从调用约定角度看,
%rbx是 x86-64 架构下的被调用者保留寄存器:callee函数如果需要使用%rbx,必须自行保存并恢复其值,因此存在%rbx里的参数值不会被破坏,完全符合调用规范。 - 若采用栈保存的方式,虽然逻辑上可行,但
push/pop涉及两次内存操作,且栈访问的延迟通常高于寄存器操作,会降低代码执行效率。
另外,返回值可用时机并非关键因素——两种方式都要等到 callee 返回后才能得到返回值,不存在谁更早可用的情况。
内容的提问来源于stack exchange,提问作者Petr Skocik
相关产品推荐
相关产品推荐

