免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1246 | 回复: 0
打印 上一主题 下一主题

关于u-boot的relocation(重定位)问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-04 10:43 |只看该作者 |倒序浏览

                    阅读一下ld相关的资料就可以知道,通过培植lds连接脚本或者在连接时提供相应的参数,可以控制连接生成的代码的起始地址,这里的起始地址有2个:
    1. VMA
    2. LMA
    其中,VMA可以认为是程序运行时,认为自己的起始地址,就是他的所有的symbol的地址的基址,即如果访问一个symbol,那么这个symbol的地址应该是VMA+symbol在代码内的偏移地址。
    而LMA可以认为是将程序装载的地址,一般情况下,2者是相同的,但是在u-boot这种需要relocatin的情况下,2这就是不同的,貌似在u-boot中,LMA压根没什么意义。
    为什么这么说,因为在连接的时候,LDFLAGS中有-Ttext $(TEXT_BASE),其含义是将text section定位基址设置成TEXT_BASE,这样生成的结果里的诸如函数地址,等symbol对应的地址都是以TEXT_BASE作为基地址的。这个据说可以通过objdump查看生成的u-boot的各条汇编代码的地址看出来。但是为什么我们还可以将u-boot烧至到flash去执行呢?这是因为u-boot的stage1的汇编代码里虽然用到了一些label,但是他们在真正使用的时候其实是采用的偏移地址跳转,因此无论烧到哪里都能执行。但是还有个问题,那么stage1跳转到stage2时有条指令:
    ldr pc _start_armboot
    _start_armboot: .word start_armboot
    这个跳转为什么可以呢,首先,start_armboot是一个函数指针,他的地址是定义在由相应的c文件生成的目标文件中的,在连接的时候,他的对应的地址受到我们指定的TEXT_BASE的影响,它的地址其实是在RAM中,因此,如果我们执行这条语句,CPU会到RAM里去寻找start_armboot的代码,因此,可以这样说,如果我们不把代码拷贝到RAM里的话,当执行到这里的时候是会出错的,CPU不会去执行位于flash中的start_armboot函数的代码,start_armboot并不指向哪里。
    如果细心的话,还会看到在 /common/hush.c 文件里,有段代码:
    static struct reserved_combo reserved_list[] = {
    { "if",    RES_IF,    FLAG_THEN | FLAG_START },
    { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
    { "elif",  RES_ELIF,  FLAG_THEN },
    { "else",  RES_ELSE,  FLAG_FI   },
    { "fi",    RES_FI,    FLAG_END  },
    { "for",   RES_FOR,   FLAG_IN   | FLAG_START },
    { "while", RES_WHILE, FLAG_DO   | FLAG_START },
    { "until", RES_UNTIL, FLAG_DO   | FLAG_START },
    { "in",    RES_IN,    FLAG_DO   },
    { "do",    RES_DO,    FLAG_DONE },
    { "done",  RES_DONE,  FLAG_END  }
};
static void u_boot_hush_reloc(void)
{
    unsigned long addr;
    struct reserved_combo *r;
    for (r=reserved_list; rliteral) + gd->reloc_off;
        r->literal = (char *)addr;
    }
}
    可见,reserved_list中的数据应该是属于data段的,我们已经把代码relocation到RAM里面了,况且连接的时候指定了VMA,为什么这里还要修改r->literal呢?首先,我们的确已经把DATA段relocation到了RAM里面,查看board/smdk2410/u-boot.lds可以知道,data段位于text段和bss段之间,而拷贝的时候是将text段到bss段之间(包括text段)的内容全都拷贝到了RAM,可有一点,在连接的时候,我们用-Ttext $(TEXT_BASE)只是指定了连接得到的代码,指令段的起始地址设置为RAM里地址TEXT_BASE,而data段我们并没有管她,造成的结果就是数据段的地址还是flash里的地址。所以现在我们要修改我们这些自身已经位于RAM中的指针变量,让它们的值指向RAM里而不再是flash里。
    gd->reloc_off, gd是一个乘放全局变量的一个好地方。gd->reloc_off应该是在relocation时记录的relocation偏移。
    可见,代码,symbol的地址我们不用操心,因为ld自动给我们改了,而数据段没有改,我们就的自己改。可是为什么不连接期间也手动指定数据段的起始地址?因为我们肯定知道代码段的地址是TEXT_BASE,但是我们压根就不知道代码段的长度,以及一些其他的段的长度,因此就不能确定data段在代码段后面的位置,因此也就不能在连接的时候给data段指定位置。
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/72383/showart_1072523.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP