LDR 指令如何将常量加载到寄存器中? [英] How does the LDR instruction load constants into registers?

查看:25
本文介绍了LDR 指令如何将常量加载到寄存器中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚阅读了一本 ARM 说明书,我看到了一条我无法解释的指令.

I just read an ARM instruction book, and I saw one instruction that I couldn't interpret.

它说 LDR 将一个 32 位常量加载到 r0 寄存器中:

It says LDR loads a 32-bit constant into the r0 register:

LDR r0, [pc, #const_number-8-{pc}]
..........
const_number
DCD 0xff00ffff

我无法理解 [pc, #const_number-8-{pc}] 是什么意思.具体:

I couldn't understand what [pc, #const_number-8-{pc}] means. Specifically:

  1. # 是什么意思?
  2. 大括号 ({}) 是什么意思?
  3. 为什么这个例子要减去 8 和 pc?
  4. r0 如何获得 0xff00ffff 的值?
  1. What does # mean?
  2. What do the curly braces ({}) mean?
  3. Why does this example subtract 8 and pc?
  4. How does r0 have the value 0xff00ffff?

推荐答案

nop
nop
nop
nop
ldr r0,hello
nop
nop
nop
nop
b .
hello: .word 0x12345678


00000000 <hello-0x28>:
   0:   e1a00000    nop         ; (mov r0, r0)
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
  10:   e59f0010    ldr r0, [pc, #16]   ; 28 <hello>
  14:   e1a00000    nop         ; (mov r0, r0)
  18:   e1a00000    nop         ; (mov r0, r0)
  1c:   e1a00000    nop         ; (mov r0, r0)
  20:   e1a00000    nop         ; (mov r0, r0)
  24:   eafffffe    b   24 <hello-0x4>
  28:   12345678

在我看来,它只是写得不好.来自地址 0x10 的 [pc,#16] 如何导致 0x28?0x28-0x10 = 0x18 或 24 是 8 到大,等一下......(我刚刚玩了新的答案)

sounds to me like it is simply poorly written. How does [pc,#16] from address 0x10 result in 0x28? 0x28-0x10 = 0x18 or 24 which is 8 to big, hang on a second...(I new the answer just playing around)

在您的 ARM 文档的其他地方,它谈到程序计数器提前 2 或可能错误地记录为 8 个字节.它实际上是前面两条指令,所以在拇指模式下是 4 个字节,在 arm 模式下是 8 个字节.当涉及到 thumb2 扩展时,lr 将根据下一条指令进行排序.但似乎对于 pc 相关的东西,thumb 提前 4(传统上两条指令),arm 提前 8(两条指令).这并不意味着 pc 真的处于这个值,在橡子时代可能是 arm1,但现在它是纯合成的,因为堆栈要深得多.

Elsewhere in your ARM documentation it talks about the program counter being two ahead or possibly incorrectly documented as 8 bytes ahead. It is actually two instructions ahead, so in thumb mode 4 bytes, and in arm mode 8 bytes ahead. When thumb2 extensions get involved the lr is sorted out based on the next instruction(s). But it appears that for pc relative stuff it is 4 ahead for thumb (traditionally two instructions ahead) and 8 ahead for arm (two ahead). This doesnt mean the pc is really at this value, maybe arm1 during the acorn days, but now it is purely synthesized as the stack is much deeper.

因此,在进行数学运算以计算立即数时,您采用目标当前指令-8所以在本例中为 0x28-0x10-8 - 16.

So when doing the math to compute the immediate you take destination-current instruction-8 so in this case 0x28-0x10-8 - 16.

注意 #16 # 只是意味着这是一个常量/立即数,就像逗号和括号一样,使解析更容易一些(并且在某些情况下,没有 # 的数字至少在一般情况下意味着其他东西不适用于 arm gnu 汇编器).

Note #16 the # just means this is a constant/immediate just like the commas and the brackets, makes parsing a little easier (and there are a few cases where the number without the # means something else at least in general perhaps not for arm gnu assembler).

因此如上所示,指令中编码的立即数是目标地址 - pc - 8 在 ARM 模式下.

So as demonstrated above, the immediate value encoded in the instruction is the destination address - pc - 8 in ARM mode.

正如您所希望的(但在某些情况下不一定期望)立即得到符号扩展

and as you would hope (but not necessarily expect in some cases) the immediate gets sign extended

00000000 <hello-0xc>:
   0:   e1a00000    nop         ; (mov r0, r0)
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)

0000000c <hello>:
   c:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
  10:   e1a00000    nop         ; (mov r0, r0)
  14:   e1a00000    nop         ; (mov r0, r0)
  18:   e1a00000    nop         ; (mov r0, r0)
  1c:   e1a00000    nop         ; (mov r0, r0)
  20:   e1a00000    nop         ; (mov r0, r0)
  24:   e51f0020    ldr r0, [pc, #-32]  ; c <hello>

同样的数学(手臂模式)

same math (arm mode)

0xC - 0x24 - 8 = -0x20

00000000 <hello-0x14>:
   0:   46c0        nop         ; (mov r8, r8)
   2:   46c0        nop         ; (mov r8, r8)
   4:   46c0        nop         ; (mov r8, r8)
   6:   46c0        nop         ; (mov r8, r8)
   8:   4802        ldr r0, [pc, #8]    ; (14 <hello>)
   a:   46c0        nop         ; (mov r8, r8)
   c:   46c0        nop         ; (mov r8, r8)
   e:   46c0        nop         ; (mov r8, r8)
  10:   46c0        nop         ; (mov r8, r8)
  12:   e7fe        b.n 12 <hello-0x2>
  14:   12345678

完成故事 0x14 - 0x8 - 4 (thumb mode) = 8

to complete the story 0x14 - 0x8 - 4 (thumb mode) = 8

完成故事将包括 thumb2 扩展.

well completing the story would include thumb2 extensions.

00000000 <hello-0x18>:
   0:   bf00        nop
   2:   bf00        nop
   4:   bf00        nop
   6:   bf00        nop
   8:   4803        ldr r0, [pc, #12]   ; (18 <hello>)
   a:   eba0 0001   sub.w   r0, r0, r1
   e:   bf00        nop
  10:   bf00        nop
  12:   bf00        nop
  14:   bf00        nop
  16:   e7fe        b.n 16 <hello-0x2>

00000018 <hello>:
  18:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

好的,所以它使用了 4,当处理预取中止时是指令的大小进入计划时,而不是这里的 pc 相对负载,所以很好.

okay good so it used 4, when dealing with a prefetch abort is when the size of the instruction comes into plan, not here with a pc relative load, so that is good.

当你有一个返回地址时,它在拇指模式下正确地完成了两个.

It is when you have a return address is when it correctly does the two ahead in thumb mode.

这是在做什么

ldr r0,[pc,#16]

处理器获取程序计数器(合成的不是真实的),即指令地址加 8,然后添加由 # 符号标记的立即数,因此如果该指令位于地址 0x1234 处,则需要 0x1234 +8 + 16 = 0x124C.这是在括号内,所以一级间接,所以它需要地址 0x124C 在那里读取 32 位值(ldr vs ldrb vs ldrh vs ldrd),然后在这种情况下将结果放在指定的目标寄存器 r0 中.在您的情况下,您有一个只是地址的标签,并且该指令将具有汇编程序提供的正确立即数,以便在执行时 r0 在该地址处获得 0xFF00FFFF.

the processor takes the program counter (synthesized not real) which is the instruction address plus 8, it then adds the immediate value which is marked by the # sign here so if this instruction was at address 0x1234 then it would take 0x1234 + 8 + 16 = 0x124C. That is inside brackets so one level of indirection, so it takes that address 0x124C reads the 32 bit value there (ldr vs ldrb vs ldrh vs ldrd) and then places the result in the specified destination register r0 in this case. In your case you have a label which is just an address, and the instruction will have the right immediate provided by the assembler such that when executed r0 gets the 0xFF00FFFF at that address.

这就是所谓的pc相对寻址,非常重要的寻址方式,尤其是RISC机器.但对CISC也有用

This is called pc relative addressing, very important addressing mode, esp for RISC machines. But also useful for CISC

在相同的指令集中

ldr r0,[r1,#16]

技术上没有什么不同 r1 中的任何值加上 16 是使用的地址,pc 是特殊的,因为pc 中的任何值"根据模式(arm/thumb)和指令所在的地址而变化,但对于a [r1,#16] r1 不会改变它是什么你设置它.

Is technically no different whatever value is in r1 plus 16 is the address used, pc is special because "whatever value is in pc" varies based on the mode (arm/thumb) and the address where the instruction is located but for a [r1,#16] r1 wont vary it is whatever you set it to.

这篇关于LDR 指令如何将常量加载到寄存器中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