天天看点

C 与汇编程序的相互调用

文章目录

  • ​​C 函数之间相互调用​​
  • ​​C 程序调用汇编程序​​
  • ​​汇编程序调用 C 程序​​
赵炯;《Linux 内核完全注释 0.11 修正版 V3.0》Chapte 3.

C 函数之间相互调用

大多数 CPU 上的程序实现使用栈来支持函数调用操作。栈被用来传递函数参数、存储返回信息、临时保存寄存器原有值以备恢复以及用来存储局部数据。

单个函数调用操作所使用的栈部分被称为栈帧结构,在函数执行过程中,栈指针 esp 会随着数据的入栈和出栈而移动,因此函数中对大部分数据的访问都基于帧指针 ebp 进行:

  • ebp:帧指针;
  • esp;栈指针;
C 与汇编程序的相互调用
对于函数 A 调用函数 B 的情况,传递给 B 的参数包含在 A 的栈帧中,当 A 调用 B 时,函数 A 的返回地址(调用返回后继续执行的指令地址)被压入栈中,栈中该位置也明确指明了 A 栈帧的结束处。而 B 的栈帧则从随后的栈部分开始。

为了保证某一时刻只有一个函数在执行,调用者调用其它函数时,被调用者不会修改或覆盖掉调用者今后要使用的寄存器内容,Intel CPU 采用了所有函数必须遵守的寄存器用法:1. 寄存器 eax、edx 和 ecx 的内容必须由调用者自己负责保存;2. ebx、esi 和 edi 必须由被调用者负责保存;3. ebp、esp 也需要由被调用者保存。

void swap(int* a, int* b)
{
  int c;
  c = *a, *a = *b, *b = c;
}
int main()
{
  int a, b;
  a = 16; b = 32;
  swap(&a, &b);
  return a - b;
}      
  • main 栈帧。保存局部变量 a 和 b、函数调用的参数 &b 和 &a、返回地址。
  • swap 栈帧。按照惯例,形成栈帧(保存ebp、esp)、使用 add/sub 取用函数参数、​

    ​leave​

    ​​ 指令一步退出栈帧。
    C 与汇编程序的相互调用

C 语言在调用函数时在堆栈上临时存放被调函数参数的值。

参数越是最后入栈,越是靠近 C 函数参数左侧。

C 程序调用汇编程序

从 C 程序中调用汇编程序函数的方法与汇编程序中调用 C 函数的原理相同,但 Linux 内核程序中不常使用。调用方法的着重点仍然是对函数参数在栈中位置的确定上。如果调用的汇编语言程序比较短,那么可以直接在 C 程序中使用内联汇编。

C 与汇编程序的相互调用

汇编程序调用 C 程序

  • 汇编中调用 C 函数比较自由,只要是在栈中适当位置的内容都可以作为参数供 C 函数使用。
  • 在调用函数返回后,汇编程序需要再把先前压入栈中的函数参数清除掉。