UBOOT之源码分析(X4412)——代码重定位

本文详细介绍了UBoot在X4412平台上的代码重定位过程,涉及board_init_f函数、relocate_code函数以及start.s中的相关代码。通过对addr_sp、id和addr参数的解释,阐述了堆栈设置、代码是否需要重定位的判断及代码拷贝到目标地址的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考http://blog.youkuaiyun.com/xieweihua2012/article/details/8474655根据X4412-uboot源码理解整理

board_init_f函数的最后返回到relocate_code,调用该函数的原型是Relocate_code(addr_sp,id,addr),其中三个参数的意义:

addr_sp是地址空间里面堆栈的首地址0xc3cf_bf50

id是存储gd_t类型全局参数的首地址0xc3cf_bf58

addruboot的重定位地址,也就是加载地址0XC3E0_0000

这三个参数的值都是在board_init_f函数里面定义好了的(UBOOT之源码分析(X4412)-----板级初始化)。

现在跳到arch/arm/cpu/armv7/start.s中的relocate_code代码标号处。

.globl         relocate_code

relocate_code:

         mov  r4, r0 /*save addr_sp */

         mov  r5, r1 /*save addr of gd */

         mov  r6, r2 /*save addr of destination */

这里面r0,r1r2分别对应上面所讲的三个参数

r0 – addr_sp

r1 – id

r2 – addr

         /* Setup the stack*/

stack_setup:

       mov sp,r4

        

设置堆栈指针

adr   r0,_start 

#ifndef CONFIG_PRELOADER 

         cmp r0,r6

         beq clear_bss   /*skip relocation*/

        

#endif

adr是小范围的地址读取伪指令,这条指令也可以理解成ldr r0,=PC+x,PC是该条指令的地址,xPC_start标号之间的偏移量(_start-PC),_start永远位于代码的最开始,当PC>_start时,x为负值,否则x为正值。所以当代码此时还在flash中时,_start0(内部ram),PC+x(x<0)=PC+_start-PC = _start=0,r0=0,如果代码此时已经在SDRAM中了(即已经拷贝过了),_start = TEXT_BASE,r0 = TEXT_BASE。所以接下来就比较r0r6(r6存储的重定位地址),如果相等,就说明已经拷贝过了,就跳过重定位代码,否则,就要执行重定位代码。我们这里是需要重定位的。

      mov r1,r6       /*r1<-scratch for copy_loop*/

     ldr r2,_TEXT_BASE   

     ldr r3,_bss_start_ofs

     add  r2,r0,r3   /*r2<-source end address*/

copy_loop:

        ldmia  r0!,{r9-r10}    /*copy from source address [r0]*/

        stmia  r1!,{r9-r10}   /**copy to target address[r1]/

       cmp r0,r2     /*until source end address[r2]*/

       blo copy_loop     

_TEXT_BASE标号处存放的是CONFIG_SYS_TEXT_BAE,改变量定义在/board/samsung/smdk4212/config.mk值为0xc3e0_0000,不过在这段程(ldr r2,_TEXT_BASE 
)序中好像没什么用,
add r2,r0,r3 使得r2 =r3(因为r0=0),即BSS段的开始地址,也就是代码段的结束地址。整个copy_loop循环就是将uboot代码拷贝到重定位地址处(即addr指明的地址)

#ifndef CONFIG_PRELOADER 
    /*
     * fix .rel.dyn relocations
     */
    ldr    r0, _TEXT_BASE        /* r0 <- Text base */
    sub    r9, r6, r0        /* r9 <- relocation offset */
    ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
    add    r10, r10, r0        /* r10 <- sym table in FLASH */
    ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
    add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
    ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
    add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
fixloop:
    ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
    add    r0, r0, r9        /* r0 <- location to fix up in RAM */
    ldr    r1, [r2, #4]
    and    r7, r1, #0xff
    cmp    r7, #23            /* relative fixup? */
    beq    fixrel
    cmp    r7, #2            /* absolute fixup? */
    beq    fixabs
    /* ignore unknown type of fixup */
    b    fixnext
fixabs:
    /* absolute fix: set location to (offset) symbol value */
    mov    r1, r1, LSR #4        /* r1 <- symbol index in .dynsym */
    add    r1, r10, r1        /* r1 <- address of symbol in table */
    ldr    r1, [r1, #4]        /* r1 <- symbol value */
    add    r1, r1, r9        /* r1 <- relocated sym addr */
    b    fixnext
fixrel:
    /* relative fix: increase location by offset */
    ldr    r1, [r0]
    add    r1, r1, r9
fixnext:
    str    r1, [r0]
    add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
    cmp    r2, r3
    blo    fixloop
在链接文件arch/arm/cpu/armv7/u-boot.lds中有两段:dynsym动态符号表,.rel.dyn动态重定位表。上面程序的主要工作就是将dynsym和.rel.dyn重定位,并遍历.rel.dyn,根据重来位表中的信息将符号表中的函数地址等进行重定位。
clear_bss:
    ldr    r0, _bss_start_ofs
    ldr    r1, _bss_end_ofs
    ldr    r3, _TEXT_BASE        /* Text base */
    mov    r4, r6            /* reloc addr */
    add    r0, r0, r4
    add    r1, r1, r4
    mov    r2, #0x00000000        /* clear                */

clbss_l:str    r2, [r0]        /* clear loop...            */
    add    r0, r0, #4
    cmp    r0, r1
    bne    clbss_l
#endif    /* #ifndef CONFIG_PRELOADER */
找到BSS段的起始地址与结束地址,然后循环清0整个BSS段。
接下来跳转到重定位后的内存位置,在内存中运行代码进入第二阶段的初始化


/*
 * We are done. Do not return, instead branch to second part of board
 * initialization, now running from RAM.
 */
jump_2_ram:
    ldr    r0, _board_init_r_ofs
    adr    r1, _start
    add    lr, r0, r1
@    add    lr, lr, r9
    /* setup parameters for board_init_r */
    mov    r0, r5        /* gd_t */
    mov    r1, r6        /* dest_addr */
    /* jump to it ... */
    mov    pc, lr

_board_init_r_ofs:
    .word board_init_r - _start

_rel_dyn_start_ofs:
    .word __rel_dyn_start - _start
_rel_dyn_end_ofs:
    .word __rel_dyn_end - _start
_dynsym_start_ofs:
    .word __dynsym_start - _start
此时的_start为重定位后代码起始地址。起始地址+board_init_r位置的偏移量即为 board_init_r函数的入口地址保存到lr。通过mov pc,lr中转到 board_init_r进行下一阶段的初始化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值