函数调用的底层机制

函数调用的底层机制

ID:6667214

大小:37.50 KB

页数:5页

时间:2018-01-21

函数调用的底层机制_第1页
函数调用的底层机制_第2页
函数调用的底层机制_第3页
函数调用的底层机制_第4页
函数调用的底层机制_第5页
资源描述:

《函数调用的底层机制》由会员上传分享,免费在线阅读,更多相关内容在应用文档-天天文库

1、函数调用的底层机制(转贴)2006-10-1816:34这是一篇介绍C语言中的函数调用是如何用实现的文章。写给那些对C语言各种行为的底层实现感兴趣人的入门级文章。如果你是C语言或者汇编、底层技术的老鸟或是对这个问题不感兴趣,那么这篇文章只会耽误您的时间,您大可不必阅读他。当然如果前辈们愿意为我指出不足,我将十分感谢您的指导,并对耽误您宝贵的时间致歉。好了,废话少说!要研究这个问题,让我们先打开VC++吧。最好是6.0的,:-P。(什么你没有VC++,倒!....赶快装一个!@#$,要快!)首先,让我们在VC++里建立一个Win32ConsoleApplication项目,并建立主

2、文件fun.c。并输入以下内容。intfun(inta,intb){  a=0x4455;  b=0x6677;  returna+b;}intmain(){  fun(0x8899,0x1100);  return0;}之后,最关键的是在项目设置里关闭优化功能。也就是把Project->Setting->C/C++->Optimizations选为Disabled。编译器的优化在分析底层实现时大多数情况不太受欢迎。按键盘上的F10键,进入单步调试模式(StepOver)。看到你的main函数左侧有个黄色的小箭头了吗?那个就是程序即将执行的语句。按Alt+8。打开反编译窗口,看到

3、汇编语句了吗?是不是想这个样子==>00401078 push    1100h  0040107D push    8899h  00401082 call    @ILT+5(fun)(0040100a)  00401087 add     esp,8看到两个PUSH指令了吗?再看看后面的数字,不正是我们要传递的参数吗。奇怪阿?我们明明是先传递的0x8899怎么反倒先push1100h呢?呵呵,这个现象就叫Callingconversion。究竟是何方神圣,我在后面会详细的给你解释的。先别着急。随后的Call指令的作用就是开始调用函数了。接下来关掉反汇编窗口,在源代码窗口按F

4、11(StepInto)进入函数体。当看到那个黄色的小箭头指向函数名的时候再调出反汇编窗口(Alt+8)。你会看到类似下面的代码:1:  intfun(inta,intb){00401000 push    ebp00401001 mov     ebp,esp00401003 sub     esp,40h00401006 push    ebx00401007 push    esi00401008 push    edi00401009 lea     edi,[ebp-40h]0040100C mov     ecx,10h00401011 mov     eax,0CC

5、CCCCCCh00401016 repstos  dwordptr[edi]2:    a=0x4455;00401018 mov     dwordptr[ebp+8],4455h3:    b=0x6677;0040101F mov     dwordptr[ebp+0Ch],6677h4:    returna+b;00401026 mov     eax,dwordptr[ebp+8]00401029 add     eax,dwordptr[ebp+0Ch]5:  }0040102C pop     edi0040102D pop     esi0040102E pop

6、     ebx0040102F mov     esp,ebp00401031 pop     ebp00401032 retVC++就是好,还在难懂的汇编语句前加入了C语言的源代码。不过同时也有不少我们不需要的代码。因此,你只需要关心红色的部分就可以了。奇怪阿?不是参数都用push传递了吗?怎么没看到被pop出来?问题其实是这样,当你调用Call进入函数的时候Call背着你做了一件事。call把它下一条语句的地址push进了堆栈。(旁人:什么!这是为什么?)原因很简单,因为函数调用完了,要用ret返回。而ret怎么知道返回哪里呢?对了,ret指令pop了call指令push给

7、他的地址(搞清楚这个关系哦),然后返回到了这个地址。call和ret配合的如此绝妙,一个PUSH一个POP肯定不会让堆栈不平衡的(老外叫nostackunwinding)。现在明白了,如果你来个popeax,那eax里面是什么?当然是ret要用的返回地址了。好啦,你要是popeax就等于抢了ret要用的东西了。不论曾程序流程和道德标准上你做的都不对:-P。可是怎么在函数体里使用参数呢?问题其实并不难,既然参数在堆栈里我们就可以使用esp(堆栈指针)来访问了。不过,我相信你也想到了

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。