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

时间:2012-12-26 21:50:21

标签: assembly arm

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

组装的第一行是:

ldr r0,=0x20200000

第二个是:

mov r1,#1

我认为ldr用于将值从内存加载到寄存器中。但似乎=表示0x20200000是一个值而不是内存地址。两条线似乎都在加载绝对值。

3 个答案:

答案 0 :(得分:18)

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

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

你看到汇编程序为你添加了数据字,并将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来鼓励汇编程序找到一个位置。

答案 1 :(得分:7)

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

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

通过这种方式,我们可以获得比4096更多的数字(有关可能的中间人的简要摘要,请参阅第34页)。

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

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

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

答案 2 :(得分:1)

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

ldr = LoaD注册

mov = MOVe

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

差异很像

之间的区别
#define CONST 5

int CONST = 5;

用C语言。

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

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

ldr 是通用的(主要是由于编译器优化)。它的工作方式如下(如反汇编程序所示)

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

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

我希望它有所帮助。