一 概述
Scatter file ( 分散加載描述文件 ) 用于 armlink 的輸入參數,他指定映像文件內部各區域的 download 與運行時位置。 Armlink 將會根據 scatter file 生成一些區域相關的符號,他們是全局的供用戶建立運行時環境時使用。
(注意:當使用了 scatter file 時將不會生成以下符號:
Image$$RW$$Base,
Image$$RW$$Limit,
Image$$RO$$Base,
Image$$RO$$Limit,
Image$$ZI$$Base,
Image$$ZI$$Limit )
二 什么時候使用 scatter file
當然首要的條件是你在利用 ADS 進行項目開發,下面我們看看更具體的一些情況。
1 存在復雜的地址映射:例如代碼和數據需要分開放在在多個區域。
2 存在多種存儲器類型:例如包含 Flash,ROM,SDRAM, 快速 SRAM 。我們根據代碼與數據的特性把他們放在不同的存儲器中,比如中斷處理部分放在快速 SRAM 內部來提高響應速度,而把不常用到的代碼放到速度比較慢的 Flash 內。
3 函數的地址固定定位:可以利用 Scatter file 實現把某個函數放在固定地址,而不管其應用程序是否已經改變或重新編譯。
4 利用符號確定堆與堆棧:
5 內存映射的 IO :采用 scatter file 可以實現把某個數據段放在精確的地指處。
因此對于嵌入式系統來說 scatter file 是必不可少的,因為嵌入式系統采用了 ROM , RAM ,和內存映射的 IO 。
三 scatter file 實例
1 簡單的內存映射
LOAD_ROM 0x0000 0x8000
{
EXEC_ROM 0x0000 0x8000
{
*(+RO)
}
RAM 0x10000 0x6000
{
*(+RW, +ZI)
}
}
LOAD_ROM( 下載區域名稱 ) 0x0000( 下載區域起始地址 ) 0x8000( 下載區域最大字節數 )
{
EXEC_ROM( 第一執行區域名稱 ) 0x0000( 第一執行區域起始地址 ) 0x8000( 第一執行區域最大字節數 )
{
*(+RO( 代碼與只讀數據 ))
}
RAM( 第二執行區域名稱 ) 0x10000( 第二執行區域起始地址 ) 0x6000( 第二執行區域最大字節數 )
{
*(+RW( 讀寫變量 ), +ZI( 未初始化變量 ))
}
}
2 復雜內存映射
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( 下載區域一起始地址 )
{
EXEC_ROM_1 0x0000( 第一執行區域開始地址 )
{
program1.o(+RO) (program1.o 內的 Code 與 RO data 放在第一執行區域 )
}
DRAM 0x18000( 第二執行區域開始地址 ) 0x8000( 第二執行區域最大字節數 )
{
program1.o (+RW, +ZI) (program1.o 內的 RW data 與 ZI data 放在第二執行區域 )
}
}
LOAD_ROM_2 0x4000( 下載區域二起始地址 )
{
EXEC_ROM_2 0x4000
{
program2.o(+RO) (program2.o 內的 Code 與 RO data 放在第一執行區域 )
}
SRAM 0x8000 0x8000
{
program2.o (+RW, +ZI) (program2.o 內的 RW data 與 ZI data 放在第二執行區域 )
}
}
2.1 BNF 符號與語法
" :由引號賴標示的符號保持其字面原意,如 A”+”B 標示 A+B 。
A ::= B :定義 A 為 B 。
[A] :標示可選部分,如 A[B]C 用來標示 ABC 或 AC 。
A+ :用來標示 A 可以重復任意次,如 A+ 可標示 A,AA,AAA, …
A* :同 A+ 。
A | B :用來標示選擇其一,不能全選。如 A|B 用來標示 A 或者 B 。
(A B) :標示一個整體,當和 | 符號或復雜符號的多次重復一起使用時尤其強大,如( AB ) +(C|D) 標示 ABC,ABD,ABABC,ABABD, …
2.2 分散加載文件各部分描述
(2.1)
如圖 2.1 所示為一個完整的分散加載腳本描述結構圖。下面我們對圖示中各個部分進行講述。
2.2.1 加載區描述
每個加載區有:
名稱:供連接器確定不同下載區域
基地址:相對或絕對地址
屬性:可選
最大字節數:可選
執行區域列:確定執行時各執行區域的類型與位置
load_region_name (base_address | ("+" offset)) [attribute_list] [ max_size ]
"{"
execution_region_description+
"}"
load_region_name :下載區域名稱,最大有效字符數 31 。(并不像執行區域段名用于 Load$$region_name ,而是 僅僅用于標示下載區域)。
base_address :本區域內部目標被連接到的地址(按字對齊)。
+offset :相對前一個下載區域的偏移量( 4 的整數倍,如果為第一個區域)。
2.2.2 執行區 描述
每個執行區有:
名稱:供連接器確定不同下載區域
基地址:相對或絕對地址
屬性:確定執行區域的屬性
最大字節數:可選
輸入段:確定放在該執行區域的模塊
exec_region_name (base_address | "+" offset) [attribute_list] [max_size]
"{"
input_section_description+
"}"
exec_region_name :執行區域名稱,最大有效字符數 31 。
base_address :本執行區域目標要被聯接到的位置,按字對齊。
+offset :相對于前一個執行區域結束地址的偏移量, 4 的整數倍;如果沒有前繼之能夠行區域(本執行區域為該下載區域的第一個執行區域),則該偏移量是相對于該下載區域的基址偏移量。
attribute_list : PI , OVERLAY , ABSOLUTE , FIXED , UNINIT 。
PI: 位置獨立。
OVERLAY: 覆蓋。
ABSOLUTE: 絕對地址。
FIXED: 固定地址,下載地址與執行地址具有該地址指示確定。
UNINIT: 未初始化數據。
RELOC :無法明確指定執行區域具有該屬性,而只能通過繼承前一個執行區或父區域獲得。
對于 PI , OVERLAY , ABSOLUTE , FIXED ,我們只能選擇一個,缺省屬性為 ABSOLUTE 。一個執行區域要么直接繼承其前面的執行區域的屬性或者具有屬性為 ABSOLUTE 。
具有 PI , OVERLAY , RELOC 屬性的執行區域允許其地址空間重疊,對于 BSOLUTE , FIXED 屬性執行區域地址空間重疊 Armlink 會報錯。
max_size :可選,他用于指使 Armlink 在實際分配空間大于指定值時報錯。
input_section_description :指示輸入段的內容。
基本語法 2
2.2.3 輸入段 描述
輸入段:
ó 模塊名:目標文件名,庫成員名,庫文件名。名稱可以使用通配符。
ó 輸入段名,或輸入段屬性 (READ-ONLY,CODE) 。
module_select_pattern
["("
("+" input_section_attr | input_section_pattern)
([","] "+" input_section_attr | "," input_section_pattern))*
")"]
2.2.3.1
module_select_pattern :選擇的模塊名稱(目標文件,庫文件成員,庫文件),模塊名可以使用通配符( * 匹配任意多個字符,?匹配任意一個字符),名稱不區分字母大小寫,它是供選擇的樣本。
例 1 : *libtx.a (+RO)
libtx.a 為 threadX 庫文件。
例 2 : tx_ill.o (INIT)
tx_ill.o 為 threadX 中斷向量目標文件。
2.2.3.2
input_section_attr :輸入段屬性選擇子,每個選擇子以” + ”開頭,選擇子不區分大小寫字符。
選擇子可選:
RO-CODE ,
RO-DATA ,
RO ( selects both RO-CODE and RO-DATA ),
RW-DATA ,
RW-CODE ,
RW ( selects both RW-CODE and RW-DATA ),
ZI ,
ENTRY ( that is a section containing an ENTRY point )。
以下同義詞可以選擇:
CODE (for RO-CODE) ,
CONST( for RO-DATA) ,
TEXT (for RO) ,
DATA (for RW) ,
BSS (for ZI) 。
還有兩個偽屬性: FIRST , LAST 。如果各段的先后順序比較重要時,可以使用 FIRST , LAST 標示一個執行區域的第一個和最后一個段。
例 1 : os_main_init.o (INIT ,+FIRST)
FIRST 表示放于本執行區域的開始處。
例 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 的一個段。
例 2 : os_stackheap.o (heap)
heap 為 os_stackheap.o 的一個段。
例 3 : os_stackheap.o (stack)
stack 為 os_stackheap.o 的一個段。
提高篇
3.1 在 scatter file 中指定膠合段
膠合段用于實現 ARM 代碼到 Thumb 代碼的切換或者實現代碼的長轉移。使用 scatter file 可以指定怎樣放置膠合輸入段。通常,在 scatter file 中一個執行區域可以擁有膠合段選擇 *(Venner$$Code) 。
Armlink 把膠合輸入段放到擁有段選擇符 *(Veneer$$Code) 的執行區域中,這樣做是安全的。
可能由于地址范圍問題或者受執行區域大小限制無法完成把膠合段分配個某個執行區域。如果當發生膠合段無法加到指定區域時,他將會被加到那些包含了生成膠合段的可重載輸入段的執行區域。
3.2 創建根執行區域
根執行區域就是指那些執行與加載時地址相同的區域。
當你為映像文件指定初始化入口點或者由于你只使用一個 ENTRY 導向符而使得連接器創建初始化入口位置時,你就必須確保該入口點位于根執行區域。如果入口點不在根執行區域,連接將會失敗,連接器會報錯。
如: ENTRY point (0x00000000) lies within non-root region ER_ROM
可以通過以下方式實現在 scatter file 中指定根執行區域。
① 顯示或缺省的指定執行區的屬性為 ABSOLUTE ,同時使得加載區域與第一個執行區域具有相同的地址。
② 使用 FIXED 屬性使得執行區域的加載地址與其執行時地址保持不變。
3.3 創建根執行區域
可以通過在 scatter file 中為某個執行區域指定 FIXED 屬性來實現該區域加載于運行時地址保持不變。
FIXED 可以用來在一個加載區中創建多個根執行區域。因此我們可以通過它實現把某個函數或一段數據放到目標地址,從而可以通過指針方便地訪問該地址。比如,我們可以實現把常量表和 checksum 放到 ROM 上的固定地址處。
?
注意:
① 為了使得代碼更加易于維護和調試,請盡量少使用 scatter file 來指定放置位置,而是應該盡可能多地讓連接器來確定函數和數據的位置。
②
3.3.1 怎樣把函數或數據放到指定地址
通常,編譯器處理來自單個源文件的 RO,RW, 和 ZI 段。這些區域包括源文件的代碼與數據。如果打算把單個函數或數據項放到某個固定地址,我們就必須讓編譯器單獨處理這些函數和數據。
我么可以通過以下方式處理單個目標:
① 把函數和數據放到其源文件。
② 使用編譯選項 –zo 為每個函數單獨生成一個目標文件。 ( 參看 ARM Compiler Guide)
③ 在 C,C++ 源文件內利用 #pragma arm section 來生成多命名段。
④ 在匯編源文件內利用 AREA 導向符來生成可重載段。
3.3.2 怎樣放置單個目標文件的內容
3.3.3 怎樣使用 ARM 的 section pragma
通常把函數和數據放到其源代碼文件,然后放到其目標文件的相應段中。然而,我們也可以 #pragma 和 scatter file 實現單獨處理某個命名段。
// file adder.c
int x1 = 5; // in.data
int y1[100];// in.bss
int const z1[3] = {1,2,3}; // in.constdata
int sub1(int x)// in.text
{
return x-1;
}
#pragma arm section rwdata = "foo", code ="foo"
int x2 = 5;// in foo (data part of region)
char *s3 = "abc";// s3 in foo, "abc" in .constdata
int add1(int x)
{
return x+1;
} // in foo (.text part of region)
#pragma arm section code, rwdata // return to default placement
FLASH 0x24000000 0x4000000
{
FLASH 0x24000000 0x4000000
{
init.o (Init, +First) ; place code from init.o first
* (+RO) ; sub1(), z1[]
}
32bitRAM 0x0000
{
vectors.o (Vect, +First)
* (+RW,+ZI) ; x1, y1
}
ADDER 0x08000000
{
adder.o (foo) ; x2, string s3, and add1()
}
}
源文檔 < http://blog.csdn.net/jianshe999/archive/2008/01/25/2065080.aspx >
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
