从指令角度掌握函数调用堆栈详细过程
c++代码
#include<iostream>
int sum(int a, int b)
{
int temp = 0;
temp = a + b;
return temp;
}
int main()
{
int a = 10;
int b = 20;
int ret = sum(a , b);
std::cout << "ret:" << ret << std::endl;
}
C++代码对应的汇编执行流程解析
以下是基于x86架构的汇编指令解析,展示代码的执行流程:
main函数执行流程:
; 函数入口,建立栈帧
main:
push ebp ; 保存调用者的ebp
mov ebp, esp ; 建立当前函数的栈帧
sub esp, 0Ch ; 为局部变量a、b、ret分配栈空间(12字节)
; 初始化变量a = 10
mov dword ptr [ebp-4], 0Ah ; [ebp-4]是变量a的地址
; 初始化变量b = 20
mov dword ptr [ebp-8], 14h ; [ebp-8]是变量b的地址
; 准备调用sum函数,参数入栈(从右到左)
push dword ptr [ebp-8] ; 压入b的值
push dword ptr [ebp-4] ; 压入a的值
; 调用sum函数
call sum ; 压入返回地址,跳转到sum函数
; 函数返回后
add esp, 8 ; 清理栈上的参数
mov dword ptr [ebp-0Ch], eax ; 将sum返回值存入ret变量([ebp-0Ch])
; 输出结果(简化表示)
; ... 调用cout相关代码 ...
; 函数返回
mov esp, ebp ; 恢复栈指针
pop ebp ; 恢复调用者的ebp
ret ; 返回
sum函数执行流程:
; sum函数实现
sum:
push ebp ; 保存调用者的ebp
mov ebp, esp ; 建立当前函数的栈帧
sub esp, 4 ; 为局部变量temp分配4字节空间
; 初始化temp = 0
mov dword ptr [ebp-4], 0 ; [ebp-4]是temp的地址
; 计算a + b
mov eax, dword ptr [ebp+8] ; 从栈中获取a的值(第一个参数)
add eax, dword ptr [ebp+0Ch] ; 加上b的值(第二个参数)
mov dword ptr [ebp-4], eax ; 结果存入temp
; 设置返回值
mov eax, dword ptr [ebp-4] ; 将temp的值存入eax寄存器(返回值)
; 函数返回
mov esp, ebp ; 恢复栈指针
pop ebp ; 恢复调用者的ebp
ret ; 返回,弹出返回地址
栈变化示意图
以下是程序执行过程中栈的变化(地址由高到低):
-
main函数刚进入时:
高地址 [ebp+4] : main函数的返回地址 [ebp] : 调用者的ebp值 [ebp-4] : 变量a (10) [ebp-8] : 变量b (20) [ebp-0Ch] : 变量ret (未初始化) 低地址 <-- esp -
调用sum函数前(参数入栈后):
高地址 [ebp+4] : main函数的返回地址 [ebp] : 调用者的ebp值 [ebp-4] : 变量a (10) [ebp-8] : 变量b (20) [ebp-0Ch] : 变量ret (未初始化) [esp+4] : 参数a (10) <-- [ebp+8] in sum [esp] : 参数b (20) <-- [ebp+0Ch] in sum 低地址 <-- esp -
进入sum函数后:
高地址 ... (main函数的栈帧) ... [ebp+8] : 参数a (10) [ebp+0Ch] : 参数b (20) [ebp] : main函数的ebp值 [ebp-4] : 局部变量temp 低地址 <-- esp -
sum函数返回后:
高地址 ... (恢复为调用sum前的状态) ... [ebp-0Ch] : 变量ret (30) <-- 已被sum的返回值更新 低地址 <-- esp
执行流程总结
- main函数初始化局部变量a和b
- 准备函数调用:将参数从右到左压栈
- 调用sum函数,自动压入返回地址
- sum函数建立自己的栈帧,计算a+b的结果
- sum函数通过eax寄存器返回计算结果
- main函数接收返回值并输出
- 程序执行结束
示意图

这个过程展示了函数调用时的栈帧建立、参数传递、局部变量存储和函数返回的完整机制。
浙公网安备 33010602011771号