函数调用
来源:互联网 发布:淘宝盗用视频怎么处理 编辑:程序博客网 时间:2024/06/05 03:44
当调用者比如h调用某个函数f时,从编译器或者汇编语言角度来看,主要分以下几个步骤进行:
- h将实参按照从右向左的顺序一个个压入stack中。
- 执行一个转移指令call f
- f执行完函数体后,将返回值传入寄存器AX/EAX/RAX中。
- f执行转移指令ret
- h将实参从stack中一个一个弹出。
具体来说,从内存的角度看,函数h调用f时,Stack是按下面步骤发生变化的:
- 实参按照从右向左的顺序一个一个进入stack中。
- 函数调用指令之后的“下一条指令地址”进入stack中。
- 函数f中的局部变量加入到stack中。
- 函数f中的局部变量从Stack中弹出。
- “下一条指令地址”从stack中弱出,流入程序计数器寄存器IP中。
- 寄存器AX/EAX/RAX中的值流入到stack中h的局部变量(或者全局变量等)中。
- 调用函数f时的实参从stack中弹出。
那么,到底是谁将“下一条指令地址”放入stack中的呢?当然是调用者h了。其实这个功能是一条汇编指令call实现的,而不是简单的用push/pop/mov指令实现的。CALL指令的执行可以视为做了以下工作:
- 将“下一条指令地址”压入stack。
- 改变IP的值为被调用的函数的地址。
想来个直观点的说明,最好还是通过一个小程序。昨天用GCC已经做过测试,由于版本比较新,它做的优化太多了,比如它尽量使用寄存器进行参数传递而非 Stack,所以介绍起来比较麻烦。并且GCC使用的AT&T汇编格式比较难懂,还是用WINDOWS下都熟悉的MASM格式的汇编来列一下吧。 同时为了清晰,少费点口舌,就用可视化的工具VC++6.0来介绍。
首先,假设程序代码如下(很简单的):
int f(int a, int b)
{
return a*b;
}
int main(int argc, char *argv[])
{
int x = 0;
x = f(5,6);
++x;
return 0;
}
{
return a*b;
}
int main(int argc, char *argv[])
{
int x = 0;
x = f(5,6);
++x;
return 0;
}
0 0
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 调用函数
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 函数调用
- 调用函数
- 函数调用
- 函数调用
- 函数调用
- oracle 12c 多租户 pdb 恢复(单个pdb数据文件、非系统pdb表空间、整个pdb数据库)
- 跳台阶 与 矩形覆盖 为啥都是斐波那契数列
- ubuntu16.10安装MySQLdb
- DTD约束
- 关于mysql乱码问题的天坑
- 函数调用
- Numpy练习100题--难度★★★
- L1-033. 出生年
- springboot学习
- 0511
- Spring第三天主要 讲解spring整合JDBC操作
- 面试6
- MyBatis框架的学习(一)——MyBatis介绍
- NDK探究之旅《五》——指针和数组之间的关系