概述 重定位(relocate)代碼將BootLoader自身由Flash復(fù)制到SDRAM,以便跳轉(zhuǎn)到SDRAM執(zhí)行。之所以需要進(jìn)行重定位是因?yàn)樵?/span>Flash中執(zhí)行速度比較慢,而系統(tǒng)復(fù)位后總是從0x00000000地址取指。 重定位代碼,位于/U-Boot/cpu/s3c44b0/start.S : relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup
ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address */
copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end address [r2] */ ble copy_loop 以上代碼首先判斷是否需要進(jìn)行重定位,如果需要的話首先確定復(fù)制的源基址、源大小和目標(biāo)基址,然后以r3 ~ r13為媒介,將BootLoader復(fù)制到SDRAM中。 分析 copy_loop很容易理解,這里主要分析relocate處的前兩條指令: 1. adr r0, _start adr是一條偽指令,匯編器總是試圖為它產(chǎn)生add/sub這樣的指令,(在這里)以pc為基址裝載目標(biāo)寄存器。以下是arm-elf-objdump產(chǎn)生的反匯編代碼: c700048: e24f0050 sub r0, pc, #80 ; 0x50 e24f0050是指令對(duì)應(yīng)的機(jī)器碼,c700048是存放該機(jī)器碼的地址(十六進(jìn)制表示)。這個(gè)地址是怎么來的呢?在/U-Boot/config.mk中有問題的答案: LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS) 上面的宏指定連接時(shí)的命令行參數(shù),-Ttext設(shè)定了.text段的地址,而TEXT_BASE在/U-Boot/board/.../config.mk中定義為0x0C700000。這些信息最后都以硬編碼的方式記錄在程序映像文件中,程序的入口_start = TEXT_BASE = 0x0C700000 : Disassembly of section .text: 0c700000 <_start>: c700000: ea00000a b c700030 <reset> 但是,程序映像是燒寫到Flash中并開始執(zhí)行的,而Flash的地址從0x00000000開始。于是,程序映像的第一條指令對(duì)齊到0x00000000處。相應(yīng)的,這條adr指令的地址應(yīng)對(duì)齊到0x00000048處,執(zhí)行后r0等于0。 2. ldr r1, _TEXT_BASE 以下是arm-elf-objdump產(chǎn)生的反匯編代碼: c70004c: e51f1034 ldr r1, [pc, #-52] ; c700020 <_TEXT_BASE> 由此可見,這里的ldr并不是簡(jiǎn)單的將_TEXT_BASE地址處的4字節(jié)裝載到r1,而同樣是以pc為基址計(jì)算得到源地址的。這里的pc = 0x4c + 8 = 0x54,于是該指令把0x54 – 52 = 0x20處的4字節(jié)(即TEXT_BASE,亦即0x0C700000)裝載到r1。 3. 源大小的確定 通過上面的分析,我們已經(jīng)有了一個(gè)概念:程序的實(shí)際執(zhí)行地址與連接時(shí)指定的加載地址可能是不一樣的。我們已經(jīng)得到BootLoader代碼開始的運(yùn)行時(shí)開始地址,存放于r0,還需要計(jì)算它的運(yùn)行時(shí)結(jié)束地址。運(yùn)行時(shí)結(jié)束地址 = 運(yùn)行時(shí)開始地址 + 代碼段大小。代碼段大小由.bss段的期望開始地址 - .text段的期望開始地址獲得。 小結(jié) 通過連接時(shí)的-Ttext選項(xiàng),將.text段的地址硬編碼到程序映像中。雖然程序映像在Flash中執(zhí)行,其實(shí)際執(zhí)行地址與期望執(zhí)行地址不一致,但在relocate之前,通過以pc為基址進(jìn)行相對(duì)尋址,使得這些代碼的執(zhí)行與其實(shí)際裝載的地址無關(guān)。 |
|