zoukankan      html  css  js  c++  java
  • LDR 和 ADR 彻底详解

    0.什么是位指令?

       答:伪指令(Pseudo instruction)是用于告诉汇编程序如何进行汇编的指令。它既不控制机器的操作也不被汇编成机器代码,

             只能为汇编程序所识别并指导汇编如何进行。

    1.LDR 大范围的地址读取伪指令(当有=号时为伪指令)

       LDR 伪指令将一个32位的常数或者一个地址值读取到寄存器中。

       语法格式

       LDR{cond}  register,={expr | label -expr}

       其中,cond为可选的指令执行条件

               register 为目标寄存器

               expr 为32位的常量。编译器将根据expr的取值情况,决定如果处理LDR指令

               ①当expr表示的地址值没有超过MOV或MVN指令中的地址取值范围时,编译器用适当的MOV或MVN指令翻译LDR 指令

               ②当expr表示的地址值超过了MOV或者MVN指令中的地址取值范围时,编译器将该常数放在数据缓冲区中,同时用一条

                 基于PC的LDR指令读取该常数

                 也就是说,LDR伪指令要么翻译为MOV指令,要么翻译为LDR指令

              label -expr为基于PC的地址表达式或者是外部表达式

              ①当label -expr为基于PC的地址表达式时,编译器将label -expr表示的数值放在数据缓冲区中,同时用一条基于PC的

                 LDR指令读取该数值

              ②当label -expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入连接重定位伪操作,这样链

                 接器将在链接时生成该地址

        使用说明

        LDR伪指令主要有以下两种用途

        ①当需要读取到寄存器中的数据超过了MOV或MVN指令可以操作的范围时,可以使用LDR伪指令将数据读取到该寄存器中

        ②将一个基于PC的地址值或者外部的地址值读取到寄存器中。由于这种地址是在链接时确定的,所以这种代码不是位置无关的。

           同时LDR伪指令处的PC值到缓冲区中的目标数据所在的地址的偏移量要小于4KB

        示例

            例1 将0xff0读取到R1中

     LDR R1,=0xff0
    
     汇编后将会得到
    
     MOV R1,0xff0

            例2 将0xfff读取到R1中          

      LDR R1,=0xfff
    
      汇编后将会得到
    
      LCD R1,[PC,OFFSET_TO_LPOOL]
    
       ...
    
      LPOOL DCD 0xFFF

            例3 将外部地址ADDR1读到R1中        

      LDR R1,=ADDR1
    
      汇编后将会得到
    
      LDR R1,[PC,OFFSET_TO_LPOOL]
    
       ...
    
      LPOOL DCD ADDR1
    
     

        实验

        1.在keil-MDK中编写如下代码

           注:代码是下载到内存运行的,地址为0x3000,0000

     1     AREA Init, CODE ,READONLY
     2     ENTRY
     3 _start        
     4     ldr r0,copy   ;这里是ldr指令,用于获取copy标号对应地址的内容
     5     ldr r0,=copy  ;这里是ldr伪指令,用于获取copy标号的绝对地址
     6     mov r1,r0
     7     mov r1,r0
     8 copy 
     9     mov r0,r0
    10     mov r0,r0
    11 test1
    12     b test1
    13     
    14     END

         经过反汇编得到的结果如下

     1      4:     ldr r0,copy 
     2 0x30000000  E59F0008  LDR       R0,[PC,#0x0008];此处R0中装的值应为地址值为(PC值+0x0008)指向的内容,PC指针值为
                                                      ;0x3000,0000 + 8,即地址值为0x3100,0010,内容为E1A00000
                                                      
     3      5:     ldr r0,=copy                       ;这是一条伪指令,这一条指令被翻译成了两条语句,一条是在END后
     4 0x30000004  E59F0010  LDR       R0,[PC,#0x0010];定义了一个变量值,另一条是读取这个变量值,地址为
     5      6:         mov r1,r0                      ;0x3000,0004 + 8 + 0x10 = 0x3000,001c  此工程的最后一条指令地
     6 0x30000008  E1A01000  MOV       R1,R0          ;址为0x3000,0018 ,即END其实并不表示汇编程序的结尾
     7      7:         mov r1,r0 
     8      8: copy                                   ;在ARM汇编中,标号没有实际的意义  
     9 0x3000000C  E1A01000  MOV       R1,R0          ;注意这里,KEIL反汇编的一个缺陷,看了半天才看懂,copy标号的
    10      9:     mov r0,r0                          ;地址实际应为0x3000,0010,KEIL把copy 和上一条指令mov r1,r0连在
    11 0x30000010  E1A00000  NOP                      ;一起进行翻译了
    12     10:         mov r0,r0 
    13     11: test1 
    14 0x30000014  E1A00000  NOP       
    15     12:     b test1 
    16 0x30000018  EAFFFFFE  B         0x30000018

    2.ADR(小范围的地址读取指令)

        该指令将基于PC的地址值或者基于寄存器的地址值读取到寄存器中

        语法格式

        ADR{cond} register,expr

        expr 为基于PC或者寄存器的地址表达式,其取值范围如下

        ①当地址值不是字对齐的,其取值范围为 -255 ~ 255

        ②当地址值是字对齐的,其取值范围为 -1020 ~ 1020

        使用说明

        在汇编程序处理源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或者SUB指令来实现

        该伪指令的功能。

        如果不能用一条指令来实现ADR伪指令的功能,编译器将报错

        因为ADR伪指令中的地址基于PC或者基于寄存器的,所以ADR读取到的地址为位置无关的地址。当ADR伪指令中的地址是基

        于PC时,该地址与ADR伪指令必须在同一代码段中

        示例   

    1 start
    2     MOV r0,#10     ; 因为PC值为当前指令地址加8字节
    3     ADR r4,start   ; 本ADR伪指令将被编译替换成 SUB r4,pc,#0xc

        实验

     1     AREA Init, CODE ,READONLY
     2     ENTRY
     3 _start        
     4     adr r0,copy
     5     mov r1,r0
     6     mov r1,r0
     7 copy 
     8     mov r0,r0
     9     mov r0,r0
    10 test1
    11     b test1
    12     
    13     END

    经过反汇编后

         4:     adr r0,copy 
    0x30000000  E28F0004  ADD       R0,PC,#0x00000004  ;R0 = 0x3000,0000 + 8 + 0x04 = 0x3000000c,正好是copy标号的地址
         5:         mov r1,r0 
    0x30000004  E1A01000  MOV       R1,R0
         6:         mov r1,r0 
         7: copy  
    0x30000008  E1A01000  MOV       R1,R0
         8:     mov r0,r0 
    0x3000000C  E1A00000  NOP       
         9:         mov r0,r0 
        10: test1 
    0x30000010  E1A00000  NOP       
        11:     b test1 
    0x30000014  EAFFFFFE  B         0x30000014

      

  • 相关阅读:
    《大道至简:软件工程实践者的思想》读后感
    周学习进度总结(2019.7.14)
    周学习进度总结(2019.7.7)
    周学习进度总结(2019.8.13)
    周学习进度总结(2019.8.4)
    石家庄铁道大学2019 年秋季 2018级JAVA课堂测试试卷(一)
    周学习进度总结(2019.7.27)
    周学习进度总结(2019.8.25)
    周学习进度总结(2019.7.20)
    C#中判断是否为数字
  • 原文地址:https://www.cnblogs.com/zhang2318/p/6089835.html
Copyright © 2011-2022 走看看