标签:
所谓过程在C语言中就是函数的意思.
本章将介绍,函数调用过程的细节.
IA32程序用栈来支持程序的运行,栈用来存放调用时候暂存的数据.
它可以:
每一段函数都会在栈中构建一块空间,名为栈帧.之所以叫栈帧是因为这块空间用栈指针和帧指针界定.
栈指针:%esp,s代表stack,它指向栈帧的顶部,该指针是可移动的.
帧指针:%ebp,b我猜应该是base,它指向栈帧的底部,该指针是不可移动的,常用它的地址加上偏移量来获取保存在栈中的数据,所以它又叫基址指针
当在一个函数中调用另一个函数时候,一般会先让%ebp指向%esp的位置,然后%esp自己往后跑,最终构建出一个栈帧空间.
为了描述栈帧,用一小段简单的程序举例
int target(int b){b=b+2;return b;}void claller(){int a=2;int c=target(a);}
汇编:
我用的是windows下的GCC
.file "1.c".text.align 2.globl target.def target; .scl 2; .type 32; .endeftarget:pushl %ebpmovl %esp, %ebpmovl 8(%ebp), %eaxaddl $2, %eaxpopl %ebpret.align 2.globl caller.def caller; .scl 2; .type 32; .endefcaller:pushl %ebpmovl %esp, %ebpsubl $4, %espmovl $2, (%esp)call targetaddl $3, %eaxleaveret
解释汇编之前先介绍几个指令
call
补充
call nextnext:pop %eax
该程序段是唯一能把程序计数器中的值保存到%exa的方式
ret
补充
在函数开头,栈指针会自动向下移动一段距离来开辟栈帧空间,这个移动的距离是根据这段函数用到的数据得出来.另外有时候这个空间并不是全部都用掉,因为GCC坚持一个x86编程指导方针,也就是一个函数使用的栈空间必须是16字节的整数倍,这种方式是为了保证数据的严格对齐,所以有时候编译器会分配这种永远不会用的空间.
在上面的例子可以看出,但调用一个函数时候,调用者(caller)不会覆盖被调用者(target)稍后要使用的寄存器的值.
比如在target开始的时候,它先把%ebp的值保存到栈中,要返回caller的时候在取出来用.这里是被调用者来负责寄存器数据不被覆盖.
IA32采用了统一的寄存器使用惯例来指示那些寄存器的数据由谁来保存.
内容是:
寄存器%eax,%edx,%ecx被划分为调用者保存的寄存器
寄存器%ebx,%esi,%edi划分为被调用者保存的寄存器
标签:
原文地址:http://www.cnblogs.com/Recoding/p/5294801.html