1

レジスタ ([ar]ax、つまり) の値を保持する必要があります。関数呼び出しの後に変更されますが、値は後で使用する必要があります。私はそうする3つの方法を考えました(例は64ビットにあります):

1.スタックにプッシュします。

__asm__ ("pushq %rax\n\t"
         "call function\n\t"
         "popq %rax");

2.レジスタに保存します。

__asm__ ("movq %%rax, %%some_register\n\t"
         "call function\n\t"
         "movq %%some_register, %%rax"
         : : : "%some_register");

3.変数に保存します。

unsigned long var;
__asm__ ("movq %%rax, %0" : "=m" (var) : : );
function();
__asm__ ("movq %0, %%rax" : : "m" (var) : );

現在、私は#1を使用しています。私の特定のケースでは意図したとおりに機能しますが、スタックにプッシュすることは悪いこと™ ではないかと心配しています。私の懸念のほとんどは、コンパイラがプッシュされていることを「認識」していないことでした。かなり制限されたスタックフレームのスペースを消費しているように見えるため、一般的に問題が発生する可能性があります。

レジスターに保存すると、コンパイラーはそれを独自のニーズに使用できなくなります。これは、x86 と比較して多くの追加レジスターがある x86-64 ではそれほど問題にならないかもしれません。ただし、x86 で使用する必要がある場合は、レジスタの量がはるかに制限されているため、パフォーマンスが低下する可能性があります。

変数に保存するのが最良の選択かもしれません。そして、コンパイラーはおそらく変数をスタックに保存し、レジスターを割り当てさえするので、それほど遅くはないかもしれません。しかし、コードが奇妙に見えるだけでなく、他の人が頭を悩ませる可能性のある変数が 1 つ追加されています。

問題は、どのソリューションが最適かということです。つまり、Right Thing™ は何をすべきでしょうか? それとも、私が考えていなかった、それを保存するためのいくつかの方法があります-さらに良い方法はありますか?

注: その関数は変数を取らず、問題がある場合は何も返しません。レジスタ内の値は、「より高いレベルの」ソリューションを介して単純に保存することはできません。したがって、インライン asm; 具体的には[er]axでなければなりません。3番目のソリューションはテストしていないため、少し不正確かもしれません.

4

2 に答える 2

0

あなたの方法はどれも正しくありません.asmステートメントの外にあるレジスタに何かを安全に保持することはできません. asm ステートメント間で値を渡したい場合は、それを変数に格納する必要があります。GCC は、可能な場合はレジスタに保持し、そうでない場合はどこかに保存します。

于 2012-06-17T18:05:09.893 に答える
0

解決策 2 では、特に最適化の場合、レジスタが上書きされないと見なすのは大胆です。解決策 1 の唯一の欠点は、スタックフレーム間の唯一のリンクがプッシュされた [er]bp であるため、(関数呼び出しスタックをデバッグする必要がある場合) スタックをアンワインドできないことです。 [er]sp と一致します。私は間違いなく、より明確なソリューション 3 を使用します。確かに、難読化の目的でローカル変数を追加しますが、少なくとも ABI を騙すことはありません!

于 2012-06-09T17:40:25.420 に答える