天天看點

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)的内容。

繼續閱讀