46

拡張 gcc インライン アセンブリを使用してレジスタ値を読み取り、それを C 変数に格納する方法を見たのを覚えています。

私は一生、asmステートメントを作成する方法を覚えていません。

4

8 に答える 8

35

編集者注:ローカルの register-asm 変数を使用するこの方法は、現在 GCC によって "サポートされていません" として文書化されています。通常は GCC で動作しますが、clang で壊れます。(ドキュメント内のこの文言は、この回答が投稿された後に追加されたと思います。)

グローバル固定レジスタ変数バージョンは、32 ビット x86 のパフォーマンス コストが大きく、7 つの GP 整数レジスタしかありません (スタック ポインタはカウントされません)。これにより、それが 6 に減ります。これは、すべてのコードで頻繁に使用されるグローバル変数がある場合にのみ考慮してください。


あなたが何を望んでいるのかわからないので、これまでの他の回答とは異なる方向に進んでいます。

GCC マニュアル § 5.40 指定されたレジスタ内の変数

register int *foo asm ("a5");

a5使用するレジスタの名前は次のとおりです…</p >

当然、レジスタ名は CPU に依存しますが、これは問題ではありません。特定のレジスタは明示的なアセンブラ命令で最も頻繁に使用されるためです ( Extended Asmを参照)。これらの両方の場合、通常、CPU の種類に応じてプログラムを条件付けする必要があります。

このようなレジスター変数を定義しても、レジスターは予約されません。フロー制御によって変数の値が有効でないと判断された場合でも、他の用途に引き続き使用できます。

GCC マニュアル § 3.18 コード生成規則のオプション

-ffixed-登録

regという名前のレジスターを固定レジスターとして扱います。生成されたコードは、それを決して参照してはなりません (スタック ポインター、フレーム ポインター、またはその他の固定された役割を除いて)。

これにより、リチャードの答えをより簡単な方法で複製できます。

int main() {
    register int i asm("ebx");
    return i + 1;
}

ebxただし、レジスターに何が入っているかわからないため、これはかなり無意味です。

これら2つを組み合わせて、これを でコンパイルするとgcc -ffixed-ebx

#include <stdio.h>
register int counter asm("ebx");
void check(int n) {
    if (!(n % 2 && n % 3 && n % 5)) counter++;
}
int main() {
    int i;
    counter = 0;
    for (i = 1; i <= 100; i++) check(i);
    printf("%d Hamming numbers between 1 and 100\n", counter);
    return 0;
}

迅速なアクセスのために C 変数が常にレジスタ内に存在することを確認でき、また、生成された他のコードによって上書きされないようにすることができます。(便利なことに、ebx通常の x86 呼び出し規則の下では呼び出し先を保存するため、 を使用せずにコンパイルされた他の関数への呼び出しによって上書きされた場合でも、-ffixed-*復元する必要があります。)

一方、コンパイラの自由を制限しているため、これは間違いなく移植性がなく、通常はパフォーマンス上の利点でもありません。

于 2010-01-22T04:26:11.810 に答える
22

ebxを取得する方法は次のとおりです。

int main()
{
    int i;
    asm("\t movl %%ebx,%0" : "=r"(i));
    return i + 1;
}

結果:

main:
    subl    $4, %esp
    #APP
             movl %ebx,%eax
    #NO_APP
    incl    %eax
    addl    $4, %esp
    ret


編集:

「=r」(i)は出力制約であり、最初の出力(%0)が変数「i」に配置する必要があるレジスターであることをコンパイラーに通知します。この最適化レベル(-O5)では、変数iはメモリに格納されませんが、戻り値レジスタでもあるeaxレジスタに保持されます。

于 2010-01-22T01:05:33.280 に答える
6

gccについてはわかりませんが、VSでは次のようになります。

int data = 0;   
__asm
{
    mov ebx, 30
    mov data, ebx
}
cout<<data;

基本的に、データをebx変数に移動しましたdata

于 2010-01-22T00:55:30.087 に答える
5

これにより、スタックポインタレジスタがsp変数に移動します。

intptr_t sp;
asm ("movl %%esp, %0" : "=r" (sp) );

'esp'を関心のある実際のレジスタに置き換え(ただし、%%を失わないように注意してください)、'sp'を変数に置き換えてください。

于 2010-01-22T01:07:19.313 に答える
2

GCCドキュメント自体から:http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

于 2010-01-22T17:40:18.543 に答える
-1

これはあなたが探しているものではありませんか?

構文:

 asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));
于 2010-01-22T00:51:24.893 に答える