web-dev-qa-db-ja.com

ARMアセンブリでLDR over MOV(またはその逆)を使用するのはなぜですか?

私はこのチュートリアルを見ています: http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/os/ok01.html

アセンブリの最初の行は次のとおりです。

ldr r0,=0x20200000

2番目は:

mov r1,#1

ldrはメモリからレジスタに値をロードするためのものだと思いました。しかし、それは=は、0x20200000がメモリアドレスではない値であることを意味します。両方の行が絶対値をロードしているようです。

23
Jonathan.

これはトリック/ショートカットです。たとえば

ldr r0,=main

起こるのは、アセンブラが命令の近くで命令パスの外側にデータワードを割り当てることです

ldr r0,main_addr
...
b somewhere
main_addr: .data main

次に、このトリックを定数/イミディエート、特に即時移動命令に適合しないものに拡張します。

top:
add r1,r2,r3
ldr r0,=0x12345678
eor r1,r2,r3
eor r1,r2,r3
b top

組み立ててから分解する

00000000 <top>:
   0:   e0821003    add r1, r2, r3
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <top+0x14>
   8:   e0221003    eor r1, r2, r3
   c:   e0221003    eor r1, r2, r3
  10:   eafffffa    b   0 <top>
  14:   12345678    eorsne  r5, r4, #125829120  ; 0x7800000

また、アセンブラーがデータWordを追加し、ldrをpcに変更してくれたことを確認します。

mov命令に適合するイミディエイトを使用する場合、おそらくアセンブラに応じて、おそらく私が使用しているgnuで、それをmovに変換しました

top:
add r1,r2,r3
ldr r0,=0x12345678
ldr r5,=1
mov r6,#1
eor r1,r2,r3
eor r1,r2,r3
b top


00000000 <top>:
   0:   e0821003    add r1, r2, r3
   4:   e59f0010    ldr r0, [pc, #16]   ; 1c <top+0x1c>
   8:   e3a05001    mov r5, #1
   c:   e3a06001    mov r6, #1
  10:   e0221003    eor r1, r2, r3
  14:   e0221003    eor r1, r2, r3
  18:   eafffff8    b   0 <top>
  1c:   12345678    eorsne  r5, r4, #125829120  ; 0x7800000

それは基本的にタイピングのショートカットです、あなたはアセンブラに定数を貼り付ける場所を見つける力を与えていることを理解してください。アセンブラーが場所を見つけるのを促すために、コードに.ltorgまたは.poolが必要になる場合があります。

18
old_timer

あなたのレベルに近い人からの短い応答は、それが役立つことを願っています:ARMでは、命令には32ビットがあります。一部のビットは操作を識別するために使用され、一部はオペランド用であり、MOV命令の場合、一部は即時値(#1など)で使用可能です。

here (33ページ)を見るとわかるように、即値に使用できるのは12ビットのみです。各ビットを数値(0〜2 ^ 12-1〜4095の範囲)として使用する代わりに、命令は、最後の4ビットで指定された量の2倍で最初の8ビットを右回転(ROR)することにより、即値を計算します。つまり、immediate = first 8 bits ROR 2*(last four bits)です。

このようにして、4096よりもはるかに多くの数値を達成できます(可能なイミディエートの簡単な要約については、34ページを参照してください)。

番号を前のような命令に変換できない場合(257は4ビットを2回回転した8ビットとして表現できない)、LDR r0、= 257を使用する必要があります

この場合、コンパイラはプログラムコードに近い257番のメモリをメモリに保存するため、dwelchが詳細に説明したように、PCを基準にしてアドレスを指定し、メモリからロードできます。

注:このチュートリアルに従う場合、mov r0、#257で 'make'を実行しようとするとエラーが発生し、ldr r0、= 257を手動で試行する必要があります。

7
Fernando

他の答えと同様に、答えを単純化できるかもしれません。

ldr= LoaDレジスタ

mov= MOVe

どちらも効果は同じですが、方法は異なります。

違いは

#define CONST 5

そして

int CONST = 5;

c言語で。

movは、命令の一部として付随する値を直接格納しているため、非常に高速です(上記の回答で説明した12ビット形式)。値の保存方法に起因するいくつかの制限があります。どうして?なぜなら

  • 32ビットのメモリアドレスのような膨大な数を格納するには、12ビットでは不十分です。
  • 最初の8ビット[〜#〜] ror [〜#〜]2 *(最後の4ビット)は、12ビットであっても数字だけを表すことはできません範囲。

ldrは、一方で、多目的です(主にコンパイラの最適化による)。このように動作します(逆アセンブルされたルーチンに示されているように)

  • 値が12ビットと最初の8ビットで表現できる場合[〜#〜] ror [〜#〜]2 *(最後の4ビット) formatを実行すると、コンパイラは値をmov命令に変更します。

  • それ以外の場合、値はデータとして保持され、RAMの特定の場所にロードされます。また、プログラムカウンタからのオフセットを使用してメモリからアクセスすることにより、必要なレジスタにロードされます。

役に立てば幸いです。

2