如何在C函数调用期间保留寄存器和其他信息?

Mic*_*sky 4 c cpu-registers

让我们说我有三个功能,f1(),f2(),和f3().当f1调用它时,它将信息存储在CPU寄存器中(我想还有其他重要信息).现在,根据编译时未知的条件,f1将调用f2f3. f2f3使用非常不同的寄存器,其中一些可能与使用的寄存器重叠f1.以下推理是否正确?

编译器知道特定功能在执行期间需要哪些寄存器.因此,当f1调用f2或者f3,函数调用代码保留那些在堆栈上使用f2f3使用的寄存器,无论它们是否被使用f1.

或者是否有一些其他机制来编译器保留寄存器,以便返回的函数不会丢失其数据?

Bas*_*tch 6

回想一下,编程语言是文档中的规范.对于C11,请阅读 n1570.

C中不存在寄存器(换句话说,几乎过时的register关键字与处理器寄存器不再相关).它们只在机器代码中起作用(通常由C编译器生成).

但是,给定编译器生成的代码(对于给定的指令集和目标系统)遵守某些约定,特别是调用约定ABI(例如,读取系统V x86-64 ABI管理Linux).这些约定定义了如何使用寄存器,以及哪些寄存器是被调用者保存的或调用者保存的.寄存器分配优化编译器工作的一个难点.

编译器通常会发出代码将一些寄存器内容溢出到调用堆栈中.并且给定的寄存器可以用于多个事物(例如,如果它们出现在同一函数中的不同位置,它可以保留两个不同的变量).

通常,调用约定不依赖于被调用的函数(回想一下你可以通过函数指针进行间接调用),但主要是它的签名.


Pau*_*vie 5

“编译器知道特定函数在执行过程中需要哪些寄存器。”

不,它通常不会知道这一点。

出于一个原因,函数可能来自编译器一无所知的(第三方)库。出于另一个原因,如果该函数调用另一个函数和另一个 etetera 呢?

编译器只会将所有“可疑”寄存器压入堆栈并在返回之前弹出它们。


cdc*_*dcd 5

我认为正如其他人所说,函数的参数通常通过多个寄存器发送(然后在堆栈上)。使用哪些寄存器取决于编译器 \xe2\x80\x93,请gcc参阅 GNU C/汇编器:http://cs.lmu.edu/~ray/notes/gasexamples/

\n\n

一些值得注意的原则:

\n\n
    \n
  1. 栈帧

  2. \n
  3. 调用者(调用 f1 的函数)和被调用者函数(您的 f1、f2...函数)

  4. \n
  5. 易失性和非易失性寄存器。对于您的问题,您只需担心非易失性寄存器即可。

  6. \n
\n\n

每个函数都有一个堆栈帧,这是堆栈的可扩展块,用于临时存储需要加载到寄存器中和从寄存器中加载出的数据。

\n\n

在每次函数调用之前(从调用者到被调用者),您希望传递的值(即您的参数)将被放置在许多预定的寄存器中(通常为 4-6 个,具体取决于编译器 \xe2\x80\x93 参见关联); 如果参数多于预定寄存器的数量,则这些附加值将存储在堆栈上(通常是调用者堆栈帧)。

\n\n

如果调用者正在使用这些预定的寄存器,那么编译器将在调用被调用者(例如您的 f1 函数)之前将参数分配给寄存器之前将这些值推送到调用者的堆栈帧上。一旦被调用函数(被调用者)返回,这些值就会从堆栈恢复到各自的寄存器中。

\n\n

当编译器将 C 代码转换为汇编/操作码时,一系列函数的调用方式或顺序都遵循相同的系统。

\n