天天看点

socfpga uboot启动流程(1)--uboot.lds启动流程

启动流程

要分析 uboot 的启动流程,首先要找到“入口”,找到第一行程序在哪里。程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。如果没有编译过 uboot 的话链接脚本为arch/arm/cpu/u-boot.lds。但是这个不是最终使用的链接脚本,最终的链接脚本是在这个链接脚本的基础上生成的。编译一下 uboot,编译完成以后就会在 uboot 根目录下生成 u-boot.lds文件

OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")   /*输出文件类型 大小端*/  
	OUTPUT_ARCH(aarch64)  /*输出架构*/ 
	ENTRY(_start)   /*指定start函数为起始点*/ 
	SECTIONS  #将各个不同的段合到一起
	{
	 /DISCARD/ : { *(.rela._secure*) }
	 . = 0x00000000;
	/*指定可执行文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成*/ 

	 . = ALIGN(8);  /*代码段8字节对齐*/ 
	 .text :  /*代码段*/ 
	 {
		  *(.__image_copy_start) /*uboot将自己从flash copy到RAM*/
		  arch/arm/cpu/armv8/start.o (.text*) /*start.S中的text*/ 
		 }
		/*在定义了efi运行时相关支持时才会出现使用的段,一般不用关心*/ 
		 .efi_runtime : {
		                __efi_runtime_start = .;
		  *(.text.efi_runtime*)
		  *(.rodata.efi_runtime*)
		  *(.data.efi_runtime*)
		                __efi_runtime_stop = .;
	 }
	 .text_rest :
	 {
		  *(.text*)#除了start.o其余的代码段
	 }
	
	
	 .__secure_start :
	 {
		  KEEP(*(.__secure_start))/*KEEP告诉链接器不要优化掉此输入section,即使没有引用到此section*/ 
		
	 }
	 .secure_text 0x00001000 :
	  AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
	 {
		  *(._secure.text)
		  . = ALIGN(8);
		  __secure_svc_tbl_start = .;
		  KEEP(*(._secure_svc_tbl_entries))
		  __secure_svc_tbl_end = .;
	 }
	 .secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text))
	 {
	  *(._secure.data)
	 }
	 .secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data),
	       CONSTANT(COMMONPAGESIZE)) (NOLOAD) :
	  AT(LOADADDR(.secure_data) + SIZEOF(.secure_data))
	 {
	  KEEP(*(.__secure_stack_start))
	  . = . + 4 * (1 << 10);
	  . = ALIGN(CONSTANT(COMMONPAGESIZE));
	  KEEP(*(.__secure_stack_end))
	 }
	 . = LOADADDR(.secure_stack);
	 .__secure_end : AT(ADDR(.__secure_end)) {
	  KEEP(*(.__secure_end))
	  LONG(0x1d1071c);
	 }
	
	
	 . = ALIGN(8);
	
	
	 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }/*只读数据段 8字节对齐*/ 
	 . = ALIGN(8);
	 .data : {
		  *(.data*)/*可读写数据段 8字节对齐*/ 
	 }
	 . = ALIGN(8);
	 . = .;
	 . = ALIGN(8);
	 .u_boot_list : {
		  KEEP(*(SORT(.u_boot_list*)))/*data段结束后,紧接着存放u-boot自有的一些function,例如boot、tftpboot等*/ 
	 }
	 . = ALIGN(8);
	 .efi_runtime_rel : {
	                __efi_runtime_rel_start = .;
	  *(.rel*.efi_runtime)
	  *(.rel*.efi_runtime.*)
	                __efi_runtime_rel_stop = .;
	 }
	 . = ALIGN(8);
	 .image_copy_end :
	 {
		  *(.__image_copy_end)/*至此,uboot需要自拷贝的内容结束*/ 
	 }
	 . = ALIGN(8);
	 .rel_dyn_start :/*在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的位置处,就可以在绝对跳转中找到正确的函数。*/ 
	 {
		  *(.__rel_dyn_start)
	 }
	 .rela.dyn : { 
		  *(.rela*)/*动态链接符放在的段*/ 
	 }
	 .rel_dyn_end :
	 {
		  *(.__rel_dyn_end) /*动态链接符段结束*/ 
	 }
	 _end = .;
	 . = ALIGN(8);
	/*bss段开始:BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。和data段的区别是不分配空间*/ 
	
	 .bss_start : {
		  KEEP(*(.__bss_start));
	 }
	 .bss : {
		  *(.bss*)
	   . = ALIGN(8);
	 }
	 .bss_end : {
	  KEEP(*(.__bss_end));
	 }
	/*bss段结束*/ 
	
	/*一些链接时没有用上丢弃的段*/ 
	 /DISCARD/ : { *(.dynsym) }
	 /DISCARD/ : { *(.dynstr*) }
	 /DISCARD/ : { *(.dynamic*) }
	 /DISCARD/ : { *(.plt*) }
	 /DISCARD/ : { *(.interp*) }
	 /DISCARD/ : { *(.gnu*) }
}
           

u-boot.lds脚本文件告诉链接器linker如何布局代码段、数据段、bss段等,已经配置了u-boot自拷贝(从flash到RAM的copy)的内容。

继续阅读