使用 GCC 编译器为代码的特定部分保留寄存器

2024-03-31

是否可以为 C 代码的特定部分保留寄存器?

-ffixed-reg 选项或声明全局寄存器变量不是我正在寻找的答案。我想保留特定范围(比如说特定函数)的寄存器值。

使用局部寄存器变量是不可能的,因为它不能保证在整个范围内保留寄存器的值。 我正在寻找类似 clobber list 的东西,带有 asm 易失性,但用于 C 语句。


GCC给出了三种机制,

  1. asm clobber
  2. 局部寄存器变量 https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Local-Register-Variables.html
  3. 全局寄存器变量 https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Global-Register-Variables.html

值得注意的是,编译器寄存器分配是现代优化的基础,保留寄存器可能会生成更糟糕的编译代码。使用 ARM 模式和 16 个寄存器(仅 13 个可用),您应该能够为某个功能保留一个这样的寄存器,而不会造成太大损害。然而,您不应该轻易使用这些设施,发现一些性能问题也就不足为奇了。

听起来全局寄存器变量最适合你。只要有register int *foo asm ("r4");在每个需要它的“C”模块的开头。

如果您有一个小的函数簇/树,您可以使用宏来保留并将其包含到一个“C”单元。

#define RESERVE_REG(reg)  register int RR_##reg asm (#reg) \
                                 __attribute__((unused))

int bar(int a) { 
  RESERVE_REG(R4); 
  int b; 
  b += CRAZY_ASM(a); 
  return b;
}
void foo(void) { 
 RESERVE_REG(R4); 
 CRAZY_ASM_SET_R4(82);
 printf("value is %d\n", bar(1));
}

了解变量的使用很重要,因为有更有效的方法(例如asmclobber)对于某些可变的寿命和用途获得相同的效果。在大多数情况下,人们只会声明一个参数。也就是说,最好让编译器知道您使用它的目的,因为它可以就何时溢出或不溢出做出明智的决定。

很难想象保留寄存器不会被误导的情况。这可能有用的一个例子是与跨语言/解释器交互。上述宏应该作为通过保留寄存器在例程之间传递信息的快速方法。

你不应该使用R0-R3因为您将限制可以在例程之间传递的参数。 ARM ABI 将参数传递给R0-R3。鉴于您可以灵活选择寄存器,请选择R4-R9(甚至可能R9是禁止的),因为这些是“被调用者”保存的寄存器,没有任何特殊用途。同样,如果你选择R0-R3您可以NOT调用标准“C”库例程或保留寄存器将保存在堆栈上。

参考: GCC 局部寄存器变量 https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Local-Register-Variables.html
ARM 寄存器调用约定 https://stackoverflow.com/questions/261419/arm-to-c-calling-convention-registers-to-save

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 GCC 编译器为代码的特定部分保留寄存器 的相关文章

随机推荐