LDR指令、LDR伪指令、ADR伪指令区别

引例如下:

        先看一段代码:

        AREA test,CODE,READONLY
                 ENTRY

         ldr r0,__main
               adr r0,__main
               ldr r0,=__main
               nop       

      __main
               nop
               END

  反汇编一下后

  编译环境:realview 4.12 

  编译的时候设置   ROM1 :start_addr 0x30000000  、size   0x200000  

          RAM1 :start_addr 0x30200000  、 size:0x4000000 

  下面是反汇编的结果:

\\   code        pc_current    binary   code after asmcc

  6: ldr r0,__main     0x300000D8  E59F0008   LDR       R0,[PC,#0x0008]    

  7: adr r0,__main    0x300000DC  E28F0004   ADD      R0,PC,#0x00000004    

  8: ldr r0,=__main   0x300000E0  E59F0004   LDR       R0,[PC,#0x0004]          

  9: nop     

  10:      

  11: EXPORT __main     

  12: __main        0x300000E4  E1A00000   NOP           

  13: b __main     0x300000E8  EAFFFFFE    B         0x300000E8

               0x300000EC  300000E8   ANDCC     R0,R0,R8,ROR #1

  下面来分析一下这三条指令

  1、ldr r0,__main    ;这条指令实现将__main位置中的装入r0中

    经过汇编后,__main将被一个相对于PC的表达式取代

    __main =>  [pc,#4]   ;应为arm指令是以三级流水线的执行,pc=pc_current+0x08   所以最后地址(pc+4)中的值装入r0中

    总结:ldr r0, __main是根据__main对PC(pc_current+8)的相对位置(+4)读取其所在地址的值,因此可以在和___main标号的相对位置不变的情况下移动。

  2、adr r0,__main       ;小范围的地址读取伪指令

    这是一条伪指令,总是会被汇编程序汇编为一个指令。汇编程序尝试产生单个 ADD 或 SUB 指令来装载该地址。如果不能在一个指令中构造该地址,则生成一个错误,并且汇编失败。

    在这里是取得标号__main 的地址到 r0,因为地址是相对程序的,因此ADR产生依赖于位置的代码。

    本例中会变成:ADD      R0,PC,#0x00000004  。因此该代码可以在和标号相对位置不变的情况下移动。假如:这段代码在 0x30000000 运行,那么 adr r0, __main得到 r0 = 0x3000000c;如果在地址 0 运行,就是 0x0000000c 了。

  3、ldr r0,=__main        ;大范围的地址读取

    LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOVMVN的范围,则使用MOVMVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。这个指令取得标号 __main 的绝对地址,这个绝对地址是在 link 的时候确定的,看上去这只是一个指令,但是它要占用 2 个 32bit 的空间,一条是指令,另一条是 __main 的数据(因为在编译的时候不能确定 __main的值,而且也不能用 mov 指令来给 r0 赋一个 32bit 的常量,所以需要多出一个空间存放 __main 的真正数据,在这里就是 0x300000EC这个地址,取其中的值300000E8 )。

    因此可以看出,这个是绝对的寻址,不管这段代码在什么地方运行,它的结果都是 r0 = 300000E8 。

 

  完整的总结一下吧:

1、ADR伪指令--- 小范围的地址读取

     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指令从文字池读出常量。

 

 

====

http://www.cnblogs.com/jack739x/articles/2060762.html

你可能感兴趣的:(LDR指令、LDR伪指令、ADR伪指令区别)