crt0.S
ENTRY(_main)
@ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
@b relocate_code
b do_relocate_code
here:
xxxxxxx
......
drivers/gic/sunxi_gic.c
extern char __bss_start[];
extern char __bss_end[];
extern char __image_copy_start[];
extern char __image_copy_end[];
extern char __rel_dyn_start[];
extern char __rel_dyn_end[];
extern ulong _TEXT_BASE; /* code start */
void do_copy_uboot2highaddr(void)
{
if( (gd->relocaddr - (ulong)__image_copy_start) == 0x00 ){
;
}else{
memcpy((char *)gd->relocaddr, __image_copy_start, __image_copy_end-__image_copy_start);
}
}
void do_fix_rel_dyn( void )
{
ulong *rel_dyn_start;
ulong *rel_dyn_end;
ulong g_off = 0x00;
int index;
ulong temp1,target_pos;
rel_dyn_start = (ulong *)__rel_dyn_start;
rel_dyn_end = (ulong *)__rel_dyn_end;
int debug_output = 0x00;
index = 0x00;
debug( "\ng_off = %lx\n", g_off );
debug( "gd->relocaddr = %lx\n", gd->relocaddr );
debug( "__image_copy_start = %p\n", __image_copy_start );
debug( "g_off = %lx\n", gd->relocaddr - (ulong)__image_copy_start );
debug( "rel len = %x\n", rel_dyn_end - rel_dyn_start );
debug( "rel_dyn_start = %p\n", rel_dyn_start );
debug( "rel_dyn_end = %p\n", rel_dyn_end );
g_off = gd->relocaddr - (ulong)__image_copy_start;
//macdbg_dmphex((char *)rel_dyn_start, 0x100);
//macdbg_dmphex((char *)rel_dyn_start+g_off, 0x100);
while(1){
if( index < 50 ){
debug_output = 0;
}else{
debug_output = 0;
}
#if 0
ldr r0, =#biaohao
ldr r0, [r0]
...
biaohao:
var:变量的绝对地址 4a000a14
假设 var相对于 ldr指令的相对偏移位置为3
ldr r0, [pc+ 3]
r0即为变量的绝对地址
然后 ldr r0, [r0] 取得变量的值
代码重定向后 ldr r0, [pc+ 3]
取得的变量的绝对地址还是原来的 4a000a14
所以需要 4a000a14 + g_off
4a000a14 + g_off 需要设置到 biaohao位置
作为他的新值
白话理解就是:修正code段中的label值
label值为 变量的绝对地址
那重定向了 比如移动了1M位置
变量的绝对地址也需要 加1M,才能正确寻址到相应的变量
先相对寻址 获取 label的地址
这个由于是pc相对寻址的指令 重定向对他没有影响
关键在于 label内的值的修正
#endif
if( (rel_dyn_start[index+1] & 0xff) == 0x17 ){
target_pos = rel_dyn_start[index] + g_off;
//重定向后的某一变量的地址的指针
if( debug_output ){
debug( "\ntarget_pos = %lx\n", target_pos );
debug( "rel_dyn_start[index] = %lx\n", rel_dyn_start[index] );
}
temp1 = *(ulong *)target_pos;
//重定向前某一变量的地址
if( debug_output ){
debug( "temp1 = %lx\n", temp1 );
}
temp1 = temp1 + g_off;
//地址重定向 + 偏移量 = 重定向后某一变量的地址
if( debug_output ){
debug( "temp11 = %lx\n", temp1 );
}
*(ulong *)target_pos = temp1;
//把某一变量的重定向的地址值 存入重定向后的某一变量的地址的地址
}
index = index+2;
if( index == (rel_dyn_end - rel_dyn_start) ){
break;
}
}
}
void do_relocate_code( void )
{
do_copy_uboot2highaddr();
do_fix_rel_dyn();
}