标签:
所谓过程在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; .endef
target:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $2, %eax
popl %ebp
ret
.align 2
.globl caller
.def caller; .scl 2; .type 32; .endef
caller:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $2, (%esp)
call target
addl $3, %eax
leave
ret
解释汇编之前先介绍几个指令
call
补充
call next
next:
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