分享

关于c语言在函数调用过程中栈布局动态变化的讨论

 zhouADNjj 2014-03-11
    测试环境:X86下Ubuntu12.04 +gcc4.6.3

引言:任何一种编程语言都会提供相应的机制对数据和过程进行抽象,同时还需要为数据的存储提供内存访问模型,以满足图灵完备性。说到编程语言就不可不提编译器,编译器以生成机器代码的形式向程序员提供了两种抽象模型:一是定义了指令格式行为及寄存器状态的ISA;二是虚拟地址空间,虽然这涉及到物理内存、内存控制器以及操作系统的软件层。

对c语言的过程调用,可大致分为三个阶段:调用前主调函数准备阶段,被调函数执行阶段以及控制返回阶段。
1、调用前准备
(1):实参入栈,最后一个参数最先入栈,第一个参数最后入栈(要视具体平台)注意:在参数个数比较少的情况下,编译器会将参数拷贝到寄存器中从而提高速度,当然这里还存在寄存器保存的问题,这些对于高级语言程序员来说是透明的,此时esp寄存器指向第一个参数的低地址位置
(2):返回地址入栈,call指令的下一条指令的地址。push作为入栈指令其实是分为两条指令完成的:R[%esp]<---R[%esp] - 4 ;M[R[%esp]]<---value
2、被调函数执行
(1):程序控制流程的跳转,控制从主调函数到被调函数的转移
(2):保存caller的栈帧指针 pushl %ebp
(3):创建被调函数栈帧 movl %esp,%ebp,此时ebp和esp指向相同的位置,即保存的caller的栈帧的低地址
(4):如果需要可以为局部变量分配空间,通过subl $16, %esp的方式,分配16个字节的局部空间
(5):执行具体计算,直到计算完成
(6):销毁局部变量,通过addl $16, %esp,当然也可以一步到位movl %ebp,%esp
(7):恢复caller栈帧指针 popl %ebp
3、控制返回
ret指令其实执行了:popl %eip,将下一条指令恢复,如果函数有返回值则保存在eax中

注意:
1、一些特殊寄存器的用途,eip指令指针,esp堆栈指针,eax函数的返回值,ebx存基址,ecx循环时候使用。
2、在被调函数中,ebp+8是第一个参数,ebp+12第二个参数,以此类推,如下图

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多