C语言函数调用是怎么样一个过程?

        大多数CPU上的程序实现使用栈来支持函数调用操作,栈被用来传递函数参数、存储返回信息、临时保存寄存器原有的值以备恢复以及用来存储局部变量。

        函数调用操作所使用的栈部分叫做栈帧结构,每个函数调用都有属于自己的栈帧结构,栈帧结构由两个指针指定,帧指针(指向起始),栈指针(指向栈顶),函数对大多数数据的访问都是基于帧指针

下面是结构图

栈指针和帧指针一般都有专门的寄存器,通常使用ebp寄存器作为帧指针,使用esp寄存器做栈指针。

帧指针指向栈帧结构的头,存放着上一个栈帧的头部地址,栈指针指向栈顶。

来分析下面的程序,下面的程序时间的功能就是调用swap函数交换两个数的值,然后返回两个数的差。

下面是这个过程对应的栈结构

可以看出,在调用swap函数后,会为更改栈指针和帧指针的指向,为swap分配一个栈帧结构。

 

调用swap函数过程做了什么?

 1、将函数参数压栈(&b,&a)

2、将返回地址压栈

3、将当前帧指针所指的地址(ebp寄存器的值)压栈

4、移动帧指针(修改ebp寄存器)与栈指针(修改esp寄存器),为swap函数创建一个栈帧结构

由于将参数(&b,&a)压入栈中,所以在swap函数要访问&b&a时,可以通过%(ebp+8)%(ebp+12)访问。 swap函数结束后,会恢复帧指针与栈指针,然后继续运行。

下面是对应的汇编代码,通过汇编代码来看这一过程

使用gcc -Wall -S -o exch.S exch.c生成对应的汇编代码

24-25行:根据帧指针(-8(%ebp))取出变量b的地址存到eax寄存器中,然后将eax寄存器的值压栈

26-27行:根据帧指针(-4(%ebp))取出变量a的地址存到eax寄存器中,然后将eax寄存器的值压栈

28行:调用_swap函数,call会将返回地址压栈

3行:将ebp寄存器(当前帧指针的值)的值压入栈中

4行:改变ebp寄存器的值(帧指针的指向)

5行:将esp寄存器的值减4,起始就是将栈指针往下移,相当于创建了一个变量

7-15行:就是操作寄存器,交换两个数的值

16行:恢复帧指针和栈指针(即函数返回) 

 到此,函数的调用过程也就分析完了。

参考:《linux内核完全注释》

猜你喜欢

转载自blog.csdn.net/weixin_42462202/article/details/88317097