ARM Scatter File詳解

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()
     }
}


ro ---- const int x = 0;
rw ---- int x = 0;
zi ----- int x;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章