2011-07-28 4 views
2

私はGCCのシナリオで問題を引き起こしています。私が得る行動は、私が期待する行動ではありません。要約すると、私は、ハードウェアシミュレータで実装されているx86-64用のいくつかの新しい命令を提案しています。これらの命令をテストするために、私は既存のCソースコードを取り、16進数を使って新しい命令をハンドコーディングしています。これらの命令は既存のx86-64レジスタとやりとりするので、I/O/clobberリストを使用してGCCの依存関係を宣言します。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が常に関数呼び出しのレジスタを保存して復元すると考えました。私はそれを強制することができる方法はありますか?

ありがとうございます!

EDIT:ところで、私はgccはこの呼び出し先保存のような明示的なレジスタ変数をすることはありません。この

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

答えて

7

ABIは、セクション3.2.1は言う:%R15を通じ

レジスタ%のRBP、%のRBXと%R12は呼び出し元の関数に「所属」と と呼ばれる機能が はその値を維持するために必要とされます。言い換えれば、呼び出される関数は、呼び出し側のためにこれらのレジスタの値を に保存する必要があります。残りのレジスタは、呼び出された 関数に属します。呼び出し元の関数が 関数呼び出しでこのようなレジスタ値を保持したい場合は、ローカルスタックフレームに値を保存する必要があります。

したがって、%rbp、%rbx、%r12から%r15以外のレジスタは関数呼び出しによって保持されるとは限りません。

+0

明快にありがとう、私はこれについて知らなかった。後続の質問として、printfの前に保存され、printfの後に復元されるカスタムレジスタセットを求める簡単な(1行の)方法がありますか? – hayesti

+0

'unsigned long tmp = r9; printf(...); r9 = tmp; ' –

2

のようなプログラムをコンパイルしています。基本的には、このレジスタ表記法を使用すると、変数がレジスタの直接のエイリアスになります。これは、呼び出し先がレジスタに残す値を読み取ることができることを前提としています。コール・クローバー(呼び出し側で保存された)レジスターの代わりに呼び出し先保存レジスターを使用した場合、問題はなくなります。

+0

ありがとうございます、私は呼び出し元/呼び出し先保存レジスタがあったことを知りませんでした! – hayesti

関連する問題