int add(int a, int b) {int c = a + b;return c;
}int main() {int result = add(1, 2);return 0;
}
生成汇编代码:g++ -S Cplus.cpp -o Cplus.s
.file "Cplus.cpp".text.globl _Z3addii.def _Z3addii; .scl 2; .type 32; .endef.seh_proc _Z3addii
_Z3addii:pushq %rbp.seh_pushreg %rbpmovq %rsp, %rbp.seh_setframe %rbp, 0subq $16, %rsp.seh_stackalloc 16.seh_endprologuemovl %ecx, 16(%rbp)movl %edx, 24(%rbp)movl 16(%rbp), %edxmovl 24(%rbp), %eaxaddl %edx, %eaxmovl %eax, -4(%rbp)movl -4(%rbp), %eaxaddq $16, %rsppopq %rbpret.seh_endproc.def __main; .scl 2; .type 32; .endef.globl main.def main; .scl 2; .type 32; .endef.seh_proc main
main:pushq %rbp # 将寄存器的值压入栈中.seh_pushreg %rbp # 上一个栈帧的基址movq %rsp, %rbp # 当前栈帧的基址.seh_setframe %rbp, 0subq $48, %rsp # 预留空间.seh_stackalloc 48.seh_endprologuecall __mainmovl $2, %edxmovl $1, %ecxcall _Z3addii # 调用函数movl %eax, -4(%rbp)movl $0, %eaxaddq $48, %rsppopq %rbpret.seh_endproc.ident "GCC: (x86_64-win32-sjlj-rev0, Built by MinGW-W64 project) 8.1.0"
- 函数调用过程:
初始状态:rbp = rsp = 0x1000
地址 | 栈中的内容 | 执行的操作 | 指令 |
---|---|---|---|
0x0ff8 | 上一个函数的栈帧基址(rbp=0x1000) | rsp-=8 0x0ff8->rsp | pushq %rbp |
rbp=rsp=0x0ff8,表示当前函数栈帧的基址 | movq %rsp, %rbp | ||
0x0ff0 | eax值(0x0ff8,0x0ff4) | ||
0x0fe8 | |||
0x0fe0 | |||
0x0fd8 | |||
0x0fd0 | |||
0x0fc8 | rsp-=48 0x0fc8->rsp | subq $48, %rsp | |
0x0fc0 | 返回地址 | rsp-=8 0x0fc0->rsp | call __main |
0x0fb8 | 返回地址 | rsp-=8 0x0fb8->rsp | call _Z3addii |
0x0fb0 | main函数的栈帧基址(rbp=0x0ff8) | rsp-=8 0x0fb0->rsp | pushq %rbp |
0x0fa8 | eax值 (0x0fb0,0x0fa4) | rbp=rsp=0x0fb0,表示当前函数栈帧的基址 | movq %rsp, %rbp |
0x0fa0 | rsp-=16 0x0fa0->rsp | subq $16, %rsp | |
0x0f98 |
注意:
- 参数传递规则
前 4 个整数参数:通过寄存器传递(顺序:rcx, rdx, r8, r9)。
多余参数:通过栈传递(从右向左压栈)。
这是反汇编或编译器生成的代码,可能是调试版本或未优化的结果。实际参数应直接从寄存器读取: movl %ecx, 16(%rbp)
的问题
虽然 subq $48, %rsp 预留了 48 字节栈空间,但:
实际只用了 4 字节(保存返回值);
剩下的是 对齐 + 编译器保守行为 + SEH支持 的结果;
并不是异常,是很正常且常见的行为。
- 函数返回过程:
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %edx
movl 24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eaxaddq $16, %rsp # 释放空间
popq %rbp # rbp = *(rsp), rsp+=8
ret # 读取rsp获得返回地址,rsp+=8
- 返回到主函数后:
movl %eax, -4(%rbp) #
movl $0, %eax # 寄存器置于0
addq $48, %rsp # 释放空间
popq %rbp # rbp = *(rsp), rsp+=8
ret # 读取rsp获得返回地址,rsp+=8,最终rsp=0x1000(初始值)