函数调用¶
函数传参¶
参数传入方式¶
- 使用寄存器
- 使用全局变量
- 使用堆栈
返回值传出方式¶
- 使用寄存器
- 使用全局变量
C语言里函数传参方式¶
- C语言里
入参使用堆栈,传入顺序和函数原型里的参数顺序相反 - C语言里
出参使用寄存器EAX,或FPU的ST(0)
函数调用过程¶
父程序执行流程:
1. 将子函数参数按逆序压栈
2. 调用CALL指令,调用的程序返回地址也将入栈(地址入栈由call触发,无需手动入栈)
此时到子程序:
子程序返回值,为了正确弹出堆栈里面的返回地址 子程序里需要保存SP的值 将SP的值保存的BP
- 将
BP入栈,保存BP原始值 - 将
SP赋值给BP,保存SP原始值 - 减小
SP的值,为局部变量预留空间 - 子程序正常运行,使用堆栈
- 子程序执行...
BP复制到SP- 弹出BP的值,还原
BP - 调用
RET,子函数结束 - 修改
SP值,将子函数的局部变量弹出(只需移动栈顶位置,无实际弹出操作)
| ... | 堆底 |
| ... | |
| ... | |
| 传入参数2 | 12(%bp) |
| 传入参数1 | 8(%bp) |
| 返回地址 | 4(%bp) |
| BP | (%bp) |
| 局部变量1 | -4(%bp) |
| 局部变量2 | ←ESP |
函数定义¶
| Bash | |
|---|---|
1 2 3 4 5 6 7 8 9 10 | |
ENTER和LEAVE专门用来建立函数开头和结尾,不用手动创建。
系统调用¶
系统调用定义文件/usr/include/asm-generic/unistd.h
系统调用用寄存器BX,CX,DX,SI,DI传参
参数按寄存器顺序依次传入(书上写的与实际有出入,后续确认下)
C库调用¶
调用C库函数使用堆栈传参
内联汇编¶
在原始的C语言代码内创建函数的汇编语言代码,使用标准C编译器链接
格式:
asm("assembly code")
多行汇编代码用\n /隔开
关键字volatile可以禁用编译器对该段代码的优化优化
使用全局变量传参
asm("assembly code" : output locations: input operands : changed registers)
汇编代码:内联汇编代码
输出位置:输出值的寄存器和内存位置列表
输入操作:输入值的寄存器和内存位置列表
改变寄存器:汇编代码中被修改的寄存器列表