You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段简单代码的汇编会修改栈指针%rsp?

关于栈指针%rsp修改的疑问

我正在学习汇编,想大致理解编译后的代码逻辑,也出于兴趣。我选了一个相对简单的示例:

int boo(int);
int bar(int, int, int);

int foo(int i) {
    int a = bar(boo(i), boo(i), boo(i));
    int b = bar(boo(i), boo(i), boo(i));
    return a + b;
}

对应的编译后汇编代码如下:

foo(int):
        pushq   %r13
        pushq   %r12
        pushq   %rbp
        pushq   %rbx
        movl    %edi, %ebx
        subq    $8, %rsp
        call    boo(int)
        movl    %ebx, %edi
        movl    %eax, %r12d
        call    boo(int)
        movl    %ebx, %edi
        movl    %eax, %ebp
        call    boo(int)
        movl    %r12d, %edx
        movl    %ebp, %esi
        movl    %eax, %edi
        call    bar(int, int, int)
        movl    %ebx, %edi
        movl    %eax, %ebp
        call    boo(int)
        movl    %ebx, %edi
        movl    %eax, %r13d
        call    boo(int)
        movl    %ebx, %edi
        movl    %eax, %r12d
        call    boo(int)
        movl    %r13d, %edx
        movl    %r12d, %esi
        movl    %eax, %edi
        call    bar(int, int, int)
        addq    $8, %rsp
        popq    %rbx
        addl    %ebp, %eax
        popq    %rbp
        popq    %r12
        popq    %r13
        ret

我疑惑的是:栈指针%rsp为何会被修改?看起来所有计算都通过寄存器完成,没有局部变量,为何需要用subq $8, %rsp在栈上分配空间?


解答

这是x86-64平台System V调用约定的强制要求:在执行call指令调用函数之前,栈指针%rsp必须保持16字节对齐。

我们一步步拆解栈的变化:

  1. 调用者调用foo时,call指令会先把8字节的返回地址压入栈,此时%rsp的地址为16n - 8(调用者调用foo前%rsp是16字节对齐的,即地址为16n),处于未对齐状态。
  2. 进入foo后,连续执行4次pushq(压入%r13、%r12、%rbp、%rbx),每次pushq让%rsp减少8字节,4次后%rsp地址变为16n - 40,此时%rsp模16的结果为8,仍然不满足对齐要求。
  3. 接下来要调用boo,必须让%rsp在call执行前回到16字节对齐状态,所以执行subq $8, %rsp,让%rsp变为16n - 48,刚好是16的倍数,符合调用约定。

这段栈空间并没有用来存储局部变量,只是为了满足调用约定的栈对齐要求。


参考资料

  • 如何去除GCC/Clang汇编输出中的“冗余”内容
  • AX、AH、AL如何映射到EAX
  • 64位架构中的汇编寄存器
  • Agner优化手册
  • X86调用约定之System V AMD64 ABI
  • Dyncall手册相关章节

内容的提问来源于Stack Exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:55:21