呼び出し元の lr レジスタの値をローカル変数に取得する C 関数があります。
私は次のコードを試しました:
volatile long lr;
asm(
"str %0, [sp, #4]\n" :
"=r", (lr)
);
ただし、これは何も変わりません。間違った値を取得しているわけではありません。lr ローカル変数の値がまったく変更されていないだけです ( ガベージが含まれています )。
何か案は?
ありがとう!
質問に直接答えるには、2 つの解決策があります。
long lr;
asm(" mov %0,lr\n" :: "=r" (lr));
これにより、lr
値がlr 変数に入れられます。何かを分析するためにこれを行いたいと思うかもしれません。lr
に返信先住所が含まれていると想定している場合、 Igorが説明しているように、これは正しくありません。非リーフ関数では、コンパイラはlr
、関数の引数を計算するときに一時的に を使用することがあります。
register long lr asm("lr");
この形式では、変数lrをどこでも参照でき、コンパイラはライブlr
値を使用します。値は関数全体で変更される場合があります。たとえば、別の関数を呼び出すと、通常、現在アクティブな関数の戻りポイントに設定されます。
Igorが説明しているように、 を取得しても期待どおりの結果がlr
得られない場合があります。そして、私たちが使用しているメカニズムはgcc固有のものです。移植可能な方法でこれを行うことはできません。しかし、へのアクセスlr
は本質的に移植性がありません。
参照:の使用についてもう少し詳しく知りたい場合は、ARM リンク レジスタとフレーム ポインタlr
の質問を参照してください。
コードは address で値を取得しますSP+4
。その場所にイニシャルが含まれるかどうかはLR
、コンパイラ、最適化設定、特定の関数、またはこのコードを配置する関数内の場所によって異なります。要するに、おそらく偶然にしか機能しないでしょう。
編集: コードは関連するものを読み取っていません。初期化されていない変数の値をスタックに格納しているだけです (ヒント: 変数に名前を付けてlr
も、魔法のようにレジスタ LR
の値を取得するわけではありません)。最良の場合は何もしません。最悪の場合、重要なものを上書きしてクラッシュします。
具体的にはLRではなく、関数の戻りアドレスを実際に取得したいと仮定します。そのためのコンパイラ固有のオプションが存在します。
GCC は__builtin_return_address()
、現在の関数 (0 で呼び出された場合) またはコール スタック内の他の関数 (後者には依存しませんが) のリターン アドレスを返す組み込み関数を提供します。
Visual C++ には組み込み関数_ReturnAddress()
さえあります。_AddressOfReturnAddress()
上記のいずれかを使用することをお勧めします(GCCまたはVCを使用していると仮定します)。いつでも機能しなくなる可能性のあるトリックに依存しないでください。