从指令角度掌握函数调用堆栈详细过程

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             ; 返回,弹出返回地址

栈变化示意图

以下是程序执行过程中栈的变化(地址由高到低):

  1. main函数刚进入时

    高地址
    [ebp+4]  : main函数的返回地址
    [ebp]    : 调用者的ebp值
    [ebp-4]  : 变量a (10)
    [ebp-8]  : 变量b (20)
    [ebp-0Ch] : 变量ret (未初始化)
    低地址  <-- esp
    
  2. 调用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
    
  3. 进入sum函数后

    高地址
    ... (main函数的栈帧) ...
    [ebp+8]  : 参数a (10)
    [ebp+0Ch] : 参数b (20)
    [ebp]    : main函数的ebp值
    [ebp-4]  : 局部变量temp
    低地址  <-- esp
    
  4. sum函数返回后

    高地址
    ... (恢复为调用sum前的状态) ...
    [ebp-0Ch] : 变量ret (30)  <-- 已被sum的返回值更新
    低地址  <-- esp
    

执行流程总结

  1. main函数初始化局部变量a和b
  2. 准备函数调用:将参数从右到左压栈
  3. 调用sum函数,自动压入返回地址
  4. sum函数建立自己的栈帧,计算a+b的结果
  5. sum函数通过eax寄存器返回计算结果
  6. main函数接收返回值并输出
  7. 程序执行结束

示意图

image

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

参考

1.x86汇编语言基础
2.《C语言》函数栈帧的创建与销毁--(内功)

posted @ 2025-09-30 21:51  焦涛  阅读(11)  评论(0)    收藏  举报