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

查看:161
本文介绍了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等于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文档中的其他地方,它都谈到程序计数器在前面,或者可能错误地在前面记录了8个字节.它实际上是前面的两个指令,因此在拇指模式下为4个字节,在手臂模式下为8个字节.涉及thumb2扩展时,将根据下一条指令对lr进行分类.但是看来,对于PC相关人员,拇指提前4位(传统上是两条指令),手臂提前8位(提前2条指令).这并不意味着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).

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

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(拇指模式)= 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,ldrb,ldrh,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中的任何值"根据模式(机械臂/拇指)和指令所在的地址而异,但对于一个[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天全站免登陆