2010年(49)
分类: 嵌入式
2010-09-07 14:40:10
Uboot的在启动后,是要拷贝代码到ram中运行的。拷贝到内存的什么地方呢?
一开始,在网络上搜索,发现都说config.mk文件中定义的TEXT_BASE地址是拷贝到内存时的地址。
首先,在连接的时候确实有TEXT_BASE作为链接地址;
其次,TEXT_BASE确实是RAM的地址;
但是,发现一个问题,网上讨论的硬件基础都是arm,在arm的开发版中,都是flash的基址为0,RAM的基址更高,这样TEXT_BASE刚好处于RAM的范围内,很好理解。
对ppc,则不同。在start.s中,由relocate_code部分代码看出,实际上TEXT_BASE在ppc中反而成为了拷贝uboot到ram中的source addr。而目标地址需要看调用relocate_code()函数的地方即board_init_f (ulong bootflag)末尾。
但是,问题随之而来,uboot编译的时候,TEXT_BASE明明是做为链接地址的啊?
通过查看编译程序,对于board.c文件编译之后是首先和其它.o做成.a库文件才和start.o链接起来。但是依然不能解释我的疑问。
问了好几个人了,没人说的清,但是uboot肯定有自己的解决办法。
最有可能是uboot自己执行的时候去计算便宜量。
当然,如果此时启动了MMU功能,那么编译的链接地址就属于虚拟内存空间,而在物理内存中的位置是任意的,mmu会进行地址的转换。
继续讨论上面的问题,mmu功能当前肯定是没开的。
那答案何在?
这时看到了start.s中在拷贝结束后,使用了GOT这个东东?GOT,搜索了一下是Global offset table的缩写,在linux中,got技术用于动态链接。GOT 表中是各个函数的动态链接地址。所以uboot参考了linux的got技术,使用了got表来保证rom拷贝到ram后程序能够在ram中执行。
另外,我发现在uboot中,只有ppc系列的cpu才会使用got技术,其它的cpu都没有使用。因为比如arm,它编译uboot时的连接地址就在ram中,所以拷贝到ram就ok了。但是偏偏ppcboot编译的连接地址是在flash中,所以需要使用got技术才能保证程序在ram中执行。
下述为从网上看到的讨论
如题
有朋友和我一样在读ppcboot的启动代码, 或者已经读过呢(我看的是mpc860)
我看到有关GOT的部分, 现在十分困惑. 经过近两周的分析和查找资料后, 初步有以下理解, 但是并没有弄清楚GOT在ppcboot中扮演的作用.
#define START_GOT
.section ".got2","aw";
.LCTOC1 = .+32768
#define END_GOT
.text
#define GET_GOT
bl
.text 2 ;
0: .long .LCTOC1
.text ;
1: mflr r14 ;
lwz r0,0b-1b(r14) ;
add r14,r0,r14 ;
#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
#define GOT(NAME) .L_ ## NAME (r14)
宏定义在include/ppc_asm.tmpl
应用在start.S中
我在网页上搜索到关于GOT的内容, 自然就关联到了ELF的GOT, 我大致看了一下, 我想这两种应该是一样的, 就是ppcboot只是使用了GOT这种技术.
不知道我理解的对不对
GOT是为了实现位置无关(position-independent)的代码. 例如在x86架构下, Linux系统下, 如果我们运行的程序调用了某个标准库, 当调用具体的函数时, 程序讲跳转到PLT, 然后从PIT跳转到GOT, 这样才会找到具体的库函数的位置.
但是我很困惑, 在ppcboot中start.S只有in_flash标签下才使用了一次"GET_GOT", 而在开始处定义的
START_GOT
GOT_ENTRY(_GOT2_TABLE_)
GOT_ENTRY(_FIXUP_TABLE_)
GOT_ENTRY(_start)
GOT_ENTRY(_start_of_vectors)
GOT_ENTRY(_end_of_vectors)
GOT_ENTRY(transfer_to_handler)
GOT_ENTRY(_end)
GOT_ENTRY(.bss)
#if defined(CONFIG_FADS) || defined(CONFIG_ICU862)
GOT_ENTRY(environment)
#endif
END_GOT
我没有看到到底起了什么作用?
我迫切希望大家能一起讨论一下, 不明白一件事情, 真的很痛苦.
1
知道一点点,不知对否
START_GOT 至 END_GOT 里放的变量,是为了方便将来程序从ROM搬至RAM。GOT表里放的应该是ROM、RAM都需用到的变量,将来搬移时只需在它基础上加偏移量即可。
访问变量时看后面的GET_GOT:
如 lwz r6,
GOT(transfer_to_handler)
2
动态库要解决的一个问题是代码/变量地址在编译时不能确定,GOT就是用来解决这个问题的技术。
u-boot运行时要从Flash搬到RAM高端,RAM大小是运行时检测出来的,编译时不能确定,这和动态库面对的问题相同,正好可以用GOT技术解决。