(八)ARM伪指令

本专栏总结王利涛《C语言嵌入式Linux高级编程》第二期课程

一、伪指令

1)什么是伪指令

  • 为了编程方便定义的伪指令,并不是ARM指令集中的指令。
  • 编译时会将这些伪指令等效为一条或多条机器指令。

4)四条伪指令

  • ADR R0, LOOP; 将LOOP标号处的地址放入R0。ARR是小范围的地址读取伪指令,该指令将基于PC的地址或基于寄存器的地址值读取到寄存器中。(反汇编:汇编翻译成类似的语句 ADD R0, PC, #0X1234)。
  • ADRL: 中等范围的地址读取伪指令。范围在[0, 64k]。
  • LDR: 大范围的地址读取伪指令,范围在[0, 4G]。 常用来加载外部设备的寄存器地址,参数有等于号,LDR R0, =0X30008000
  • NOP: 空操作伪指令,常用来延时,被翻译成 MOV R0, R0

二、LDR,MOV和LDR伪指令的区别

1)指令格式

  • LDR伪指令的指令格式为
    • LDR R0, =0X3000800; 有“=”表示伪指令,常数0x30008000写入R0
    • LDR R0, =LOOP; 将标号LOOP所代表的内存地址写入R0
  • LDR指令(非伪指令)通常用于寄存器间接寻址
    • LDR R0, [R1]; 将R1值作为内存地址,取该内存地址内容,存入R0
    • LDR R0, LOOP; 将标号LOOP代表的内存地址处的内容,存入R0
  • MOV 通常用于寄存器间传输数据
    • MOV R0, R1; 将寄存器R1的值,存入R0
    • MOV R0, #20; 将立即数20,存入R0

2) 用途

  • ARM 是 RISC结构,不能直接操作内存数据,要通过LDR/STD指令在内存和寄存器之间搬运数据;
  • MOV用来在寄存器之间搬运数据;
  • LDR伪指令常用来加载一个32位立即数或地址到指定寄存器。

三、思考

1)有了MOV指令和LDR指令,为什么还要使用LDR伪指令?

  • 为什么不能 LDR R0, 0X30008000
  • 在32位ARM中,外设寄存器地址是一个32位的地址。
  • ARM指令通常是 :32位 = 操作码 + 操作数 的thumb 16位指令
    在这里插入图片描述
    如果 0x30008000作为操作数,肯定存不进 ARM指令里,此时,需要通过伪指令,一条伪指令可以等效成多条指令。

四、LDR伪指令

1)转换为MOV 指令形式

  • 当立即数效于 8bit数范围时
  • LDR R0, =200
  • 相当于 MOV R0, #200

2)转换为LDR指令 + 文字池形式

	LDR R0, =0X30008000
	LDR R0,[PC, #offset]
	...
	DCD 0X30008000
  • PC的值是当前指令的地址,然后计算得到DCD处的偏移地址,从而找到DCD的地址,最后[ ]间接读0x30008000, 送入R0。
  • DCD它是定义一个数在内存中,编译器是知道这条指令的存在,从而可以计算出偏移数,同时,当前运行地址 =PC-8(由于ARM是采用多级流水线)。
  • 在内存中定义一个字的存储单元,将32bit地址 0x30008000 存放在存储单元中,该存储单元通常叫做 文字池(literal poll)。
  • 算出该存储单元到LDR伪指令之间的偏移offset,即可用相对寻址,将这个地址值送到R0寄存器。

五、ADR伪指令

1) 小范围地址读取的伪指令

  • 将基于PC相对偏移的地址值读到寄存器中。
  • 相对地址,做到代码与位置无关,即不管基地址是多少,只关系它的偏移量。
  • 实例
	ADR  R0, _start
	...
	_start
		b   _start
①采用相对地址,ADR伪指令当前地址+标号_start 与 ADR伪指令的偏移量。
②ADR当前指令地址是已知的 (PC -8)
③偏移量:offset = _start - (PC - 8)
④该指令被翻译成一条合适的指令:
		ADD R0, PC, #offset  (范围不超过8bit, 不然不够放,然后采用其它语句)

六、LDR和ADR比较

1)相同点

  • 都是ARM 伪指令,加载一个地址到指定寄存器。

2)不同点

  • LDR伪指令通过被翻译为 LDR 或 MOV指令, 而ADR 伪指令通常被翻译为 ADD或SUB指令
  • 用途上,LDR主要用来操作外设寄存器。ADR主要通过相对寻址,生成与位置无关的代码,只要各标号相对位置不变,就可以做到位置无关。
  • 实现上, LDR使用绝对地址, 而ADR使用相对地址
  • 地址范围:LDR为 [0, 4G], 但ADR要求标号必须在同一个段中,地址偏移范围:地址对齐[0, 1024], 未对齐[0, 4096]。
  • 位置无关代码经常被运用到 uboot启动和动态库 -fPIC

猜你喜欢

转载自blog.csdn.net/weixin_38956024/article/details/107445421