函数的调用过程

函数的调用过程

函数调用过程学习 笔记 主要是自己根据调用过程看汇编代码理解的知识,并不全面

栈帧介绍

在计算机的栈区大小在windows平台下位1M,在Linux平台下位8M

栈帧: 计算机把栈区分区域划分为栈帧,当函数需要调用栈空间计算机按栈帧进行分配栈空间

寄存器 函数调用的过程中需要使用的寄存器简介

esp寄存器:存放当前线程的栈顶指针 栈顶寄存器

ebp寄存器:存放当前线程的栈底指针 栈底寄存器

eip寄存器: 指向下一条指令的寄存器 指令寄存器

cal 调用指令

ret 返回指令

call:影响eip esp

ret:影响eip esp

源代码

int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int a = 10;
	int b = 20;
	int c;
	c = Add(a, b);
	cout << c;
	return 0;
}

源代码经过编译连接后成为可执行文件,执行可执行文件(进程)就会给这个进程分配内存空间(栈,堆,数据区,代码区),在分配的时候会有一个前期函数的调用用来初始化栈区,堆区,数据区,然后在由这个函数调用主函数

1.主函数是否是入口函数?

主函数在逻辑上是入口函数,但是物理上并不是入口函数

2.主函数中的变量地址如何确定?

主函数当中变量的地址都是以ebp为基准来确定的

函数的调用过程中 主函数中的参数 由 ebp栈底指针进行操作

在这里插入图片描述

函数调用会什么会进行现场保护?

程序在main函数当中执行由call指令 转到 Add函数执行 在Add函数执行完毕程序需要回到调用点处继续运行 所以把call的地址 入栈进行现场保护,因为是回到后续指令执行,所以把后续指令地址 入栈进行保护

001A32A5 C7 45 F8 0A 00 00 00 mov         dword ptr [a],0Ah  
    16: 	int b = 20;//主函数参数的定义
001A32AC C7 45 EC 14 00 00 00 mov         dword ptr [b],14h  
    17: 	int c=0;
001A32B3 C7 45 E0 00 00 00 00 mov         dword ptr [c],0  
    18: 	c = Add(a, b);
001A32BA 8B 45 EC             mov         eax,dword ptr [b]  
001A32BD 50                   push        eax  
    //先把 b的值给寄存器 eax 然后压栈eax   push 通过影响esp进行入栈
001A32BE 8B 4D F8             mov         ecx,dword ptr [a]  
001A32C1 51                   push        ecx
    //把c的值给寄存器ecx  然后压栈exc
    //这样就是Add函数的形参传递 从右先做传递 依次压栈
001A32C2 E8 E9 E1 FF FF       call        Add (01A14B0h)  
    //call命令影响 esp eip 
    
001A32C7 83 C4 08             add         esp,8 //被保护的值 
    //现场保护
    //程序在main函数当中执行由call指令 转到 Add函数执行 在Add函数执行完毕程序需要回到调用点处继续运行 所以把call的地址 入栈进行现场保护,因为是回到后续指令执行,所以把后续指令地址 入栈进行保护
    
001A32CA 89 45 E0             mov         dword ptr [c],eax  
    19: 	cout << c;
001A32CD 8B F4                mov         esi,esp  
001A32CF 8B 45 E0             mov         eax,dword ptr [c]  
001A32D2 50                   push        eax  
001A32D3 8B 0D B0 00 1B 00    mov         ecx,dword ptr [__imp_std::cout (01B00B0h)]  
001A32D9 FF 15 C0 00 1B 00    call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (01B00C0h)]  
001A32DF 3B F4                cmp         esi,esp  
001A32E1 E8 EF DF FF FF       call        __RTC_CheckEsp (01A12D5h)  
    20: 	return 0;
001A32E6 33 C0                xor         eax,eax  
    21: }

Add汇编代码

     9: int Add(int a, int b)
    10: {
004C2D40 55                   push        ebp  
    //入栈 ebp对ebp进行现场保护
004C2D41 8B EC                mov         ebp,esp  
    //把 esp 给ebp
004C2D43 81 EC C0 00 00 00    sub         esp,0C0h  
004C2D49 53                   push        ebx  
004C2D4A 56                   push        esi  
004C2D4B 57                   push        edi  
    //压栈主函数中使用的三个寄存器 需要进行保护
004C2D4C 8B FD                mov         edi,ebp  
004C2D4E 33 C9                xor         ecx,ecx  
004C2D50 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
    //对 esp  ebp的空间进行冲洗
004C2D55 F3 AB                rep stos    dword ptr es:[edi]  
004C2D57 B9 E6 20 4D 00       mov         ecx,offset _98E7F853_Day6_5@cpp (04D20E6h)  
004C2D5C E8 8C E6 FF FF       call        @__CheckForDebuggerJustMyCode@4 (04C13EDh)  
    11: 	return a + b;
004C2D61 8B 45 08             mov         eax,dword ptr [a]  
    // a的值给寄存器eax
004C2D64 03 45 0C             add         eax,dword ptr [b]  
    // b的值给寄存器eax  进行累加
    12: }
004C2D67 5F                   pop         edi  
004C2D68 5E                   pop         esi  
004C2D69 5B                   pop         ebx  
    //弹栈三个寄存器
004C2D6A 81 C4 C0 00 00 00    add         esp,0C0h  
004C2D70 3B EC                cmp         ebp,esp  
004C2D72 E8 5E E5 FF FF       call        __RTC_CheckEsp (04C12D5h)  
004C2D77 8B E5                mov         esp,ebp  
    //esp恢复到 ebp现场保护的地址
004C2D79 5D                   pop         ebp  
    //弹栈ebp  使得ebp继续成为栈底指针
004C2D7A C3                   ret  
    //ret 影响esp eip寄存器
    //把 ret弹出来  给给eip寄存器  这时候 弹出来的就是call(现场保护)后面的的一条指令

c 调用者完成 栈平衡

__stdcall __fastcall 回调函数约定 被调用者完成栈平衡

在这里插入图片描述

函数的调用过程

1.在主函数调用之前 ,主函数当中的变量 是通过ebp**(栈底指针)**作为基准值来确定的

2.当主函数调用被调用函数的时候,call会进行现场保护,把call的下一条指令入栈

3.先入栈ebp 对ebp进行现场保护

4.然后 把ebp 升到esp的位置

5.然后对esp-若干个字节 形成被调用函数的栈帧空间

6.入栈esi,edi等在主函数中使用到的寄存器

7.对esp – ebp内的若干字节空间进行冲洗 0xcccccccc进行填充

8.以ebp作为基准值 入栈被调用函数的变量

9.执行被调用函数

10.被调用函数有返回值的话,会由某一个寄存器来返回

11.pop 弹栈 esi edi等主函数需要使用的寄存器

12.esp 回到ebp的位置

13.弹栈 ebp (因为进行了现场保护) 弹栈使得ebp栈底指针回到主函数的栈底

14.ret 栈平衡操作

c的默认调用约定 调用者进行栈平衡

stdcall 回调函数调用约定 被调用者进行栈平衡

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值