为什么在ARM汇编中使用LDR而不是MOV(反之亦然)?

Jon*_*an. 25 assembly arm

我正在浏览本教程:http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/os/ok01.html

第一行组装是:

ldr r0,=0x20200000
Run Code Online (Sandbox Code Playgroud)

第二个是:

mov r1,#1
Run Code Online (Sandbox Code Playgroud)

我以为ldr是将值从内存加载到寄存器中.但似乎=意味着0x20200000是一个值而不是内存地址.两条线似乎都在加载绝对值.

old*_*mer 18

这是一个技巧/捷径.比如说

ldr r0,=main
Run Code Online (Sandbox Code Playgroud)

会发生什么事情是汇编器会在指令附近但在指令路径之外分配一个数据字

ldr r0,main_addr
...
b somewhere
main_addr: .data main
Run Code Online (Sandbox Code Playgroud)

现在将这个技巧扩展到常量/立即数,尤其是那些不能适应移动立即指令的技巧:

top:
add r1,r2,r3
ldr r0,=0x12345678
eor r1,r2,r3
eor r1,r2,r3
b top
Run Code Online (Sandbox Code Playgroud)

组装然后拆卸

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
Run Code Online (Sandbox Code Playgroud)

并且您看到汇编程序已为您添加了数据字,并将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
Run Code Online (Sandbox Code Playgroud)

所以它基本上是一个打字快捷方式,明白你给装配工有能力找到一个坚持常数的地方,这通常做得很好,有时抱怨,不确定我是否看到它不能安全地做到.有时您需要在代码中使用.ltorg或.pool来鼓励汇编程序找到一个位置.

  • mov表示将值移入寄存器.Ldr表示将值加载到寄存器中.str,store是从寄存器到内存.并且=地址快捷方式没有意义.(有意义的做一个ldr =地址将地址放入寄存器然后存储以将某个寄存器的内容放入该地址的内存中) (2认同)
  • 也明白"太大"意味着什么,它意味着有超过8位分开的那些.所以mov rd,#0x21000000完全有效,但0x201不是. (2认同)

小智 8

较短的响应,仅来自更接近您级别的人,希望它有所帮助:在ARM中,指令有32位.一些位用于标识操作,一些用于操作数,并且在MOV指令的情况下,一些位可用于立即值(例如,#1).

正如您在此处所见(第33页),立即值只有12位可用.该指令不是将每个位用作数字(范围从0到2 ^ 12-1~4095),而是通过将前8位向右旋转(ROR)两倍于最后4位中指定的量来计算立即数.就是这样immediate = first 8 bits ROR 2*(last four bits).

这样,我们可以获得比4096更多的数字(有关可能的immediates的简短摘要,请参见第34页).

如果我们的数字不能转换成像前一个那样的指令(257不能表示为8位旋转两次任意4位),那么,我们必须使用LDR r0,= 257

在这种情况下,编译器将数字257保存在内存中,靠近程序代码,因此可以相对于PC进行寻址,并从内存加载它,就像详细解释的那样.

注意:如果您遵循该教程,那么当您尝试使用mov r0,#257'make'时,您将收到错误,并且您必须手动尝试ldr r0,= 257.

  • 那么,更短的响应是 `ldr` 可以让您使用更大的数字? (2认同)

Suh*_*rty 5

与其他答案一样好,我想我可以简化答案。

ldr = 负载寄存器

移动= 移动

两者都有效地做同样的事情,但方式不同。

区别很像之间的区别

#define CONST 5
Run Code Online (Sandbox Code Playgroud)

int CONST = 5;
Run Code Online (Sandbox Code Playgroud)

在 C 语言中。

mov非常快,因为它具有直接存储为指令一部分的伴随值(以上述答案中描述的 12 位格式)。由于它存储值的方式,它有一些限制。为什么?因为

  • 12 位不足以存储像 32 位内存地址这样的大数字。
  • 前 8 位ROR 2 *(后 4 位)不能代表任何数字,即使在 12 位范围内。

另一方面,ldr是多功能的(主要是由于编译器优化)。它是这样工作的(如反汇编程序所示)

  • 如果该值可以用 12 位和前 8 位ROR 2 *(后 4 位)格式表示,则编译器将其更改为伴随该值的mov指令。

  • 否则,该值将作为数据保存,加载到 RAM 中的某个位置。并且通过使用程序计数器的偏移量从内存访问,将其加载到所需的寄存器中。

我希望它有所帮助。