u-boot-spl.lds詳解

u-boot-spl.lds 源碼解讀


/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <[email protected]>
 */

/* 指定輸出可執行文件:"elf32位小端格式" */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/* 指定輸出可執行文件的目標架構:"arm" */
OUTPUT_ARCH(arm)
/* 指定輸出可執行文件的入口地址(起始代碼段):"_start" */
ENTRY(_start)
SECTIONS
{
	/* 
	 * 設置0的原因是,arm內核的處理器,三點後默認是從0x00000000處啓動
	 * 1.以stm32爲例片內的nor-flash起始地址是0x08000000,這裏是我們燒寫u-boot.bin的位置
	 * 2.上電後,系統會自動將該地址(0x0800:0000)映射到0x0000:0000(硬件完成)
	 */
	. = 0x00000000;
	
	/* 
	 * 代碼以4字節對齊 .text爲代碼段
	 * 各個段按先後順序依次排列 
	 * 在cortex-m的內核中,首地址存放的是主堆棧的地址,其次存放中斷向量表
	 */
	. = ALIGN(4);
	.text :
	{
		__image_copy_start = .; /* u-boot裏默認會將u-boot的鏡像拷貝到ram(sdram,ddr....)中執行 */
		*(.vectors)				/* 存放的是中斷向量表 */
		CPUDIR/start.o (.text*) /* 存放CPUDIR/start.o中的所有.text段 */
		*(.text*)					/* 存放其他.o中的所有.text段 */
		*(.glue*)					/* 存放其他.o中的所有.glue段 */
	}
	/* 從上面的結構中可以發現這種格式都是:地址(.段) 這樣的形式出現 */

	/* 
	 * .rodata段,確保是以4字節對齊處開始 
	 */
	. = ALIGN(4);	
	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }	/* 從名稱上就可以知道,按名稱依次存放其他.o文件中的.rodata */

	/* 
	 *data段,確保是以4字節對齊處開始 
	 */
	. = ALIGN(4);	
	.data : {
		*(.data*) 
	}

	/* 
	 * u_boot_list段,確保是以4字節對齊處開始 
	 * 這裏存放的都是u_boot_list中的函數
	 * 例如:base/bdinfo/blkcache/cmp....
	 * 具體的可參看./u-boot.map .u_boot_list
	 * tips:要想優化編譯出來的u-boot.bin大小,可以參看此文件進行對照裁剪
	 */
	. = ALIGN(4);
	.u_boot_list : {
		KEEP(*(SORT(.u_boot_list*)));
	}

	/* 
	 * binman_sym_table段,確保是以4字節對齊處開始 
	 * binman實現的功能是讓c代碼通過binman_*的函數接口字節調用鏡像中的個別函數
	 * 具體可參看binman_sym.h中的接口
	 */
	. = ALIGN(4);
	.binman_sym_table : {
		__binman_sym_start = .;
		KEEP(*(SORT(.binman_sym*)));
		__binman_sym_end = .;
	}

	/* 
	 * __image_copy_end段,確保是以4字節對齊處開始 
	 * 鏡像拷貝的完成
	 */
	. = ALIGN(4);

	__image_copy_end = .;

	.rel.dyn : {
		__rel_dyn_start = .;
		*(.rel*)
		__rel_dyn_end = .;
	}

	.end :
	{
		*(.__end)
	}
	/* bin文件結束 */
	_image_binary_end = .;

	.bss __rel_dyn_start (OVERLAY) : {
		__bss_start = .;
		*(.bss*)
		 . = ALIGN(4);
		__bss_end = .;
	}
	__bss_size = __bss_end - __bss_start;
	.dynsym _image_binary_end : { *(.dynsym) }
	.dynbss : { *(.dynbss) }
	.dynstr : { *(.dynstr*) }
	.dynamic : { *(.dynamic*) }
	.hash : { *(.hash*) }
	.plt : { *(.plt*) }
	.interp : { *(.interp*) }
	.gnu : { *(.gnu*) }
	.ARM.exidx : { *(.ARM.exidx*) }
}

#if defined(CONFIG_SPL_MAX_SIZE)
ASSERT(__image_copy_end - __image_copy_start < (CONFIG_SPL_MAX_SIZE), \
	"SPL image too big");
#endif

#if defined(CONFIG_SPL_BSS_MAX_SIZE)
ASSERT(__bss_end - __bss_start < (CONFIG_SPL_BSS_MAX_SIZE), \
	"SPL image BSS too big");
#endif

#if defined(CONFIG_SPL_MAX_FOOTPRINT)
ASSERT(__bss_end - _start < (CONFIG_SPL_MAX_FOOTPRINT), \
	"SPL image plus BSS too big");
#endif


相關知識總結

[彙編]SECTIONS

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

SECTIONS
{
    . = 0x00000000;      // 應該是存儲地址,存儲地址(加載的地址)
    . = ALIGN(4);        // 4字節對齊
    .text      :         //此處應該是secname 段名
   {
         cpu/arm920t/start.o (.text)//大括號,contents段,指示該段存放的內容
        *(.text)
   }
   . = ALIGN(4);                    //以下類似
   .rodata : { *(.rodata) }
標示 規則
secname 段名, 比如常見的.text/.data等等
contents 決定哪些內容存放在此段
start 本段的連接地址(實際運行地址)
AT(ldadr) 存儲地址(加載的地址)

[彙編]arm的.text段/.code段/.bss段…

  • bss段(bsssegment)
    通常是指用來存放程序中未初始化的全局變量的一塊內存區域。BSS段屬於靜態內存分配.

  • data段(datasegment)
    通常是指用來存放程序中已初始化的全局變量的一塊內存區域。BSS段屬於靜態內存分配.

  • text段(textsegment)
    通常是指用來存放程序執行代碼的一塊內存區域。就是我們編寫的程序代碼(函數等等).

  • rodata段(rodatasegment)
    通常是指用來存放C中的字符串和宏定義的常量.

總結

總的來說,我們能大概的瞭解到我們編寫的c/c++源代碼大概經歷先單個編譯產生.o,這裏麪包含了這個文件的.text/.bss/.data等等段,而我們的鏈接文件,最後會大一統,將工程下的所有目標文件,按鏈接腳本的規則(按各種段分門別類的)把各個文件彙總,最終產生.bin文件.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章