乙個典型的嵌入式系統中,bootloader**放在nor flash或nand flash裡面,系統加電或復位後,首先執行這段**。通常把bootloader**放在nor flash裡面,nand flash由於硬體原因不能隨機訪問,需要特殊的硬體支援機制。
bootloader**除了初始化以外就是搬運程式,即位址重定位(relocate)。我們為什麼需要relocate?主要是經濟方面和速度方面的原因。經濟方面,nor flash和nand flash每兆**相差懸殊,bootloader**一般在幾十到幾百k大小,而應用程式通常都很大,幾m到幾十m的大小,所以用**低廉的nand flash儲存。速度方面,程式在nor flash裡執行的速度遠遠小於在sdram中執行的速度,為了追求更高的速度,也需要relocate,讓程式在sdram裡面執行。
relocate涉及到載入域(vma)和執行域(lma)兩個概念。載入域是程式**在rom、flash中的排列次序及位址安排,執行域是程式執行時**在sram、sdram中位址安排。儲存**時按照載入域存放在flash中,執行時再從flash中取出**到ram執行域執行,一段**的載入域和儲存域可以不同。(可以參考杜春雷的《arm體系結構與程式設計》一書的有關章節)。
以smdk2410為例,密切相關的就兩個資料夾/board/smdk2410和/cpu/arm920t,裡面核心檔案就u-boot.lds 、config.mk 、start.s。
/cpu/arm920t/u-boot.lds
output_format("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
output_arch(arm)
entry(_start)
sections
. = align(4);
.rodata :
. = align(4);
.data :
. = align(4);
.got :
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd :
__u_boot_cmd_end = .;
. = align(4);
__bss_start = .;
.bss (noload) :
_end = .;
}連線指令碼檔案lds中沒有設定lma,只是設定了vma。vma的設定是通過頂層目錄下的config.mk檔案中的ldflags實現的,text_base在/board/smdk2410/config.mk中定義為0x33f80000(sdram位址)。
ldflags += -bstatic -t $(obj)u-boot.lds $(platform_ldflags)
ifneq ($(text_base),)
ldflags += -ttext $(text_base)
endif
檢視u-boot.map檔案,**的連線位址是從0x33f80000開始的。
167 .text
0x33f80000
0x232c8
168
cpu/arm920t/start.o(.text)
169
.text
0x33f80000
0x4a0 cpu/arm920t/start.o
170
0x33f80048
_bss_start
171
0x33f8004c
_bss_end
172
0x33f80044
_armboot_start
173
0x33f80000
_start
174
board/samsung/fs2410/lowlevel_init.o(.text)
175
.text
0x33f804a0
0x64 board/samsung/fs2410/lowlevel_init.o
176
0x33f804a4
lowlevel_init
177
board/samsung/fs2410/nand_read.o(.text)
178
.text
0x33f80504
0xe8 board/samsung/fs2410/nand_read.o
179
0x33f80504
wait_idle
180
0x33f80518
nand_read_ll
bootloader**上電之後之所以能夠正確執行,有個很重要的原因,就是最初執行的bootloader**是位址無關的,即這個映象檔案可以被放在記憶體中的任何乙個位址上執行。
對於位址無關的**, 定址是基於pc值的,在pc值上+/-乙個偏移值得到執行位址,如跳轉指令b。當執行完**搬運,就需要跳到和位址相關的地方去執行,即ram中。一般是跳轉到乙個標號,這時位址相關**就開始執行了,如:ldr pc,_start_armboot。
因為在bin映象生成的時候,就已經把_start_armboot這個符號和實際位址繫結在一起,當執行ldr pc,_start_armboot 語句時,程式就從在rom中執行跳入到ram中了,前提是進行了**搬移。如果沒有**搬運就執行ldr pc,_start_armboot,因為ram中沒有正確的可執行**,程式就馬上飛掉了,所有在搬運之前不能定址絕對位址有關**,必須執行**位址無關.
下面的**是從nor flash向sdram搬運的**:
relocate:
adr r0, _start
ldr r1, _text_base
cmp r0, r1
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2
add r2, r0, r2
copy_loop:
ldmia r0!,
stmia r1!,
cmp r0, r2
ble copy_loop
u boot鏈結分析
華清遠見嵌入式培訓中心 講師。乙個典型的嵌入式系統中,bootloader 放在nor flash或nand flash裡面,系統加電或復位後,首先執行這段 通常把bootloader 放在nor flash裡面,nand flash由於硬體原因不能隨機訪問,需要特殊的硬體支援機制。bootload...
uboot鏈結指令碼
gnu編譯器生成的目標檔案預設為elf格式,elf檔案由若干段 section 組成,如不特殊指明,由c源程式生成的目標 中包含如下段 text 正文段 包含程式的指令 data 資料段 包含固定的資料,如常量 字串 bss 未初始化資料段 包含未初始化的變數 陣列等。c 源程式生成的目標 中還包括...
U boot分析(一) 物件鏈結
預備知識 可執行檔案由許多鏈結在一起的物件檔案組成。物件檔案有許多節,如文字 資料 init 資料 bss等。這些物件檔案都是由乙個稱為 鏈結器指令碼 lds 的檔案鏈結並裝入的。這個鏈結器指令碼的功能是將輸入物件檔案的各節對映到輸出檔案中 換句話說,它將所有輸入物件檔案都鏈結到單一的可執行檔案中,...