CSAPP函数调用

过程(函数调用的原理)

过程在高级语言中称为函数或者方法,一个过程包括将数据和控制从代码的一部分传递到另一部分。此外,它还必须在进入时为过程中的局部变量分配空间,并在退出时释放空间,大多数机器只提供了转移控制到过程和从过程中转移控制这种简单的指令。数据传递和局部变量的分配释放都是通过操纵程序栈来实现。合理的构建方法并调用,能大大增加代码的复用性,也能是代码结构更加清晰。

要提供对过程的机器级支持,必须要处理许多不同的属性。举例,假设过程 P 调用过程 Q ,Q 执行后返回 P 。这些动作包括下面一个或多个机制:

传递控制:在进入过程 Q  的时候,程序计数器必须被设置为 Q 的代码的起始地址,然后在返回的时候,要把程序计数器设置为 P 中调用 Q 后面那条指令的地址。

传递数据:P 必须能够向 Q 提供一个或多个参数,Q 必须能够向 P 返回一个值。

分配和释放内存:开始时,Q 可能需要为局部变量分配空间,而在返回前,又必须释放这些存储空间。

程序用栈来管理它的过程所需要的存储空间,栈和程序寄存器存放着传递控制和数据,分配内存所需的信息。栈在转移控制和数据传送过程中扮演重要角色。

下面以例子说明函数调用的过程:

源代码:下图中swap_add函数交换指针xp和yp指向的两个值,并返回两个值得和。函数calller调用局部变量arg1和arg2的栈帧地址进行计算返回结果。

汇编代码:下图可以看到calller代码开始的地方把栈指针减少16($16代表立即数),实际上就是在栈上分配16个字节,然后把$534分配到(%rsp)栈指针中,把$1057分配到(%rsp)+8的栈指针中,然后将两个地址分别存储到%rsi和%rdi中,调用call进行计算。继续,将(%rsp)的值放到(%rdx)中,调用subq指令将(%rsp)加8的地址放到%rdx中计算两个参数的差,imulq进行求和运算。然后将栈指针加上16释放栈帧。函数调用完毕。

过程的实现主要就是在于数据如何在调用者和被调用者之间传递,以及在被调用者当中局部变量内存的分配以及释放。而过程实现当中,参数传递以及局部变量内存的分配和释放都是通过以上介绍的栈帧来实现的,大部分情况下,我们认为过程调用当中做了以下几个操作(32位):

1、备份原有栈帧。调整当前帧指针到栈指针的位置。

pushl  %ebp ;movl  %esp,%ebp

2、建立起来的栈帧就是为被调用者准备的。当被调用者使用栈帧时,需要为局部变量分配预留内存。

subl $16 ,%esp

3、备份被调用者保存的寄存器的值,如果有值得话,备份的方式就是压入栈顶。

pushl  %ebx

4、使用建立好的栈帧。

5、恢复调用者寄存器中的值。

6、弹出返回地址,跳出当前过程,继续执行调用者的代码。

上面主要讲了栈规则的机制,解决了数据如何在调用者和被调用者之间传递,以及在被调用者当中局部变量内存的分配以及释放。

你可能感兴趣的:(CSAPP函数调用)