IMX8 UBOOT源码分析七)relocate_code重定位代码分析

上篇博客主要分析了main函数的主要框架,还要relocate_code、board_init_f、board_init_r   三个主要函数没有分析。这篇博客主要分析relocate_code重定位函数。

重定位代码的作用:

    我们知道当从NAND FLASH中启动代码的时候,SOC系统会自动复制4K的内容到片内内存中,然后从片内内存中开始执行。而我们的U-BOOT程序大小远远大于4K,那多余的代码怎么加载到内存运行,这个时候就需要对代码进行重定位。

重定位的功能是将我们的程序拷贝到内存的某块地址中,在片内4K的程序执行结束之前跳到重定向的位置处进行执行

在上篇博客中,我们分析了:

        ldr    x0, [x18, #GD_START_ADDR_SP]        //x0存入gd->start_addr_sp的地址
        bic    sp, x0, #0xf                                            //sp指向x0并且16字节对齐

       //重新设置栈指针的地址为gd->start_addr_sp
        ldr    x18, [x18, #GD_NEW_GD]                    //x18存入gd->new_gd的地址

       //将x18设置为新的gd地址gd->new_gd

        adr    lr, relocation_return                              //设置lr为relocation_return的地址

        ldr    x9, [x18, #GD_RELOC_OFF]               //x9存入gd->reloc_off 的地址
        add    lr, lr, x9                                                //设置新的返回地址为lr+x9

        //设置程序新的返回地址为重定向处的地址lr + gd->reloc_off
        ldr    x0, [x18, #GD_RELOCADDR]              //将重定向的地址gd->relocaddr赋值给x0传入重定向函数
        b    relocate_code

       //关于gd重定位变量的初始化主要在board_init_f中,后续分析board_init_f函数中在分析

relocate_code代码分析:

    ENTRY(relocate_code)
        stp    x29, x30, [sp, #-32]!                            //保存x29和x30寄存器的值
        mov    x29, sp                                              //保存栈的地址到x29中
        str    x0, [sp, #16]                                        //将重定向地址x0存入到sp+16处

      adr    x1, __image_copy_start                     //__image_copy_start在连接文件中定义,程序的起始地址
      subs    x9, x0, x1       
      b.eq    relocate_done        

      //如果重定向地址等于程序的起始地址,则跳过重定向过程

      ldr    x1, _TEXT_BASE        
      subs    x9, x0, x1        

     //计算出重定向地址与程序代码段地址的偏移量offset并存入x9寄存器中

    adr    x1, __image_copy_start    
    adr    x2, __image_copy_end    
copy_loop:
    ldp    x10, x11, [x1], #16    /* copy from source address [x1] */
    stp    x10, x11, [x0], #16    /* copy to   target address [x0] */
    cmp    x1, x2            /* until source end address [x2] */
    b.lo    copy_loop
    str    x0, [sp, #24]

    //将__image_copy_start 到__image_copy_end 中的代码拷贝到重定向地址处,并保存新的代码段地址到sp+24中

    adr    x2, __rel_dyn_start    /* x2 <- Run &__rel_dyn_start */
    adr    x3, __rel_dyn_end    /* x3 <- Run &__rel_dyn_end */
fixloop:
    ldp    x0, x1, [x2], #16    /* (x0,x1) <- (SRC location, fixup) */
    ldr    x4, [x2], #8        /* x4 <- addend */
    and    x1, x1, #0xffffffff
    cmp    x1, #R_AARCH64_RELATIVE
    bne    fixnext

fixnext:
    cmp    x2, x3
    b.lo    fixloop

   /*由于重定向之后,程序的运行地址与链接地址不一致,需要使用需要使用“位置无关代码”技术。对于一些绝对地址符号,使用位置无关码技术会将其以label的形式放在每个函数的代码实现的末端,统一保存在rel_dyn段中。该处程序的功能即将这些绝对地址转化为重定位之后的新的地址。

  从反汇编代码中截取一段rel_dyn段的信息如下:

    80074698:    80021758     .word    0x80021758
    8007469c:    00000000     .word    0x00000000
    800746a0:    00000403     .word    0x00000403
    800746a4:    00000000     .word    0x00000000

    800746a8:    8007eb98     .word    0x8007eb98
    800746ac:    00000000     .word    0x00000000
    800746b0:    80021760     .word    0x80021760
    800746b4:    00000000     .word    0x00000000
    800746b8:    00000403     .word    0x00000403
    800746bc:    00000000     .word    0x00000000

    800746c0:    8009ebf8     .word    0x8009ebf8
    800746c4:    00000000     .word    0x00000000

每个标签有24个字节,其中中间8个字节是标签地址标识00000403即为R_AARCH64_RELATIVE(1027),该程序的含义为,取出标签中的24个字节分别放入x0/x1/x4中,当x2等于R_AARCH64_RELATIVE时说明为标签地址,故需要重定向x0、x4的地址,即加上偏移值x9,然后将新的全局变量地址x4写入到重定位后的地址x0处。

relocate_done:
    switch_el x1, 3f, 2f, 1f
    bl    hang
3:    mrs    x0, sctlr_el3
    b    0f
2:    mrs    x0, sctlr_el2
    b    0f
1:    mrs    x0, sctlr_el1

//根据不同中断等级读取相应的sctlr_el寄存器值存入到x0中
0:    tbz    w0, #2, 5f                        //如果w0的第2位为0则跳到5,即跳过刷新缓存
    tbz    w0, #12, 4f                         //如果w0的第12位为0则跳到4,即跳过对i-cache的影响
    ic    iallu                                      //设置对整个i-cache有效
    isb    sy                                       //指令同步
4:    ldp    x0, x1, [sp, #16]             //取出sp+16处的值分别赋给x0、x1,从上面分析可知,x0为重定向地址,x1为重定向代码末端地址
    bl    __asm_flush_dcache_range      //刷新数据缓存区
5:    ldp    x29, x30, [sp],#32                 //取出保存的 x29, x30寄存器的值
    ret
ENDPROC(relocate_code)

关于代码的重定向就分析到这里,由于水平有限,欢迎大家批评指正

  

猜你喜欢

转载自blog.csdn.net/yanggx0929/article/details/88625845
今日推荐