免费注册 查看新帖 |

Chinaunix

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

系统上电时的启动代码分析 [复制链接]

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

                                                            
对U-BOOT的第1阶段代码的分析(基于SMDK2410的板子):
   
都知道U-BOOT分为两个阶段,第一阶段是(~/cpu/arm920t/start.S中)在FLASH上运行(一般情况下),完成对硬件的初始化,
包括看门狗,中断缓存等,并且负责把代码搬移到SDRAM中(在搬移的时候检查自身代码是否在SDRAM中),然后完成C程序运行所需要环境的建立,包括
堆栈的初始化等,最后执行一句跳转指令ldr pc, _start_armboot
                                                    _start_armboot: .word start_armboot,
进入到/lib_arm/board.c中的函数void start_armboot (void),从此就进入了第二阶段.这是在很多资料上都有讲述的,所以勿需多言了.
   
现在对于第一阶段有几个问题,以前我一直是没有搞明白的,既然在FLASH中的代码是把自己拷贝到SDRAM中,那么在S3C2410的内存地址空间,就
有两份的启动代码,第一份就是在FLASH中,第二份就是在SDRAM中.根据链接脚本文件(~/board/smdk2410/u-boot.lds)
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text      :
{
   cpu/arm920t/start.o (.text)
   *(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
    其中的链接命令 . =
0x00000000;表示地址计数器从0地址开始计数,而且_start 是程序代码段的入口,那么*.text中的所有地址标号
(cpu/arm920t/start.S中定义的)就应该从0地址开始计数,那么标号start_armboot(就是void
start_armboot (void)函数的入口地址)应该在FLASH中才对啊,所以按照上边的分析,
ldr pc, _start_armboot
_start_armboot: .word start_armboot
此条语句后,并没有跳转到SDRAM中的void start_armboot (void),而是跳转到了FLASH中的void start_armboot (void)中,
所以就出现了这样的矛盾,在FLASH中有一段代码把自己拷贝到SDRAM中,产生了两份UBOOT可执行的指令流,但是最后却没有跳转到SDRAM中去运行以提高指令执行的速度.
     产生以上的认识是基于以下几个认识(肯定是错误的):
1.*.text中的所有地址标号(在链接时确定)是从0地址开始生成的.
2.relocate:    /* relocate U-Boot to RAM     */
adr r0, _start  /* r0 144页.

现在继续:
   
刚才分析所得到的矛盾,肯定是在认识上存在的偏差,经过把U-BOOT进行make后,从所生成的两个.map文件来看(~/u-boot.map和
Systen.map),所有的地址标号都是从0x3ff80000开始的,就是从SDRAM的高地址开始,等于TEXT_BASE的值,也就是说,链接
器是从
0x3FF80000开始来链接所编译生成的目标文件的,而不是从0地址开始,经过查看,start_armboot=0x33f80d9c,就是说
void start_armboot (void)函数的入口地址在SDRAM中(链接器决定),所以执行ldr pc,
_start_armboot
                                                                                _start_armboot: .word start_armboot,
PC指针肯定就指向了SDRAM中,换句话就是说进入到SDRAM中了,对于ldr pc,
_start_armboot,其仍然是GNU中的伪指令,翻译以下就是ldr pc,
[pc+pc到_start_armboot的偏移值],结果就把_start_armboot地址中的数start_armboot放入pc中完成了跳
转.因为在整个UBOOT的阶段1中所有的寻址都是相对位置的寻址(虽然链接器认为是阶段1的代码是从地址0x3ff80000中开始链接的),把阶段1
的代码放在0地址开始的FLASH中也是可以正确的运行的,如果ARM的复位向量是在0x00000001(假设),那么把代码烧写到从
0x00000001处开始的地方,上电时也可以正确的运行(假设ARM的复位向量是在0x00000001成立),当然ARM的复位向量不在这里,只是
以此假设来说明以上的对于阶段1的分析.
   现在最后一个矛盾就是链接脚本(~/board/smdk2410/u-boot.lds)所描述的链接地址与实际的链接地址不相同的问题,因为根据链接脚本,所有的地址标号应该从0地址开始计数的,然而不是,经过查找Makefile文件,在顶层的Makefile文件中,在166行中链接是的链接命令:
$(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) \,
其中的LDFLAGS在定义在顶层的config.mk中的145行:LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS),
最关键的就是 -Ttext $(TEXT_BASE)命令了,他的含义就是说,起始地址在TEXT_BASE,而TEXT_BASE在~/board/smdk2410/config.mk中TEXT_BASE = 0x3FF80000;
到此就弄清楚为什么链接从
0x3ff80000开始的了,至于链接脚本,其作用是用来指明各个*.o文件的顺序,如入口地址标号(_start)等,以及使两个地址标号得到当前的地址
     __u_boot_cmd_start = .;    *.u_boot_cmd段的起始地址
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;       *.u_boot_cmd段的结束地址
以供C程序使用. __u_boot_cmd_start和__u_boot_cmd_end可以作为全局的一个常数使用


总结:
    因为-Ttext
$(TEXT_BASE)命令的使用,链接器把UBOOT从地址0x3ff80000开始连接,在第一阶段中,所有使用的目标地址寻址都是使用的当前PC
值加减偏移量的方法,所以把UBOOT烧写到0地址开始的FLASH中,不影响第一阶段的正确执行.

    文字功底有限,且由于本人不是计算机专业的,难免有许多错误 偏差和遗漏,望各位大虾斧正.
参考资料:U-BOOT-1.1.4
              GCC技术参考大全
              ARM体系结构与编程
              链接器与加载器
                  
                                                        
               
               
               

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP