跳转至

函数调用


函数传参

参数传入方式

  • 使用寄存器
  • 使用全局变量
  • 使用堆栈

返回值传出方式

  • 使用寄存器
  • 使用全局变量

C语言里函数传参方式

  • C语言里入参使用堆栈,传入顺序和函数原型里的参数顺序相反
  • C语言里出参使用寄存器EAX,或FPU的ST(0)

函数调用过程

父程序执行流程:
1. 将子函数参数按逆序压栈
2. 调用CALL指令,调用的程序返回地址也将入栈(地址入栈由call触发,无需手动入栈)

此时到子程序:

子程序返回值,为了正确弹出堆栈里面的返回地址 子程序里需要保存SP的值 将SP的值保存的BP

  1. BP入栈,保存BP原始值
  2. SP赋值给BP,保存SP原始值
  3. 减小SP的值,为局部变量预留空间
  4. 子程序正常运行,使用堆栈
  5. 子程序执行...
  6. BP复制到SP
  7. 弹出BP的值,还原BP
  8. 调用RET,子函数结束
  9. 修改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
.type function_name, @function
function_name:
    pushl %ebp
    movl %esp, %ebp
    ...
    ...
    ...
    movl %ebp, %esp
    popl %ebp
    ret
ENTERLEAVE专门用来建立函数开头和结尾,不用手动创建。

系统调用

系统调用定义文件/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)
汇编代码:内联汇编代码
输出位置:输出值的寄存器和内存位置列表
输入操作:输入值的寄存器和内存位置列表
改变寄存器:汇编代码中被修改的寄存器列表