代码重定位可以将一段代码镜像到另一个地址,有点像链接,不过镜像位置所占空间大小和原代码位置所占大小相同。

那么为什么要这么做呢

我们知道,越是高速的设备越贵,因此为了节约成本,这些高速设备空间都比较小,比如像S5PV210中的SRAM,只有96KB的大小,但是不需要初始化;SDRAM虽然可以做到很大,多以G做单位,但是需要软件初始化。

产品中使用的bootloader可能可以裁剪到几十K的大小,但是如果想使用uboot的话,就会发现,才几十K的空间根本不够用;为了解决这个办法,只好使用重定位的方法,将uboot的代码重定位到容量比较大,速度又还过得去的SDRAM中,在SDRAM中运行系统。

长跳转与短跳转

在镜像后,运行时地址相关函数地址也会被映射到镜像地址处,要想执行镜像代码处的函数,就需要使用长跳转ldr,而不是短跳转bl。

adr短加载和ldr长加载的不同

1
2
3
4
5
6
7
8
9
10
11
//file: .S
...
adr r0, _start
ldr r1, =_start
...

//file: .dis
...
d002401c: e24f0024 sub r0, pc, #36 ; 0x24
d0024020: e59f1048 ldr r1, [pc, #72] ; d0024070 <run_on_dram+0x10>
...

清bss

把链接地址处把bss段清零,这是为了避免脏数据,万一连接处的bss段不为0,会导致c语言中的全局变量不为0。

运行处的bss段不需要清0,编译器已经帮忙清0过了。

需要重定位的长度为代码段+数据段

两级流水线导致pc的值指向前2两个字节

而且pc指针指向的是当前地址,而不是被链接到的地址,实际pc的地址为当前地址加两个字节