使用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寄存器的主要内容,如果未能解决你的问题,请参考以下文章