bugfix> c > 投稿

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 件
  • I want to create functions that save/restore state of the CPU registers via GCC compiler.

    Register- asm  ローカル変数はこの目的には役に立ちません。

    これらは、拡張asmステートメントのオペランドとして使用される場合にのみ、指定されたレジスタにあることが保証されます(gccマニュアル)。これにより、コンパイラは必要に応じて関数呼び出し間でレジスタをスピル/リロードできます。

    さらに重要なこととして、関数内のregister-asmローカル変数に新しい値を割り当てると、コンパイラーは関数のプロローグ/エピローグで呼び出し元の値を保存/復元します。 Godboltコンパイラエクスプローラーでこの例を参照してください。

    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がないと、コンテキストスイッチの一部としてレジスターを復元するコードを作成できません。

    それに、 CR の8ニブルすべてを保存/復元したくない  とにかく別々に!通常の人のように32ビットレジスタ全体を保存します。または、コンテキストスイッチ関数を、コンパイラによって生成されたコードが呼び出す実際の関数にすることで、コールクローバーレジスタを保存/復元する必要がなくなります。 (コンパイラは期待する 返される前にこれらすべてのレジスタを消去する関数)

    PowerPCの呼び出し規則はわかりませんが、CRのすべてが呼び出しで上書きされていると推測しています。単一のFLAGS /条件コードレジスタのみを備えたISAでは、常にコールクローバーが行われます。


    CRを保存/復元する必要がある場合は、おそらく、関数全体を純粋なasmで作成する必要があります。これは、コンパイラーが生成したコードが復元後にCRを上書きする可能性があるためです。

    CR全体を保存/復元するには、このPPC ISAクイックリファレンスをご覧ください。

    使用する mfcr r1  (CRから移動)32ビットすべてを整数レジスタにコピーします(これをメモリに保存できます)。使用する mtcr r1  にCRに移動 復元するとき。任意のレジスタで動作します。 r1  単なる例です。

  • gcc拡張機能 register int cr0 __asm__("cr0");  C変数(ローカルまたはグローバル)に特定のレジスタを割り当てるために使用されます。あなたが言及するレジスタは、実際にはタイプ int の値を格納するのに不適切であるため、目的に使用することはできません。 。この方法で使用できるレジスタのセットには他の制限がありますが、これは一般的な方法ではありませんセーブ レジスタ値。

    インラインアセンブリを使用して、これらの特殊レジスタの値をローカル変数に読み込み、それらを別の場所に保存する必要があります。

あなたの答え