很多人在写简单的裸机代码或分析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大概是编译器的机械动作,把一个数字翻译成了指令。
上一篇:tiny4412开发板GPIO试验
下一篇:tiny4412裸机程序之位置无关码
推荐阅读最新更新时间:2024-11-13 13:31
设计资源 培训 开发板 精华推荐
- BTS4130QGA智能高端电源开关典型应用电路
- 2019年(F题)纸张计数显示装置+662763A
- RXCA10X115BF40-FHP00A,基于 Altera FPGA Arria 10 GX 的 ATTILA 即时开发套件 (COTS GX ES2)
- STM32F072RB MCU探索套件
- EVAL-AD7623CB,AD7623 评估板,16 位,1.33 Msps PulSAR 模数转换器
- 使用 Analog Devices 的 LT3470HDDB 的参考设计
- MC33072ADR2G 二阶高通有源滤波器的典型应用
- CN0209
- 适用于STM32F042K6 MCU的STM32 Nucleo-32开发板,支持Arduino nano连接
- 使用 Analog Devices 的 LTC1266 的参考设计