这种调用规范保存和恢复寄存器是函数做还是调用者做
时间: 2024-04-17 08:27:55 浏览: 29
在 C calling convention 中,寄存器的保存和恢复通常是由函数来完成的,而不是调用者。根据规范,函数在被调用时会保存可能被修改的寄存器的值,并在函数返回时恢复这些寄存器的值,以确保调用者的寄存器状态不会被破坏。
具体来说,根据调用规范,一般来说,函数需要保存并恢复以下寄存器的值:一般用于传递函数参数的寄存器(如 eax、edx、ecx 等),栈指针寄存器(如 esp、rsp 等),基址寄存器(如 ebp、rbp 等),帧指针寄存器(如 ebp、rbp 等),返回地址寄存器(如 eip、rip 等),以及其他可能被函数使用的寄存器。
通过将寄存器值保存到栈上,并在函数返回前从栈上恢复这些值,可以确保函数的执行不会对调用者的寄存器状态产生影响。这种方式也有助于实现函数的嵌套调用和正确处理异常情况。
相关问题
A)呼叫者保存寄存器 B)呼叫保存寄存器 C)假设编译器可以从这个过程中的某个点确定一个变量不再被使用(活性)。为了最大限度地提高编译代码的速度,在调用者保存寄存器和被调用者保存寄存器之间,编译器应该在哪里保存寄存器变量a、b和c ?证明你的答案。 (提示)函数"fn2(b)"可以递归地多次调用自己。如果"b"是在被调用者保存寄存器中分配的,那么每当"fn2(b)"被调用时,它将被保存并恢复,即使它可能不会在"fn2(b)*中使用
根据调用者保存寄存器和被调用者保存寄存器的定义,我们可以得知:
- 调用者保存寄存器是指在调用函数之前,调用者将需要用到的寄存器的值保存起来,以便在函数调用之后回复这些寄存器的值。
- 被调用者保存寄存器是指在函数中使用的寄存器的值需要被保存,以便在函数返回时恢复这些寄存器的值。
因此,在这个问题中,如果编译器可以确定变量a、b和c在某个点不再被使用,那么编译器应该选择调用者保存寄存器来保存这些寄存器变量。这是因为如果使用被调用者保存寄存器,当函数fn2(b)被递归调用时,寄存器b的值将被保存和恢复,即使它可能不会在fn2(b)中使用。这将导致额外的开销和性能损失。
为了证明这个答案,我们可以考虑以下伪代码:
```
fn1() {
// 在调用之前保存调用者保存寄存器
save_registers();
// 使用寄存器a、b和c
a = ...
b = ...
c = ...
// 当变量a、b和c不再使用时,可以选择调用者保存寄存器
// 来保存这些寄存器变量
// 因为函数fn2(b)可能会递归多次调用自己,如果使用被调用者保存寄存器,
// 寄存器b的值将被保存和恢复,即使它可能不会在fn2(b)中使用
fn2(b);
// 在返回之前恢复调用者保存寄存器
restore_registers();
}
fn2(b) {
// 在调用之前保存被调用者保存寄存器
save_registers();
// 使用寄存器b
...
// 在返回之前恢复被调用者保存寄存器
restore_registers();
}
```
如果我们使用调用者保存寄存器来保存寄存器变量a、b和c,那么在函数fn2(b)被调用时,只有调用者保存寄存器被保存和恢复。这将导致更少的开销和更好的性能。
因此,在这个问题中,编译器应该在调用者保存寄存器和被调用者保存寄存器之间选择调用者保存寄存器来保存寄存器变量a、b和c。
MIPS中怎么写函数和调用函数
在MIPS汇编中,函数的定义和调用与其他汇编语言基本相同。下面是一个简单的例子,演示如何定义和调用一个函数:
```
# 函数定义
my_func:
addi $sp, $sp, -4 # 分配4字节的栈空间
sw $ra, 0($sp) # 保存返回地址
# 函数体
add $v0, $a0, $a1 # 计算a+b
lw $ra, 0($sp) # 恢复返回地址
addi $sp, $sp, 4 # 释放栈空间
jr $ra # 返回
# 函数调用
main:
li $a0, 1 # 设置参数a=1
li $a1, 2 # 设置参数b=2
jal my_func # 调用函数
# 此时$v0中存放了my_func的返回值
```
在上面的代码中,`my_func`是一个简单的函数,它将$a0和$a1相加,并将结果存放在$v0中。在函数调用时,我们将参数a和b分别存放在$a0和$a1中,然后使用`jal`指令调用函数。
在`my_func`函数内部,我们首先分配了4字节的栈空间,并将返回地址保存在栈中。函数体中的代码处理完毕后,我们恢复了返回地址,并释放了栈空间,然后使用`jr $ra`指令返回到调用者。
需要注意的是,MIPS函数调用时使用的是寄存器传递参数,而不是堆栈传递参数。在调用函数之前,需要将参数存放在$a0、$a1、$a2和$a3中,如果有更多的参数,需要将它们存放在栈中。函数返回值通常存放在$v0中,如果有多个返回值,可以使用$v0和$v1来存放。