空程序:

int main()

{

00411360  push        ebp       ;压入ebp

00411361  mov         ebp,esp     ;ebp = esp,保留esp,待函数调用完再恢复,因为函数调用中肯定会用到esp.

00411363  sub         esp,0C0h ;esp-=0C0h(192);为该函数留出临时存储区

;将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。

00411369  push        ebx       ;压入ebx

0041136A  push        esi       ;压入esi

0041136B  push        edi       ;压入edi

0041136C  lea         edi,[ebp-0C0h] ;读入[ebp-0C0h]有效地址,即原esp-0C0h,正好是为该函数留出的临时存储区的最低位

00411372  mov         ecx,30h   ;ecx = 30h(48),30h*4 = 0C0h

00411377  mov         eax,0CCCCCCCCh ;eax = 0CCCCCCCCh;

0041137C  rep stos    dword ptr es:[edi] ;重复在es:[edi]存入30个;0CCCCCCCCh? Debug模式下把Stack上的变量初始化为0xcc,检查未初始化的问题

return 0;

0041137E  xor         eax,eax   ;将eax清零,作为返回值

}

;各指针出栈

00411380  pop         edi          ;弹出edi

00411381  pop         esi          ;弹出esi

00411382  pop         ebx          ;弹出ebx

00411383  mov         esp,ebp      ;esp复原

00411385  pop         ebp          ;弹出ebp,也复原

00411386  ret                      ;返回

函数调用:

int _tmain(int argc, _TCHAR* argv[])

{

同上理解, 保存现场

004113D0  push        ebp

004113D1  mov         ebp,esp

004113D3  sub         esp,0F0h ;一共留了0F0h(240)空间

004113D9  push        ebx

004113DA  push        esi

004113DB  push        edi

004113DC  lea         edi,[ebp-0F0h]

004113E2  mov         ecx,3Ch ; ecx = 3C(60),3C*4 = 0F0h,

004113E7  mov         eax,0CCCCCCCCh

004113EC  rep stos    dword ptr es:[edi]

同上理解.

int a = 1, b = 2, c = 3;

定义a,b,c并存储在为函数留出的临时存储空间中.

004113EE  mov         dword ptr [a],1

004113F5  mov         dword ptr [b],2

004113FC  mov         dword ptr [c],3

int d = Fun1(a, b, c);

参数反向入栈

00411403  mov         eax,dword ptr [c]

00411406  push        eax

00411407  mov         ecx,dword ptr [b]

0041140A  push        ecx

0041140B  mov         edx,dword ptr [a]

0041140E  push        edx

调用Fun1

0041140F  call        Fun1 (4111DBh) ;Call调用时将下一行命令的EIP压入堆栈

恢复因为Fun1参数入栈改变的栈指针,因为Fun1有3个参数,一个整数4个字节,共0Ch(12)个字节

00411414add         esp,0Ch

00411417  mov         dword ptr [d],eax

将返回值保存在d中.

return 0;

返回值为0,让eax清零

0041141A  xor         eax,eax

}

恢复现场

0041141C  pop         edi

0041141D  pop         esi

0041141E  pop         ebx

以下全为运行时ESP检查:

先恢复因为为main预留空间而改变的栈指针

0041141F  add         esp,0F0h

00411425  cmp         ebp,esp

00411427  call        @ILT+320(__RTC_CheckEsp) (411145h)

正常时只需要以下两句就可以正常恢复esp,再出栈,又可以恢复ebp.

0041142C  mov         esp,ebp

0041142E  pop         ebp

0041142F  ret     ;main返回

int Fun1(int a, int b, int c)

