2

GCC で問題を引き起こすシナリオがあります。私が得る行動は、私が期待する行動ではありません。状況を要約すると、ハードウェア シミュレータに実装される x86-64 用のいくつかの新しい命令を提案しています。これらの命令をテストするために、既存の C ソース コードを使用し、16 進数を使用して新しい命令をハンドコーディングしています。これらの命令は既存の x86-64 レジスターと対話するため、入力/出力/クロバー リストを使用して GCC の依存関係を宣言します。

何が起こっているかというと、printf などの関数を呼び出すと、依存するレジスタが保存および復元されません。

例えば

register unsigned long r9  asm ("r9")  = 101;
printf("foo %s\n", "bar");
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9) );

101 は r9 に割り当てられ、インライン アセンブリ (この例では偽物) は r9 に依存しています。これはprintfがなくても正しく実行されますが、ある場合、GCCはr9を保存および復元せず、カスタム命令が呼び出されるまでに別の値がそこにあります。

おそらくGCCが変数r9への代入をこっそり変更したのではないかと思ったのですが、こうすると

asm volatile (".byte %0" : /* no output */ : "q" (r9) );

アセンブリの出力を確認すると、実際に %r9 が使用されています。

gcc 4.4.5 を使用しています。何が起こっていると思いますか?GCC は常に関数呼び出しでレジスタを保存および復元すると思っていました。強制できる方法はありますか?

ありがとう!

編集:ちなみに、私はこのようなプログラムをコンパイルしています

gcc -static -m64 -mmmx -msse -msse2 -O0 test.c -o test
4

2 に答える 2

7

ABI、セクション3.2.1は次のように述べています。

レジスタ%rbp、%rbx、および%r12から%r15は、呼び出し元の関数に「属し」、呼び出された関数はそれらの値を保持する必要があります。つまり、呼び出された関数は、呼び出し元のためにこれらのレジスタの値を保持する必要があります。残りのレジスタは、呼び出された関数に「属します」。呼び出し元の関数が関数呼び出し全体でそのようなレジスタ値を保持したい場合は、その値をローカルスタックフレームに保存する必要があります。

したがって、%rbp、%rbx、および%r12から%r15以外のレジスタが関数呼び出しによって保持されることを期待しないでください。

于 2011-07-28T17:52:53.443 に答える
2

gccは、このcallee-savedのような明示的なレジスタ変数を作成しません。基本的に、使用しているこのレジスタ表記は、呼び出し先がレジスタに残した値を読み戻すことができるようにすることを前提として、変数をレジスタの直接エイリアスにします。コールクローバー(呼び出し元保存)レジスターの代わりに呼び出し先保存レジスターを使用した場合、問題は解決します。

于 2011-07-28T17:50:34.133 に答える