b/bl解析:
sdram.lds:
SECTIONS
{
. = 0X30000000;
...
}
start.S:
...
bl main
sdram.dis:
3000005c: eb000105 bl 30000478
...
30000478 :
将sdram.lds进行修改:. = 0X32000000; 重新编译,查看sdram.dis:
3200005c: eb000105 bl 32000478
...
32000478
可得,这个跳转不是跳到0X30000478去执行,而是相对地址,即: 跳到当前pc+offset(也就
是sdram_init的位置)去执行。
b/bl指令不关心运行(链接)地址,它只是找到想要跳转的目标, 然后用pc进行偏移来过去执行,
不关心目标的链接地址:如果程序是从0X30000000开始执行,则跳到0X30000478 去执行;如果程序是从
0 开始执行,则跳到0X478去执行。看上边链接地址不同时,机器码却是相同的。
反汇编文件.dis中左边那一列地址,仅仅是供我们查看。
ldr解析:
sdram.lds:
SECTIONS
{
. = 0X30000000;
...
}
start.S:
...
ldr pc, =main
sdram.lds
300000a0: e59ff01c ldr pc, [pc, #28] ; 300000c4 <.text+0xc4>
...
3000062c :
3000062c: e1a0c00d mov ip, sp
用ldr伪指令时,它是跳到pc+offset地址处的值来执行,即执行*(pc + offset),而b/bl指令执行(pc + offset)
怎么写位置无关的程序:
使用位置无关码,不使用绝对地址,最根本的办法是看反汇编
a. 调用程序时使用B/BL相对跳转指令,而不是ldr pc, =main这种
b. 重定位之前, 不可使用绝对地址,比如:
不可访问全局变量/静态变量
不可访问有初始值的数组(因为初始值放在rodata里,使用绝对地址来访问)
c. 重定位之后, 使用绝对跳转命令跳到Runtime Addr,比如:
ldr pc, =main