uboot-relocation学习总结
来源:互联网 发布:php curl exec返回空 编辑:程序博客网 时间:2024/06/06 18:23
近期学习uboot,在relocation部分看了不少大神的分析,下面将自己的理解写下来,也是对此部分功能的学习巩固。
1.1 为什么要relocation
uboot从SDRAM低位拷贝到高位后,各指令存储地址改变,对位置无法指令的执行,不受影响;但位置相关指令的执行,比如说读取一个全局变量(存储在一个绝对地址处),按照之前的寻址无法找到拷贝后的变量值,导致程序执行错误,这时即需要relocation来解决。
通过下面这个例子说明:
Static int G_test = 1;Uboot中执行函数:
Void Fun_test(void)
{
G_test = 0xff;
}
图中标识说明:
Fun_test: uboot中函数;
G_test: 全局变量,被函数Fun_test使用;
G_test_lable: 函数Fun_test尾端lable,其值是变量G_test的地址。
Fun_test_addr: 函数Fun_test拷贝前存储地址;
G_test_lable_addr:G_test_lable拷贝前存储地址;
G_test_addr:变量G_test拷贝前存储地址;
Fun_test_rel_addr:函数Fun_test拷贝后存储地址;
G_test_lable_rel_addr:G_test_lable拷贝后存储地址;
G_test_rel_addr:变量G_test拷贝后存储地址;
此处插入一个知识点,arm如何对变量G_test进行寻址:
(1)将变量G_test的地址存储在函数尾端的Label中(这段内存空间是由编译器自动分配的,而非人为);
(2)基于PC相对寻址获取函数尾端Label上的变量地址;
(3)对G_test变量地址进行读写操作。
下面看uboot在拷贝前函数Fun_test的执行:
1、调用函数Fun_test;
2、通过函数尾端lable:G_test_lable(存储地址是G_test_lable_addr)得到变量G_test存储地址G_test_addr,即[G_test_lable_addr] = G_test_addr;
3、根据变量G_test的存储地址对其进行读写操作,例子中将其赋值为0xFF。
4、函数执行结束,返回。
再看uboot拷贝后函数Fun_test的执行:
1、调用函数Fun_test;
2、通过函数尾端lable:G_test_lable(存储地址是G_test_lable_rel_addr)得到变量G_test存储地址仍然是G_test_addr,而不是我们期望的G_test_rel_addr,这样既无法准确获取变量的存储地址,导致程序执行出错。
relocation就是解决这个问题,使得uboot在拷贝后,仍能准确的寻址,避免程序执行出错,这就是relocation的原因。
由上面描述我们可以看出,问题出现在变量G_test的寻址上,不难看出只要将拷贝后的G_test_lable保存的值更新成拷贝后的变量存储地址G_test_rel_addr,问题就解决了,那如何操作呢,下面就是如何进行relocation。
1.2 如何relocation
直接看源码(uboot2014.10 arch/arm/lib/relocate.S)
ENTRY(relocate_code)ldrr1, =__image_copy_start/* r1 <- SRC &__image_copy_start */subsr4, r0, r1/* r4 <- relocation offset */beqrelocate_done/* skip relocation */ldrr2, =__image_copy_end/* r2 <- SRC &__image_copy_end */ copy_loop:ldmiar1!, {r10-r11}/* copy from source address [r1] */stmiar0!, {r10-r11}/* copy to target address [r0] */cmpr1, r2/* until source end address [r2] */blocopy_loop/*-------------------------------------dividing line-------------------------------------------*//* * fix .rel.dyn relocations */ldrr2, =__rel_dyn_start/* r2 <- SRC &__rel_dyn_start */ldrr3, =__rel_dyn_end/* r3 <- SRC &__rel_dyn_end */fixloop:ldmiar2!, {r0-r1}/* (r0,r1) <- (SRC location,fixup) */andr1, r1, #0xffcmpr1, #23/* relative fixup? */bnefixnext /* relative fix: increase location by offset */addr0, r0, r4ldrr1, [r0]addr1, r1, r4strr1, [r0]fixnext:cmpr2, r3blofixloop
分界线前面是uboot数据拷贝,后面是relocation,从代码可以看到,relocation对__rel_dyn_start与__rel_dyn_end之间数据进行了处理,专为relocation使用,其结构如下:
连续2个4字节(共8字节)组成一relocation处理部分,其中前4字节保存需要relocation的存储地址,后面4个字节是一个lable,标记前一地址需要relocation。__rel_dyn_start与__rel_dyn_end这段数据编译器在编译时产生,编译器讲uboot拷贝后需要relocation的存储地址(即例中的G_test_lable_addr)均记录在此段中,然后由上述代码进行遍历,实现relocation,下面看代码实现:
ldrr2, =__rel_dyn_start/* r2 <- SRC &__rel_dyn_start */ldrr3, =__rel_dyn_end/* r3 <- SRC &__rel_dyn_end */fixloop:ldmiar2!, {r0-r1}//从__rel_dyn_start开始,每次连续读取8字节andr1, r1, #0xffcmpr1, #23//判断后面四字节低字节是否为0x17bnefixnext//不是不进行relocation,跳至fixnext /* relative fix: increase location by offset *///是0x17,开始进行relocation//结合前面举例分析此段代码//r4保存拷贝偏移量offsetaddr0, r0, r4//r0=r0+offset,即例中,r0=G_test_lable_rel_addrldrr1, [r0]//将r0中的值(变量拷贝前的存储地址G_test_addr)赋值r1addr1, r1, r4//将存储地址+offset,即r1=G_test_addr+offset=G_test_rel_addrstrr1, [r0]//将变量存储地址存储到lable中(G_test_lable_rel_addr) fixnext:cmpr2, r3//判断遍历是否结束blofixloop
从上面代码可以看出,relocation处理即是例中所说,将拷贝后的变量lable存储的变量地址更新成拷贝后的变量存储地址。
除了全局变量以外,还有存储变量或函数的指针变量也需要relocation,其实道理是一样的,只是指针变量处理起来复杂一点。
1)首先根据上面方法将指针变量的lable存储的地址更新为拷贝后的存储地址;
2)再将存储地址的值(即变量或函数的地址)更新为拷贝后的存储地址。
此处的更新即是在原先的存储地址增加偏移量offset,类似于拷贝中的处理。
下面引用一位大神的总结:
总结一下,可以看出,
使用-pie选项的compiler,将需要relocate的值(全局变量地址 函数入口地址)的地址存储在rel.dyn段中,uboot运行中relocate_code遍历rel.dyn段,根据rel.dyn中存储的值,对以(这些值+offset)为地址上的值进行了relocate,完成对所有需要relocate的变量的修改!
需要注意的是,在uboot的整个relocate_code中rel.dyn不仅没有拷贝,也没有修改,修改只是针对rel.dyn中值+offset为地址上的值!
本文参考:《uboot的relocation原理详细分析》
更详细的分析请看此篇博客。
- uboot-relocation学习总结
- uboot relocation 重定位的总结与分析
- uboot relocation原理详细分析
- uboot relocation section .rel.dyn
- [UBOOT]uboot的relocation原理详细分析
- [uboot] (番外篇)uboot relocation介绍
- [uboot] (番外篇)uboot relocation介绍
- Uboot学习总结
- UBOOT学习总结
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- uboot的relocation原理详细分析
- 线程结束,GetExitCodeThread后结束值一直STILL_ACTIVE,259的问题
- 奎特尔入侵指南
- dubbo学习进度追踪
- CCF 公共钥匙盒
- Redis 高可用集群
- uboot-relocation学习总结
- LeetCode刷题(48)--Remove Duplicates from Sorted List II
- 初探OAuth2.0第三方认证登录
- 菜鸡的Django学习笔记(一)Linux+deepin+pycharm
- jdk 常用的queue
- 现代软件工程_团队项目_阿尔法阶段_第六次会议记录_2017.11.30
- 之前项目再集成webService发布服务 + log4j框架日志文件
- 程序员 30 岁前,该如何规划自己的职业发展?
- PyCharm3.0默认快捷键