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