Chinaunix
标题:
关于uboot重定位方面的总结和问题
[打印本页]
作者:
likelinux123
时间:
2013-12-01 18:04
标题:
关于uboot重定位方面的总结和问题
在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可,然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。
在最新的uboot里(2013.07),TEXT_BASE的含义改变了。他表示用户要把这个代码下载到哪里,通常是通过串口等工具。然后搬移的时候由uboot自己计算一个地址来进行搬移。在init_f函数中计算出了要搬移到的地方,然后relocate.S来进行搬移。问题是我们在编译的时候明明指定的TEXT_BASE和这个地址不一致,那么在搬移到新的地址后,代码运行不会跑飞吗?在代码阅读的过程中发现,新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的位置处,就可以在绝对跳转中找到正确的函数。
我的开发环境是2440,现在还留有两个问题:
1.在新版的uboot中如果我定义TEXT_BASE是0x32000000,但是下载代码到0x30000000启动会不会能正确运行?
初步分析:不能
因为在拷贝之前执行了init_f函数,这个函数中程序跑飞了,具体原因可能是有绝对的跳转,但是没有足够证据。
2.在relocate.S中有以下代码:
copy_loop:这段主要是进行代码段拷贝
46 ldmia r1!, {r10-r11} /* copy from source address [r1] */
47 stmia r0!, {r10-r11} /* copy to target address [r0] */
48 cmp r1, r2 /* until source end address [r2] */
49 blo copy_loop
50
51 /*
52 * fix .rel.dyn relocations
53 */
54 ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
55 ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
56 fixloop:/这段进行了根据动态链接区域修改函数跳转表的动作,加了偏移的地址
57 ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
58 and r1, r1, #0xff
59 cmp r1, #23 /* relative fixup? */
60 bne fixnext
61
62 /* relative fix: increase location by offset */
63 add r0, r0, r9/r9为偏移数值,基本原理就是取出之前函数对应的位置,加上偏移,写到新地址的对应位置处(应该是跳转表什么的)。
64 ldr r1, [r0]
65 add r1, r1, r9
66 str r1, [r0]
67 fixnext:
68 cmp r2, r3
69 blo fixloop
这里有个疑问,这里判断r1 和#23的关系,通过察看二进制文件可以发现确实有这样的一个排布:
7545 001d780: 1700 0000 3800 0032 1700 0000 8407 0032 ....8..2.......2
7546 001d790: 1700 0000 8807 0032 1700 0000 8c07 0032 .......2.......2
7547 001d7a0: 1700 0000 e407 0032 1700 0000 e807 0032 .......2.......2
7548 001d7b0: 1700 0000 ec07 0032 1700 0000 f007 0032 .......2.......2
7549 001d7c0: 1700 0000 4808 0032 1700 0000 4c08 0032 ....H..2....L..2
7550 001d7d0: 1700 0000 7808 0032 1700 0000 4009 0032
....x..2....@..2
7551 001d7e0: 1700 0000 4409 0032 1700 0000 4809 0032 ....D..2....H..2
7552 001d7f0: 1700 0000 4c09 0032 1700 0000 5009 0032 ....L..2....P..2
7553 001d800: 1700 0000 5409 0032 1700 0000 5809 0032 ....T..2....X..2
7554 001d810: 1700 0000 5c09 0032 1700 0000 6009 0032 ....\..2....`..2
7555 001d820: 1700 0000 6409 0032 1700 0000 a00a 0032 ....d..2.......2
7556 001d830: 1700 0000 a40a 0032 1700 0000 a80a 0032 .......2.......2
这里为什么要用0x17(23)呢?他的来历是什么?每一个地址后面都跟了一个0x17.比如:
0x32000038 0x00000017
作者:
likelinux123
时间:
2013-12-02 23:27
今天貌似又有点进展:
之前看老的版本的uboot,比如1.1.6.它是用了got表,具体用到没有分析,但是教新的版本(2013.07)采用了动态链接段。先贴段代码:
{
30 *(.__image_copy_end)
31 }
32 .rel_dyn_start :
33 {
34 *(.__rel_dyn_start)
35 }
36 .rel.dyn : {
37 *(.rel*)
38 }
39 .rel_dyn_end :
40 {
41 *(.__rel_dyn_end)
42 }
这是u-boot.lds文件中的一段:有个rel.dyn段,这个段里面存放的是动态链接的信息。这个是我们在写lds文件的时候事先设置好的。那么怎么让ld能根据我们的设定来进行操作呢?在arch/arm目录下有一个config.mk文件,里面有LDFLASG_u-boot += pie,这个选项表示的意思我们可以在 doc/README.arm-relocation 文件中找到说明,也可以man elf找到。他就是告诉ld要动态链接,ld看到有这个选项就会去找rel区域。
在GCC的文档中找到:
fpie
-fPIE
These options are similar to ‘-fpic’ and ‘-fPIC’, but generated position inde-
pendent code can be only linked into executables. Usually these options are
used when ‘-pie’ GCC option will be used during linking.
‘-fpie’ and ‘-fPIE’ both define the macros __pie__ and __PIE__. The macros
have the value 1 for ‘-fpie’ and 2 for ‘-fPIE’.
就是说我们在编译的时候需要指定fpie这个选项,这样在编译的时候就给ld提供了需要rel段数据,这个数据应该是保存在每个.o文件中的。然后ld根据这些rel数据在最后的elf类型文件中合成一个大的rel段。这个区域必须以.rel开头,后面可以是.dyn也可以不是,ld只认.rel开头的区域。
不知道这样理解对不对,先写到这里,后期要把gcc的编译选项了解一下,ld的选项,和elf文件的格式也要学习。
作者:
EZWORD
时间:
2013-12-06 08:41
一般下载地址与执行地址关系不大。
至少以前的代码中,下载地址与链接地址不一样是可以执行的。
这个也与程序有关系的,当然你可以搞成原地执行。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2