uboot中的汇编 adr r0, _start详解

在U-Boot的代码重定位部分(start.S)有这么一段:

relocate:           /* relocate U-Boot to RAM       */
adr r0, _start      /* r0 <- current position of code   */
ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
cmp r0, r1          /* don't reloc during debug         */
beq stack_setup

从注释可知,adr r0, _start虽加载的是同一个标号_start的地址,但是其结果会因为当前U-Boot到底是运行于Flash还是运行于RAM而有所不同!主要是由于链接地址与运行地址的不一致导致的。

1 位置无关指令

根据参考资料[2]的指出,在汇编语言中,bl、b、adr(adr属于伪指令,一般被编译器解释成sub指令)指令都属于位置无关指令,不管程序装载在哪个位置上,bl、b、adr指令都能正确的运行,其原因是bl、b、adr指令的地址域是基于PC的相对偏移寻址,相当于PC+offset。当ARM启动时,ARM自动取0x00000000位置上的指令,此时PC=0x00000000。基于PC偏移量的指令都能正确的执行。

2 偏移offset

对于adr r0, _start,标号_start的值在链接的时候已经确定(smdk2410将_start链接为0x33f80000),在后期运行时也是无法改变的。同时adr r0, _start命令的链接地址也是在链接时就已经确定了(这里假设为0x33f80010)。因此_start链接地址与adr r0, _start链接地址之间的偏移offset = 0x33f80000 - 0x33f80010 = -0x10。这个偏移是固定的(因为链接地址是固定的)。

3 FLASH运行

在FLASH运行时候,标号_start存储于0x00000000地址处,而相应的adr r0, _start命令存储于地址0x00000010处。当执行adr r0, _adr命令时,PC等于其存储地址0x00000010,因此r0 = PC + offset = 0x00000010 - 0x10 = 0x00000000。

4 RAM运行

假设已经通过重定位将U-Boot的代码复制到SDRAM 0x33f80000开始的位置,此时_start存储于0x33f80000地址处,adr r0, _ad命令存储于0x33f80010地址处。当在RAM中执行该命令时,PC等于其存储地址0x33f80010,偏移地址offset不变,因此r0 = PC + offset = 0x33f80010 - 0x10 = 0x33f80000。

5 总结

通过上述分析可知,当U-Boot分别运行的FLASH和RAM时,adr r0, _start的结果是不一样的,主要是因为PC不一样,但是偏移offset是不变的。

参考资料

[1]从两句汇编认识运行时地址与链接地址

[2]U-Boot移植过程中的运行地址和装载地址的区别

你可能感兴趣的:(❏【u-boot,分析】)