使用GCC的4位PowerPC CR0寄存器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用GCC的4位PowerPC CR0寄存器相关的知识,希望对你有一定的参考价值。

我想创建通过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中有4bits整数的解决方法吗?或者如何解决完整的cr 32位寄存器,不仅仅是它的部分?

答案

我想创建通过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都是call-clobbered。在仅具有单个FLAGS /条件代码寄存器的ISA上,它总是被调用破坏。


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

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

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

另一答案

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

您应该使用内联汇编将这些特殊寄存器的值读取到局部变量中,并将其保存在其他位置。

以上是关于使用GCC的4位PowerPC CR0寄存器的主要内容,如果未能解决你的问题,请参考以下文章

powerpc调试工具的使用

YJX_Driver_021_绕过驱动保护

x86CPU 实模式 保护模式 傻傻分不清楚? 基于Xv6-OS 分析CR0 寄存器

PowerPC基础知识

PowerPC基础知识

基于51单片机定时器计数+2片74HC595联级+8位数码管时钟+按键修改时间