我正在尝试为以下功能编写汇编代码:
#include <iostream>
void f(int x) {
if (x > 0) {
std::cout << x << std::endl;
f(x-1);
std::cout << x << std::endl;
}
}
int main() {
f(1);
}
此功能脚本的输出为1 1
。我尝试为所谓的“低成本计算机”汇编器编写汇编代码,这是安东尼·多斯·里斯(Anthony Dos Reis)为他的书《引擎盖下的C和C ++》发明的计算机。我写的汇编代码是:
startup jsr main
halt ; back to operating system
;==============================================================
; #include <stdio.h>
greater dout
nl
sub r1, r0, 1
push lr
push fp
mov fp, sp
push r1
jsr f
add sp, sp, 1
dout
nl
mov sp, fp
pop fp
pop lr
ret
;==============================================================
f push lr ; int f()
push fp ; {
mov fp, sp
ldr r0, fp, 2
cmp r0, 0
brgt greater
mov sp, fp
pop fp
pop lr
ret
;==============================================================
main push lr
push fp
mov fp, sp
mov r0, 1
push r0
jsr f
add sp, sp, 1
mov sp, fp
pop fp
pop lr
ret
该代码打印1 0
到stdout,并且显然是错误的。错误输出的原因在于,在分支评估期间,寄存器r0
包含1
在跳转到函数之前包含的内容,然后函数在进行比较时修改寄存器并设置为。这让我想知道汇编器如何在函数调用期间使寄存器保持不变。我想到了以下几点:f
greater
f
r0
0
cmp
我认为解决方案1很有防御性,而且成本可能很高,而解决方案2可能很复杂并且需要很多知识。最有可能的是,我在编写程序集时犯了一个错误,但是我仍然不明白汇编程序如何在一般情况下在需要时保持其寄存器不变,或者如何解决上面概述的问题。有人知道在这种情况下该怎么做吗?感谢您的帮助或建议!
通常,计算平台包括应用二进制接口(ABI),该应用二进制接口除其他外还指定了函数调用协议。ABI指定某些处理器寄存器用于传递参数或返回结果,某些寄存器可以由调用例程自由使用(临时或易失性寄存器),某些寄存器可以由调用例程使用,但必须将其恢复为原始值(保留或非易失性寄存器)和/或某些寄存器不得被调用例程更改。有关调用例程的规则也可以称为“调用约定”。
如果您的例程使用了被调用函数可以自由使用的寄存器之一,并且希望在函数调用期间保留该寄存器的值,则该例程必须在函数调用之前保存该寄存器,然后再进行恢复。
通常,ABI和功能会在它们使用的寄存器之间寻求平衡。如果ABI表示必须保存和恢复所有寄存器,则调用的函数将必须保存和恢复它使用的每个寄存器。相反,如果ABI表示不必保存和恢复任何寄存器,则调用函数将必须保存和恢复所需的每个寄存器。混合使用时,调用例程可能经常将某些数据保存在寄存器中(因此不必在调用之前将其保存并在之后恢复它们),并且被调用例程将不会使用它必须使用的所有寄存器保留(因此不必保存和恢复它们;它使用暂存寄存器),因此减少了执行的寄存器保存和恢复的总数。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句