理解adr,ldr指令

在阅读u-bootstart.S时,对adr和ldr指令有些疑惑,经韦老师指点,在参阅了一些网上的博文后,做了这个实验:

参照韦老师的代码和Makefile写了

test_adr.S

.text

.globl _start

_start:
    ldr r0,test

    adr r0,test

    ldr r0,=test

    nop

test:

    nop

Makefile

all:test_adr.S

        arm-linux-gcc -c -o test_adr.o test_adr.S
        arm-linux-ld -Ttext 0x00000000 -g test_adr.o -o test_adr_elf

        arm-linux-objcopy -O binary -S test_adr_elf test_adr.bin

        arm-linux-objdump -D -m arm test_adr_elf > test_adr.dis

clean:

        rm -f test_adr.dis test_adr.bin test_adr_elf *.o

对test_adr.S:反汇编得到test_adr.dis

test_adr_elf:
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

首先很显然,ldr获取的是内存的值(至于这个内存存的是数据还是地址,这个不是问题的重点,先不讨论),像指针一样间接寻址(看到了[]符号咯

而adr是得到了一个与PC有关的值,必定是个地址,韦老师举了个例子:

adr r0, _start 时,r0就是_start对应的指令当前的地址

对于“_start对应的指令当前的地址”,我理解了很久,终于想清楚,比如在uboot中,_start标号对应的指令(即b reset这条指令)的链接地址是0x33f80000这个确凿无疑。

如果从NORFlash启动时,b reset被烧在NORFlash的0地址,那么b reset相对于此时的PC来说,它的地址就是0;

如果u-boot是被直接下载到SDRAM的0x33f80000运行,那么b reset这条指令自然也就处在SDRAM的0x33f80000处;

所谓“当前”是以运行时的PC为参照。

下面基于以上理解,分析一下test_adr.dis

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

先分析第一条指令ldr r0,test别编译成ldr
r0, [pc, #8],也就是到当前PC+8的存储器取值,当运行第一条指令时,PC其实已经是8了(流水线决定的)

那么8+8就等于0x10,所以r0就等于e1a00000,这条指令的作用就是读取test地址处存放的值。由于此处放了一条nop,那么就是得到了nop的机器码而已

第二条adr r0,test被编译成add r0, pc, #4
这显然是依赖程序执行到此处时的PC值了。
ADR是小范围的地址读取伪指令.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
这个东西大概是编译器的机械动作,把一个数字也翻译成了指令
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值