如何在函数调用期间防止寄存器被覆盖?

法比安

我正在尝试为以下功能编写汇编代码:

#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在跳转到函数之前包含的内容,然后函数在进行比较时修改寄存器并设置这让我想知道汇编器如何在函数调用期间使寄存器保持不变。我想到了以下几点:fgreaterfr00cmp

  1. 只需将整个寄存器推入堆栈,然后再加载
  2. 从某种程度上收集函数调用的内容,然后在需要时“保护”寄存器。

我认为解决方案1很有防御性,而且成本可能很高,而解决方案2可能很复杂并且需要很多知识。最有可能的是,我在编写程序集时犯了一个错误,但是我仍然不明白汇编程序如何在一般情况下在需要时保持其寄存器不变,或者如何解决上面概述的问题。有人知道在这种情况下该怎么做吗?感谢您的帮助或建议!

埃里克·波斯蒂奇

通常,计算平台包括应用二进制接口(ABI),该应用二进制接口除其他外还指定了函数调用协议。ABI指定某些处理器寄存器用于传递参数或返回结果,某些寄存器可以由调用例程自由使用(临时或易失性寄存器),某些寄存器可以由调用例程使用,但必须将其恢复为原始值(保留或非易失性寄存器)和/或某些寄存器不得被调用例程更改。有关调用例程的规则也可以称为“调用约定”。

如果您的例程使用了被调用函数可以自由使用的寄存器之一,并且希望在函数调用期间保留该寄存器的值,则该例程必须在函数调用之前保存该寄存器,然后再进行恢复。

通常,ABI和功能会在它们使用的寄存器之间寻求平衡。如果ABI表示必须保存和恢复所有寄存器,则调用的函数将必须保存和恢复它使用的每个寄存器。相反,如果ABI表示不必保存和恢复任何寄存器,则调用函数将必须保存和恢复所需的每个寄存器。混合使用时,调用例程可能经常将某些数据保存在寄存器中(因此不必在调用之前将其保存并在之后恢复它们),并且被调用例程将不会使用它必须使用的所有寄存器保留(因此不必保存和恢复它们;它使用暂存寄存器),因此减少了执行的寄存器保存和恢复的总数。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么在ARM ABI中的函数调用期间未保存CPSR寄存器?

来自分类Dev

函数调用后寄存器的状态是什么?

来自分类Dev

调用函数时保存状态寄存器

来自分类Dev

如何在.c文件中使用asm函数将文字插入寄存器

来自分类Dev

如何在 AVX 寄存器上打包 16 个 16 位寄存器/变量

来自分类Dev

调用同一活动时如何防止分数被覆盖

来自分类Dev

如何在python中锁定方法(防止被覆盖)?

来自分类Dev

创建cdecl函数时如何保留寄存器的状态?

来自分类Dev

如何在装配中分割寄存器?

来自分类Dev

GDB:如何在特定地址打印寄存器的内容?

来自分类Dev

如何在MIPS中更改寄存器的值

来自分类Dev

如何在ZMM寄存器上实现vpmovmskb的效果?

来自分类Dev

如何在寄存器中写入地址?

来自分类Dev

如何在多任务环境中使用寄存器

来自分类Dev

如何在Verilog中为输出分配寄存器?

来自分类Dev

如何在LLVM的foreach循环中引用寄存器?

来自分类Dev

libc如何在Linux中修改CS寄存器

来自分类Dev

如何在TASM中查看寄存器值?

来自分类Dev

如何在调用期间覆盖服务参数

来自分类Dev

写入系统调用参数寄存器

来自分类Dev

让编译器在调用函数之前忽略设置参数寄存器

来自分类Dev

如何防止UserControl的内容被覆盖?

来自分类Dev

如何防止特定方法被覆盖?

来自分类Dev

如何防止对象属性被覆盖

来自分类Dev

如何防止数据被覆盖?Matlab的

来自分类Dev

如何防止记录对象被覆盖

来自分类Dev

如何防止方法在Java中被覆盖

来自分类Dev

如何防止 HTTP_REFERER 被覆盖

来自分类Dev

如何防止类在 Ruby 中被覆盖?