【问题标题】:Using 4bit PowerPC CR0 register from GCC使用来自 GCC 的 4 位 PowerPC CR0 寄存器
【发布时间】:2018-05-25 07:23:08
【问题描述】:

我想创建通过 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 32bit 寄存器,而不仅仅是它的部分?

【问题讨论】:

  • 您不太可能手动管理 gcc 对条件寄存器不同部分的使用。 Register-asm 变量仅适用于通用整数寄存器,或用于 FP 变量的 FP 寄存器。
  • 请注意您的特定平台的 ABI 约定。它们很重要。

标签: c gcc assembly powerpc


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    Register-asm 局部变量对此没有用处。

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

    对于您的情况更重要的是,为函数内的 register-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
    

    因此,您也许可以编写恰好可以保存调用者寄存器的代码,但是如果没有内联汇编,您将无法编写将寄存器恢复为上下文一部分的代码-切换。

    此外,无论如何,您都不想单独保存/恢复CR 的所有 8 个半字节!像普通人一样保存整个 32 位寄存器。或者更好的是,使您的上下文切换函数成为编译器生成的代码调用的实际函数,这样您就不必保存/恢复任何调用破坏的寄存器。 (因为编译器期望你的函数在返回之前破坏所有这些寄存器。)

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


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

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

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

    【讨论】:

    • 问题是我在二进制代码任意位置手动调用了我的上下文切换函数,所以编译器不会保存调用破坏的regs。我想保存所有调用破坏的寄存器并恢复它们。如我所见,它只能通过 asm inlines 来完成。但是我怎样才能访问所有的 CR 寄存器呢?它似乎不是编译器的有效寄存器名称
    • 对,你不能让编译器生成代码来保存/恢复 CR,你必须用 asm 编写。使用您需要的 mfcrmtcr 说明更新了我的答案。不要忘记保存/恢复 LR、CTR 和任何其他特殊用途的寄存器。
    • CR2-4 在函数调用中是非易失性的。
    猜你喜欢
    • 2021-03-29
    • 2011-04-27
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多