________________________________________
目的,
瞭解鏈接器用到的腳本文件u-boot.lds。
________________________________________
在開始這篇博文之前,需要先了解一些GNU linker script的基本知識,可以參考博主的另外一篇分享《GNU linker script,ld script,GNU鏈接腳本》
________________________________________
在《u-boot分析 二》中,我們分析u-boot的目錄結構,提及到了程序入口start.S,但在開始瞭解start.S之前,我們先聊聊鏈接器ld程序的腳本文件u-boot.lds。
下面我們就來品味一下UT4418開發板的u-boot.lds腳本,即u-boot/arch/arm/cpu/slsiap/u-boot.lds。如果讀者正好需要看source code,可以參看之前的文章《u-boot分析 一》中的源碼分享。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*指定輸出可執行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*指定輸出可執行文件的平臺爲ARM*/
ENTRY(_stext)
/*指定輸出可執行文件的起始代碼段爲_stext*/
SECTIONS
{
/*指定可執行文件的全局入口點,通常這個地址都放在ROM(flash)0x0位置。必須使編譯器知道這個地址,通常都是修改此處來完成*/
. = 0x00000000;
/*從0x0位置開始*/
. = ALIGN(4);
/*代碼以4字節對齊*/
.text :
/*代碼段*/
{
*(.__image_copy_start)
/*u-boot將自己copy到RAM,此爲需要copy的程序的start*/
SOCDIR/start.o (.text*)
/*./arch/arm/cpu/slsiap/s5p4418/start.S*/
SOCDIR/vectors.o (.text*)
/*./arch/arm/cpu/slsiap/s5p4418/vectors.S,異常向量表*/
*(.text*)
/*其他的代碼段放在這裏,即start.S/vector.S之後*/
}
. = ALIGN(4);
/*代碼段結束後,有可能4bytes不對齊了,此時做好4bytes對齊,以開始後面的.rodata段*/
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
/*在代碼段之後,存放read only數據段*/
. = ALIGN(4);
/*和前面一樣,4bytes對齊,以開始接下來的.data段*/
.data : {
*(.data*)
/*可讀寫數據段*/
}
. = ALIGN(4);
/*和前面一樣,4bytes對齊*/
. = .;
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
/*.data段結束後,緊接着存放u-boot自有的一些function,例如u-boot command等*/
}
. = ALIGN(4);
.image_copy_end :
{
*(.__image_copy_end)
/*至此,u-boot需要自拷貝的內容結束,總結一下,包括代碼段,數據段,以及u_boot_list*/
}
.rel_dyn_start :
/*在老的uboot中,如果我們想要uboot啓動後把自己拷貝到內存中的某個地方,只要把要拷貝的地址寫給TEXT_BASE即可,然後boot啓動後就會把自己拷貝到TEXT_BASE內的地址處運行,在拷貝之前的代碼都是相對的,不能出現絕對的跳轉,否則會跑飛。在新版的uboot裏(2013.07),TEXT_BASE的含義改變了。它表示用戶要把這段代碼加載到哪裏,通常是通過串口等工具。然後搬移的時候由uboot自己計算一個地址來進行搬移。新版的uboot採用了動態鏈接技術,在lds文件中有__rel_dyn_start和__rel_dyn_end,這兩個符號之間的區域存放着動態鏈接符號,只要給這裏面的符號加上一定的偏移,拷貝到內存中代碼的後面相應的位置處,就可以在絕對跳轉中找到正確的函數。*/
{
*(.__rel_dyn_start)
}
.rel.dyn : {
*(.rel*)
/*動態鏈接符存放在的段*/
}
.rel_dyn_end :
{
*(.__rel_dyn_end)
/*動態鏈接符段結束*/
}
.end :
{
*(.__end)
}
_image_binary_end = .;
/*bin文件結束*/
/*
* Deprecated: this MMU section is used by pxa at present but
* should not be used by new boards/CPUs.
*/
. = ALIGN(4096);
.mmutable : { /*for MMU*/
*(.mmutable)
}
/*
* Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
* __bss_base and __bss_limit are for linker only (overlay ordering)
*/
/*bss段的描述*/
.bss_start (OVERLAY) : {
KEEP(*(.__bss_start));
__bss_base = .;
}
.bss __bss_base (OVERLAY) : {
*(.bss*)
. = ALIGN(4);
__bss_limit = .;
}
.bss_end __bss_limit (OVERLAY) : {
KEEP(*(.__bss_end));
}
/*bss段的描述結束*/
.dynsym _image_binary_end : { *(.dynsym) }
.dynbss : { *(.dynbss) }
.dynstr : { *(.dynstr*) }
.dynamic : { *(.dynamic*) }
.plt : { *(.plt*) }
.interp : { *(.interp*) }
.gnu.hash : { *(.gnu.hash) }
.gnu : { *(.gnu*) }
.ARM.exidx : { *(.ARM.exidx*) }
.gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}
________________________________________
總結一下,u-boot.lds腳本文件告訴鏈接器linker如何佈局代碼段、數據段、bss段等,已經配置了u-boot自拷貝(從flash到RAM的copy)的內容。另外,還簡要的涉及了動態鏈接技術等。
在多個地方都存有u-boot.lds文件,例如u-boot/u-boot.lds,u-boot/arch/arm/cpu/u-boot.lds,u-boot/arch/arm/cup/slsiap/u-boot.lds。那麼,我們會問一個問題,鏈接器到底是參照哪個script呢? 要找到這個問題的答案,我們需要看看u-boot/Makefile,其中有這樣一段: ifndef LDSCRIPT ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds endif endif 由上面的這段Makefile分析,我們可以知道u-boot/arch/arm/cpu/u-boot.lds纔是linker使用到的script