u-boot start.S中关于代码重定位的分析

为何需要重定位?

对于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;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值