代码之家  ›  专栏  ›  技术社区  ›  Scher Khan

使用GCC中的4位PowerPC CR0寄存器

  •  2
  • Scher Khan  · 技术社区  · 6 年前

    我想通过GCC编译器创建保存/恢复CPU寄存器状态的函数。 在PowerPC中,它是8个条件4位寄存器(“cr0”-“cr7”),我想获取它们的值并将其保存在内存中。我的解决方案(不起作用):

    register int cr0 __asm__("cr0");
    

    这是通用寄存器('r1'-'r30'),在定义了寄存器之后,可以以任何方式使用它。 但在编译上述代码时,它会失败,并出现以下错误:

    hello.c: In function ‘foo’:
    hello.c:58:22: error: register specified for ‘cr0’ isn’t suitable for data type
             register int cr0 __asm__("cr0");
    

    我认为问题在于cr0寄存器是4位宽的,所以不能放入32位int变量中。(16位和8位也失败)

    如何处理这个问题?GCC中是否有4位整数的变通方法?或者如何处理完整的 cr 32位寄存器,不仅仅是它的部件?

    2 回复  |  直到 6 年前
        1
  •  3
  •   chqrlie    6 年前

    gcc扩展 register int cr0 __asm__("cr0"); 用于为C变量(本地甚至全局)分配特定寄存器。它不能用于您的目的,因为您提到的寄存器确实不适合存储类型的值 int 。对于可以用这种方式使用的寄存器集还有其他限制,这不是一种通用的方法 拯救 注册值。

    您应该使用内联汇编将这些特殊寄存器的值读入局部变量,并将它们保存到其他地方。

        2
  •  2
  •   Peter Cordes    6 年前

    我想通过GCC编译器创建保存/恢复CPU寄存器状态的函数。

    登记册- asm 局部变量在这方面是无用的。

    只有当它们被用作扩展asm语句的操作数时,才能保证它们位于指定的寄存器中( gcc manual )。这允许编译器在需要时跨函数调用溢出/重新加载寄存器。

    更重要的是,为函数中的寄存器asm局部变量指定一个新值将导致编译器在函数序言/尾声中保存/恢复调用者的值。看见 this example on the Godbolt compiler explorer :

    int call_clobbered(int x) {
        register int a asm("r2") = 123;
        asm("" :: "r"(a)); // force the compiler to have the value in the register
        return a;
    }
    
       # gcc4.8.5 -O3 -mregnames
        li %r2,123
        li %r3,123      # return-value register
        blr
    
    
    int call_preserved(int x) {
        register int a asm("r22") = 123;
        asm("" :: "r"(a)); // force the compiler to have the value in the register
        return a;
    }
    
       # gcc4.8.5 -O3 -mregnames
        stwu %r1,-48(%r1)
        stw %r22,8(%r1)     # save caller's r22
        li %r22,123
        li %r3,123
        lwz %r22,8(%r1)     # restore caller's r22
        addi %r1,%r1,48     # deallocate stack space
        blr
    

    因此,您可能能够生成恰好适用于您的代码 节省物 调用方的寄存器,但如果没有内联asm,您将无法编写作为上下文切换的一部分恢复寄存器的代码。

    此外,您不想保存/恢复所有8个字节的 CR 反正是分开的!像普通人一样保存整个32位寄存器。或者更好的方法是,将上下文切换函数设置为编译器生成代码调用的实际函数,这样就不必保存/恢复任何调用失败的寄存器。(因为编译器是 期望 你的功能是在所有寄存器返回之前将其清除。)

    我不知道PowerPC的调用惯例,但我猜所有的CR都是调用失败的。在只有一个标志/条件代码寄存器的ISA上,它总是调用Clobbred。


    如果确实需要保存/恢复CR,则可能必须用纯asm编写整个函数,因为任何编译器生成的代码在恢复CR后都可能会破坏CR。

    要保存/恢复整个CR,请参阅 this PPC ISA quick reference .

    使用 mfcr r1 ( )将所有32位复制到整数寄存器(然后可以将其存储到内存中)。使用 mtcr r1 转到CR 恢复时。与任何注册机构合作; r1 这只是一个例子。