{

同上理解, 保存现场

00411A70  push        ebp

00411A71  mov         ebp,esp

00411A73  sub         esp,0E4h ;留了0E4H(228)空间,

00411A79  push        ebx

00411A7A  push        esi

00411A7B  push        edi

00411A7C  lea         edi,[ebp-0E4h]

00411A82  mov         ecx,39h ; 39H(57)*4 = 0E4H(228)

00411A87  mov         eax,0CCCCCCCCh

00411A8C  rep stos    dword ptr es:[edi]

int d = 4, e = 5;

定义变量

00411A8E  mov         dword ptr [d],4

00411A95  mov         dword ptr [e],5

int f = Fun2(a, b, c, d, e);

再次参数反向入栈

00411A9C  mov         eax,dword ptr [e]

00411A9F  push        eax

00411AA0  mov         ecx,dword ptr [d]

00411AA3  push        ecx

00411AA4  mov         edx,dword ptr [c]

00411AA7  push        edx

00411AA8  mov         eax,dword ptr [b]

00411AAB  push        eax

00411AAC  mov         ecx,dword ptr [a]

00411AAF  push        ecx

调用Fun2

00411AB0  call        Fun2 (4111D6h) ;Call调用时将下一行命令的EIP压入堆栈

00411AB5  add         esp,14h ;恢复因为参数入栈改变的栈指针,因为Fun2有5个参数,一个整数4个字节,共14h(20)个字节

将Fun2函数的返回值(保存在eax中),赋值给f;

00411AB8  mov         dword ptr [f],eax

return f;

将保留在f中的Fun1的返回值保存在eax中返回

00411ABB  mov         eax,dword ptr [f]

}

恢复现场

00411ABE  pop         edi

00411ABF  pop         esi

00411AC0  pop         ebx

以下全为运行时ESP检查:

先恢复因为预留函数存储控件而改变的栈指针,

00411AC1  add         esp,0E4h

再比较ebp,esp,假如程序运行正确,两个值应该相等.

00411AC7  cmp         ebp,esp

00411AC9  call        @ILT+320(__RTC_CheckEsp) (411145h)

正常时只需要以下两句就可以正常恢复esp,再出栈,又可以恢复ebp.

00411ACE  mov         esp,ebp

00411AD0  pop         ebp

返回main从pop堆栈中的EIP开始执行

00411AD1  ret

int Fun2(int a, int b, int c, int d, int e)

{

同上理解, 保存现场

00412050  push        ebp

00412051  mov         ebp,esp

00412053  sub         esp,0E4h ;保留0E4H(228)

00412059  push        ebx

0041205A  push        esi

0041205B  push        edi

0041205C  lea         edi,[ebp-0E4h]

00412062  mov         ecx,39h ; 39H(57)*4 = 0E4H(228)

00412067  mov         eax,0CCCCCCCCh

0041206C  rep stos    dword ptr es:[edi]

int f  = 6, g = 7;

定义变量

0041206E  mov         dword ptr [f],6

00412075  mov         dword ptr [g],7

int h = a + b + c + d + e + f + g;

相加,存入a,再保存在h

0041207C  mov         eax,dword ptr [a]

0041207F  add         eax,dword ptr [b]

00412082  add         eax,dword ptr [c]

00412085  add         eax,dword ptr [d]

00412088  add         eax,dword ptr [e]

0041208B  add         eax,dword ptr [f]

0041208E  add         eax,dword ptr [g]

00412091  mov         dword ptr [h],eax

return  h;

将返回值h的值保存在eax中

00412094  mov         eax,dword ptr [h]

}

恢复现场

00412097  pop         edi

00412098  pop         esi

00412099  pop         ebx

0041209A  mov         esp,ebp

0041209C  pop         ebp

0041209D  ret ;返回fun1,从pop堆栈中的EIP开始执行

