ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

U-Boot relocate_code功能

2022-02-06 23:35:26  阅读:237  来源: 互联网

标签:code r0 r1 r2 Boot label 地址 uboot relocate


 所谓的relocation,就是重定位,uboot运行后会将自身代码拷贝到sdram的另一个位置继续运行。新版uboot跟老版uboot不太一样的地方在于新版uboot不管uboot的load addr(entry pointer)在哪里,启动后会计算出一个靠近sdram顶端的地址,将自身代码拷贝到该地址,继续运行。

uboot的编译选项发现,在arch/arm/config.mk,如下: 

# needed for relocation

LDFLAGS_u-boot += -pie

uboot只指定了-pie给ld,而没有指定-fPIC或-fPIE给gcc。 

指定-pie后编译生成的uboot中就会有一个rel.dyn段,uboot就是靠rel.dyn段实现了完美的relocation!

    ldr    r0, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp */
    bic    r0, r0, #7    /* 8-byte alignment for ABI compliance */
    mov    sp, r0
    ldr    r9, [r9, #GD_NEW_GD]        /* r9 <- gd->new_gd */

    adr    lr, here
    ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off */
    add    lr, lr, r0
#if defined(CONFIG_CPU_V7M)
    orr    lr, #1                /* As required by Thumb-only */
#endif
    ldr    r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr */
    b    relocate_code
here:
/*
 * now relocate vectors
 */

    bl    relocate_vectors

 

NTRY(relocate_code)
    ldr    r1, =__image_copy_start    /* r1 <- SRC &__image_copy_start */
    subs    r4, r0, r1        /* r4 <- relocation offset */
    beq    relocate_done        /* skip relocation */
    ldr    r2, =__image_copy_end    /* r2 <- SRC &__image_copy_end */

copy_loop:
    ldmia    r1!, {r10-r11}        /* copy from source address [r1]    */
    stmia    r0!, {r10-r11}        /* copy to   target address [r0]    */
    cmp    r1, r2            /* until source end address [r2]    */
    blo    copy_loop

r1=__image_copy_start,也就是 r1 寄存器保存源地址
r0=  gd->relocaddr 这个地址就是 uboot 拷贝的目标首地址, 此处的gd为放置到sdram高端的gd,是在setup_reloc函数中对原来gd的复制。

    /*主要目的是修改label中的地址。
   *对于一些绝对地址符号(例如已经初始化的全局变量),会将其以label的形式放在每个函数的代码实现的末端。
*同时,在链接的过程中,会把这些label的地址统一维护在.rel.dyn段中,当relocation的时候,方便对这些地址的fix。 * fix .rel.dyn relocations */ ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */ ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */ fixloop: ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */ and r1, r1, #0xff cmp r1, #R_ARM_RELATIVE bne fixnext /* relative fix: increase location by offset */
// label在relocate uboot的时候也已经复制到了新的uboot地址空间了!!!
// 这里要注意,是对新的uboot地址空间label进行修改!!!
add r0, r0, r4
// 根据前面的描述,我们的目的就是要fix label中绝对地址符号的地址,也就是将其修改为新地址空间的地址

// 所以为r1加上偏移之后,重新存储到label中。

// 后面CPU就可以根据LABEL在新uboot的地址空间中寻址到正确的符号。
//对于一些绝对地址符号(例如已经初始化的全局变量),会将其以label的形式放在每个函数的代码实现的末端。
//同时,在链接的过程中,会把这些label的地址统一维护在.rel.dyn段中,当relocation的时候,方便对这些地址的fix
ldr r1, [r0]
// 从label中获取绝对地址符号的地址,存放在r1中 add r1, r1, r4 str r1, [r0]
// 根据前面的描述,我们的目的就是要fix label中绝对地址符号的地址,也就是将其修改为新地址空间的地址

// 所以为r1加上偏移之后,重新存储到label中。

// 后面CPU就可以根据LABEL在新uboot的地址空间中寻址到正确的符号。 fixnext: cmp r2, r3 blo fixloop

 

可以看出__image_copy_start---end之间包括了text data rodata段,但是没有包括rel_dyn。
继续看relocate_code函数,拷贝__image_copy_start----end之间的数据,但没有拷贝rel.dyn段。

首先获取__rel_dyn_start地址到r2,将start地址上连续2个4字节地址的值存在r0 r1中

判断r1中的值低8位,如果为0x17,则将r0中的值加relocation offset。

获取以此r0中值为地址上的值,存到r1中

将r1中值加relocation offset,再存回以r0中值为地址上。

以此循环,直到__rel_dyn_end。

* 绝对地址符号的地址会放在label中提供位置无关代码使用
* label的地址会放在.rel.dyn段中

当uboot对自身进行relocate之后,此时全局变量的绝对地址已经发生变化,如果函数按照原来的label去获取全局变量的地址的时候,这个地址其实是relocate之前的地址。因此,在relocate的过程中需要对全局变量的label中的地址值进行修改,所以uboot将这些label的地址全部维护在.rel.dyn段中,然后再统一对.rel.dyn段指向的label进行修改。后续代码可以看出来。可以看出.rel.dyn段用了8个字节来描述一个label,其中,高4字节是label地址标识0x17,低4字节就是label的地址。
所以需要先判断label地址标识是否正确,然后再根据第四字节获取label,对label中的符号地址进行修改。

  ARM9中断向量重定位   
* Copy the relocated exception vectors to the * correct address * CP15 c1 V bit gives us the location of the vectors: * 0x00000000 or 0xFFFF0000. */ ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ mrc p15, 0, r2, c1, c0, 0 /* V bit (bit[13]) in CP15 c1 */ ands r2, r2, #(1 << 13) ldreq r1, =0x00000000 /* If V=0 */ ldrne r1, =0xFFFF0000 /* If V=1 */ ldmia r0!, {r2-r8,r10} stmia r1!, {r2-r8,r10} ldmia r0!, {r2-r8,r10} stmia r1!, {r2-r8,r10}

arm9手册中:

 [13] V bit Location of exception vectors:
0 = Normal exception vectors selected, address range = 0x0000 0000 to
0x0000 001C
1 = High exception vectors selected, address range = 0xFFFF 0000 to
0xFFFF 001C. Set to the value of VINITHI on reset.

/*
* Copy the relocated exception vectors to the
* correct address
* CP15 c1 V bit gives us the location of the vectors:
* 0x00000000 or 0xFFFF0000.
*/
@@ 注意看注释,通过cp15协处理器的c1寄存器的V标志来判断cpu从什么位置获取中断向量表,
@@ 换句话说,就是中断向量表应该被复制到什么地方!!!

ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
@@ 获取uboot新地址空间的起始地址,存放到r0寄存器中

mrc p15, 0, r2, c1, c0, 0 /* V bit (bit[13]) in CP15 c1 */
ands r2, r2, #(1 << 13)
ldreq r1, =0x00000000 /* If V=0 */
ldrne r1, =0xFFFF0000 /* If V=1 */
@@ 获取cp15协处理器的c1寄存器的V标志,当V=0时,cpu从0x00000000获取中断向量表,当V=1时,cpu从0xFFFF0000获取中断向量表
@@ 将该地址存在r1中

ldmia r0!, {r2-r8,r10}
stmia r1!, {r2-r8,r10}
@@ 前面说了异常中断向量表就是从偏移0x20开始的32个字节。
@@ 所以这里是过滤掉前面的0x20个字节(32个字节,8*4)
@@ 但是不明白为什么还要stmia r1!, {r2-r8,r10},理论上只需要让r0的值产生0x20的偏移就可以了才对???不明白。

//一下的数据是中断矢量的全局符号,这些符号在rel段中已经进行了位置重新计算。

@@ 经过上述两行代码之后,此时r0的值已经偏移了0x20了
ldmia r0!, {r2-r8,r10}
stmia r1!, {r2-r8,r10}
@@ 继续从0x20开始,获取32个字节,存储到r1指向的地址,也就是cpu获取中断向量表的地址
@@ r2-r8,r10表示从r2到r8寄存器和r10寄存器,一个8个寄存器,每个寄存器有4个字节,所以就从r0指向的地址处获取到了32个字节
@@ 再把 {r2-r8,r10}的值存放到r1指向的地址,也就是cpu获取中断向量表的地址



标签:code,r0,r1,r2,Boot,label,地址,uboot,relocate
来源: https://www.cnblogs.com/liujunhuasd/p/15864658.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有