Tiny4412裸機程序之代碼重定位初體驗

從前面一節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處繼續運行咱們的代碼。函數

1、程序說明

基於上一個實驗的代碼進行修改,修改了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

2、編譯、燒寫、運行

1.編譯htm

經過FTP或者其餘工具將文件上傳到服務器上去,輸入make命令進行編譯將獲得reload.bin文件。

2.燒寫

將SD卡插入電腦,並讓VmWare裏的Ubuntu識別出來,而後執行以下命令:

sudo ./sd_fusing.sh /dev/sdb ../8_reload/reload.bin

將SD卡插入Tiny4412開發板,上電,你會看到和上一節的運行效果同樣(由於咱們沒有修改LED的顯示效果,只是修改了程序的運行地址,這個對外是看不出區別的)。

3、反彙編文件分析

將反彙編文件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函數的入口地址。

我在本身的開發板上面試驗成功。有興趣的小夥伴能夠自行試驗。

相關文章
相關標籤/搜索