C++函数调用原理理解的更多相关文章

  1. JUC回顾之-ConcurrentHashMap源码解读及原理理解

    ConcurrentHashMap结构图如下: ConcurrentHashMap实现类图如下: segment的结构图如下: package concurrentMy.juc_collections ...

  2. POJ1523(割点所确定的连用分量数目,tarjan算法原理理解)

    SPF Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7406   Accepted: 3363 Description C ...

  3. java的classLoader原理理解和分析

    java的classLoader原理理解和分析 学习了:http://blog.csdn.net/tangkund3218/article/details/50088249 ClassNotFound ...

  4. js 闭包原理理解

    问题?什么是js(JavaScript)的闭包原理,有什么作用? 一.定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 很显然 ...

  5. 我也谈javascript闭包的原理理解

    参考原文:http://www.oschina.net/question/28_41112 前言:还是一篇入门文章.Javascript中有几个非常重要的语言特性——对象.原型继承.闭包.其中闭包 对 ...

  6. kalman filter卡尔曼滤波器- 数学推导和原理理解-----网上讲的比较好的kalman filter和整理、将预测值和观测值融和

    = 参考/转自: 1 ---https://blog.csdn.net/u010720661/article/details/63253509 2----http://www.bzarg.com/p/ ...

  7. debug 调试原理理解

    引言: 昨天,看了一篇文章,很受启发,记得之前听别的人远程调试过代码,觉得很神奇,在自己程序里打断点,连接远程服务器,开启调试后可以调用远程方法来看数据的输入和输出,不需要查找问题,重新部署,测试问题 ...

  8. shiro的原理理解

    1.shiro原理图如下: 框架解释: subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证.授权. securityManager:安全管理器,主体进行认证和授权都 ...

  9. JAVA 1.7并发之LinkedTransferQueue原理理解

    昨天刚看完BlockingQueue觉得好高级啊,今天扫到1.7就发现了升级版.... 如果对内容觉得不够充分,可以去看http://www.cs.rochester.edu/u/scott/pape ...

随机推荐

  1. 笔记51 Mybatis快速入门(二)

    Mybatis的CRUD 1.修改配置文件Category.xml,提供CRUD对应的sql语句. <?xml version="1.0" encoding="UT ...

  2. Codeigniter设置时区

    Codeigniter 3.x,在application/config/config.php 末尾加上 date_default_timezone_set("Asia/Shanghai&qu ...

  3. [JZOJ6355] 【NOIP2019模拟】普 24/100

    题目 题目大意 给你一个序列,对于所有\(k\in [1,n]\),求长度为\(k\)的子序列的最大权值,权值为\(a_1-a_2+a_3-...\pm a_k\) 思考历程 这题显然可以背包对吧-- ...

  4. 单源最短路径问题1 (Bellman-Ford算法)

    /*单源最短路径问题1 (Bellman-Ford算法)样例: 5 7 0 1 3 0 3 7 1 2 4 1 3 2 2 3 5 2 4 6 3 4 4 输出: [0, 3, 7, 5, 9] */ ...

  5. QT 环境变量配置

    //注意每个人的习惯不一样 在系统变量中新建: { QT = C:\Qt\Qt5.13.1\5.13.1 QT_TOOL = C:\Qt\Qt5.13.1\Tools } 然后在path 中加入 { ...

  6. Delphi txt文件读取及写入

    简介:Delphi支持三种文件类型:文本文件.记录文件.无类型文件.文本文件的读...   在进行win32开发中对文件的读写是最常用的操作之一 Delphi 支持三种文件类型:  文本文件.记录文件 ...

  7. 【缓存】缓存穿透、缓存雪崩、key重建方案

    一.缓存穿透预防及优化 缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步: 缓存层 ...

  8. thinkphp PATH_INFO支持

    如果发生在本地测试正常,但是一旦部署到服务器环境后会发生只能访问首页的情况,很有可能是你的服务器或者空间不支持PATH_INFO所致. 系统内置提供了对PATH_INFO的兼容判断处理,但是不能确保在 ...

  9. 线性dp——cf988F

    不是很难,dp[i]表示到位置i的最小花费 #include<bits/stdc++.h> using namespace std; #define ll long long #defin ...

  10. 【牛客提高训练营5B】旅游

    题目 吉老师的题时过一年还是不会做 从\(1\)号点出发经过每条边至少一次并且还要回到\(1\)号点,这跟欧拉回路的条件非常像,但是欧拉回路的实际上是"经过每一条边恰好一次并且回到出发点&q ...