# 函数调用原理
> [x86_64架构下的函数调用及栈帧原理](https://zhuanlan.zhihu.com/p/107455887)
>
> [简单函数的调用原理](https://zhuanlan.zhihu.com/p/64915630)
>
> [调用一个函数之后发生了什么?](https://segmentfault.com/a/1190000040387043)
[译:深入理解x64的代码模型](https://zhuanlan.zhihu.com/p/58774036)
[函数调用栈](https://www.jianshu.com/p/0299f56edab5)
首先需要关注下面这几个寄存器:
- `%rsp`:保存栈顶指针
- `%rbp`:保存栈底指针
- `%rbp~%rsp` 这一段向下伸展的区域,就是栈帧。
- `%rip`:保存下条指令的地址
- `%rdi`:保存函数的第一个参数
- `%rsi`:保存函数的第二个参数
- `%rax`:保存返回值
从rsp到rbp之间的这段内存就是当前函数的栈帧。
> 所以函数调用就是改变这两个值
### 函数调用
在对子函数进行调用时,栈帧情况如下:
![](assets/函数调用时栈帧情况.jpg)
- 调用者栈帧中,保存了被调用函数的参数以及调用者的返回地址,其流程大致如下:
**父函数将调用参数从右到左依次压栈->返回地址入栈->跳转到子函数起始地址->子函数将父函数栈帧起始地址(%rbp)压栈->将%rbp 的值设置为当前 %rsp 的值,开辟栈帧空间**
- 函数调用时的汇编指令如下:
`... ;参数压栈`
`call Func ;将返回地址压栈,并跳转到子函数处执行`
`... ;函数调用的返回位置`
`Func: ;子函数入口`
`pushq``%rbp ;保存父函数的帧指针,创建新栈帧`
`movq ``%rsp,``%rbp ;让``%rbp 指向新栈帧的起始位置`
`subq $N,``%rsp ;开辟栈帧空间供子程序使用`
以上过程由编译器自动完成。需要注意的是,父函数中进行参数压栈时,顺序为从右到左,但并不