码迷,mamicode.com
首页 > 其他好文 > 详细

C函数调用 栈

时间:2015-04-13 22:36:03      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:

这篇blog试图说明这么一个问题,当一个c函数被调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的。这些细节跟操作系统平台及编译器的实现有关,下面的描述是针对运行在Linux的gcc编译器而言的。c语言的标准并没有描述实现的方式。所以,不同的编译器、不同的操作系统都可能有自己的建立栈帧的方式。

下面先看一个典型的栈帧:

技术分享

上面个的这个图是一个典型的栈帧,图中,栈顶在上,地址空间往下增长。

在看看这个栈对应的函数代码:

int foo(int arg1, int arg2, int arg3);

并且假设foo有两个局部的int变量(各占4个字节).

在上面的栈帧对应的场景中,main调用foo,而程序的控制仍在foo中。这里,main是调用者(caller),foo是被调用者(callee)。

ESP被foo使用来指示栈顶,EBP相当于一个“基准指针”。从main传递到foo的参数以及foo本身的局部变量都可以通过这个基准指针为参考,加上偏移量找到。

由于被调用者允许使用EAX、ECX和EDX寄存器,所以如果调用者希望保存这些寄存器的值,就必须在调用子函数之前显式地把它们保存在栈中。另一方面,如果除了上面提到的几个寄存器,被调用者还想使用别的寄存器,比如EBX、ESI和EDI,那么,被调用者就必须在栈中保存这些被额外允许使用的寄存器,并在调用返回前恢复它们。也就是说,如果被调用者只使用约定的EAX、ECX和EDX寄存器,它们由调用者负责保存并恢复,但是如果被调用者还额外的使用了其他的寄存器,则必须有被调用者自己保存并恢复这些寄存器的值。

传递给foo的参数被压到栈中,最后一个参数先进栈,所以第一个参数是位于栈顶的。foo中声明的局部变量以及函数执行过程中需要用到的一些临时变量也都存在栈中。

小于等于4个字节的返回值会被保存到EAX寄存器中,如果大于4字节,小于8字节,那么EDX也会被用来保存返回值。如果返回值占用的控件还要大,那么调用者会向被调用者传递一个额外的参数,这个额外的参数指向将要保存返回值的地址。用c语言来说,就是函数调用:

x = foo(a, b, c);

被转化为:

foo(&x, a, b, c);

注意,这仅仅在返回值占用大于8个字节时才发生。有的编译器不用EDX保存返回值,所以当返回值大于4个字节时,就用这种转换。

http://www.cnblogs.com/dahai/archive/2011/07/29/2120651.html

http://www.cnblogs.com/DylanWind/archive/2008/12/08/1349822.html

http://www.cnblogs.com/shitouer/archive/2010/04/05/1704554.html

http://johnlxj.diandian.com/post/2011-03-20/16690291

http://www.cnblogs.com/dolphin0520/archive/2011/04/04/2005061.html

http://blog.chinaunix.net/uid-29584360-id-4207364.html

http://blog.csdn.net/zsy2020314/article/details/9429707

http://www.360doc.com/content/12/1009/13/1317564_240416017.shtml

C函数调用 栈

标签:

原文地址:http://www.cnblogs.com/stemon/p/4423288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!