我在 MIPS 教程中读到,只有寄存器 $s0-$s7 在过程调用中被保留。但我认为(也许我错了?)创建有副作用的程序并不优雅 - 我认为程序应该只更改 $v0、$v1 寄存器和堆栈(如果需要的话)(我是对的吗?)。所以我认为在我的程序中我只能使用 $t0-$t9 寄存器。但是当我在程序中调用一些过程时,它可以更改 $t0-$t9 寄存器。所以我必须存储临时寄存器并在程序中的过程调用后恢复它。但是当我的程序如下所示时:
call procedure1
compute something on temporary reginsters
call procedure2
compute something on temporary reginsters
call procedure3
compute something on temporary reginsters
...
Run Code Online (Sandbox Code Playgroud)
我的程序需要大量的内存访问。所以我的想法是使用:
Store at the begining of my procedure reginsters $s0-$s7.
Use reginsters $s0-$s7 in my procedure.
Restore old values of reginsters $s0-$s7.
Run Code Online (Sandbox Code Playgroud)
它优雅吗?有什么不好的后果吗?
我在 MIPS 教程中读到,只有寄存器 $s0-$s7 在过程调用中被保留。
没有什么神奇的事情发生$s0-$s7跨调用(例如jal some_routine,只是将返回地址粘贴$ra并跳转到some_routine;没有其他事情发生)。
在调用过程中保存这些寄存器只是一种约定:它是标准“应用程序二进制接口”(ABI) 的一部分,这是一组涵盖寄存器使用、堆栈使用、数据格式等的约定。 -- 不同的代码位符合相同 ABI 的应用程序(应用程序、库等)将能够相互操作。
如果您希望您的代码可以从其他地方调用,您的代码需要符合调用者期望的 ABI。例如,如果您正在编写一些需要从 C 代码调用的汇编例程,则需要符合 C 编译器生成的代码所使用的 ABI。
对于通常的 MIPS ABI,这意味着调用例程的代码将假定在调用之前输入的任何值$s0-$s7在调用返回后仍然存在,但它不会假定$t0-的内容$t9仍然是相同的。(类似地,如果您的代码调用库例程(例如),它可以做出相同的假设:调用返回后,$s0-中的任何内容$s7都已保留,但是$t0-$t9可能包含任何内容。)
这意味着您的代码必须在更改之前保存任何内容$s0,并在返回之前恢复它们。$s7保存和恢复它们之间的作用并不重要——重要的是调用者看不到任何变化。
所以,是的,你的想法是正确的(实际上也是明智的做法)。
(请注意,如果您的子过程(procedure1等prodcedure2)仅从您的主过程调用,并且不调用外部例程,则它们不一定必须符合此标准 ABI - 因为在这种情况下, 它们只需要与你的主程序进行互操作, 而不需要与任何其他代码进行互操作。但是无论如何遵循 ABI 是一个好主意, 除非有很好的理由不这样做; 它使代码更容易阅读, 更容易如有必要,稍后使内部过程之一更加公开,以便更容易添加对其他代码的调用等)