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

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

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(初始值)

相关文章:

  • Softhub软件下载站实战开发(二):项目基础框架搭建
  • 【FineDance】训练:accelerate config 的作用
  • 项目管理工具在并行管理中如何充分发挥作用
  • c++中vector的使用
  • 性能测试详解
  • Java面向对象this关键字和static关键字
  • 【LUT技术专题】4DLUT代码讲解
  • 单测时如何让 mock 的接口在长链路调用时一直生效
  • XCTF-misc-base64÷4
  • [直播推流] 编译 librtmp 库
  • cannot allocate memory in static TLS block昇腾910报错
  • 详解智能指针
  • 会计 - 财务报告
  • IO之详解cin(c++IO关键理解)
  • Java基础复习之static
  • 【数据集成与ETL 04】dbt实战指南:现代化数据转换与SQL代码管理最佳实践
  • 修改Typora快捷键
  • XCTF-misc-Test-flag-please-ignore
  • 【redis——缓存雪崩(Cache Avalanche)】
  • 实习记录1
  • 网站开发怎样转h5页面/论坛推广怎么做
  • 怎么做视频平台网站/给公司做网站的公司
  • 中国投诉网站做袜子机器多少钱一台/百度ai人工智能
  • 北京网站建设维护/优秀营销软文范例800字
  • 哪个网站建设公司/steam交易链接怎么看
  • 网站怎么做百度推广/seo网站优化师