1. ホーム
  2. assembly

[解決済み] BL命令ARM - その仕組み

2022-02-16 19:30:33

質問事項

ARM Assemblyを勉強しているのですが、今、行き詰まっていることがあります。

リンクレジスターについては知っています。間違っていなければ、関数呼び出しが完了したときに戻るアドレスを保持しています。

というようなものがあれば(ARMのドキュメントから引用)。

0 | here
1 |   B there
2 |   
3 |   CMP R1, #0
4 |   BEQ anotherfunc
5 |
6 |   BL sub+rom ;  Call subroutine at computed address.

つまり、左の列を各命令のアドレスと考えると、そこのBのアドレス1の後、リンク・レジスタは1の値を保持していることになりますね。

そして、プログラムはそこのメソッドに行き、リンクレジスターの値を使って戻る場所を知るのです。

今、私が行き詰っている6番地まで飛ばすと、次の命令のアドレスをどのBLがlr(r14、リンクレジスタ)にコピーしているかが分かります。

ということは、今度はサブルーチンであるsubのアドレス(サブルーチンって何?)+rom(数字?

しかし、一般的に、BLはどんな時に必要なのでしょうか?上の例では、なぜそれが必要なのでしょうか?どなたか、本当に必要な例を教えてください。

ありがとうございます。

解決方法は?

少し混乱されているようですね。以下はその説明です。

B 命令は分岐します。他の命令にジャンプし、リターンは期待できません。リンクレジスタ(LR)は触れません。

BL 命令は分岐しますが、リンクもします。の後の命令のアドレスでLRがロードされます。 BL の後に実行される命令ではなく、メモリ上の BL . そうすると、LRを使って分岐から戻ることができるようになります。

例:

start:
01:  MOV r0, r2     ; some instruction
02:  B there        ; go there and never return !

there:
11:  MOV r1, r0         ; some instruction
12:  BL some_function   ; go to some_function, but hope to return !
                        ; this BL will load 13 into LR
13:  MOV r5, r0
14:  BL some_function   ; this BL will load 15 into LR
15:  MOV r6, r0


some_function:
     MOV r0, #3
     B LR               ; here, we go back to where we were before

関数の中で別の関数を呼び出したい場合、LRは上書きされてしまうので、戻ることができません。一般的な解決策は、LRをスタックに保存するために PUSH {LR} で復帰する前に復元します。 POP {LR} . リストアとリターンを1つの POP {PC} これは LR の値を復元しますが、プログラムカウンタでは事実上関数を返します。