ADR伪指令

    这是一个特别有意思,有难度的指令,理解起来确实比较绕。

    ADR——小范围的地址读取伪指令,该指令将基于PC的地址或基于寄存器的地址值读取到寄存器中。

    这里特别注意,是“基于PC”,不是什么链接地址、绝对地址啥的,很固定,一定是基于PC.

    语法格式: ADR {cond}  reg,expr

    其中:cond——可选的指令执行条件。

                reg——目标寄存器。

                expr——基于PC或基于寄存器的地址表达式。

使用说明:       

     在汇编编译器处理源程序时,ADR伪指令会被编译器替换成一条合适的指令,通常,编译器会用一条ADD指令或SUB指令来实现该ADR伪指令的功能,如果不能用一条指令来实现ADR伪指令的功能,编译器将会报错。

    因为ADR伪指令中的地址是基于PC或基于寄存器的,所以ADR读取到的地址是一个与位置无关的地址当ADR伪指令中的地址是基于PC时,该地址与ADR伪指令必须在同一个代码段中,因为ADR寻址范围有限,只能小范围。

示例1:


start:
    MOV r0,#10
    ADR r4,start

   

       程序在运行到ADR r4,start时,由于ARM三、五级流水线的架构,此时PC = 执行地址 + 8,而start是在该条指令的前面,所以此时该条命令的目的是要读取start相对于PC的地址,很明显,start的地址是相对于PC - 8 -4 = PC - 12 = PC - 0x0C .所以本ADR伪指令将被编译器替换成 SUB r4,pc,#0x0C

示例2:  

       ADR r4,start
start:
       MOV r0,#10

        程序在运行到ADR r4,start时,同样的道理,此时PC = 执行地址 + 8,而start此时是在紧跟在这条指令的后面,所以start的地址是 “执行地址 + 4”,所以相对于 PC,start的地址为 PC - 4,所以本ADR伪指令将被编译器替换成 SUB r4,pc,#0x04

示例3:

   

      ADR r4,start
      nop;
      nop;
      nop;
      nop;
start:
     MOV r0,#10

      程序在执行到ADR  r4,start时,同样,PC = 执行地址 + 8,而start此时在该条指令的下面,所以start的地址为“执行地址 + 4*4(nop)”,也就是start地址为“执行地址 + 16”,所以start相对于PC 的地址为“16 - 8”,也就是 PC + 8,所以本ADR伪指令将被编译器替换成ADD r4,pc,#0x08

    前面说了那么多,可能会觉得不以为然,这tmd那么绕,有什么用啊?有用,有大用,这里相当于告诉程序员一个容易忽略的好用功能,也就是ADR可以自动的鉴别当前相对于PC的地址(感觉还是废话),这个用在BootLoader启动,如u-boot启动的代码重新加载上会有意想不到的作用,因为ARM的CPU在上电瞬间,不是直接在ram中运行的,而是在Nor flash等外围flash中,那么PC可能是从0开始,但是最终肯定是希望代码在RAM中运行,所以就涉及到将代码搬到RAM中运行,这个代码的“搬迁”,就可以巧妙的使用ADR命令,判断当前是在RAM中运行,还是在Nor Flash运行,这个在后面的博客中,会单独介绍这个“巧招”在relocate中的使用。

猜你喜欢

转载自blog.csdn.net/u012351051/article/details/80900459