1 空函数
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  ;返回

2 函数调用
 
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)个字节
00411414 add 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. Python使用Ctypes与C/C++ DLL文件通信过程介绍及实例分析

    项目中可能会经常用到第三方库,主要是出于程序效率考虑和节约开发时间避免重复造轮子.无论第三方库开源与否,编程语言是否与当前项目一致,我们最终的目的是在当前编程环境中调用库中的方法并得到结果或者借助库中 ...

  2. [20190401]跟踪dbms_lock.sleep调用.txt

    [20190401]跟踪dbms_lock.sleep调用.txt --//自己在semtimedop函数调用理解错误,加深理解,跟踪dbms_lock.sleep调用的情况. 1.环境:SCOTT@ ...

  3. Python开发【第九篇】:协程、异步IO

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回 ...

  4. 【Python】【异步IO】

    # [[异步IO]] # [协程] '''协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在 ...

  5. 【Python】协程

    协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在 ...

  6. 一步一步pwn路由器之radare2使用实战

    前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 前文讲了一些 radare2 的特性相关的操作方法.本文以一个 c ...

  7. python 协程(单线程中的异步调用)(转廖雪峰老师python教程)

    协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在 ...

  8. 【转载】python-协程

    转载自:廖雪峰的官方网站 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层 ...

  9. python的协程和_IO操作

    协程Coroutine: 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行. 注意,在一个子程序中中断,去执行其他子程序,不是函数调用,有点 ...

随机推荐

  1. mac 添加环境变量

    1.Mac系统的环境变量,加载顺序为: a. /etc/profile b. /etc/paths c. ~/.bash_profile d. ~/.bash_login e. ~/.profile ...

  2. Python之逻辑运算符

    这一小节我在动笔之前犹豫到底要不要动手写,虽然简单但是防止遗忘,博主还是决定记录一下.Python中运算符主要分为算术运算符,赋值运算符,比较运算符,逻辑运算符以及成员运算符.下面详细记录这5种运算符 ...

  3. XSS攻击的防御

    XSS攻击的防御 XSS 攻击是什么 XSS 又称 CSS,全称 Cross SiteScript,跨站脚本攻击,是 Web 程序中常见的漏洞,XSS 属于被动式且用于客户端的攻击方式,所以容易被忽略 ...

  4. C# 调用键盘

    首先我们说的键盘指的是:tabtip和osk.但这两个所在的位置不同,样貌也不一样 C:\Windows\System32\osk.exe C:\Program Files\Common Files\ ...

  5. pyspider的基本操作

    一.安装 pip install pyspider 1.修改 pyspider/webui/webdav.py 第209行:否则启动会报错 把: 'domaincontroller': NeedAut ...

  6. element-ui多选框reserve-selection指定row-key保留数据更新之前的数据

    element-UI 的table表格数据有提供多项框的功能,只要在表格列中多加一列就可以选择表格的数据 但是有时候表格的数据是有分页的,分页一般是要重新请求后台数据,这样上一页也就是上一次请求的数据 ...

  7. 使用 PuTTY 时遇到错误:“expected key exchange group packet from server”

    情况 使用 PuTTY 通过 SSH 访问 ProxySG 或 Advanced Secure Gateway (ASG) 时,您会看到如下错误:"expected key exchange ...

  8. Gradle发布项目到 maven 之novoda/bintray-release(3)

    novoda/bintray-release 使用这个插件上传比较简单,只需要两步就可以 1.在项目根目录下的 build.gradle 添加插件依赖 // Top-level build file ...

  9. pyspark 读写csv、json文件

    from pyspark import SparkContext,SparkConf import os from pyspark.sql.session import SparkSession de ...

  10. [转]ClassPath是什么

    from: https://my.oschina.net/GivingOnenessDestiny/blog/603505 classpath 是什么classpath实际上就是编译后的 以 clas ...