韋東山嵌入式第一期學習筆記DAY 11 13 5

2021-09-25 05:10:13 字數 4032 閱讀 2274

一、課程內容:

摘要:本節課講解了整體的**重定位與位置無關碼,其中重點和難點是位置無關碼。

實現第二種方法的**重定位:在第二節課講的第乙個**實現的功能,是分段重定位的,本節講的是整體形式的鏈結指令碼。

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...