汇编分析函数调用时栈空间情况

  • 栈:往低地址方向生长
     栈中填充 cc --> int3(汇编指令):起到中断的作用。即使栈被当做代码段来执行,也不会出现大问题。
  • esp:栈顶指针。通过push、pop操作
     push 4:压栈,减
     pop eax:出栈,加
     call 地址:将下一条指令地址压栈
  • ebp:栈底指针。局部变量的地址都是相对与他的。(参数+;局部变量-)

函数调用

	test(1, 3);
//将函数参数压入栈空间
00D21868  push        3  
00D2186A  push        1 
//调用 __empty_global_delete,后jmp到test函数代码,同时将下条指令的地址压栈
00D2186C  call        __empty_global_delete (0D213B1h)  
//因为压入了两个参数,所以要出栈。堆栈平衡
00D21871  add         esp,8  

void test(int val1, int val2)
{
//将ebp压栈,同时ebp=esp都在栈顶  
00D21800  push        ebp  
00D21801  mov         ebp,esp  
//指定栈空间大小
00D21803  sub         esp,0C0h  
//保护现场
00D21809  push        ebx  
00D2180A  push        esi  
00D2180B  push        edi  

00D2180C  lea         edi,[ebp-0C0h]  
00D21812  mov         ecx,30h  
00D21817  mov         eax,0CCCCCCCCh  
00D2181C  rep stos    dword ptr es:[edi]  
00D2181E  mov         ecx,offset _280923C9_main@cpp (0D2C029h)  
00D21823  call        @__CheckForDebuggerJustMyCode@4 (0D21311h)  
	return;
}
//恢复现场
00D21828  pop         edi  
00D21829  pop         esi  
00D2182A  pop         ebx
//栈顶回到压入test函数参数、压入ebp后的栈顶位置  
00D2182B  add         esp,0C0h  
00D21831  cmp         ebp,esp  
00D21833  call        __RTC_CheckEsp (0D2123Ah)  
//ebp回到栈顶
00D21838  mov         esp,ebp  
00D2183A  pop         ebp  
//执行主函数call后,保存地址的指令
00D2183B  ret  

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
绝大部分编译器在Debug下,会在所分配的空间前/后添加一些额外的空间,并根据不同的情况为这些额外的空间设定特定的初值。当这些初值被用户程序修改时,就说明程序发生了越界等错误行为。 在Release下,将取消这些额外的空间,并进行优化(如果你定义的变量(部分类对象除外,因为类有构造和析构)未被使用过,将被忽略,也就是说,不会为它分配空间)。
在这里插入图片描述

函数调用过程是程序中常见的一种操作,它通常涉及到参数传递、栈帧的建立与销毁、返回值的传递等多个方面。从汇编的角度来看,函数调用过程可以分为以下几个步骤: 1. 将函数的参数压入栈中。在调用函数,需要将函数所需的参数传递给它。这些参数通常以一定的顺序压入栈中,以便在函数内部使用。在 x86 架构中,参数的传递是通过将参数压入栈顶实现的。 2. 调用函数函数调用的指令通常是 CALL 指令。在调用函数前,需要将函数的入口地址压入栈中,以便在函数执行完毕后返回到调用位置。CALL 指令会将当前的程序计数器(PC)压入栈中,并将函数的入口地址作为新的 PC。 3. 建立栈帧。在函数被调用,需要为函数建立一个独立的栈帧,以便在函数内部使用局部变量和临变量。栈帧通常包括以下几个部分:返回地址、旧的基址指针、局部变量和临变量。在 x86 架构中,栈帧的建立是通过将 ESP 寄存器减去一个固定的值实现的。 4. 执行函数。在函数被调用后,CPU 会跳转到函数的入口地址并开始执行函数函数内部可以通过栈中的参数和局部变量完成相应的计算和操作。 5. 返回值传递。在函数执行完毕后,需要将函数的返回值传递给调用者。在 x86 架构中,函数的返回值通常通过 EAX 寄存器传递。 6. 销毁栈帧。在函数执行完毕后,需要将栈帧销毁,以便释放栈空间。栈帧的销毁通常是通过将 ESP 寄存器还原到旧的基址指针处实现的。 7. 返回到调用位置。在函数执行完毕后,需要返回到函数被调用的位置。在 x86 架构中,返回指令通常是 RET 指令。RET 指令会将栈顶的返回地址弹出,并将其作为新的 PC。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值