一、課程內容:
摘要:本節課講解了整體的**重定位與位置無關碼,其中重點和難點是位置無關碼。
實現第二種方法的**重定位:在第二節課講的第乙個**實現的功能,是分段重定位的,本節講的是整體形式的鏈結指令碼。
1、問:位置無關碼怎麼理解?(很關鍵,一開始沒理解!!!!)
答:位置無關碼說白了就是相對跳轉指令與絕對跳轉指令的關係。譬如bl 0x30000478的意思並不是跳到0x30000478,實際意義是由當前的pc值跳到乙個偏移位址。若當前指令pc值是0,則跳到0x00000478了。在程式中寫這個值只是為了方便看**。
注:在彙編檔案中b/bl只是方便檢視作用,不是跳到這個位址。
例:
這裡bl 300001d0的意思相當於乙個「標號」只是方便程式設計師到0x300001d0這個「標號」位置去檢視**,真實情況中這個**在哪個位置中執行是與pc指標的位置有關係的。理解這點很重要,我們看下一點就知道這個知識點的重要性了。
2、問、1與2的彙編**一樣但是區別在**?
答:首先看實驗現象,當燒寫1語句時,串列埠列印的速度明顯沒有語句2速度快,由此可知**1的時候程式還是在nor中執行。
其次分析**:語句1就是相對跳轉指令,此時pc指標並不是真正的0x300005b0只相當於標號,**只是偏移了0x5b0還在nor中執行,執行語句2是絕對跳轉指令,是真的把0x30000640給了pc指標,程式在sdram中執行了。
3、問:那麼什麼時候用相對跳轉(位置無關),什麼時候用絕對跳轉(位置相關)呢?
答:
這張圖展示了啟動的流程,bin檔案包含段和位址的資訊,燒寫進nor_flash中,在nor中執行,然後重定位到sdram,所以可知,在重定位之前的**應該是位置無關的(相對跳轉在nor中執行),重定位之後的**要位置相關(在sdram中執行);
4、問:說了這麼多怎麼寫位置無關的程式呢?
答:a. 呼叫程式時使用b/bl相對跳轉指令
b. 重定位之前, 不可使用絕對位址,比如:
不可訪問全域性變數/靜態變數
不可訪問有初始值的陣列(因為初始值放在rodata裡,使用絕對位址來訪問)
c. 重定位之後, 使用絕對跳轉命令跳到runtime addr,比如: ldr pc, =main
5、問:相對位址與絕對位址怎麼理解區分呢?
答:相對位址就是跳轉,所有的跳轉都是以當前為基準的。相對於當前的位址;絕對位址是直接去了。絕對唯一的位址,在彙編的過程中,會根據跳轉的距離自動形成。相對位址的範圍一般比較短。在中國說故宮大家都知道,要是在美國說故宮就要說中國北京故宮。所以要是需要絕對位址的時候為了保險不讓編譯器自己做主就要用ldr pc,=***避免程式沒跳出nor。
二、**編寫過程
1、寫乙個新的鏈結指令碼,首先參考u-boot
這種整體的鏈結指令碼,要比之前的分體的好,用的也多,分體的適合微控制器,微控制器內部有可以執行程式的flash,這樣可以節省記憶體,但是對於嵌入式系統記憶體很龐大,不用省這一點記憶體。還有乙個原因是,jtag一般只支援這種整體的鏈結指令碼
2、在start.s中修改重定位前後的**,重定位前用位置無關碼(相對位址),重定位後用絕對跳轉指令(絕對位址)
三、**
鏈結指令碼
sections
. = align(4);
.rodata :
. = align(4);
.data :
. = align(4);
bss_start = .;
.bss :
end =.;
}
start.s
.text
.global _start
_start:
/* 關閉看門狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 設定mpll, fclk : hclk : pclk = 400m : 100m : 50m */
/* locktime(0x4c000000) = 0xffffffff */
ldr r0, =0x4c000000
ldr r1, =0xffffffff
str r1, [r0]
/* clkdivn(0x4c000014) = 0x5, tfclk:thclk:tpclk = 1:4:8 */
ldr r0, =0x4c000014
ldr r1, =0x5
str r1, [r0]
/* 設定cpu工作於非同步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //r1_nf:or:r1_ia
mcr p15,0,r0,c1,c0,0
/* 設定mpllcon(0x4c000004) = (92<<12)|(1<<4)|(1<<0)
* m = mdiv+8 = 92+8=100
* p = pdiv+2 = 1+2 = 3
* s = sdiv = 1
* fclk = 2*m*fin/(p*2^s) = 2*100*12/(3*2^1)=400m
*/ldr r0, =0x4c000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦設定pll, 就會鎖定lock time直到pll輸出穩定
* 然後cpu工作於新的頻率fclk
*//* 設定記憶體: sp 棧 */
/* 分辨是nor/nand啟動
* 寫0到0位址, 再讀出來
* 如果得到0, 表示0位址上的內容被修改了, 它對應ram, 這就是nand啟動
* 否則就是nor啟動
*/mov r1, #0
ldr r0, [r1] /* 讀出原來的值備份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是nand啟動 */
ldr sp, =0x40000000+4096 /* 先假設是nor啟動 */
moveq sp, #4096 /* nand啟動 */
streq r0, [r1] /* 恢復原來的值 */
bl sdram_init
/*重定位data段*/
mov r1,#0
ldr r2, = _start
ldr r3, = bss_start
cpy:
ldr r4,[r1]
str r4,[r2]
add r1,r1,#4
add r2,r2,#4
cmp r2,r3
bne cpy
/*清除bss段*/
ldr r1,= bss_start
ldr r2,= end
mov r3,#0
clean:
str r3,[r1]
add r1,r1,#4
cmp r1,r2
bne clean
//bl main
ldr pc,=main
halt:
b halt
韋東山嵌入式第一期學習筆記DAY 11 13 4
一 課程內容 摘要 本節課主要講解了將之前start.s中的strb,ldrb 單位元組操作 換成str,ldr 4位元組操作 減少硬體的訪問次數和align函式實現的 4位元組對齊 1 問 是怎麼減少硬體訪問次數從而優化strb的?答 使用strb,ldrb若操作16位元組資料硬體總共訪問32次 ...
韋東山嵌入式第一期學習筆記DAY 19 17 6
一 課程內容 完善上節課的程式,實現設定4.3寸lcd的引數與,第一步 設定lcd顯示屏的引數 第二步 寫乙個註冊函式,用於註冊不同型號的lcd顯示器 define lcd num 10 static p lcd params p array lcd lcd num static p lcd par...
韋東山嵌入式第一期學習筆記DAY 19 17 7
一 課程內容 概述 本節課完善了之前的程式bug,並且讓顯示器顯示全屏紅 綠 藍三種顏色。1 新建lcd test.c 1 首先lcd test函式要獲得lcd顯示器的引數,比如x,y的畫素等等。所以要構建乙個獲得引數的函式,在上一層中。void get lcd params unsigned in...