一. uboot启动流程
本文学习 uboot 的启动流程中涉及的 uboot 代码重定位部分。
_main 函数中会调用 relocate_code 函数,本文继续简单分析一下 relocate_code 函数。
relocate_code 函数分两个部分:
1. 拷贝 uboot 代码部分
2. 有关 " 重定位后有关函数调用或全局变量地址的问题"的解决方法。
二. uboot代码重定位
1. uboot一些变量的地址
要分析 uboot 的启动流程,首先要找到“入口”,找到第一行程序在哪里。
程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。连接脚本在uboot的根目录下u-boot.lds文件。
在 u-boot.lds 中有一些跟地址有关的“变量”,我所编译后的uboot源码涉及的变量的值如下:
变量 | 数值 | 描述 |
__image_copy_start | 0X87800000 | uboot拷贝的首地址 |
__image_copy_end | 0X8786B03C | uboot拷贝的结束地址 |
__rel_dyn_start | 0X8786B03C | .rel.dyn 段起始地址 |
__rel_dyn_end | 0X8787459C | .rel.dyn 段结束地址 |
_image_binary_end | 0X8787459C | 镜像结束地址 |
__bss_start | 0X8786B03C | .bss 段起始地址 |
__bss_end | 0X878B7314 | .bss 段结束地址 |
2. _main函数
_main 函数中会调用 relocate_code 函数,调用的地方如下:
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */b relocate_code
可以看出,relocate_code函数有一个参数,r0=gd->relocaddr=0X8FF38000,uboot重定位后的首地址。
3. relocate_code 函数:拷贝代码部分
relocate_code 函数是用于代码拷贝的,此函数定义在文件 arch/arm/lib/relocate.S 中。relocate_code 函数的前半部分代码如下:
79 ENTRY(relocate_code)
80 ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
81 subs r4, r0, r1 /* r4 <- relocation offset */
82 beq relocate_done /* skip relocation */
83 ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */
84
85 copy_loop:
86 ldmia r1!, {r10-r11} /* copy from source address [r1] */
87 stmia r0!, {r10-r11} /* copy to target address [r0] */
88 cmp r1, r2 /* until source end address [r2] */
89 blo copy_loop
我们知道,一个可执行的 bin 文件,其链接地址和运行地址要相等,也就是链接到哪个地址, 在运行之前,就要拷贝到哪个地址去。现在我们重定位以后,运行地址就和链接地址不同了,这 样寻址的时候不会出问题吗?