ARM汇编ADR,LDR等伪指令
中LDR伪指令与LDR加载指令LDR伪指令的形式是“LDR Rn,=expr”。下⾯举⼀个例⼦来说明它的⽤法。 COUNT EQU 0x40003100 …… LDR R1,=COUNT MOV R0,#0 STR R0,[R1] COUNT是我们定义的⼀个变量,地址为
0x40003100.这中定义⽅法在汇编语⾔中是很常见的,如果使⽤过单⽚机的话,应该都熟悉这种⽤法。 LDR
x86架构和arm架构区别R1,=COUNT是将COUNT这个变量的地址,也就是0x40003100放到R1中。 MOV R0,#0是将⽴即数0放到R0中。最后⼀句STR R0,[R1]是⼀个典型的指令,将R0中的值放到以R1中的值为地址的单元去。实际就是将0放到地址为
0x40003100的存储单元中去。可 见这三条指令是为了完成对变量COUNT赋值。⽤三条指令来完成对⼀个变量的赋值,看起来有点不太舒服。这可能跟的采⽤RISC有关。 下⾯还有⼀个例⼦ ;将COUNT的值赋给R0 LDR R1,=COUNT LDR R0,[R1] LDR R1,=COUNT这条伪指令,是怎样完成将COUNT的地址赋给R1,有兴趣的可以看它编译后的结果。这条指令实际上会编译成⼀条LDR指令和⼀条 DCD伪指令。
  请问ARM指令LDR和伪指令LDR有什么区别伪指令LDR{cond} register, ={expr|label-expr} expr为32为常量。编译器根据expr的取值情况来处理这条伪指令:1、当expr表⽰的地址没有超过mov或mvn指令中地址的取值范围时,编译器⽤合适的mov指令或mvn指令代替该LDR伪指令。
  2、当expr表⽰的地址超过了mov或mvn指令中地址的取值范围时,编译器将该常数放在缓冲区中,同时⽤⼀条基于PC的LDR指令读取该常数。
  ……
  通过上⾯两种可以得出伪指令LDR和指令LDR的区别,具体使⽤时,可以不⽤考虑⼆者的区别,由编译器决定的,看源码时,你只要搞清楚它的功能就⾏。
  第⼀个就是把0xf830这个值放到r2中去,第⼆个和第三个的意义也是⼀样的。最后⼀条指令应该是错误的。
  由 于arm是risc精简指令集,指令都是32位的,在编码中操作码,⽬标和源寄存器是要占掉32位⼀部分,所以⼀条指令⾥⾯不可能存⼀个32位的⽴即数, 所以提供了⼀条伪指令来完成⼀条指令load⼀个32位的⽴即数。⽅法是在这条指令附近放要load的值,再利⽤当前的pc+偏移load这个数, 注意ldr的原来的意义是将内存的某个值load到寄存器⾥⾯。
  ⽐如:ldr r0, =0x5000010经过arm的assembler的翻译实际上就是:ldr r0,[pc+#0x4] ;指令是4byte 32位,就是将内存中下⼀个word放到r0中,0x5000010 这个地⽅放的是数值,这⾥0x4是在它⽴即数的范围,具体的看看⽂档ads的pdf⽬录下有⼀个AssemblerGuide 。
arm指令中mov和ldr的区别是RISC结构,数据从内存到CPU(寄存器)之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
  ⽐如想把数据从内存中某处读取到寄存器中,只能使⽤ldr⽐如:ldr r0,0x12345678就是把0x12345678这个地址中的值存放到r0中。
  ⽽mov不能⼲这个活,mov只能在寄存器之间移动数据,或者把⽴即数移动到寄存器中,这个和x86这种CISC架构的芯⽚区别最⼤的地⽅。
----------------------------------------------------------------------------------------------------------------------------------------------------------
  x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。
  另外还有⼀个就是ldr伪指令,虽然ldr伪指令和的ldr指令很像,但是作⽤不太⼀样。ldr伪指令可以在⽴即数前加上=,以表⽰把⼀个地址写到某寄存器中,⽐如:ldr r0, =0x12345678这样,就把0x1234
5678这个地址写到r0中了。所以,ldr伪指令和mov是⽐较相似的。只不过mov指令限制了⽴即数的长度为8位,也就是不能超过512。⽽ldr伪指令没有这个限制。如果使⽤ldr伪指令时,后⾯跟的⽴即数没有超过8位,那么在实际汇编的时候该ldr伪指令是被转换为mov指令的。
  ldr伪指令和ldr指令不是⼀个同东西。
  LDR R1,=COUNT
MOV R0,#0
STR R0,[R1]
COUNT是我们定义的⼀个变量,地址为0x40003100。这中定义⽅法在汇编语⾔中是很常见的,如果使⽤过单⽚机的话,应该都熟悉这种⽤法。
  LDR R1,=COUNT是将COUNT这个变量的地址,也就是0x40003100放到R1中。
  MOV R0,#0是将⽴即数0放到R0中。最后⼀句STR R0,[R1]是⼀个典型的存储指令,将R0中的值放到以R1中的值为地址的存储单元去。实际就是将0放到地址为0x40003100的存储单元中去。可 见这三条指令是为了完成对变量COUNT 赋值。⽤三条指令来完成对⼀个变量的赋值,看起来有点不太舒服。这可能跟的采⽤RISC有关。
  伪指令之地址读取:ADR ADRL,⼩范围的地址读取ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成⼀条合适的指令。通常,编译器⽤⼀条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能⽤⼀条指令实现,则产⽣错误,编译失败。
  ADR伪指令格式:ADR{cond} register,expr地址表达式expr的取值范围:当地址值是字节对齐时,其取指范围为: +255 ~ 255B;当地址值是字对齐时,其取指范围为: -1020 ~ 1020B;2、ADRL伪指令——中等范围的地址读取ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,⽐ADR伪指令可以读取更⼤范围的地址。在汇编编译器编译源程序时,ADRL伪指令被编译器替换成两条合适的指令。若不能⽤两条指令实现,则产⽣错误,编译失败。
  ADRL伪指令格式:ADRL{cond} register, expr地址表达式expr的取值范围:当地址值是字节对齐时,其取指范围为: -64K~64K;当地址值是字对齐时,其取指范围为: -256K~256K;3、LDR伪指令——⼤范围的地址读取LDR 伪指令⽤于加载32位的⽴即数或⼀个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成⼀条合适的指令。若加载的常数未超出MOV或 MVN的范围,则使⽤MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放⼊⽂字池,并使⽤⼀条程序相对偏移的LDR指令从⽂字池读出常量。