從前面一節Exynos 4412的啓動過程分析 ,咱們知道:一上電,exynos4412首先執行固化在IROM中的代碼,iROM首先設置程序運行環境 (好比關看門狗、關中斷、關MMU 、設置棧 、設置棧 、啓動PLL等 ),而後根據OM引腳肯定啓動設備 (NAND Flash/SD 卡/其餘 ),把 BL1從裏面讀出存入iRAM的0x02021400地址處,最後啓動 BL1; BL1從SD卡適當的位置讀入14K 字節的數據,存在iRAM地址0x02023400處,因此BL2不能大於(14K – 4) 字節,這裏引出了爲何寫這一節的緣由:若是咱們的程序很大,大於14K怎麼辦????html
一是程序當前所處的地址,即程序在運行時,所處的當前地址;二是程序的連接地址,即程序運行時應該位於的運行地址。編譯程序時,能夠指定程序的連接地址。面試
對於Tiny4412而言,前面咱們已經說過:啓動時BL1只會從sd等啓動設備中拷貝14K的代碼到IRAM中,那麼當咱們的程序超過14K怎麼辦?那就須要咱們在前14K的代碼中將整個程序完完整整地拷貝到DRAM等其餘更大存儲空間,而後再跳轉到DRAM中繼續運行咱們的代碼,這個拷貝而後跳轉的過程就叫重定位。服務器
本章中咱們主要學習如何重定位,可是並不會涉如何使用到DRAM,而是簡單地將代碼從IRAM的0x02023400處拷貝到IRAM的0x0202a000處,而後跳轉到0x0202a000處繼續運行咱們的代碼。函數
基於上一個實驗的代碼進行修改,修改了start,S文件以及連接腳本文件:工具
在start.S文件中增長以下代碼:oop
.text .globl _start _start: /* 關閉看門狗 */ ldr r0, =0x10060000 mov r1, #0x0 str r1, [r0] /* 啓動Icache */ mrc p15, 0, r0, c1, c0, 0 orr r0, r0, #0x00001000 //打開ICache //bic r0, r0, #0x00001000 //關閉ICache mcr p15, 0, r0, c1, c0, 0 /* 重定位 - 將代碼從0x02023400處拷貝到連接地址0x0202a000處(在連接腳本里指定的),並跳轉到這個地址去執行 */ adr r0, _start /* adr指令用於讀取_start在當前的運行的物理地址,即0x02023400 */ ldr r1, =_start /* 讀取_start的連接地址,即0x0202a000 */ ldr r2, =bss_start /* 讀取bss段的起始地址,用於計算須要拷貝的字節多少 */ cmp r0, r1 beq clean_bss /* 若是r0=r1,則跳轉到clean_bss,說明此時已經在連接地址處了 */ /* 若是r0!=r1,則進行以下的拷貝 */ copy_loop: ldr r3, [r0], #4 /* 源 */ str r3, [r1], #4 /* 目的 */ cmp r1, r2 /* 判斷是否已經拷貝完 */ bne copy_loop /* 若是沒有拷貝完就繼續拷貝 */ /* 清bss段 */ clean_bss: ldr r0, =bss_start /* r0保存bss段的起始地址 */ ldr r1, =bss_end /* r1保存bss段的起始地址 */ cmp r0, r1 beq run_on_dram /* 若是r0=r1,則跳轉到run_on_dram,說明bss段裏邊沒有變量 */ mov r2, #0 clear_loop: str r2, [r0], #4 cmp r0, r1 bne clear_loop ldr sp, =0x02060000 /* 跳轉 */ run_on_dram: ldr pc, =main /* 執行完這句話以後,PC就指向了main的連接地址 */
這段代碼主要實現了代碼重定位、清除BSS段、以及跳轉到連接地址繼續運行,註釋說的已經很明白了,有什麼的不熟悉的,你們能夠留言共同探討。學習
連接腳本reload.lds修改成以下:spa
SECTIONS { . = 0x0202A000; .text : { *(.text) } .rodata ALIGN(4) : { *(.rodata*) } .data ALIGN(4) : { *(.data*) } bss_start = . ; .bss ALIGN(4) : { *(.bss) *(COMMON) } bss_end = . ; }
主要增長了bss段的起始bss_start及結束bss_end 的定義,這兩個標號在start.S中被用到。code
1.編譯htm
經過FTP或者其餘工具將文件上傳到服務器上去,輸入make命令進行編譯將獲得reload.bin文件。
2.燒寫
將SD卡插入電腦,並讓VmWare裏的Ubuntu識別出來,而後執行以下命令:
sudo ./sd_fusing.sh /dev/sdb ../8_reload/reload.bin
將SD卡插入Tiny4412開發板,上電,你會看到和上一節的運行效果同樣(由於咱們沒有修改LED的顯示效果,只是修改了程序的運行地址,這個對外是看不出區別的)。
將反彙編文件reload.dis,從服務器上下載下來,咱們進行簡單分析一下:
從上圖能夠看出,程序的連接地址確實是咱們在鏈接腳本里指定的0x0202a000
咱們再來看看跳轉的那條指令;
202a060: e59ff010 ldr pc, [pc, #16] ; 202a078 <run_on_dram+0x18>
將當前PC的值加上24後的地址的內容賦給PC,即:
0x202a060 + 8 +16 = 0x0202a078
將0x0202a078這個地址的值賦給PC
0x0202a0b0這個地址正是main函數的入口地址。
我在本身的開發板上面試驗成功。有興趣的小夥伴能夠自行試驗。