为何需要重定位?
对于s3c2440cpu来说,如果选择了nand启动,系统启动时只将NandFlash的前4K拷贝到了BootSRAM中,如果BootLoader程序大于4k,就需要在这4K代码中将完整代码拷贝到内存中,之后再跳转到内存中执行。
如果选择了nor启动,系统会从nor的0开始执行,但是norflash不能直接写入,当程序需要对一些全局变量进行修改的时候,会发现值修改不成功,程序运行出错。所以需要将代码拷贝到内存中执行。
4K的启动代码内只能使用位置无关码。
贴上代码:文件位置为u-boot-1.1.6/cpu/arm920t/start.s
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */ /
beq clear_bss ///比较两者的运行地址和链接地址 如果相等跳转到clear_bss执行
//如果不等 重定位u-boot代码 拷贝代码到链接地址上去
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size *///拷贝u-boot到SDRAM中 r0 r1 r2作为参数传入CopyCode2Ram
#else
....
在GNU中:adr r0, _start 作用是获得 _start 的实际运行所在的地址值,而ldr r1, _TEXT_BASE 为获得地址_TEXT_BASE中所存放的数据,其中adr r0, _start翻译成 add r0,(PC+#offset),offset 就是 adr r0, _start 指令到_start 的偏移量,在链接时确定,这个偏移量是地址无关的。
ldr r1, _TEXT_BASE 指令表示以程序相对偏移的方式加载数据,是索引偏移加载的另外一种形式,等同于ldr r1,[PC+#offset],offset 是 ldr r1, _TEXT_BASE 到 _TEXT_BASE 的偏移量。
注意这种用法并不是伪指令,伪指令的特征是 ldr r1, =expr/lable_expr。对于LDR伪指令,ADS的情况有些不一样(细微差别),在ADS中的情况可以参考杜春雷<ARM体系结构与编程>144页。
所以获取到的r0为_start 的实际运行所在的地址值,值为0,定义在start.S文件的最开始,因为在jz2440中无论是nand启动还是nor启动,两者开始执行的地址都是0(烧录的位置也都是0)。
获取到的r1为_TEXT_BASE为链接地址,值为0x33F80000,是在编译u-boot.bin时使用-Ttext 0x33F80000设置的,具体定义位置在\u-boot-1.1.6\board\100ask24x0\config.mk中。
运行地址和链接地址在一般情况下应该相同,出现不同时代表程序未在链接地址上执行,需要执行重定位。
程序在调用访问全局变量、静态变量、调用函数时是使用"基于链接地址编译得到的地址",如果在两者不相同的情况下,直接调用这些东西会出现问题。
程序中比较了两者大小,如果相等跳转到clear_bss标号执行,跳过重定位。如果不是,执行重定位。
重定位时,将r0 r1 r2作为参数传入CopyCode2Ram()函数。r0为0,r1为0x33F80000,r2为代码段。数据段、只读数据段的总长度
int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
unsigned int *pdwDest;
unsigned int *pdwSrc;
int i;
if (bBootFrmNORFlash())
{
pdwDest = (unsigned int *)buf;
pdwSrc = (unsigned int *)start_addr;
/* 从 NOR Flash启动 */
for (i = 0; i < size / 4; i++)
{
pdwDest[i] = pdwSrc[i];
}
return 0;
}
else
{
/* 初始化NAND Flash */
nand_init_ll();
/* 从 NAND Flash启动 */
nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));
return 0;
}
}

622

被折叠的 条评论
为什么被折叠?



