浅析函数堆栈调用的过程

本文从汇编代码出发,探讨函数堆栈调用过程。讲解了esp和ebp寄存器的作用,以及eax、ebx、ecx、edx、esi、edi等寄存器的功能。通过简单的汇编指令示例,展示了数据传送、减法、取偏移地址、压栈和弹栈等操作。同时,分析了内存布局和函数调用时的参数传递规则,强调了被调用方如何保存调用方的栈底地址以确保返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从汇编的角度出发

int Add(int x,int y)
{
    int sum = 0;
    sum = x + y;
    return sum;
}

int main ()
{
    int a = 10;
    int b = 12;
    int ret = 0;
    ret = Add(a,b);
    return 0;
}

我们写了一段简单的函数来分析栈的调用,首先在我们从汇编代码入手来观察之前,我们先要了解一些简单的汇编指令和寄存器的意思

  1. esp ,栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

  2. ebp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部

  3. eax 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。

  4. ebx 是”基地址”(base)寄存器, 在内存寻址时存放基地址

  5. ecx 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器

  6. **edx **则总是被用来放整数除法产生的余数。

  7. esi/edi分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

简单的汇编指令:
mov:数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址
sub:减法指令
lea:取偏移地址
push:实现压入操作的指令是PUSH指令
pop:实现弹出操作的指令
call:用于保存当前指令的下一条指令并跳转到目标函数

内存布局

在这里插入图片描述
这里我画了一张内存布局图,看出栈是从高地址向低地址走向,空间大小有限,这里不多做说明

汇编代码

main的反汇编代码

int main()
	{
00271400  push        ebp  
00271401  mov         ebp,esp  
00271403  sub         esp,0E4h  
00271409  push        ebx  
0027140A  push        esi  
0027140B  push        edi  
0027140C  lea         edi,[ebp-0E4h]  
00271412  mov         ecx,39h  
00271417  mov         eax,0CCCCCCCCh  
0027141C  rep stos    dword ptr es:[edi]  
	    int a = 10;
0027141E  mov         dword ptr [a],0Ah  
	    int b = 20;
00271425  mov         dword ptr [b],14h  
	    int sum = Add(a, b);
0027142C  mov         eax,dword ptr [b]  
0027142F  push        eax  
00271430  mov         ecx,dword ptr [a]  
00271433  push        ecx  
00271434  call        Add (02711DBh)  
00271439  add         esp,8  
0027143C  mov         dword ptr [sum],eax  
	    return 0;
0027143F  xor         eax,eax  
	}
00271441  pop         edi  
00271442  pop         esi  
00271443  pop         ebx  
00271444  add         esp,0E4h  
0027144A  cmp         ebp,esp  
0027144C  call        __RTC_CheckEsp (0271136h)  
00271451  mov         esp,ebp  
00271453  pop         ebp  
00271454  ret  

Add的反汇编代码

int Add(int x, int y)
{
002713C0  push        ebp  
002713C1  mov         ebp,esp  
002713C3  sub         esp,0CCh  
002713C9  push        ebx  
002713CA  push        esi  
002713CB  push        edi  
002713CC  lea         edi,[ebp-0CCh]  
002713D2  mov         ecx,33h  
002713D7  mov         eax,0CCCCCCCCh  
002713DC  rep stos    dword ptr es:[edi]  
	int sum = 0;
002713DE  mov         dword ptr [sum],0  
	sum = x + y;
002713E5  mov         eax,dword ptr [x]  
002713E8  add         eax,dword ptr [y]  
002713EB  mov         dword ptr [sum],eax  
	return sum;
002713EE  mov         eax,dword ptr [sum]  
}
002713F1  pop         edi  
002713F2  pop         esi  
002713F3  pop         ebx  
002713F4  mov         esp,ebp  
002713F6  pop         ebp  
002713F7  ret  

画图分析

在这里插入图片描述

总结

形参由调用方在栈上开辟,入栈顺序为从右至左
被调用方返回值的带出(非类类型):
0-4字节:eax寄存器
4-8字节:edx、eax寄存器
8字节以上:临时量带出来
被调用方保存着调用方的栈底地址,因此调用完成后可以回到调用前
形参压栈完成后,保存着下一行指令的地址,因此可以沿着调用点继续往下执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值