在C中调用函数时,寄存器和其他信息是如何保存的?

在C中调用函数时,寄存器和其他信息是如何保存的?,c,cpu-registers,C,Cpu Registers,假设我有三个函数,f1(),f2(),和f3()。调用f1时,它将信息存储在CPU寄存器中(我想还有其他重要信息)。现在,根据编译时未知的条件,f1将调用f2或f3f2和f3使用非常不同的寄存器,其中一些寄存器可能与f1使用的寄存器重叠。以下推理正确吗 编译器知道特定函数在执行过程中需要哪个寄存器。因此,当f1调用f2或f3时,函数调用代码会保留那些f2或f3在堆栈上使用的寄存器,无论它们是否正被f1使用 或者编译器是否有其他机制来保留寄存器,以便返回的函数不会丢失其数据 “编译器知道特定函数在

假设我有三个函数,
f1()
f2()
,和
f3()
。调用
f1
时,它将信息存储在CPU寄存器中(我想还有其他重要信息)。现在,根据编译时未知的条件,
f1
将调用
f2
f3
f2
f3
使用非常不同的寄存器,其中一些寄存器可能与
f1
使用的寄存器重叠。以下推理正确吗

编译器知道特定函数在执行过程中需要哪个寄存器。因此,当
f1
调用
f2
f3
时,函数调用代码会保留那些
f2
f3
在堆栈上使用的寄存器,无论它们是否正被
f1
使用

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

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

不,它通常不知道这一点

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


编译器只需将所有“可疑”寄存器推送到堆栈上,并在返回之前弹出它们。

回想一下,编程语言是文档中的规范。例如,阅读

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

但是,由给定编译器生成的代码(对于给定的指令集和目标系统)遵守一些约定,特别是和(请阅读Linux的管理示例)。这些约定定义了如何使用寄存器,以及哪些寄存器被调用者保存或调用者保存。这是安工作中很困难的一部分

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


一般来说,调用约定不依赖于被调用函数(回想一下,您可以通过函数指针进行间接调用),而主要依赖于它的签名。

我认为,正如其他人所说的那样,函数的参数通常是通过多个寄存器(此后在堆栈上)向下发送的。使用哪些寄存器取决于编译器–有关
gcc
的信息,请参阅GNU C/assembler:

值得注意的若干原则:

  • 堆叠框架

  • 调用者(调用f1的函数)和被调用者函数(f1、f2…函数)

  • 易失性和非易失性寄存器。对于您的问题,您不需要担心非易失性寄存器

  • 每个函数都有一个堆栈帧,这是堆栈的一个可扩展块,用于临时存储需要装入和移出寄存器的数据

    在每次函数调用(从调用者向被调用者)之前,您希望传递的值,即您的参数,将被放置在一些预定的寄存器中(通常为4-6,具体取决于编译器-请参阅链接);如果参数多于预定寄存器的数量,那么这些附加值将存储在堆栈上(通常是调用者堆栈帧)

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


    当编译器将您的C代码转换为汇编代码/操作码时,一系列函数的调用方式或调用顺序无关紧要。我不确定您到底在寻找什么,因为1。每个编译器可能执行不同的操作(因为这取决于目标机器)。这在编程语言标准和3中没有规定。它可能会根据调用约定和使用的优化而改变。当然,我正在尝试理解函数调用是如何工作的。我试图理解这样的事情:如果我在一个调用共享库函数的函数中,是什么保存了寄存器上的数据之类的东西。一个答案指出,由于编译器不知道该函数需要什么,所以由被调用函数本身来保存东西,不是吗?