1?
ARM映像文件組成
ARM 映像文件其實(shí)就是源文件經(jīng)編譯器生成的目標(biāo)文件,一般是bin文件或者h(yuǎn)ex文件,可以直接燒錄到ROM中執(zhí)行(一般是內(nèi)部FLASH),這個(gè)文件稱為可執(zhí)行映像文件(image file)。
映像文件一般由域組成,域最多由三個(gè)輸出段組成(RO,RW,ZI)組成,輸出段又由輸入段組成。所謂域,指的就是整個(gè)映像文件所處在的區(qū)域,它又分為加載域和運(yùn)行域。我們輸入的代碼,一般有代碼部分和數(shù)據(jù)部分,這就是所謂的輸入段,經(jīng)過(guò)編譯后就變成了映像文件中的RO段和RW段,還有所謂的ZI段,這就是輸出段。
加載域:映像文件被靜態(tài)存放的工作區(qū)域。
運(yùn)行域:程序運(yùn)行起來(lái)的存儲(chǔ)區(qū)域。
程序在存儲(chǔ)狀態(tài)時(shí),RO段及RW段都被保存在ROM區(qū)。
當(dāng)程序開(kāi)始運(yùn)行時(shí),內(nèi)核直接從 ROM 中讀取代碼,并且在執(zhí)行主體代碼前,會(huì)先執(zhí)行一段加載代碼,它把 RW 段數(shù)據(jù)從 ROM 復(fù)制到 RAM,并且在 RAM加入 ZI 段,ZI 段的數(shù)據(jù)都被初始化為 0。加載完后 RAM 區(qū)準(zhǔn)備完畢,正式開(kāi)始執(zhí)行主體程序。
2?
分散加載機(jī)制
分散加載機(jī)制允許開(kāi)發(fā)者為代碼或數(shù)據(jù)變量在加載和執(zhí)行時(shí)指定不同的存儲(chǔ)空間,通知鏈接器把程序的某一部分鏈接在存儲(chǔ)器的某個(gè)地址空間。
2.1 何時(shí)使用分散加載
實(shí)現(xiàn)嵌入式系統(tǒng)通常需要分散加載,這些系統(tǒng)使用ROM、RAM和內(nèi)存映射的外設(shè)。通常需要分散加載的情況如下:
1)復(fù)雜內(nèi)存映射:
必須放置在許多不同內(nèi)存區(qū)域的代碼和數(shù)據(jù)需要詳細(xì)的指令來(lái)說(shuō)明在內(nèi)存空間中放置這些部分的位置。
2)不同類型的內(nèi)存:
許多系統(tǒng)包含各種物理存儲(chǔ)設(shè)備,如FLASH、ROM、SDRAM和快速SRAM。分散加載描述可以將代碼和數(shù)據(jù)與最合適的內(nèi)存類型相匹配。例如,中斷代碼可以放在快速的SRAM中以改善中斷響應(yīng)時(shí)間,但不常用的配置信息可以放在較慢的閃存中。
3)內(nèi)存映射的外設(shè):
分散加載描述可以將數(shù)據(jù)段放置在內(nèi)存映射中的精確地址上,以便可以訪問(wèn)內(nèi)存映射的外設(shè)。
4)函數(shù)在固定位置:
即使周?chē)膽?yīng)用程序已被修改和重新編譯,也可以將函數(shù)放置在內(nèi)存中的相同位置。這對(duì)于跳轉(zhuǎn)表的實(shí)現(xiàn)很有用。
5)使用符號(hào)來(lái)標(biāo)識(shí)堆和堆棧:
在鏈接應(yīng)用程序時(shí),可以為堆和堆棧位置定義符號(hào)。
2.2 怎么使用分散加載
1)對(duì)于具有簡(jiǎn)單內(nèi)存映射(僅有SRAM和ROM)的image文件,可以僅使用鏈接器命令行選項(xiàng)或scatter文件來(lái)指定內(nèi)存映射。下圖顯示了一個(gè)簡(jiǎn)單的內(nèi)存映射:
2)對(duì)于具有復(fù)雜內(nèi)存映射(具有DRAM、SRAM、ROM2、ROM1等)的image文件,不能僅使用鏈接器命令行選項(xiàng)指定內(nèi)存映射,需要使用scatter文件。下圖顯示了一個(gè)復(fù)雜的內(nèi)存映射:
3?
分散加載文件說(shuō)明
分散加載文件(scatter file)是一個(gè)文本文件,它的作用是可以用于描述 ARM 鏈接器生成映像文件所需要的信息。如果不使用分散加載文件來(lái)指定,那么 ARM 鏈接器會(huì)按照默認(rèn)的方式來(lái)生成映像文件。Keil的分散加載主要是通過(guò) .sct 文件實(shí)現(xiàn)的,鏈接器根據(jù) .sct 文件的配置分配各個(gè)段區(qū)地址,生成分散加載代碼。
編寫(xiě)分散加載文件中可以指定下列信息:
1)各個(gè)加載域的加載起始地址、最大尺寸和屬性。
2)各個(gè)加載域中包含的輸出段。
3)各個(gè)運(yùn)行域的運(yùn)行起始地址、最大尺寸、存儲(chǔ)訪問(wèn)特性和屬性。
4)各個(gè)運(yùn)行域中包含的輸入段。
一個(gè)Scatter文件包含若干個(gè)加載域,一個(gè)加載域包含若干個(gè)輸出段,一個(gè)輸出段由若干個(gè)具有相同屬性的輸入段組成。
4?
分散加載文件語(yǔ)法
Scatter文件是一個(gè)文本文件,使用BNF語(yǔ)法來(lái)描述ARM鏈接器生成映像文件時(shí)所需要的信息。
BNF符號(hào)與語(yǔ)法:
" :由雙引號(hào)標(biāo)識(shí)的符號(hào)保持其字面原意,如A”+”B表示A+B。
A ::= B :定義A為B。
[A] :用來(lái)表示可選部分,如A[B]C表示ABC或AC。
A+ :用來(lái)表示A可以重復(fù)任意次,如A+表示A,AA,AAA,......
A* :同A+。
A | B :用來(lái)表示選擇其一,不能全選。如A|B表示A或者B。
(AB) :表示一個(gè)整體,通常其他符號(hào)一起使用,如(AB)+(C|D)表示ABC,ABD,ABABC,ABABD,......
一個(gè)Scatter文件包含一個(gè)或多個(gè)加載區(qū)域,每個(gè)加載區(qū)域可以包含一個(gè)或多個(gè)執(zhí)行區(qū)域。下圖顯示了典型的Scatter文件的組成結(jié)構(gòu):
4.1 加載域描述
加載域可以包含一個(gè)或多個(gè)執(zhí)行域。
加載域描述的語(yǔ)法如下:
load_region_description::= load_region_name(base_address|("+"offset))[attribute_list][max_size] "{" execution_region_description+ "}"
1)load_region_name:命名加載區(qū)域。你可以使用帶引號(hào)的名字。只有在使用任何與區(qū)域相關(guān)的鏈接器定義的符號(hào)時(shí),該名稱才區(qū)分大小寫(xiě)。
2)base_address:指定區(qū)域內(nèi)對(duì)象的鏈接地址。base_address必須滿足加載區(qū)域的對(duì)齊約束。
3)+offset:描述基址,該基址在前面的加載區(qū)域的末尾以外偏移字段。偏移量的值必須是0取4的模。如果這是第一個(gè)加載區(qū)域,那么+offset表示基址從零開(kāi)始偏移字段。如果使用+offset,則加載區(qū)域可能會(huì)從前一個(gè)加載區(qū)域繼承某些屬性。
4)attribute_list:指定加載區(qū)域內(nèi)容的屬性。
5)max_size:指定加載區(qū)域的最大大小。這是在進(jìn)行任何解壓縮或零初始化之前加載區(qū)域的大小。如果指定了可選的max_size值,那么如果分配給該區(qū)域的字段超過(guò)max_size, armlink將生成一個(gè)錯(cuò)誤。
6)execution_region_description:指定執(zhí)行區(qū)域的名稱、地址和內(nèi)容。
4.2 執(zhí)行域描述
執(zhí)行域指定在運(yùn)行時(shí)將輸入段放置在目標(biāo)內(nèi)存中的位置。
執(zhí)行域描述的語(yǔ)法如下:
execution_region_description::= exec_region_name(base_address|"+"offset)[attribute_list][max_size|length] "{" input_section_description* "}"
1)exec_region_name:命名執(zhí)行區(qū)域。你可以使用帶引號(hào)的名字。只有在使用任何與區(qū)域相關(guān)的鏈接器定義的符號(hào)時(shí),該名稱才區(qū)分大小寫(xiě)。
2)base_address:指定區(qū)域內(nèi)對(duì)象的鏈接地址。Base_address必須與字對(duì)齊。
注意:在執(zhí)行區(qū)域上使用ALIGN會(huì)導(dǎo)致加載地址和執(zhí)行地址對(duì)齊。
+offset:描述一個(gè)基址,該基址在前面執(zhí)行區(qū)域的末尾以外偏移字段。偏移量的值必須是0取4的模。如果這是加載區(qū)的第一個(gè)執(zhí)行區(qū),則+offset表示基址在包含加載區(qū)的基址之后開(kāi)始偏移字段。如果使用+offset,則執(zhí)行區(qū)域可能會(huì)從父加載區(qū)域繼承某些屬性,或者從同一加載區(qū)域內(nèi)的前一個(gè)執(zhí)行區(qū)域繼承某些屬性。
4)attribute_list:指定執(zhí)行區(qū)域內(nèi)容的屬性。
5)max_size:對(duì)于標(biāo)記為EMPTY或FILL的執(zhí)行區(qū)域,max_size值被解釋為該區(qū)域的長(zhǎng)度。否則,max_size值將被解釋為執(zhí)行區(qū)域的最大大小。
6)-length:只能與EMPTY一起使用,表示在內(nèi)存中增長(zhǎng)的堆棧。如果長(zhǎng)度為負(fù)值,則base_address被視為該區(qū)域的結(jié)束地址。
7)input_section_description:指定輸入段的內(nèi)容。
4.3 輸入段描述
輸入段描述指定將哪些輸入段加載到執(zhí)行區(qū)域。
輸入段描述的語(yǔ)法是:
input_section_description::= module_select_pattern["("input_section_selector(","input_section_selector)*")"] input_section_selector::="+"input_section_attr |input_section_pattern |input_section_type |input_symbol_pattern |section_properties
1)module_select_pattern:
一種由文本構(gòu)成的模式。當(dāng)module_select_pattern匹配以下選項(xiàng)之一時(shí),輸入段匹配模塊選擇器模式:
包含該段的目標(biāo)文件的名稱。
庫(kù)成員的名稱(不帶前導(dǎo)路徑名)。
提取部分的庫(kù)的全名(包括路徑名)。如果名稱包含空格,請(qǐng)使用通配符以簡(jiǎn)化搜索。
例如,使用*libname來(lái)匹配C:lib dirlibname.lib。
通配符 * 匹配零個(gè)或多個(gè)字符,? 匹配任意單個(gè)字符。匹配不區(qū)分大小寫(xiě),即使在文件命名區(qū)分大小寫(xiě)的主機(jī)上也是如此。使用 *.o 匹配所有對(duì)象,使用 * 來(lái)匹配所有的目標(biāo)文件和庫(kù)??梢允褂脦б?hào)的文件名,例如”file one.o”。
在一個(gè)Scatter文件中不能有兩個(gè) * 選擇器。但是可以使用兩個(gè)修改過(guò)的選擇器,例如*A和*B,并且可以將. any選擇器與*模塊選擇器一起使用。*模塊選擇器的優(yōu)先級(jí)高于.any。如果文件中包含*選擇器的部分被刪除,則. any選擇器將變?yōu)榛顒?dòng)的。
2)input_section_attr:
與輸入部分屬性匹配的屬性選擇器。每個(gè)input_section_attr后面跟著一個(gè)+。選擇器不區(qū)分大小寫(xiě),可以識(shí)別以下選擇器:
RO-CODE
RO-DATA
RO,同時(shí)選擇RO-CODE和RO-DATA
RW-DATA
RW-CODE
RW,同時(shí)選擇RW-CODE和RW-DATA
XO
ZI
ENTRY,包含入口點(diǎn)的部分。
可以識(shí)別以下同義詞:
CODE代表RO-CODE
CONST代表RO-DATA
TEXT代表RO
DATA代表RW
BSS代表ZI
可以識(shí)別以下偽屬性:
FIRST
LAST
如果放置順序很重要,則使用FIRST和LAST標(biāo)記執(zhí)行區(qū)域中的第一部分和最后一部分。例如,如果特定的輸入部分必須在區(qū)域中位于第一個(gè),并且包含校驗(yàn)和的輸入部分必須位于最后。
FIRST和LAST必須不違反基本屬性排序順序。例如,F(xiàn)IRST RW放在任何只讀代碼或只讀數(shù)據(jù)之后。
一個(gè)執(zhí)行區(qū)域只能有一個(gè)FIRST或一個(gè)LAST屬性,并且它必須遵循一個(gè)input_section_selector。例如:
*(section, +FIRST) 這種模式是正確的。
*(+FIRST, section) 此模式不正確,并產(chǎn)生錯(cuò)誤消息。
3)input_section_pattern:
一種模式,不區(qū)分大小寫(xiě),與輸入段名匹配。它是由文字構(gòu)成的。通配符 * 匹配0個(gè)或多個(gè)字符,而 ? 匹配任何單個(gè)字符??梢允褂脦б?hào)的輸入段名。
如果使用多個(gè)input_section_pattern,請(qǐng)確保在不同的執(zhí)行區(qū)域中沒(méi)有重復(fù)的模式,以避免歧義錯(cuò)誤。
4)input_section_type:
與輸入段類型進(jìn)行比較的數(shù)字。支持十進(jìn)制或十六進(jìn)制。
5)input_symbol_pattern:
可以通過(guò)該段定義的全局符號(hào)名選擇輸入段。全局名稱能夠使你從部分鏈接的對(duì)象中選擇具有相同名稱的單個(gè)段。
6)section_properties:
section屬性可以是+FIRST、+LAST和OVERALIGN值。OVERALIGN的值必須是2的正冪,且必須大于或等于4。
5?
如何打開(kāi).sct文件
在Options for Targets->Linker界面,Keil默認(rèn)選擇了“Use Memory Layout from Target Dialog”,勾掉復(fù)選框里面的對(duì)號(hào),就可以使用自己定義的分散加載文件。
6?
練習(xí)
根據(jù)前面介紹的語(yǔ)法編輯 .sct文件,將函數(shù)和數(shù)據(jù)放到指定地址:
1)在LR_ROM加載域中定義2個(gè)執(zhí)行域RW_RAM1、RW_RAM2:
RW_RAM1基地址為0x20001000,域大小為0x400,將TEST_FUNCTION_ADDR段最先加載到本域的起始地址。
RW_RAM2基地址為0x20001400,域大小為0x400,將TEST_DATA_ADDR段最先加載到本域的起始地址。
LR_ROM__RO_BASE__RO_SIZE{;loadregionsize_region ER_ROM__RO_BASE__RO_SIZE{;loadaddress=executionaddress *.o(RESET,+First) *(InRoot$$Sections) ;*(Veneer$$CMSE);uncommentforsecureapplications .ANY(+RO) .ANY(+XO) } RW_RAM__RW_BASE__RW_SIZE{;RWdata .ANY(+RW+ZI) } RW_RAM10x200010000x400{;RWdata *.o(TEST_FUNCTION_ADDR,+First) } RW_RAM20x200014000x400{;RWdata *.o(TEST_DATA_ADDR,+First) } #if__HEAP_SIZE>0 ARM_LIB_HEAP__HEAP_BASEEMPTY__HEAP_SIZE{;Reserveemptyregionforheap } #endif ARM_LIB_STACK__STACK_TOPEMPTY-__STACK_SIZE{;Reserveemptyregionforstack } }
2)使用__attribute__((section("section_name"))) 定義函數(shù)和數(shù)據(jù)如下:
(表示將函數(shù)或數(shù)據(jù)放入指定名為"section_name"的段)
uint32_ttest_data__attribute__((section("TEST_DATA_ADDR"))); voidtest_function(void)__attribute__((section("TEST_FUNCTION_ADDR")));
3)調(diào)用上述函數(shù)和數(shù)據(jù):
intmain(void) { test_function(); while(1) { test_data++; if(test_data>=1000) { test_data=0; } } }
編譯后查看map文件中內(nèi)存映射部分:
TEST_FUNCTION_ADDR段對(duì)應(yīng)的執(zhí)行域基地址為0x20001000,TEST_DATA_ADDR段對(duì)應(yīng)的執(zhí)行域基地址為0x20001400,和在Scatter文件定義一致,即將函數(shù)和數(shù)據(jù)放到了指定地址。
7?
小結(jié)
分散加載文件(scatter file)是一個(gè)文本文件,用于描述 ARM 鏈接器生成映像文件所需要的信息,在一些應(yīng)用場(chǎng)景中嵌入式系統(tǒng)可能會(huì)使用分散加載。本章節(jié)簡(jiǎn)要介紹了分散加載文件的基本概念和語(yǔ)法,旨在對(duì)分散加載文件有初步認(rèn)識(shí),具體內(nèi)容可以參考官方文檔或查閱資料進(jìn)行詳細(xì)了解。
審核編輯:劉清
-
ARM
+關(guān)注
關(guān)注
134文章
9353瀏覽量
377600 -
SDRAM
+關(guān)注
關(guān)注
7文章
442瀏覽量
56318 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7653瀏覽量
167418 -
ROM
+關(guān)注
關(guān)注
4文章
578瀏覽量
87364 -
keil
+關(guān)注
關(guān)注
69文章
1223瀏覽量
169619 -
內(nèi)存映射
+關(guān)注
關(guān)注
0文章
15瀏覽量
7542 -
靈動(dòng)微
+關(guān)注
關(guān)注
4文章
176瀏覽量
22972 -
MM32
+關(guān)注
關(guān)注
1文章
108瀏覽量
1102
原文標(biāo)題:靈動(dòng)微課堂 (第278講)|Keil分散加載文件淺析
文章出處:【微信號(hào):MindMotion-MMCU,微信公眾號(hào):靈動(dòng)MM32MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
如何把文件系統(tǒng)燒到EMMC并從EMMC加載

ARM分散加載及應(yīng)用
請(qǐng)問(wèn)怎樣去修改STM32F2中ROM分區(qū)的分散加載文件呢
如何使用BitTorrent下載文件
使用KEIL下載文件到單片機(jī)外置存儲(chǔ)器的方法

ARM分散加載文件

什么是分散加載文件?何時(shí)進(jìn)行分散加載
深入分析一下MDK的分散加載文件

評(píng)論