使用来自 GCC 的 4 位 PowerPC CR0 寄存器

Using 4bit PowerPC CR0 register from GCC

我想创建 save/restore 状态 CPU 通过 GCC 编译器注册的函数。 在 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 位寄存器,而不仅仅是它的部分?

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

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

I want to create functions that save/restore state of the CPU registers via GCC compiler.

注册-asm局部变量对此没有用。

只有当它被用作扩展 asm 语句的操作数时,它们才能保证在指定的寄存器中 (gcc manual)。这允许编译器在需要时 spill/reload 跨函数调用进行注册。

对于您的情况更重要的是,将新值分配给函数内的 register-asm 局部变量将导致编译器 save/restore 函数中调用者的值 prologue/epilogue。见 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,您将无法编写将寄存器恢复为上下文切换的一部分。

此外,您不想 save/restore CR 的所有 8 个半字节分开!像正常人一样保存整个32位寄存器。或者更好的是,使您的上下文切换函数成为编译器生成的代码调用的实际函数,因此您不必 save/restore 任何调用破坏的寄存器。 (因为编译器 期望 你的函数破坏它之前的所有寄存器 returns。)

我不知道 PowerPC 调用约定,但我猜所有 CR 都被调用破坏了。在只有一个 FLAGS / 条件代码寄存器的 ISA 上,它总是被调用破坏。


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

要save/restore整个CR,见this PPC ISA quick reference

使用mfcr r1从CR移动)将所有32位复制到一个整数寄存器(然后你可以存入内存)。恢复时使用mtcr r1移动到CR。适用于任何寄存器; r1 只是一个例子。