要了解RO,,RW和ZI需要首先了解以下知識(shí): ARM程序的組成 (2) ARM程序的執(zhí)行過(guò)程
(5) Image$$??$$Limit 的含義 對(duì)于剛學(xué)習(xí)ARM的人來(lái)說(shuō),如果分析它的啟動(dòng)代碼,,往往不明白下面幾個(gè)變量的含 義:|Image$$RO$$Limit|,、|Image$$RW$$Base|、|Image$$ZI$$Base|,。 當(dāng)把程序編寫(xiě)好以后,,就要進(jìn)行編譯和鏈接了,在ADS1.2中選擇MAKE按鈕,,會(huì)出現(xiàn)一個(gè)Errors and Warnings
的對(duì)話框,,在該欄中顯示編譯和鏈接的結(jié)果,如果沒(méi)有錯(cuò)誤,,在文件的最后應(yīng)該能看到Image component sizes,,后面緊跟的依次是Co Co Tatal RO size (Co Tatal RW size(RW Da Tatal ROM size(Co 后面的字節(jié)數(shù)是根據(jù)用戶不同的程序而來(lái)的,下面就以上面的數(shù)據(jù)為例來(lái)介紹那幾個(gè)變量的計(jì)算,。 在ADS的Debug Settings中有一欄是Linker/ARM Linker,,在output選項(xiàng)中有一個(gè)RO base選項(xiàng), 假如 RO base設(shè)置為0x0c100000,,后面的RW base 設(shè)置為0x0c200000,,然后在Options選項(xiàng)中有Image entry point ,是一個(gè)初始程序的入口地址,,設(shè)置為0x0c100000 ,。 有了上面這些信息我們就可以完全知道這幾個(gè)變量是怎么來(lái)的了: |Image$$RO$$Base| = Image entry point =RO base =0x0c100000 ;表示程序代 碼存放的起始地址 |Image$$RO$$Limit|=程序代碼起始地址+代碼長(zhǎng)度+1=0x0c100000+Tatal RO size+1 = 0x0c100000 + 184571 + 1 = 0x0c100000 +0x2D0FB + 1 = 0x0c12d0fc |Image$$RW$$Base| = 0x0c200000=RW base 地址指定 |Image$$RW$$Limit| =|Image$$RW$$Base|+ RW Da =0x0c200037 |Image$$ZI$$Base| = |Image$$RW$$Limit| + 1 =0x0c200038 |Image$$ZI$$Limit| = |Image$$ZI$$Base| + ZI Da =0x0c200038 + 0x4284 =0x0c2042bc 也可以由此計(jì)算: |Image$$ZI$$Limit| = |Image$$RW$$Base| +TatalRWsize(RWData+ZIData) 17081 =0x0c200000+0x42b9+3(要滿足4的倍數(shù)) =0x0c2042bc
一 概述 Scatter file (分散加載描述文件)用于armlink的輸入?yún)?shù),他指定映像文件內(nèi)部各區(qū)域的download與運(yùn)行時(shí)位置,。Armlink將會(huì)根據(jù)scatter file生成一些區(qū)域相關(guān)的符號(hào),,他們是全局的供用戶建立運(yùn)行時(shí)環(huán)境時(shí)使用。(注意:當(dāng)使用了scatter file 時(shí)將不會(huì)生成以下符號(hào) Image$$RW$$Base, Image$$RW$$Limit, Image$$RO$$Base, Image$$RO$$Limit, Image$$ZI$$Base, and Image$$ZI$$Limit) 二 什么時(shí)候使用scatter file 當(dāng)然首要的條件是你在利用ADS進(jìn)行項(xiàng)目開(kāi)發(fā),,下面我們看看更具體的一些情況,。 1 存在復(fù)雜的地址映射:例如代碼和數(shù)據(jù)需要分開(kāi)放在在多個(gè)區(qū)域。 2 存在多種存儲(chǔ)器類型:例如包含 Flash,ROM,SDRAM,快速SRAM,。我們根據(jù)代碼與數(shù)據(jù)的特性把他們放在不同的存儲(chǔ)器中,,比如中斷處理部分放在快速SRAM內(nèi)部來(lái)提高響應(yīng)速 度,而把不常用到的代碼放到速度比較慢的Flash內(nèi),。 3 函數(shù)的地址固定定位:可以利用Scatter file實(shí)現(xiàn)把某個(gè)函數(shù)放在固定地址,,而不管其應(yīng)用程序是否已經(jīng)改變或重新編譯。 4 利用符號(hào)確定堆與堆棧: 5 內(nèi)存映射的IO:采用scatter file可以實(shí)現(xiàn)把某個(gè)數(shù)據(jù)段放在精確的地指處,。 因此對(duì)于嵌入式系統(tǒng)來(lái)說(shuō)scatter file是必不可少的,,因?yàn)榍度胧较到y(tǒng)采用了ROM,RAM,,和內(nèi)存映射的IO,。 三 scatter file 實(shí)例 1 簡(jiǎn)單的內(nèi)存映射 LOAD_ROM 0x0000 0x8000 { EXEC_ROM 0x0000 0x8000 { *( RO) } RAM 0x10000 0x6000 { *( RW, ZI) } }
LOAD_ROM(下載區(qū)域名稱) 0x0000(下載區(qū)域起始地址) 0x8000(下載區(qū)域最大字節(jié)數(shù)) { EXEC_ROM(第一執(zhí)行區(qū)域名稱) 0x0000(第一執(zhí)行區(qū)域起始地址) 0x8000(第一執(zhí)行區(qū)域最大字節(jié)數(shù)) { *( RO(代碼與只讀數(shù)據(jù))) } RAM(第二執(zhí)行區(qū)域名稱) 0x10000(第二執(zhí)行區(qū)域起始地址) 0x6000(第二執(zhí)行區(qū)域最大字節(jié)數(shù)) { *( RW(讀寫(xiě)變量), ZI(未初始化變量)) } } 2 復(fù)雜內(nèi)存映射 LOAD_ROM_1 0x0000 { EXEC_ROM_1 0x0000 { program1.o( RO) } DRAM 0x18000 0x8000 { program1.o ( RW, ZI) } }
LOAD_ROM_2 0x4000 { EXEC_ROM_2 0x4000 { program2.o( RO) } SRAM 0x8000 0x8000 { program2.o ( RW, ZI) } }
LOAD_ROM_1 0x0000(下載區(qū)域一起始地址) { EXEC_ROM_1 0x0000(第一執(zhí)行區(qū)域開(kāi)始地址) { program1.o( RO) (program1.o內(nèi)的Co } DRAM 0x18000(第二執(zhí)行區(qū)域開(kāi)始地址) 0x8000(第二執(zhí)行區(qū)域最大字節(jié)數(shù)) { program1.o ( RW, ZI) (program1.o內(nèi)的RW da } } LOAD_ROM_2 0x4000(下載區(qū)域二起始地址) { EXEC_ROM_2 0x4000 { program2.o( RO) (program2.o內(nèi)的Co } SRAM 0x8000 0x8000 { program2.o ( RW, ZI) (program2.o內(nèi)的RW da } } Part2 基本語(yǔ)法 2.1 BNF 符號(hào)與語(yǔ)法 " :由引號(hào)賴標(biāo)示的符號(hào)保持其字面原意,如A” ”B標(biāo)示A B,。 A ::= B :定義A為B,。 [A] :標(biāo)示可選部分,如A[B]C用來(lái)標(biāo)示ABC或AC,。 A :用來(lái)標(biāo)示A可以重復(fù)任意次,,如A 可標(biāo)示A,AA,AAA, … A* :同A 。 A | B :用來(lái)標(biāo)示選擇其一,,不能全選,。如A|B用來(lái)標(biāo)示A或者B。 (A B) :標(biāo)示一個(gè)整體,,當(dāng)和|符號(hào)或復(fù)雜符號(hào)的多次重復(fù)一起使用時(shí)尤其強(qiáng)大,,如(AB) (C|D)標(biāo)示ABC,ABD,ABABC,ABABD, … 2.2 分散加載文件各部分描述 (2.1) 如圖2.1所示為一個(gè)完整的分散加載腳本描述結(jié)構(gòu)圖。下面我們對(duì)圖示中各個(gè)部分進(jìn)行講述,。 2.2.1 加載區(qū)描述 每個(gè)加載區(qū)有: ó名稱:供連接器確定不同下載區(qū)域 ó基地址:相對(duì)或絕對(duì)地址 ó屬性:可選 ó最大字節(jié)數(shù):可選 ó執(zhí)行區(qū)域列:確定執(zhí)行時(shí)各執(zhí)行區(qū)域的類型與位置 load_region_name (base_address | (" " offset)) [attribute_list] [ max_size ] "{" execution_region_description "}"
load_region_name:下載區(qū)域名稱,,最大有效字符數(shù)31。(并不像執(zhí)行區(qū)域段名用于Load$$region_name,,而是僅僅用 于標(biāo)示下載區(qū)域),。 base_address:本區(qū)域內(nèi)部目標(biāo)被連接到的地址(按字對(duì)齊)。 offset:相對(duì)前一個(gè)下載區(qū)域的偏移量(4的整數(shù)倍,,如果為第一個(gè)區(qū)域),。
2.2.2 執(zhí)行區(qū)描述 每個(gè)執(zhí)行區(qū)有: ó名稱:供連接器確定不同下載區(qū)域 ó基地址:相對(duì)或絕對(duì)地址 ó屬性:確定執(zhí)行區(qū)域的屬性 ó最大字節(jié)數(shù):可選 ó輸入段:確定放在該執(zhí)行區(qū)域的模塊 exec_region_name (base_address | " " offset) [attribute_list] [max_size] "{" input_section_description "}" exec_region_name:執(zhí)行區(qū)域名稱,,最大有效字符數(shù)31。 base_address:本執(zhí)行區(qū)域目標(biāo)要被聯(lián)接到的位置,,按字對(duì)齊,。 offset:相對(duì)于前一個(gè)執(zhí)行區(qū)域結(jié)束地址的偏移量,4的整數(shù)倍,;如果沒(méi)有前繼之能夠行區(qū)域(本執(zhí)行區(qū)域?yàn)樵撓螺d區(qū)域的第一個(gè)執(zhí)行區(qū)域),,則該偏 移量是相對(duì)于該下載區(qū)域的基址偏移量。 attribute_list:PI,,OVERLAY,,ABSOLUTE,F(xiàn)IXED,,UNINIT,。 PI: 位置獨(dú)立。 OVERLAY: 覆蓋,。 ABSOLUTE: 絕對(duì)地址,。 FIXED: 固定地址,下載地址與執(zhí)行地址具有該地址指示確定,。 UNINIT: 未初始化數(shù)據(jù),。 RELOC:無(wú)法明確指定執(zhí)行區(qū)域具有該屬性,而只能通過(guò)繼承前一個(gè)執(zhí)行區(qū)或父區(qū)域獲得,。 對(duì)于PI,,OVERLAY,ABSOLUTE,,F(xiàn)IXED,,我們只能選擇一個(gè),缺省屬性為ABSOLUTE,。一個(gè)執(zhí)行區(qū)域要么直接繼承其前面的執(zhí)行 區(qū)域的屬性或者具有屬性為ABSOLUTE,。 具有PI,OVERLAY,,RELOC屬性的執(zhí)行區(qū)域允許其地址空間重疊,,對(duì)于BSOLUTE,,F(xiàn)IXED 屬性執(zhí)行區(qū)域地址空間重疊Armlink會(huì)報(bào)錯(cuò),。 max_size:可選,他用于指使Armlink在實(shí)際分配空間大于指定值時(shí)報(bào)錯(cuò),。 input_section_description:指示輸入段的內(nèi)容,。
2.2.3 輸入段描述 輸入段: ó模塊名:目標(biāo)文件名,庫(kù)成員名,,庫(kù)文件名,。名稱可以使用通配符,。 ó輸入段名,或輸入段屬性(READ-ON module_select_pattern ["(" (" " input_section_attr | input_section_pattern) ([","] " " input_section_attr | "," input_section_pattern))* ")"] 2.2.3.1 module_select_pattern:選擇的模塊名稱(目標(biāo)文件,,庫(kù)文件成員,庫(kù)文件),,模塊名可以使用通配符(*匹配任意多個(gè)字符,,?匹 配任意一個(gè)字符),,名稱不區(qū)分字母大小寫(xiě),,它是供選擇的樣本。 例1:*libtx.a ( RO) libtx.a為threadX庫(kù)文件,。 例2:tx_ill.o (INIT) tx_ill.o為threadX中斷向量目標(biāo)文件,。 2.2.3.2 input_section_attr:輸入段屬性選擇子,每個(gè)選擇子以” ”開(kāi)頭,,選擇子不區(qū)分大小寫(xiě)字符,。 選擇子可選RO-CO 以下同義詞可以選擇:CO 還有兩個(gè)偽屬性:FIRST,,LAST,。如果各段的先后順序比較重要時(shí),可以使用FIRST,,LAST標(biāo)示一個(gè)執(zhí)行區(qū)域的第一個(gè)和最后一個(gè)段,。 例1:os_main_init.o (INIT , FIRST) FIRST表示放于本執(zhí)行區(qū)域的開(kāi)始處。 例2:*libtx.a ( RO) RO 表示*libtx.a的只讀部分,。 2.2.3.3 input_section_pattern:輸入段名,。 例1:os_main_init.o (INIT , FIRST) INIT 為os_main_init.o的一個(gè)段。 例2:os_stackheap.o (heap) heap 為os_stackheap.o的一個(gè)段,。 例3:os_stackheap.o (stack) stack為os_stackheap.o的一個(gè)段,。
//-------------------------------------------------------------------------------------------------------------------------- 分散加載文件事例
ADS下的分散加載文件應(yīng)用實(shí)例 load_region_name start_address | " "offset [attributes] [max_size] { execution_region_name start_address | " "offset [attributes][max_size] { module_select_pattern ["(" (" " input_section_attr | input_section_pattern) ([","] " " input_section_attr | "," input_section_pattern)) * ")"] } } load_region: 加載區(qū),,用來(lái)保存永久性數(shù)據(jù)(程序和只讀變量)的區(qū)域; execution_region: 執(zhí)行區(qū),,程序執(zhí)行時(shí),,從加載區(qū)域?qū)?shù)據(jù)復(fù)制到相應(yīng)執(zhí)行區(qū)后才能被正確執(zhí)行; load_region_name: 加載區(qū)域名,,用于“Linker”區(qū)別不同的加載區(qū)域,,最多31個(gè)字符; start_address: 起始地址,,指示區(qū)域的首地址,; offset: 前一個(gè)加載區(qū)域尾地址+offset 做為當(dāng)前的起始地址,且“offset”應(yīng)為“0”或“4”的倍數(shù),; attributes: 區(qū)域?qū)傩?,可設(shè)置如下屬性: PI 與地址無(wú)關(guān)方式存放; RELOC 重新部署,,保留定位信息,,以便重新定位該段到新的執(zhí)行區(qū); OVERLAY 覆蓋,,允許多個(gè)可執(zhí)行區(qū)域在同一個(gè)地址,,ADS不支持; ABSOLUTE 絕對(duì)地址(默認(rèn)),; max_size: 該區(qū)域的大?。?/p> execution_region_name:執(zhí)行區(qū)域名,; start_address: 該執(zhí)行區(qū)的首地址,,必須字對(duì)齊; offset: 同上,; attributes: 同上,; PI 與地址無(wú)關(guān),該區(qū)域的代碼可任意移動(dòng)后執(zhí)行,; OVERLAY 覆蓋,; ABSOLUTE 絕對(duì)地址(默認(rèn)); FIXED 固定地址,; UNINIT 不用初始化該區(qū)域的ZI段,; module_select_pattern: 目標(biāo)文件濾波器,支持通配符“*”和“?”,; *.o匹配所有目標(biāo),,* (或“.ANY”)匹配所有目標(biāo)文件和庫(kù),。 input_section_attr: 每個(gè)input_section_attr必須跟隨在“+”后,;且大小寫(xiě)不敏感,; RO-CO RO-DA RO或TEXT, selects both RO-CO RW-DA RW-CO RW 或 DA ZI 或 BSS ENTRY, that is a section containing an ENTRY point. FIRST,用于指定存放在一個(gè)執(zhí)行區(qū)域的第一個(gè)或最后一個(gè)區(qū)域,; LAST,,同上; input_section_pattern: 段名,; 匯編中指定段: AREA vectors, CO C中指定段: #pragma arm section [sort_type[[=]"name"]] [,sort_type="name"]* sort_type: co 如果“sort_type”指定了但沒(méi)有指定“name”,,那么之前的修改的段名將被恢復(fù)成默認(rèn)值。 #pragma arm section // 恢復(fù)所有段名為默認(rèn)設(shè)置,。 應(yīng)用: #pragma arm section rwdata = "SRAM",zidata = "SRAM" static OS_STK SecondTaskStk[256]; // “rwdata”“zidata”將定位在“sram”段中,。 #pragma arm section // 恢復(fù)默認(rèn)設(shè)置 分散加載文件中定義如下: Exec_Sram 0x80000000 0x40000 { * (sram) } “PI” 屬性使用示例: LR_1 0x010000 PI ; The first load region is at 0x010000. { ER_RO 0 ; The PI attribute is inherited from parent. ; The default execution address is
0x010000, but the co { *( RO) ; All the RO sections go here. } ER_RW 0 ABSOLUTE ; PI attribute is overridden by ABSOLUTE. { *( RW) ; The RW sections are placed next. They cannot be moved. } ER_ZI 0 ; ER_ZI region placed after ER_RW region. { *( ZI) ; All the ZI sections are placed consecutively here. } } LR_1 0x010000 ; The first load region is at 0x010000. { ER_RO 0 ; Default ABSOLUTE attribute is inherited from parent. The execution address ; is 0x010000. The co { *( RO) ; All the RO sections go here. } ER_RW 0x018000 PI ; PI attribute overrides ABSOLUTE { *( RW) ; The RW sections are placed at 0x018000 and they can be moved. } ER_ZI 0 ; ER_ZI region placed after ER_RW region. { *( ZI) ; All the ZI sections are placed consecutively here. } } 程序中對(duì)某區(qū)域地址等的引用方法: Load$$region_name$$Base Load address of the region. Image$$region_name$$Base Execution address of the region. Image$$region_name$$Length Execution region length in bytes (multiple of 4). Image$$region_name$$Limit Address of the byte beyond the end of the execution region. Image$$region_name$$ZI$$Base Execution address of the ZI output section in this region. Image$$region_name$$ZI$$Length Length of the ZI output section in bytes (multiple of 4). Image$$region_name$$ZI$$Limit Address of the byte beyond the end of the ZI output sectionin the execution region. SectionName$$Base Input Address of the start of the consolidated section called SectionName. SectionName$$Limit Input Address of the byte beyond the end of the consolidated section called SectionName. Load: 加載區(qū),即存放地址,; Image: 執(zhí)行區(qū),,即運(yùn)行地址; Base: 區(qū)首地址,; Limit: 區(qū)尾地址,; Length: 區(qū)長(zhǎng)度; region_name: RO,、RW,、ZI、load_region_name,、execution_region_name,; 例如: “RAM1”區(qū)域的首地址: Image$$RAM1$$Base 上例中“sram”段首地址: sram$$Base 匯編引用示例: IMP IMP IMP IMP LDR R0, =|Load$$Exec_RAM1$$Base| LDR R1, =|Image$$Exec_RAM1$$Base| LDR R2, =|Image$$Exec_RAM1$$Limit| 0 CMP R1, R2 LDRCC R3, [R0], #4 STRCC R3, [R1], #4 BCC %b0 C 引用: extern unsigned char Load$$Exec_RAM1$$Base; extern unsigned char Image$$Exec_RAM1$$Base; extern unsigned char Image$$Exec_RAM1$$Length; void MoveRO(void) { unsigned char * psrc, *pdst; unsigned int count; count = (unsigned int) &Image$$Exec_RAM1$$Length; psrc = (unsigned char *)&Load$$Exec_RAM1$$Base; pdst = (unsigned char *)&Image$$Exec_RAM1$$Base; while (count--) { *pdst = *psrc ; } } 加載文件示例一: 起始地址 大小 ROM: 0x00000000 256K ;0x1fc 保留為加密字,,程序在ROM中運(yùn)行,; RAM 0x40000000 16K ;用于全局變量及任務(wù)堆棧,; SRAM 0x80000000 512K ,;SRAM速度慢,主要用于存放大的數(shù)據(jù)表,; LOAD_ROM1 0x00000000 0x1f8 ; 指定該加載區(qū)域首地址,、大小 { EXEC_ROM1 0 0x1f8 ; 沒(méi)有前一加載區(qū)域,所以該執(zhí)行區(qū)域首地址為加載去首地址 ; 并指定該區(qū)域長(zhǎng)度 { Startup.o (vectors, FIRST) ; 目標(biāo)文件的“vectors”段放在該執(zhí)行區(qū)域的第一段 irq.o ( RO) ; 目標(biāo)文件的所有“RO”段放在該執(zhí)行區(qū)域 } } LOAD_ROM2 0x00000200 ; 第二個(gè)加載區(qū)域 { EXEC_ROM2 0 0x3e600 { * ( RO) ; 所有目標(biāo)文件和庫(kù)文件中的“RO”段存放在該區(qū)域 } RAM1 0x40000000 0x4000 { * ( RW, ZI) ; 所有目標(biāo)文件和庫(kù)文件的“RW”和“ZI”段存放在該區(qū)域 } SRAM2 0x80000000 0x80000 { * (sram) ; 所有目標(biāo)文件中的“sram”段存放在該區(qū)域 } } 示例二: “iap.o”定義在“Exec_RAM1”中運(yùn)行,,所以設(shè)置“PI”屬性,; 在調(diào)用“iap.c”中函數(shù)之前應(yīng)該將其從“Load$$Exec_IAP$$Base”復(fù)制到指定的“Exec_RAM1”區(qū)域; Load_region1 0x00000000 0x1fc { EXEC_ROM1 0 { Startup.o (vectors, FIRST) irq.o ( RO) } } Load_region2 0x00000200 0x3e600 { EXEC_ROM2 0 { * ( RO) } Exec_IAP 0 PI // 可能引起鏈接器未使用該屬性警告,,忽略 { iap.o ( RO) } Exec_RAM1 0x40000000 0x4000 { * ( RW, ZI) } Exec_Sram 0x80000000 0x40000 { * (SRAM) } } // 移動(dòng)“IAP.o”中的所有函數(shù)到“ImageExecIAPBase”加載區(qū),,并調(diào)用其中的函數(shù) extern unsigned char Load$$Exec_IAP$$Base; extern unsigned char Image$$Exec_IAP$$Length; #define ImageExecIAPBase (0x40000000 0x1000) // 加載區(qū)首址 void MoveIAPRO(void) { unsigned char * psrc, *pdst; unsigned int count; count = (unsigned int) &Image$$Exec_IAP$$Length; psrc = (unsigned char *)&Load$$Exec_IAP$$Base; pdst = (unsigned char *)ImageExecIAPBase; while (count--) { *pdst = *psrc ; } } // 調(diào)用“IAP.O”中的某函數(shù) { void (* pfnIAPWrite)(unsigned long, int); pfnIAPWrite = (void (*)(unsigned long, int)) (ImageExecIAPBase (unsigned int)IAPWrite - // 被調(diào)用函數(shù)名 (unsigned int)&Load$$Exec_IAP$$Base); pfnIAPWrite((int)((CUPDATA *)CODESTARTADDR)->da ((CUPDATA *)CODESTARTADDR)->length); }
//———————————————————————————————————————————————————————————— Pragmas
* check_printf_formats 該編譯指示標(biāo)記類似于printf的函數(shù),,如果存在文字格式串,,則對(duì)照進(jìn)行類型檢查。 * check_scanf_formats 該編譯指示對(duì)聲明為類似于scanf的函數(shù)做標(biāo)記,,以便對(duì)照文字格式串檢查自變量的格式,。 * debug 該編譯指示可打開(kāi)或關(guān)閉調(diào)試表生成, 如果指定#pragma
no_debug,則不會(huì)為隨后的聲明和函數(shù)生成調(diào)試信息表?xiàng)l目,,直到下一個(gè)#pragma debug出現(xiàn),。 Ospace * Pragmas controlling co 內(nèi)聯(lián)函數(shù)(及其局部靜態(tài)變量) int x2 = 5; // in foo (da
|
|
來(lái)自: kyosho > 《我的圖書(shū)館》