U-Boot2018.11 下ARMV7 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文件.