当前位置: 首页 > ai >正文

函数调用过程中的栈帧变化

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->rsppushq %rbp
rbp=rsp=0x0ff8,表示当前函数栈帧的基址movq %rsp, %rbp
0x0ff0eax值(0x0ff8,0x0ff4)
0x0fe8
0x0fe0
0x0fd8
0x0fd0
0x0fc8rsp-=48 0x0fc8->rspsubq $48, %rsp
0x0fc0返回地址rsp-=8 0x0fc0->rspcall __main
0x0fb8返回地址rsp-=8 0x0fb8->rspcall _Z3addii
0x0fb0main函数的栈帧基址(rbp=0x0ff8)rsp-=8 0x0fb0->rsppushq %rbp
0x0fa8eax值 (0x0fb0,0x0fa4)rbp=rsp=0x0fb0,表示当前函数栈帧的基址movq %rsp, %rbp
0x0fa0rsp-=16 0x0fa0->rspsubq $16, %rsp
0x0f98

注意:

  1. 参数传递规则​​
    ​​前 4 个整数参数​​:通过寄存器传递(顺序:rcx, rdx, r8, r9)。
    ​​多余参数​​:通过栈传递(从右向左压栈)。
    这是反汇编或编译器生成的代码,可能是调试版本或未优化的结果。实际参数应直接从寄存器读取:
  2. 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(初始值)
http://www.xdnf.cn/news/14171.html

相关文章:

  • 普通Dom转换为可拖拽、最大化、最小化窗口js插件
  • 【在线五子棋对战】六、项目结构设计 工具模块实现
  • 【unitrix】 1.6 数值类型基本结构体(types.rs)
  • 商用油烟净化器日常维护的标准化流程
  • Arduino入门教程:4-1、代码基础-进阶
  • 静态变量详解(static variable)
  • 微博项目(总体搭建)
  • Javascript什么是原型和原型链,八股文
  • java面试总结-20250609
  • 数据结构 学习 图 2025年6月14日 12点57分
  • spring如何处理bean的循环依赖
  • NuttX 调度器源码学习
  • 吃透 Golang 基础:方法
  • 湖南源点(市场研究)咨询 DNF下沉市场用户研究项目之调研后感
  • 03、继承与多态
  • 使用C/C++的OpenCV 构建人脸识别并自动抓拍系统
  • 使用DuckDB查询DeepSeek历史对话
  • AI首次自主发现人工生命
  • C++编程语言
  • Spring Cloud 原生中间件
  • Linux免驱使用PCAN,使用方法以Ubuntu为例
  • Java基础复习之static
  • Dify动手实践教程1
  • Day 49 训练
  • 1.4、SDH网状拓扑
  • 5、ZYNQ PL 点灯--流水灯
  • 深入解析JVM类加载机制
  • 人工智能学习22-Pandas
  • Java大模型开发入门 (7/15):让AI拥有记忆 - 使用LangChain4j实现多轮对话
  • 【Linux知识】curl命令行从入门到进阶实战