ARM指令adr和ldr的区别

很多人在写简单的裸机代码或分析uboot时,常常遇到adr和ldr指令。却分不清这2者的区别,现在谈谈adr与ldr指令。先写启动代码start.S。

.text
.globl _start
_start:
    ldr r0, test
    adr r0, test
    ldr r0, =test
    nop
test:
    nop

Makefile文件内容如下:

all : start.S
	arm-linux-gcc -c -o start.o start.S
	arm-linux-ld -Ttext 0x00000000 -g start.o -o start_elf
	arm-linux-objcopy -O binary -S start_elf start.bin
	arm-linux-objdump -D -m arm start_elf > start.dis
clean:
	rm -f *.dis  *.bin  start_elf  *.o

反汇编start.S得到start.dis:

file format elf32-littlearm
Disassembly of section .text:
	00000000 _start:
	0: e59f0008 ldr r0, [pc, #8]; 10 test
	4: e28f0004 add r0, pc, #4; 0x4
	8: e59f0004 ldr r0, [pc, #4]; 14.text+0x14
	c: e1a00000 nop (mov r0,r0)

	00000010 test:
	10:e1a00000 nop (mov r0,r0)
	14:00000010 andeq r0, r0, r0, lsl r0

1、先分析第一条指令ldr r0,test被编译成ldr r0, [pc, #8],即到当前PC+8的存储器取值,运行第一条指令时,PC其实已经是8了(流水线决定的)。那么8+8等于0x10,所以r0等于e1a00000,此指令的作用就是读取test地址处存放的值。由于此处放了一条nop,即得到nop的机器码。

2、第二条adr r0,test被编译成add r0, pc, #4 这显然是依赖程序执行到此处的PC值。ADR是小范围地址读取伪指令,会将基于PC 相对偏移的地址值读取到寄存器中,此指令在4地址,PC是4+8=0xc再加4,于是r0=0x10。从结果上来看,test自身的值(标号值),被读到了r0,这个值是以PC为参考的,也就是test对应的指令(第二个nop)当前的地址。r0=(标号test的地址与此指令的距离差)+(此指令的地址)=((0x10-0x4=12)+(4))=16=0x10。假如在0x30000000以上运行,r0=((12)+(0x30000004))= 0x30000010。

3、ldr r0,=test被编译成两个字,一个指令,一个文字池。执行到这里PC=8, 8+8+4=0x14,所以在14地址取值,编译器在14地址处放了0x00000010,0x00000010是test的值,假如在Makefile指定连接地址是0x30000000,那么编译器放在这里的就是0x30000010,可见,这个值是编译时确定的。最后一行andeq r0, r0, r0, lsl r0大概是编译器的机械动作,把一个数字翻译成了指令。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值