《u-boot.lds分析》
u-boot.lds (~/board/smdk2410/u-boot.lds) /*指定输出可执行文件是elf格式,32位ARM指令,小端*/ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ /*指定输出可执行文件的平台为ARM*/ OUTPUT_ARCH(arm) /*指定输出可执行文件的起始代码段为_start*/ ENTRY(_start) SECTIONS { /*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成*/ . = 0x00000000;/*;从0x0位置开始*/ . = ALIGN(4);/*代码以4字节对齐*/ .text: { /*代码的第一个代码部分*/ cpu/arm920t/start.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } /*指定只读数据段*/ . = ALIGN(4); .data : { *(.data) }/* 可读写数据段,所有的可读写数据段都放在这里*/ . = ALIGN(4); .got : { *(.got) }/*指定got段, got段是uboot自定义的一个段, 非标准段*/ . = .; __u_boot_cmd_start = .; /*把__u_boot_cmd_start赋值为当前位置, 即起始位置*/ .u_boot_cmd : { *(.u_boot_cmd) } /*指定u_boot_cmd段, uboot把所有的uboot命令放在该段.*/ __u_boot_cmd_end = .;/*把__u_boot_cmd_end赋值为当前位置,即结束位置*/ . = ALIGN(4); __bss_start = .; /*把__bss_start赋值为当前位置,即bss段的开始位置*/ .bss : { *(.bss) } _end = .;/*把_end赋值为当前位置,即bss段的结束位置*/ }
以上是smdk2410中的u-boot.lds。
U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中:
relocate:/* 把U-Boot重新定位到RAM*/
adr r0, _start /* r0是代码的当前位置*/
/*adr伪指令,汇编器自动通过当前PC的值算出这条指令中"_start"的值,执行到_start时PC的值放到r0中:当此段在flash中执行时r0= _start = 0;当此段在RAM中执行时_start=_TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,即u-boot在把代码拷贝到RAM中去执行的代码段的开始)*/
上面start.o中的代码装载地址和运行地址都为0x00000000,但是在start.o中会有一个u-boot自拷贝及重定位过程,start.o执行到最后时,整个u-boot已经被复制到了内 存的TEXT_BASE(0x33f80000)位置,开始执行下面的跳转语句:
ldr pc, _start_armboot /*将标号_start_armboot的值传给pc,实际上是将start_armboot函数的首地址传给pc但是此时的start_armboot应该是在内存中,因为start_armboot一定是在4kB之后,而nandflash4kB之后的代码是无法直接访问的,必须先读入内存。而这时候u-boot的代码已经被拷贝并重定位到内存中,所以此处加在到pc的地址应当是内存中的地址,即33f800之后的某一地址*/_start_armboot: .word start_armboot