- STARTUP
1 ARM的啟動
一般的嵌入式系統(tǒng)在主程序執(zhí)行之前都需要執(zhí)行一些初始化的過程以創(chuàng)造嵌入式程序運(yùn)行的環(huán)境,尤其是一些高級的嵌入式系統(tǒng),由于核心芯片使用內(nèi)存映射、內(nèi)存保護(hù)等機(jī)制以及編程使用高級語言C,C++甚至JAVA語言,都需要先創(chuàng)建一個(gè)適合程序運(yùn)行的硬件環(huán)境,然后初始化或者配置或者剪裁run-time library, 這些工作都必須在主程序運(yùn)行前完成,所以一個(gè)startup程序或者程序組對于一個(gè)嵌入式系統(tǒng)來說是非常重要的。要編寫startup程序,需要對編譯器、鏈接器和匯編器的細(xì)節(jié)有一定的了解,同時(shí)對ARM芯片硬件本身的地址分配以及memory mapping機(jī)制也需要有一些了解。
2 ARM 程序的工作過程
首先由各種source file經(jīng)過編譯產(chǎn)生object文件,然后object文件經(jīng)過鏈接生成Image文件,然后通過ICE的方法,根據(jù)描述文件的指定下載到目標(biāo)板上的固態(tài)存儲器指定地址當(dāng)中,比如flash,EEPROM, ROM等等。在程序執(zhí)行之前,根據(jù)某些描述文件,將需要讀寫數(shù)據(jù)的部分讀出放入動態(tài)存儲器比如RAM當(dāng)中,然后程序從ROM開始執(zhí)行。或者有時(shí)為了提高程序的運(yùn)行速度,也可以將所有的程序(有一些root的部分除外,以后會提及)通過一個(gè)描述文件放入指定的RAM當(dāng)中,然后程序從RAM開始執(zhí)行,但是這樣會耗費(fèi)大量的動態(tài)存儲器,所以大部分程序會取折中的方法,將需要快速運(yùn)行的部分和要讀寫的部分放入RAM中(一般讀固態(tài)存儲器的過程和動態(tài)存儲器的過程是一樣的,但是寫就不同了,所以讀寫的部分一定要放到RAM中),而只讀的部分和對速度要求不是那么高的部分放入固態(tài)存儲器。同時(shí)ARM結(jié)構(gòu)的異常向量表規(guī)定放在地址為0x00000000開始的地址空間上,而一般的CPU為了提高異常相應(yīng)速度,會將這個(gè)向量段remap到其他的RAM當(dāng)中,所以在描述文件當(dāng)中必須精確指定異常向量跳轉(zhuǎn)程序的地址到remap的地方。在application程序執(zhí)行前,還需要由一些文件描述application程序執(zhí)行的環(huán)境。比如系統(tǒng)工作時(shí)鐘,總線頻率。現(xiàn)在一般嵌入式編程語言為C,C++等。如果在使用它們的時(shí)候使用的runtime-library,那么在程序執(zhí)行前還需要為這些庫函數(shù)初始化heap。然后ARM可能工作在不同的模式,還需要為不同的工作模式設(shè)置stack。這樣,描述鏈接地址的文件,以及在application運(yùn)行前所有的初始化程序就是startup程序組
3 STARTUP分類
這樣,將startup程序所完成的功能分類。一類是鏈接地址描述,一類是各種初始化的程序。根據(jù)不同的應(yīng)用,描述文件和初始化程序的內(nèi)容以及結(jié)構(gòu)和復(fù)雜程度都會不同。但是基本上,它們都必須實(shí)現(xiàn)以下功能。
3.1 描述文件實(shí)現(xiàn)功能
描述文件可以是鏈接命令行上簡單的幾個(gè)字符,也可以是一個(gè)非常復(fù)雜的文件,但是它必須完成如下功能:
; 指定程序下載的地址
; 指定程序執(zhí)行的地址
3.2 初始化程序?qū)崿F(xiàn)的功能
初始化程序根據(jù)不同的應(yīng)用,其結(jié)構(gòu)和復(fù)雜度也不同,但是它必須完成如下基本功能:
; 異常向量初始化
; 內(nèi)存環(huán)境初始化
; 其他硬件環(huán)境初始化
基于ARM的芯片多數(shù)為復(fù)雜的片上系統(tǒng),這種復(fù)雜系統(tǒng)里的多數(shù)硬件模塊都是可配置的,需要由軟件來設(shè)置其需要的工作狀態(tài)。因此在用戶的應(yīng)用程序之前,需要由專門的一段代碼來完成對系統(tǒng)的初始化。由于這類代碼直接面對處理器內(nèi)核和硬件控制器進(jìn)行編程,一般都是用匯編語言。一般通用的內(nèi)容包括:
中斷向量表
初始化存儲器系統(tǒng)
初始化堆棧
初始化有特殊要求的斷口,設(shè)備
初始化用戶程序執(zhí)行環(huán)境
改變處理器模式
呼叫主應(yīng)用程序
1. 中斷向量表
ARM要求中斷向量表必須放置在從0地址開始,連續(xù)8X4字節(jié)的空間內(nèi)。
每當(dāng)一個(gè)中斷發(fā)生以后,ARM處理器便強(qiáng)制把PC指針置為向量表中對應(yīng)中斷類型的地址值。因?yàn)槊總(gè)中斷只占據(jù)向量表中1個(gè)字的存儲空間,只能放置一條ARM指令,使程序跳轉(zhuǎn)到存儲器的其他地方,再執(zhí)行中斷處理。
中斷向量表的程序?qū)崿F(xiàn)通常如下表示:
AREA Boot ,CODE, READONLY
ENTRY
B ResetHandler
B UndefHandler
B SWIHandler
B PreAbortHandler
B DataAbortHandler
B
B IRQHandler
B FIQHandler
其中關(guān)鍵字ENTRY是指定編譯器保留這段代碼,因?yàn)榫幾g器可能會認(rèn)為這是一段亢余代碼而加以優(yōu)化。鏈接的時(shí)候要確保這段代碼被鏈接在0地址處,并且作為整個(gè)程序的入口。
2. 初始化存儲器系統(tǒng)
(1)存儲器類型和時(shí)序配置
通常Flash和SRAM同屬于靜態(tài)存儲器類型,可以合用同一個(gè)存儲器端口;而DRAM因?yàn)橛袆討B(tài)刷新和地址線復(fù)用等特性,通常配有專用的存儲器端口。
存儲器端口的接口時(shí)序優(yōu)化是非常重要的,這會影響到整個(gè)系統(tǒng)的性能。因?yàn)橐话阆到y(tǒng)運(yùn)行的速度瓶頸都存在于存儲器訪問,所以存儲器訪問時(shí)序應(yīng)盡可能的快;而同時(shí)又要考慮到由此帶來的穩(wěn)定性問題。
(2)存儲器地址分布
一種典型的情況是啟動ROM的地址重映射。
3. 初始化堆棧
因?yàn)锳RM有7種執(zhí)行狀態(tài),每一種狀態(tài)的堆棧指針寄存器(SP)都是獨(dú)立的。因此,對程序中需要用到的每一種模式都要給SP定義一個(gè)堆棧地址。方法是改變狀態(tài)寄存器內(nèi)的狀態(tài)位,使處理器切換到不同的狀態(tài),讓后給SP賦值。注意:不要切換到User模式進(jìn)行User模式的堆棧設(shè)置,因?yàn)檫M(jìn)入U(xiǎn)ser模式后就不能再操作CPSR回到別的模式了,可能會對接下去的程序執(zhí)行造成影響。
這是一段堆棧初始化的代碼示例,其中只定義了三種模式的SP指針:
MRS R0,CPSR
BIC R0,R0,#MODEMASK 安全起見,屏蔽模式位以外的其他位
ORR R1,R0,#IRQMODE
MSR CPSR_cxfs,R1
LDR SP,=UndefStack
ORR R1,R0,#FIQMODE
MSR CPSR_cxsf,R1
LDR SP,=FIQStack
ORR R1,R0,#SVCMODE
MSR CPSR_cxsf,R1
LDR SP,=SVCStack
4. 初始化有特殊要求的端口,設(shè)備
5. 初始化應(yīng)用程序執(zhí)行環(huán)境
映像一開始總是存儲在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面執(zhí)行,也可以轉(zhuǎn)移到速度更快的RAM中執(zhí)行;而RW和ZI這兩部分是必須轉(zhuǎn)移到可寫的RAM里去。所謂應(yīng)用程序執(zhí)行環(huán)境的初始化,就是完成必要的從ROM到RAM的數(shù)據(jù)傳輸和內(nèi)容清零。
下面是在ADS下,一種常用存儲器模型的直接實(shí)現(xiàn):
LDR r0,=|Image$$RO$$Limit| 得到RW數(shù)據(jù)源的起始地址
LDR r1,=|Image$$RW$$Base| RW區(qū)在RAM里的執(zhí)行區(qū)起始地址
LDR r2,=|Image$$ZI$$Base| ZI區(qū)在RAM里面的起始地址
CMP r0,r1 比較它們是否相等
BEQ %F1
0 CMP r1,r3
LDRCC r2,[r0],#4
STRCC r2,[r1],#4
BCC %B0
1 LDR r1,=|Image$$ZI$$Limit|
MOV r2,#0
2 CMP r3,r1
STRCC r2,[r3],#4
BCC %B2
程序?qū)崿F(xiàn)了RW數(shù)據(jù)的拷貝和ZI區(qū)域的清零功能。其中引用到的4個(gè)符號是由鏈接器第一輸出的。
|Image$$RO$$Limit|:表示RO區(qū)末地址后面的地址,即RW數(shù)據(jù)源的起始地址
|Image$$RW$$Base|:RW區(qū)在RAM里的執(zhí)行區(qū)起始地址,也就是編譯器選項(xiàng)RW_Base指定的地址
|Image$$ZI$$Base|:ZI區(qū)在RAM里面的起始地址
|Image$$ZI$$Limit|:ZI區(qū)在RAM里面的結(jié)束地址后面的一個(gè)地址
程序先把ROM里|Image$$RO$$Limt|開始的RW初始數(shù)據(jù)拷貝到RAM里面|Image$$RW$$Base|開始的地址,當(dāng)RAM這邊的目標(biāo)地址到達(dá)|Image$$ZI$$Base|后就表示RW區(qū)的結(jié)束和ZI區(qū)的開始,接下去就對這片ZI區(qū)進(jìn)行清零操作,直到遇到結(jié)束地址|Image$$ZI$$Limit|
6. 改變處理器模式
因?yàn)樵诔跏蓟^程中,許多操作需要在特權(quán)模式下才能進(jìn)行(比如對CPSR的修改),所以要特別注意不能過早的進(jìn)入用戶模式。
內(nèi)核級的中斷使能也可以考慮在這一步進(jìn)行。如果系統(tǒng)中另外存在一個(gè)專門的中斷控制器,這么做總是安全的。
7. 呼叫主應(yīng)用程序
當(dāng)所有的系統(tǒng)初始化工作完成之后,就需要把程序流程轉(zhuǎn)入主應(yīng)用程序。最簡單的一種情況是:
IMPORT main
B main
直接從啟動代碼跳轉(zhuǎn)到應(yīng)用程序的主函數(shù)入口,當(dāng)然主函數(shù)名字可以由用戶隨便定義。
在ARM ADS環(huán)境中,還另外提供了一套系統(tǒng)級的呼叫機(jī)制。
IMPORT __main
B __main
__main()是編譯系統(tǒng)提供的一個(gè)函數(shù),負(fù)責(zé)完成庫函數(shù)的初始化和初始化應(yīng)用程序執(zhí)行環(huán)境,最后自動跳轉(zhuǎn)到main()函數(shù)。
中斷向量表
初始化存儲器系統(tǒng)
初始化堆棧
初始化有特殊要求的斷口,設(shè)備
初始化用戶程序執(zhí)行環(huán)境
改變處理器模式
呼叫主應(yīng)用程序
1. 中斷向量表
ARM要求中斷向量表必須放置在從0地址開始,連續(xù)8X4字節(jié)的空間內(nèi)。
每當(dāng)一個(gè)中斷發(fā)生以后,ARM處理器便強(qiáng)制把PC指針置為向量表中對應(yīng)中斷類型的地址值。因?yàn)槊總(gè)中斷只占據(jù)向量表中1個(gè)字的存儲空間,只能放置一條ARM指令,使程序跳轉(zhuǎn)到存儲器的其他地方,再執(zhí)行中斷處理。
中斷向量表的程序?qū)崿F(xiàn)通常如下表示:
AREA Boot ,CODE, READONLY
ENTRY
B ResetHandler
B UndefHandler
B SWIHandler
B PreAbortHandler
B DataAbortHandler
B
B IRQHandler
B FIQHandler
其中關(guān)鍵字ENTRY是指定編譯器保留這段代碼,因?yàn)榫幾g器可能會認(rèn)為這是一段亢余代碼而加以優(yōu)化。鏈接的時(shí)候要確保這段代碼被鏈接在0地址處,并且作為整個(gè)程序的入口。
2. 初始化存儲器系統(tǒng)
(1)存儲器類型和時(shí)序配置
通常Flash和SRAM同屬于靜態(tài)存儲器類型,可以合用同一個(gè)存儲器端口;而DRAM因?yàn)橛袆討B(tài)刷新和地址線復(fù)用等特性,通常配有專用的存儲器端口。
存儲器端口的接口時(shí)序優(yōu)化是非常重要的,這會影響到整個(gè)系統(tǒng)的性能。因?yàn)橐话阆到y(tǒng)運(yùn)行的速度瓶頸都存在于存儲器訪問,所以存儲器訪問時(shí)序應(yīng)盡可能的快;而同時(shí)又要考慮到由此帶來的穩(wěn)定性問題。
(2)存儲器地址分布
一種典型的情況是啟動ROM的地址重映射。
3. 初始化堆棧
因?yàn)锳RM有7種執(zhí)行狀態(tài),每一種狀態(tài)的堆棧指針寄存器(SP)都是獨(dú)立的。因此,對程序中需要用到的每一種模式都要給SP定義一個(gè)堆棧地址。方法是改變狀態(tài)寄存器內(nèi)的狀態(tài)位,使處理器切換到不同的狀態(tài),讓后給SP賦值。注意:不要切換到User模式進(jìn)行User模式的堆棧設(shè)置,因?yàn)檫M(jìn)入U(xiǎn)ser模式后就不能再操作CPSR回到別的模式了,可能會對接下去的程序執(zhí)行造成影響。
這是一段堆棧初始化的代碼示例,其中只定義了三種模式的SP指針:
MRS R0,CPSR
BIC R0,R0,#MODEMASK 安全起見,屏蔽模式位以外的其他位
ORR R1,R0,#IRQMODE
MSR CPSR_cxfs,R1
LDR SP,=UndefStack
ORR R1,R0,#FIQMODE
MSR CPSR_cxsf,R1
LDR SP,=FIQStack
ORR R1,R0,#SVCMODE
MSR CPSR_cxsf,R1
LDR SP,=SVCStack
4. 初始化有特殊要求的端口,設(shè)備
5. 初始化應(yīng)用程序執(zhí)行環(huán)境
映像一開始總是存儲在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面執(zhí)行,也可以轉(zhuǎn)移到速度更快的RAM中執(zhí)行;而RW和ZI這兩部分是必須轉(zhuǎn)移到可寫的RAM里去。所謂應(yīng)用程序執(zhí)行環(huán)境的初始化,就是完成必要的從ROM到RAM的數(shù)據(jù)傳輸和內(nèi)容清零。
下面是在ADS下,一種常用存儲器模型的直接實(shí)現(xiàn):
LDR r0,=|Image$$RO$$Limit| 得到RW數(shù)據(jù)源的起始地址
LDR r1,=|Image$$RW$$Base| RW區(qū)在RAM里的執(zhí)行區(qū)起始地址
LDR r2,=|Image$$ZI$$Base| ZI區(qū)在RAM里面的起始地址
CMP r0,r1 比較它們是否相等
BEQ %F1
0 CMP r1,r3
LDRCC r2,[r0],#4
STRCC r2,[r1],#4
BCC %B0
1 LDR r1,=|Image$$ZI$$Limit|
MOV r2,#0
2 CMP r3,r1
STRCC r2,[r3],#4
BCC %B2
程序?qū)崿F(xiàn)了RW數(shù)據(jù)的拷貝和ZI區(qū)域的清零功能。其中引用到的4個(gè)符號是由鏈接器第一輸出的。
|Image$$RO$$Limit|:表示RO區(qū)末地址后面的地址,即RW數(shù)據(jù)源的起始地址
|Image$$RW$$Base|:RW區(qū)在RAM里的執(zhí)行區(qū)起始地址,也就是編譯器選項(xiàng)RW_Base指定的地址
|Image$$ZI$$Base|:ZI區(qū)在RAM里面的起始地址
|Image$$ZI$$Limit|:ZI區(qū)在RAM里面的結(jié)束地址后面的一個(gè)地址
程序先把ROM里|Image$$RO$$Limt|開始的RW初始數(shù)據(jù)拷貝到RAM里面|Image$$RW$$Base|開始的地址,當(dāng)RAM這邊的目標(biāo)地址到達(dá)|Image$$ZI$$Base|后就表示RW區(qū)的結(jié)束和ZI區(qū)的開始,接下去就對這片ZI區(qū)進(jìn)行清零操作,直到遇到結(jié)束地址|Image$$ZI$$Limit|
6. 改變處理器模式
因?yàn)樵诔跏蓟^程中,許多操作需要在特權(quán)模式下才能進(jìn)行(比如對CPSR的修改),所以要特別注意不能過早的進(jìn)入用戶模式。
內(nèi)核級的中斷使能也可以考慮在這一步進(jìn)行。如果系統(tǒng)中另外存在一個(gè)專門的中斷控制器,這么做總是安全的。
7. 呼叫主應(yīng)用程序
當(dāng)所有的系統(tǒng)初始化工作完成之后,就需要把程序流程轉(zhuǎn)入主應(yīng)用程序。最簡單的一種情況是:
IMPORT main
B main
直接從啟動代碼跳轉(zhuǎn)到應(yīng)用程序的主函數(shù)入口,當(dāng)然主函數(shù)名字可以由用戶隨便定義。
在ARM ADS環(huán)境中,還另外提供了一套系統(tǒng)級的呼叫機(jī)制。
IMPORT __main
B __main
__main()是編譯系統(tǒng)提供的一個(gè)函數(shù),負(fù)責(zé)完成庫函數(shù)的初始化和初始化應(yīng)用程序執(zhí)行環(huán)境,最后自動跳轉(zhuǎn)到main()函數(shù)。
* 文件 : 連載二
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
*********************************************************************************************************
*/
4 描述文件
要編寫描述文件,必須知道ARM Image文件的組成及ARM Image文件執(zhí)行的機(jī)理。
4.1 ARM Image的結(jié)構(gòu)
一個(gè)ARM Image structure由linker在以下幾個(gè)方面定義:
組成它的regions 和 output sections
當(dāng)Image 下載的時(shí)候這些regions 和 sections 在內(nèi)存中的位置
當(dāng)Image 執(zhí)行時(shí)這些regions和sections在內(nèi)存中的位置
4.1.1 ARM Image的組成
一個(gè)ARM Image被保存在可執(zhí)行文件當(dāng)中,它的層次結(jié)構(gòu)可以包括Image,regions,output sections和input sections。
一個(gè)Image由一個(gè)或多個(gè)regions組成,每個(gè)region包括一個(gè)或多個(gè)output sections
每個(gè)output section由一個(gè)或多個(gè)input sections組成
Input sections是一個(gè)object file中的code和data信息。
Image的結(jié)構(gòu)如
下圖:
1 附圖: tu1.JPG (24684 字節(jié))
NOTE Input section,output section和region的定義見ADS_LinkerGuide 3-3頁。
同時(shí)Input section 有幾種屬性,分別為readonly,read-write,zero-initialized。分別稱為RO,RW和ZI。屬性來源于AREA后的attr屬性。
比如CODE是RO,DATA是RW,NOINT默認(rèn)為ZI,即用0值初始化,但是可以選擇不進(jìn)行0值初始化。ZI屬性僅僅來源于SPACE, DCB, DCD, DCDU, DCQ, DCQU, DCW, 或者DCWU。由以上定義,ZI屬性的包含于RW屬性,它是有初始值的RW數(shù)據(jù)。又例如在C語言中,代碼為RO,靜態(tài)變量和全局變量是RW,ZI的。
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
*********************************************************************************************************
*/
4 描述文件
要編寫描述文件,必須知道ARM Image文件的組成及ARM Image文件執(zhí)行的機(jī)理。
4.1 ARM Image的結(jié)構(gòu)
一個(gè)ARM Image structure由linker在以下幾個(gè)方面定義:
組成它的regions 和 output sections
當(dāng)Image 下載的時(shí)候這些regions 和 sections 在內(nèi)存中的位置
當(dāng)Image 執(zhí)行時(shí)這些regions和sections在內(nèi)存中的位置
4.1.1 ARM Image的組成
一個(gè)ARM Image被保存在可執(zhí)行文件當(dāng)中,它的層次結(jié)構(gòu)可以包括Image,regions,output sections和input sections。
一個(gè)Image由一個(gè)或多個(gè)regions組成,每個(gè)region包括一個(gè)或多個(gè)output sections
每個(gè)output section由一個(gè)或多個(gè)input sections組成
Input sections是一個(gè)object file中的code和data信息。
Image的結(jié)構(gòu)如
下圖:
1 附圖: tu1.JPG (24684 字節(jié))
NOTE Input section,output section和region的定義見ADS_LinkerGuide 3-3頁。
同時(shí)Input section 有幾種屬性,分別為readonly,read-write,zero-initialized。分別稱為RO,RW和ZI。屬性來源于AREA后的attr屬性。
比如CODE是RO,DATA是RW,NOINT默認(rèn)為ZI,即用0值初始化,但是可以選擇不進(jìn)行0值初始化。ZI屬性僅僅來源于SPACE, DCB, DCD, DCDU, DCQ, DCQU, DCW, 或者DCWU。由以上定義,ZI屬性的包含于RW屬性,它是有初始值的RW數(shù)據(jù)。又例如在C語言中,代碼為RO,靜態(tài)變量和全局變量是RW,ZI的。
1xx
文件 : 連載三
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
*********************************************************************************************************
*/
4.1.2 Image 的Load view 和 execution view
在下載的時(shí)候Image regions被放置在memory map當(dāng)中,而在執(zhí)行Image前,或許你需要將一些regions放置在它們執(zhí)行時(shí)的地址上,并建立起ZI regions。例如,你初始化的RW數(shù)據(jù)需要從它在下載時(shí)的在ROM中的地址處移動到執(zhí)行時(shí)RAM的地址處。
1 附圖: tu2.jpg (640566 字節(jié))
NOTE Load view 和execution view的詳細(xì)定義見ADS_LinkerGuide 3-4
以上的描述包括二個(gè)內(nèi)容,一是要指定各個(gè)section在load view和execution view時(shí)的地址即memory map,二是要在執(zhí)行前根據(jù)這些地址進(jìn)行section的初始化。
4.1.3 制定Memory map
制定memory map的方法基本上有二種,一是在link時(shí)使用命令行選項(xiàng),并在程序執(zhí)行前利用linker pre-define symbol使用匯編語言制定section的段初始化,二是使用scatter file。以上二種方法依應(yīng)用程序的復(fù)雜度而定,一針對簡單的情況,二針對復(fù)雜的情況。
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
*********************************************************************************************************
*/
4.1.2 Image 的Load view 和 execution view
在下載的時(shí)候Image regions被放置在memory map當(dāng)中,而在執(zhí)行Image前,或許你需要將一些regions放置在它們執(zhí)行時(shí)的地址上,并建立起ZI regions。例如,你初始化的RW數(shù)據(jù)需要從它在下載時(shí)的在ROM中的地址處移動到執(zhí)行時(shí)RAM的地址處。
1 附圖: tu2.jpg (640566 字節(jié))
2xx
NOTE Load view 和execution view的詳細(xì)定義見ADS_LinkerGuide 3-4
以上的描述包括二個(gè)內(nèi)容,一是要指定各個(gè)section在load view和execution view時(shí)的地址即memory map,二是要在執(zhí)行前根據(jù)這些地址進(jìn)行section的初始化。
4.1.3 制定Memory map
制定memory map的方法基本上有二種,一是在link時(shí)使用命令行選項(xiàng),并在程序執(zhí)行前利用linker pre-define symbol使用匯編語言制定section的段初始化,二是使用scatter file。以上二種方法依應(yīng)用程序的復(fù)雜度而定,一針對簡單的情況,二針對復(fù)雜的情況。
* 文件 : 連載四
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
******************************************************************************
***************************
*/
4.1.1.1 利用linker pre-define symbol使用匯編程序
這是簡單的方法,針對簡單的memory map。在link時(shí)使用選項(xiàng)-ro, -rw, 等等指定memory map的地址。詳細(xì)說明參看ADS_LinkerGuide中命令行選項(xiàng)說明。然后利用匯編使用pre-define symbol,來進(jìn)行各種段的定位。Linker pre-define定義如下:
1 附圖: tu1.jpg (22811 字節(jié))
由前面對ZI的說明,Image$$RW$$Limit = Image$$ZI$$Limit。
2 附圖: tu2.jpg (30577 字節(jié))
這些都是linker預(yù)先定義的外部變量,在使用的時(shí)候可以用IMPORT引入。下面給出一個(gè)例子。
假設(shè)linker 選項(xiàng)為:-ro-base 0x40000000 -rw-base 0x40003000。程序和只讀變量(const 變量)大小為0x84,這樣RO section的大小為0x84 bytes。Data的大小為0x04 bytes,并且data被初始化,則RW section的大小為0x04,ZI section的大小為0x04。這樣程序
在load view,地址是這樣的:
0x40000000開始到地址0x40000080,是RO section部分(程序從0x40000000開始),Image$$RO$$Limit = 0x40000084.
0x40000084地址開始到地址0x40000084,是RW section部分。
在execution view,由linker的選項(xiàng),各個(gè)section的地址是這樣的:
RO section的地址不變。
RW section的起始地址應(yīng)當(dāng)為0x40003000,則Image$$RW$$Base = 0x40003000。
因?yàn)槿康?x04 bytes data被初始化,所以Image$$RW$$Limit = Image$$ZI$$Limt = 0x40003004。
現(xiàn)在要做的就是將RW section移到以0x40003000開始的地方,并且創(chuàng)造一個(gè)ZI section。
一個(gè)更通用的做法是:
首先比較Image$$RO$$Limit和mage$$RW$$Base,如果相等,說明execution view下RW section的地址和load view 下RW section的地址相同,這樣,不需要移動RW section;如果不等,說明需要移動RW section 到它在execution view中的地方。然后將Image$$ZI$$Base地址到Image$$ZI$$Limt地址的內(nèi)容清零。
示例代碼如下:
;讀入linker pre-define symbols
IMPORT |Image$$RO$$Limit|
IMPORT |Image$$RW$$Base|
IMPORT |Image$$ZI$$Base|
IMPORT |Image$$ZI$$Limit|
; .......一些其他的代碼或偽指令
;R0讀入section load address
LDR R0,=|Image$$RO$$Limit|
;R1讀入section execution address
LDR R1,=|Image$$RW$$Base|
;R2讀入execution section 后的緊跟的word address
LDR R2,=|Image$$ZI$$Base|
;檢查RW section的地址在load view和execution view下
;是否相等,如果相等,就不移動RW section,直接建立
;ZI scetion
CMP R0,R1
BEQ do_zi_init
;否則就copy RW section到execution view下指定的地址
BL copy
; ......
; ......
;copy 是一個(gè)用于copy的子函數(shù),它把從R0中的地址開始的
;section copy到R1中的地址開始的section,這個(gè)section的
;上限地址后緊跟的word address保存在R2中
copy
CMP R1,R2
LDRCC R3,[R0],#4
STRCC R3,[R1],#4
BCC copy
MOV PC,LR
; ......
; ......
;do_zi_int子函數(shù)是為創(chuàng)建ZI section做一些準(zhǔn)備工作
do_zi_int
;將ZI section開始的地址裝入R1
LDR R1,=|Image$$ZI$$Base|
;將ZI section結(jié)束后緊跟的word address裝入R2
LDR R2,=|Image$$ZI$$Limit|
;將ZI section 需要的初始化量裝入R3
MOV R3,#0
BL zi_int
; ......
; ......
;zi_int子函數(shù)用于建立并初始化ZI section,ZI section的
;開始地址儲存在R1,ZI section結(jié)束后緊跟的word address
;地址儲存在R2
zi_int
CMP R1,R2
STRCC R3,[R1],#4
BCC zi_int
MOV PC,LR
; ......
; ......
這個(gè)方法針對比較簡單的應(yīng)用,如果需要進(jìn)行一個(gè)比較復(fù)雜的memory map,如下圖,那么這個(gè)方法就不適用了。為了解決復(fù)雜memory map的問題
需要用到scatter load 機(jī)制。
3 附圖: tu3.jpg (32473 字節(jié))
* 版本 : V1.00
* 作者 : 潘自強(qiáng)
*
* 對象 : ARM7
* 模式 : ARM
* 工具 : ADS1.20
******************************************************************************
***************************
*/
4.1.1.1 利用linker pre-define symbol使用匯編程序
這是簡單的方法,針對簡單的memory map。在link時(shí)使用選項(xiàng)-ro, -rw, 等等指定memory map的地址。詳細(xì)說明參看ADS_LinkerGuide中命令行選項(xiàng)說明。然后利用匯編使用pre-define symbol,來進(jìn)行各種段的定位。Linker pre-define定義如下:
1 附圖: tu1.jpg (22811 字節(jié))
3xx
由前面對ZI的說明,Image$$RW$$Limit = Image$$ZI$$Limit。
2 附圖: tu2.jpg (30577 字節(jié))
4xx
這些都是linker預(yù)先定義的外部變量,在使用的時(shí)候可以用IMPORT引入。下面給出一個(gè)例子。
假設(shè)linker 選項(xiàng)為:-ro-base 0x40000000 -rw-base 0x40003000。程序和只讀變量(const 變量)大小為0x84,這樣RO section的大小為0x84 bytes。Data的大小為0x04 bytes,并且data被初始化,則RW section的大小為0x04,ZI section的大小為0x04。這樣程序
在load view,地址是這樣的:
0x40000000開始到地址0x40000080,是RO section部分(程序從0x40000000開始),Image$$RO$$Limit = 0x40000084.
0x40000084地址開始到地址0x40000084,是RW section部分。
在execution view,由linker的選項(xiàng),各個(gè)section的地址是這樣的:
RO section的地址不變。
RW section的起始地址應(yīng)當(dāng)為0x40003000,則Image$$RW$$Base = 0x40003000。
因?yàn)槿康?x04 bytes data被初始化,所以Image$$RW$$Limit = Image$$ZI$$Limt = 0x40003004。
現(xiàn)在要做的就是將RW section移到以0x40003000開始的地方,并且創(chuàng)造一個(gè)ZI section。
一個(gè)更通用的做法是:
首先比較Image$$RO$$Limit和mage$$RW$$Base,如果相等,說明execution view下RW section的地址和load view 下RW section的地址相同,這樣,不需要移動RW section;如果不等,說明需要移動RW section 到它在execution view中的地方。然后將Image$$ZI$$Base地址到Image$$ZI$$Limt地址的內(nèi)容清零。
示例代碼如下:
;讀入linker pre-define symbols
IMPORT |Image$$RO$$Limit|
IMPORT |Image$$RW$$Base|
IMPORT |Image$$ZI$$Base|
IMPORT |Image$$ZI$$Limit|
; .......一些其他的代碼或偽指令
;R0讀入section load address
LDR R0,=|Image$$RO$$Limit|
;R1讀入section execution address
LDR R1,=|Image$$RW$$Base|
;R2讀入execution section 后的緊跟的word address
LDR R2,=|Image$$ZI$$Base|
;檢查RW section的地址在load view和execution view下
;是否相等,如果相等,就不移動RW section,直接建立
;ZI scetion
CMP R0,R1
BEQ do_zi_init
;否則就copy RW section到execution view下指定的地址
BL copy
; ......
; ......
;copy 是一個(gè)用于copy的子函數(shù),它把從R0中的地址開始的
;section copy到R1中的地址開始的section,這個(gè)section的
;上限地址后緊跟的word address保存在R2中
copy
CMP R1,R2
LDRCC R3,[R0],#4
STRCC R3,[R1],#4
BCC copy
MOV PC,LR
; ......
; ......
;do_zi_int子函數(shù)是為創(chuàng)建ZI section做一些準(zhǔn)備工作
do_zi_int
;將ZI section開始的地址裝入R1
LDR R1,=|Image$$ZI$$Base|
;將ZI section結(jié)束后緊跟的word address裝入R2
LDR R2,=|Image$$ZI$$Limit|
;將ZI section 需要的初始化量裝入R3
MOV R3,#0
BL zi_int
; ......
; ......
;zi_int子函數(shù)用于建立并初始化ZI section,ZI section的
;開始地址儲存在R1,ZI section結(jié)束后緊跟的word address
;地址儲存在R2
zi_int
CMP R1,R2
STRCC R3,[R1],#4
BCC zi_int
MOV PC,LR
; ......
; ......
這個(gè)方法針對比較簡單的應(yīng)用,如果需要進(jìn)行一個(gè)比較復(fù)雜的memory map,如下圖,那么這個(gè)方法就不適用了。為了解決復(fù)雜memory map的問題
需要用到scatter load 機(jī)制。
3 附圖: tu3.jpg (32473 字節(jié))
5xx