4.ARM伪指令
ARM伪指令不属于ARM指令集中的指令,但是编译器能识别,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。 (1)ADR 小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。
地址表达式expr的取指范围:
A.当地址值不是字对齐时,其取指范围为-255~255; B.当地址值是字对齐时,其取指范围为-1020~1020; C.当地址值是16字节对齐时,其取指范围将更大。 应用举例:
指定链接-Ttext 0x30008000 生成的可执行文件反汇编后的结果如下:
可以看到, r3 = 当前pc - 0x14。 ADR这条指令经常用来获取代码运行的地址。
假如,这段代码放在内存中运行,其所在的内存存储空间的首地址为0x30008000 。当CPU运行到红线框起来的那条指令时,大家可以思考一下此时PC的值为多少呀?聪明的你一定还记得,PC指向的永远都是预取指令的地址,即当前指令所在的地址+8。
呵呵,这样PC = 0x3000800c + 8 = 0x30008014 。r3 = pc - 0x14 = 0x30008014 - 0x14 = 0x30008000。 (2)ADRL中等范围的地址读取
ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址 。在汇编编译器编译源程序时,ADRL伪指令被编译器替换成两条合适
的指令。若不能用两条指令实现,则产生错误,编译失败。 当地址值是字节对齐时,取值范围为?64~64KB;当地址值是字对齐时,取值范围为?256~256KB。
(3)LDR 大范围的地址读取
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。
从上图可以知道,ldr r6,=0x12 指令在进行处理的时候,编译器知道0x12是一个立即数,就直接将其翻译成mov 指令的。如果操作的不是立即数,则用文字池的形式进行存储,然后通过ldr指令从对应的地址读取数据。 注意:
1.从指令位置到文字池的偏移量必须小于4KB;
2.与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。 (4)空操作伪指令
NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOV R0,R0”指令等。NOP可用于延时操作。
应用示例(延时子程序):