uboot在启动时的运行地址一般不是链接时指定的地址,这也使得uboot的前面部分代码需要对代码进行重定位,重定位的目标地址便是链接时指定的运行地址。另外能够在非链接地址位置运行的代码都是相对寻址的。
        为了和源码当中对重定位的描述保持一致,下面所有的重定位都叫relocate(虽然重定位翻译过来就是relocate,但很多文章一会用英文,一会用中文,在描述上又存在一定的差异,导致概念认知混乱)。随着uboot的发展,基于一定原因的考虑,uboot的地址重定位已经有很多个版本,本文仅对2010-12之前的拷贝方式(基于arm920t核)进行阐述,在2010-12之前包括命名更改之前的所有版本都使用同一种地址重定位方式,这是由程序的布局决定的。
拷贝部分的源码:

点击(此处)折叠或打开

  1. relocate: /* relocate U-Boot to RAM */
  2.         adr     r0, _start                          /* r0 <- current position of code */
  3.         ldr      r1, _TEXT_BASE             /* test if we run from flash or RAM */
  4.         cmp   r0, r1                          /* don't reloc during debug         */
  5.         beq    stack_setup
  6.         ldr     r2, _armboot_start
  7.         ldr     r3, _bss_start
  8.         sub    r2, r3, r2                      /* r2
  9.         add    r2, r0, r2                      /* r2
  10.       
  11. copy_loop:
  12.         ldmia   r0!, {r3-r10}               /* copy from source address [r0]    */
  13.         stmia   r1!, {r3-r10}               /* copy to   target address [r1]    */
  14.         cmp     r0, r2                          /* until source end addreee [r2]    */
  15.         ble       copy_loop

        这就是u-boot拷贝的代码,其思路是找到当前程序运行的首地址在哪里,程序的总大小是多少,目标地址在哪里,知道了这些信息,则只需要一边读,一边写直到写完即可。

1.当前程序运行的首地址在哪里?
    adr     r0, _start                          /* r0 <- current position of code */    
    这是一条adr伪指令,目的便是为了获取_start标号在初始运行时的地址是多少。这条指令在编译的时候就会被真实的指令所替代,如:
    sub     r0, pc, #164                    /* _start标号的地址在pc前面164byte处 */    
    在编译时,编译器便确定pc指向这条语句时和_start标号的地址差多少,然后用实际的指令进行替代。这样在relocate之前,程序到底位于什么地方,即首地址便知道了。

2.程序的大小有多大?
        ldr     r2, _armboot_start 
        ldr     r3, _bss_start
        sub    r2, r3, r2                      /* r2   
         _armboot_start是一个地址,该地址存放的是_start地址,和当前程序运行的首地址不同,_start标号是链接时指定的首地址,即链接时指定的程序首地址,如果链接时指定首地址为0x3f000000,那么_start标号便是0x3f000000。_bss_start也是一个地址,存放的是链接时指定的bss段的首地址,也就说armboot_start和bss_start之间存放着程序所需要的正文段、数据段等,通过这两个地址相减,便得到了中间部分的大小。

3.拷贝的目标地址在哪里?
        ldr      r1, _TEXT_BASE         
        毫无疑问,relocate的目标地址便是链接时指定的首地址,uboot的编译系统会将TEXT_BASE的值最终反应到链接命令当中去,让其成为程序链接的首地址,所以目标地址就是TEXT_BASE。

        有了这三个要素,拷贝便可完成。
12-10 05:35