为什么在子例程调用中没有完整的上下文保存?

Sar*_*nan 2 assembly call cpu-registers context-switch subroutine

在子例程调用中,我们保存了PC的内容,以便重新启动我们的调用例程。但是,如果被调用的子例程更改了通用寄存器的值,会发生什么?如果必须访问存储在寄存器中的旧值,它不会对调用子例程造成任何问题吗?

Cor*_*lks 5

但是,如果被调用的子例程更改了通用寄存器的值,会发生什么?

它取决于子例程修改的寄存器。根据调用约定,有一个合同规定子例程必须不修改的寄存器列表(以及该子例程可以自由修改的另一个寄存器列表)。

如果子例程不遵守该合同并修改了它不应该拥有的寄存器,那么就会发生不好的事情。

如果子例程要使用它必须不修改的寄存器,则它必须首先将那些寄存器值保存到堆栈中。一旦保存了寄存器值,便可以将寄存器用于新值。子例程完成后,必须使用堆栈上保存的值来恢复原始寄存器值。这样,子例程可以根据需要使用寄存器,但是对于调用方而言,对寄存器没有可观察到的修改。

如果必须访问存储在寄存器中的旧值,它不会对调用子例程造成任何问题吗?

只要子例程遵循调用约定,否。如果该子例程没有执行,并且销毁了(或“ clobbers”)“保留”寄存器中的原始值,那么是的,它将引起问题。

但是,并非所有寄存器都必须保留。根据调用约定,某些寄存器可以由子例程修改。如果这些寄存器对调用者很重要,则调用者必须在调用子例程之前将这些寄存器保存到堆栈中,然后在调用子例程之后使用堆栈来恢复寄存器值。