tiny4412 裸机程序 六、重定位代码到IRAM+0x8000
一、重定向
對(duì)于程序而言,我們需要理解兩個(gè)概念,一是程序當(dāng)前所處的地址,即程序在運(yùn)行時(shí),所處的當(dāng)前地址;二是程序的鏈接地址,即程序運(yùn)行時(shí)應(yīng)該位于的運(yùn)行地址。編譯程序時(shí),可以指定程序的鏈接地址。對(duì)于Tiny4412而言,啟動(dòng)時(shí)只會(huì)從MMC/sd等啟動(dòng)設(shè)備中拷貝前16K的代碼到IRAM中,那么當(dāng)我們的程序超過(guò)16K怎么辦?那就需要我們?cè)谇?6K的代碼中將整個(gè)程序完完整整地拷貝到DRAM等其他更大存儲(chǔ)空間,然后再跳轉(zhuǎn)到DRAM中繼續(xù)運(yùn)行我們的代碼,這個(gè)拷貝然后跳轉(zhuǎn)的過(guò)程就叫重定位。
本章中我們主要學(xué)習(xí)如何重定位,但是并不會(huì)涉如何使用到DRAM,而是簡(jiǎn)單地將代碼從IRAM的0x02020010處拷貝到IRAM的0x02028000處,然后跳轉(zhuǎn)到0x02028000處繼續(xù)運(yùn)行我們的代碼。
二、程序說(shuō)明
完整代碼見(jiàn)目錄5_link_0x8000,該目錄下的代碼與上一章的代碼的差別在于start.S和使用了
鏈接腳本link.lds,我們首先分析link.lds。
1. link.lds
什么是鏈接腳本?鏈接腳本就是程序鏈接時(shí)的參考文件,其主要目的是描述如何把輸入文件中的段(SECTION)映射到輸出文件中,并控制輸出文件的存儲(chǔ)布局。鏈接腳本的基本命令式SECTIONS命令,一個(gè)SECTIONS命令內(nèi)部包含一個(gè)或多個(gè)段,段(SECTION)是鏈接腳本的基本單元,它表示輸入文件中的某個(gè)段是如何放置的。
鏈接腳本的標(biāo)準(zhǔn)格式如下:
SECTIONS
{
sections-command
sections-command
}
下面我們配合link.lds進(jìn)行具體講解:
SECTIONS
{
. = 0x02028000;
.text : {
start.o
* (.text)
}
.data : {
* (.data)
}
bss_start = .;
.bss : {
* (.bss)
}
bss_end = .;
}
1)? 在鏈接腳本中,單獨(dú)的點(diǎn)號(hào)(.)代表了當(dāng)前位置,. =0x02028000;表示程序的鏈接地址是00x02028000;
2)? link.lds中的.text 、 .data 、 .bss分別是text段、data段、bss段的段名(這些段名并不是固定的,是可以隨便起的)。.text 段包含的內(nèi)容是start.o 和其余代碼中所有的text段;.data段包含的內(nèi)容是代碼中所有的data段;.bss段包含的內(nèi)容是代碼中所有的bss段。
3)? bss_start和bss_end保存的是bss段的起始地址和結(jié)束地址,在start.S中會(huì)被用到。
下面解釋一下什么是data、text、bss段:
1)? data段:數(shù)據(jù)段(datasegment)通常是指用來(lái)存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配。
2)? text段:代碼段通常是指用來(lái)存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于只讀,某些架構(gòu)也允許代碼段為可寫(xiě),即允許修改程序。在代碼段中,也有可能包含一些只讀的常數(shù)變量,例如字符串常量等。
3)? bss段:指用來(lái)存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域。BSS是英文BlockStarted by Symbol的簡(jiǎn)稱。當(dāng)我們的程序有全局變量是,它是放在bss段的,由于全局變量默認(rèn)初始值都是0,所有我們需要手動(dòng)清bss段。
2. start.S
在start.S中,我們初始化時(shí)鐘后,增加了3個(gè)步驟:
第一步重定位,代碼如下:
// _start當(dāng)前所位于的地址
adr r0, _start??
// _start的鏈接地址
ldr r1, =_start??
ldr r2, =bss_start
cmp r0, r1
beq clean_bss
copy_loop:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r1, r2
bne copy_loop
首先需要知道的是,adr指令獲取的值是代碼當(dāng)前位于的地址,而ldr指令獲取的值是代碼的鏈接地址。再來(lái)看代碼,代碼里首先獲得_start標(biāo)號(hào)的當(dāng)前地址(即0x02020010),然后獲取_start標(biāo)號(hào)的鏈接地址(即0x02028000),因?yàn)閎in文件中不需要保存bss段,所有拷貝的代碼長(zhǎng)度為bss_start的運(yùn)行地址-_start的運(yùn)行地址,使用copy_loop進(jìn)行拷貝。
?
第二步清bss,代碼如下:
ldr r0, =bss_start????????
ldr r1, =bss_end
cmp r0, r1
beq run_on_dram
mov r2, #0
clear_loop:
str r2, [r0], #4
cmp r0, r1
bne clear_loop
首先獲得bss段的起始地址(即bss_start),然后獲得bss段的結(jié)束地址(即bss_end),最后使用clear_loop將bss段所位于的內(nèi)存清0,bss_start和bss_end的定義位于link.lds。
第三步跳轉(zhuǎn),代碼如下:
run_on_dram:???
ldr pc, =main
由于ldr 指令獲取的是main函數(shù)的鏈接地址,所以執(zhí)行l(wèi)drpc, =main 后,程序就跳轉(zhuǎn)到
0x02020000+main函數(shù)的offset的地址處了。
三、完整的燒寫(xiě)過(guò)程
已將SD卡插入電腦,假設(shè)linux識(shí)別了SD卡,其識(shí)別號(hào)為sdb。執(zhí)行下面命令:
# chmod 777 –R 5_link_0x8000
# cd 5_link_0x8000
# make
# cd sd_fuse
# make
# ./ fast_fuse /dev/sdb
四、上電實(shí)驗(yàn)
將sd卡插入Tiny4412中,選擇sd卡啟動(dòng),然后上電,可以看到以下現(xiàn)象:
LED正常閃爍,該現(xiàn)象與前面章節(jié)的代碼的運(yùn)行效果一模一樣,但是程序的運(yùn)行過(guò)程卻有了很大的區(qū)別。通過(guò)本章的學(xué)習(xí),我們已經(jīng)知道了如何對(duì)代碼進(jìn)行重定位,這為我們下一章節(jié)將代碼重定位到DRAM奠定了基礎(chǔ)。
備注:說(shuō)明一下,代碼已上傳到我的資源里,我要了兩個(gè)下載分,不好意思,我的資源分太少了,我得賺點(diǎn),我相信我的程序是絕對(duì)能運(yùn)行的,覺(jué)得值就去下載。
總結(jié)
以上是生活随笔為你收集整理的tiny4412 裸机程序 六、重定位代码到IRAM+0x8000的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: flowable 会签和或签的实现 任务
- 下一篇: 南京印象之出租车司机