加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 13.4  映像文件存儲(chǔ)器映射調(diào)整
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

嵌入式軟件開(kāi)發(fā)之: 映像文件存儲(chǔ)器映射調(diào)整

2013/09/30
1
閱讀需 57 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

?

13.4? 映像文件存儲(chǔ)器映射調(diào)整

13.4.1? 關(guān)于分散加載

映像由域(Regions)和輸出段(Output Sections)組成。每個(gè)域可以有不同的加載地址和執(zhí)行地址。

分散加載可以更加方便準(zhǔn)確的指定映像存儲(chǔ)器映射,為映像組件分組和布局提供了全面控制。它能夠描述由載入時(shí)和執(zhí)行時(shí)分散在存儲(chǔ)器映射中的多個(gè)區(qū)組成的復(fù)雜映像映射。雖然,分散加載可以用于簡(jiǎn)單映像,但它通常僅用于具有復(fù)雜存儲(chǔ)器映射的映像。

要構(gòu)建映像的存儲(chǔ)器映射,必須向armlink提供以下信息:

·? 分組信息:決定如何將各輸入段組織成相應(yīng)的輸出段和域;

·? 定位信息:決定各域在存儲(chǔ)空間的起始地址。

有兩種方法可以配置指定映像文件的分組和定位信息:如果映像文件中地址映射關(guān)系比較簡(jiǎn)單,可以使用命令行選項(xiàng);如果映像文件中地址映射關(guān)系比較復(fù)雜的情況,可以使用一個(gè)配置文件。使用該配置文件可以告訴鏈接器相關(guān)的地址映射關(guān)系。配置文件又叫Scatter文件,是一個(gè)文本文件,通過(guò)下面的鏈接選項(xiàng)來(lái)實(shí)現(xiàn)。

-scatter? filename

1.為分散加載定義的符號(hào)

當(dāng)armlink使用Scatter文件創(chuàng)建映像時(shí),它創(chuàng)建一些區(qū)相關(guān)符號(hào)。表13.2概括了這些符號(hào)的意義。

表13.2???????? 域相關(guān)符號(hào)

符??? 號(hào)

意??? 義

Load$$region_name$$Base

域的載入地址

Image$$region_name$$Base

域的執(zhí)行地址

Image$$region_name$$Length

執(zhí)行域字節(jié)長(zhǎng)度(4的倍數(shù))

Image$$region_name$$Limit

執(zhí)行區(qū)末尾地址

Image$$region_name$$ZI$$Base

執(zhí)行域中ZI段的執(zhí)行地址

Image$$region_name$$ZI$$Length

ZI輸出段的長(zhǎng)度(4的倍數(shù))

Image$$region_name$$ZI$$Limit

執(zhí)行域中ZI段的末尾地址

2.使用Scatter文件的優(yōu)勢(shì)

鏈接程序的命令行選項(xiàng)提供了一些對(duì)數(shù)據(jù)和代碼布局的控制,但要實(shí)現(xiàn)對(duì)布局的全面控制命令行輸入的指令是遠(yuǎn)遠(yuǎn)不夠的。在下面一些情況下,就需要使用Scatter文件對(duì)映像布局進(jìn)行控制。

① 需要實(shí)現(xiàn)復(fù)雜存儲(chǔ)器映射

系統(tǒng)中的代碼和數(shù)據(jù)必須放在多個(gè)不同存儲(chǔ)器區(qū)域中,這樣連接器必須知道哪個(gè)段放在哪個(gè)儲(chǔ)存器空間的詳細(xì)信息。這種情況下,最好用Scatter文件實(shí)現(xiàn)代碼映像的分散加載。

② 系統(tǒng)中存在多種不同類型存儲(chǔ)器

許多系統(tǒng)包含多種不同類型存儲(chǔ)器,如flash存儲(chǔ)器ROM、SDRAM和快速SRAM。分散載入描述可以將代碼和數(shù)據(jù)放置在最適合的存儲(chǔ)器類型中。例如,中斷代碼可能放在快速SRAM中,以加快中斷響應(yīng)時(shí)間,而不頻繁使用的配置信息可能放在較慢的flash存儲(chǔ)器中。

③ 存儲(chǔ)器映射I/O

分散載入描述可以將數(shù)據(jù)精確定位在內(nèi)存地址中,而避免數(shù)據(jù)和內(nèi)存映射外圍地址相沖突。

④ 位于固定位置函數(shù)

可以將特定函數(shù)放在存儲(chǔ)器中的同一個(gè)位置,這樣即使周圍的應(yīng)用程序已經(jīng)被修改并重新編譯,也可以使具有特定功能的函數(shù)地址保持不變。

⑤ 使用符號(hào)識(shí)別堆和棧

可以為堆和棧的位置定義符號(hào),鏈接應(yīng)用程序時(shí)可以指定該封閉模塊的位置。

隨著目前嵌入式系統(tǒng)越來(lái)越復(fù)雜,系統(tǒng)中可能同時(shí)使用flash、ROM和RAM,所以建議在生產(chǎn)系統(tǒng)映像時(shí)使用Scatter文件。

3.分散加載命令行選項(xiàng)

可以使用下面的命令行選項(xiàng)使用分散加載文件。

-scatter description_file_name

使用該命令可以使鏈接器使用命令中給出的description_file_name文件生成最終的映像文件。

4.簡(jiǎn)單存儲(chǔ)器映像舉例

例如,一個(gè)實(shí)際系統(tǒng)的存儲(chǔ)器映射如圖13.7所示。

圖13.7? 簡(jiǎn)單存儲(chǔ)器映射

為了實(shí)現(xiàn)圖13.7的存儲(chǔ)器映射,使用圖13.8所現(xiàn)實(shí)的Scatter文件。

5.復(fù)雜存儲(chǔ)器映像實(shí)現(xiàn)舉例

一個(gè)復(fù)雜存儲(chǔ)器映射如圖13.9所示。

圖13.8? 實(shí)現(xiàn)簡(jiǎn)單內(nèi)存映射的Scatter文件

圖13.9? 復(fù)雜存儲(chǔ)器映射實(shí)例

?

為了實(shí)現(xiàn)圖13.9的存儲(chǔ)器映射,使用以下程序所現(xiàn)實(shí)的Scatter文件。

LOAD_ROM_1 0x0000??????????????????? ;第一個(gè)加載時(shí)域的起始地址

{

? EXEC_ROM_1 0x0000????????????????? ;第一個(gè)運(yùn)行時(shí)域的起始地址

??? {

????? programl.o(+RO)???????????????? ;放置program.o中所以的RO段

??? {

??? SRAM 0x9000????????????????????? ;運(yùn)行時(shí)域的起始地址

??? {

????? programl.o(+RW,+ZI)????????????? ;放置program.o中所有的RW和ZI段

??? }

}

LOAD_ROM_2 0x4000??????????????????? ;第二個(gè)加載時(shí)域的起始地址

{

? EXEC_ROM_2 0x4000????????????????? ;運(yùn)行時(shí)域的起始地址

??? {

????? program2.o(+RO)

??? }

??? DRAM 0x18000???????????????????? ;運(yùn)行時(shí)域的起始地址

??? {

????? program2.o(+RW,+ZI)

??? }

}

上面兩個(gè)例子中,簡(jiǎn)單存儲(chǔ)器映射可以使用命令行選項(xiàng)實(shí)現(xiàn),但第二個(gè)復(fù)雜存儲(chǔ)器映射的例子卻只能使用Scatter文件實(shí)現(xiàn)。

13.4.2? Scatter文件語(yǔ)法

分散載入描述文件是一個(gè)文本文件,它向 armlink 描述目標(biāo)系統(tǒng)的存儲(chǔ)器映射。如果從命令行加載Scatter文件,可以使用任意類型的文件擴(kuò)展名。

在Scatter文件中,用戶可以指定以下存儲(chǔ)器映像內(nèi)容:

·? 每個(gè)載入?yún)^(qū)的載入地址和最大尺寸;

·? 每個(gè)載入?yún)^(qū)的屬性;

·? 從每個(gè)載入?yún)^(qū)派生的執(zhí)行區(qū);

·? 每個(gè)執(zhí)行區(qū)的執(zhí)行地址和最大尺寸;

·? 每個(gè)執(zhí)行區(qū)的輸入節(jié)。

描述文件的格式反映出載入?yún)^(qū)、執(zhí)行區(qū)和輸入節(jié)的層次結(jié)構(gòu)。

1.BNF的表示法和語(yǔ)法

所謂BNF(Backus Naur Format)即Scatter文件所用的形式語(yǔ)言。表13.3概括了其所用的符號(hào)和語(yǔ)法規(guī)則。

表13.3????? BNF語(yǔ)法

符??? 號(hào)

說(shuō)??? 明

引號(hào)用于表示BNF語(yǔ)法中的字符被用作普通字符。

例如,定義B"+"C,它只能替換為模式B+C。而定義B+C可以替換為模式BC、BBC或BBBC

A ::= B

將A定義為B。例如,A::= B"+" | C 表示A相當(dāng)于B+或C。

在其組件方面,::=表示法用于定義高級(jí)結(jié)構(gòu)。每個(gè)組件可能還有一個(gè)::=定義,對(duì)更簡(jiǎn)單的組件進(jìn)行定義。

例如,A::=B以及B::= C | D表示定義A相當(dāng)于模式C或D

續(xù)表

符??? 號(hào)

說(shuō)??? 明

[A]

可選元素A。例如,A::= B[C]D 表示定義A可以擴(kuò)展為BD或BCD

A+

元素A可以出現(xiàn)一次或多次。例如,A::= B+表示定義A可以擴(kuò)展為B、BB或BBB等

A*

元素A可以不出現(xiàn)或多次出現(xiàn)

A|B

出現(xiàn)元素A或B,但不能同時(shí)出現(xiàn)

(A|B)

元素A和B組合在一起。

這在使用 | 操作符時(shí),或重復(fù)復(fù)雜模式時(shí)尤其適用。

例如,A::=(B C)+ (D | E) 表示定義A可以擴(kuò)展為BCD、BCE、BCBCD、BCBCE、BCBCBCD或BCBCBCE

2.Scatter文件語(yǔ)法概述

分散加載描述scatter_description被定義為一個(gè)或多個(gè)load_region_description模式:

Scatter_description ::=

??load_region_description+

加載域描述load_region_description 被定義為載入?yún)^(qū)名稱,可以選擇性地在其后跟隨屬性、尺寸說(shuō)明符以及一個(gè)或多個(gè)執(zhí)行區(qū)描述:

load_region_description ::=

? ?load_region_name (base_address | ("+" offset)) [attributes] [max_size]

? ?"{"

?? ????????execution_region_description+

? ?"}"

執(zhí)行域描述execution_region_description 被定義為執(zhí)行區(qū)名稱,是一種基址規(guī)范,可以選擇性地在其后跟隨屬性、尺寸說(shuō)明符以及一個(gè)或多個(gè)輸入段描述:

execution_region_description ::=

? ?exec_region_name (base_address | "+" offset) [attribute_list] [max_size | "–"

length]

??? ??????"{"

???????? ?????input_section_description*

??????? ??"}"

輸入段描述input_section_description被定義為源模塊選擇程序模式,可以在其后選擇性地跟隨輸入節(jié)選擇程序:

input_section_description ::=

???module_select_pattern

? ?[ "("

??? ??????("+" input_section_attr | input_section_pattern)

?????? ???([","] "+" input_section_attr | "," input_section_pattern))*

?? ???")" ]

?

圖13.10顯示一個(gè)典型的分散載入描述文件的內(nèi)容和組織結(jié)構(gòu)。

圖13.10? 典型的分散載入描述文件的內(nèi)容和組織結(jié)構(gòu)

3.加載域描述

一個(gè)加載域具有以下屬性:

·? 名稱:鏈接程序使用它識(shí)別不同的加載域;

·? 基址:載入視圖中的代碼和數(shù)據(jù)的起始地址;

·? 屬性:可選;

·? 最大尺寸:可選;

·? 執(zhí)行區(qū)列表:這些執(zhí)行區(qū)標(biāo)識(shí)執(zhí)行視圖中模塊的類型和位置。

圖13.11顯示了加載域的描述。

BNF語(yǔ)法為:

load_region_description ::=

???load_region_name? (base_address? | ("+" offset)) [attribute_list] [ max_size

]

??? ?????"{"

????????? ??execution_region_description+

????? ???"}"

語(yǔ)法說(shuō)明如下。

① load_region_name為加載域的名稱。只有前31個(gè)字符有效。該名稱僅用于識(shí)別每個(gè)域。

注意

load_region_name與執(zhí)行域exec_region_name不同,load_region_name不用于生成Load$$region_
name符號(hào)。

② base_address是區(qū)中對(duì)象的鏈接地址。base_address必須是一個(gè)字對(duì)齊數(shù)值。

③ +offset描述基址,它從前一個(gè)加載域的末尾偏移offset個(gè)字節(jié)。offset的值必須能被4整除。如果是第一個(gè)加載域,則+offset表示該域的基地址是從0之后的offset字節(jié)開(kāi)始。

④ attribute_list指定加載域內(nèi)容的屬性:

·? PI:位置獨(dú)立;

·? RELOC:可重定位;

·? OVERLAY:重疊;

·? ABSOLUTE:絕對(duì)地址;

·? NOCOMPRESS:代碼不被壓縮。

可以指定這些屬性中的一項(xiàng)(除NOCOMPRESS外,其他4項(xiàng)屬性為互斥關(guān)系)。默認(rèn)的加載域?qū)傩允茿BSOLUTE。具有PI、RELOC或OVERLAY屬性之一的加載域可以有重疊的地址范圍。對(duì)于ABSOLUTE加載域,armlink不允許重疊的地址范圍。OVERLAY關(guān)鍵字允許在同一個(gè)地址有多個(gè)執(zhí)行區(qū)。

注意

ARM在RVCT中不提供重疊機(jī)制。要在同一個(gè)地址使用多個(gè)執(zhí)行區(qū),必須提供自己的重疊管理程序。

⑤ max_size:它指定加載域的最大尺寸。(如果指定了可選的max_size值,但分配給該區(qū)的字節(jié)超過(guò)max_size字節(jié),armlink將生成錯(cuò)誤。)

⑥ execution_region_description:它指定執(zhí)行區(qū)名稱、地址和內(nèi)容。

4.執(zhí)行域描述符

執(zhí)行域具有以下一些屬性:

·?

域名稱;

·? 執(zhí)行域基地址(支持絕對(duì)地址的或相對(duì)地址的);

·? 執(zhí)行域的最大尺寸(可選);

·? 指定執(zhí)行域?qū)傩裕?/p>

·? 一個(gè)或多個(gè)輸入段描述(放在本執(zhí)行區(qū)中的模塊)。

圖13.12顯示了一個(gè)典型的執(zhí)行域描述。

執(zhí)行域描述符中的BNF語(yǔ)法為:

execution_region_description ::=

??exec_region_name (base_address | "+" offset) [attribute_list] [max_size | "–"

length]

? ????????"{"

??? ???????????input_section_description+

?????? ???"}"

其語(yǔ)法說(shuō)明如下。

① exec_region_name 為執(zhí)行域命名。(只有前31個(gè)字符有效。)

② base_address是域中對(duì)象的鏈接地址。base_address必須是字對(duì)齊的。

③ +offset是描述基址,它從前一個(gè)執(zhí)行區(qū)的末尾偏移offset個(gè)字節(jié)。offset的值必須能被4整除。如果前面沒(méi)有執(zhí)行區(qū)(即,這是載入?yún)^(qū)中的第一個(gè)執(zhí)行區(qū)),則+offset表示基址從它所在的載入?yún)^(qū)的基址之后offset個(gè)字節(jié)開(kāi)始。如果使用+offset格式并且所在的加載域具有RELOC屬性,則執(zhí)行區(qū)繼承該RELOC屬性。但是,如果使用固定的base_address,則隨后出現(xiàn)的offset不繼承RELOC屬性。

④ attribute_list指定執(zhí)行區(qū)內(nèi)容的屬性:

·? PI:位置獨(dú)立。

·? OVERLAY:重疊。

·? ABSOLUTE:絕對(duì)地址。域的執(zhí)行地址由base_designator指定。

·? FIXED:固定地址。執(zhí)行域的加載地址和執(zhí)行地址都由base_designator指定。base_designator必須是絕對(duì)基址,或者偏移量為+0。

·? EMPTY:它在執(zhí)行區(qū)中保留一個(gè)已知長(zhǎng)度的空白存儲(chǔ)器塊,通常用作堆或棧。

·? PADVALUE:指定填充字的默認(rèn)值,如果在域定義中指定了該屬性,則必須為該屬性賦值。使用該屬性的例子如下。

EXEC 0x10000 PADVALUE 0xffffffff EMPTY ZEROPAD 0x2000

?

通過(guò)該Scatter文件描述符,創(chuàng)建了一個(gè)長(zhǎng)度為0x2000的域,該域中的所有內(nèi)容用0xffffffff填充。

注意

所指定的域值必須以字為單位。

·? ZEROPAD 0:初始化一塊內(nèi)容全為0的內(nèi)存區(qū)域,并將其作為一個(gè)輸入段填充到ELF映像文件中。這樣減少了在運(yùn)行時(shí)將某段內(nèi)存初始化為0的操作。

注意

只有根執(zhí)行區(qū)可以使用ZEROPAD屬性進(jìn)行0初始化。對(duì)非根執(zhí)行區(qū)使用ZEROPAD屬性將出現(xiàn)警告信息,并且忽略該屬性。

·? UNINIT:指示該段為不能被初始化為0。

⑤ max_size為可選的參數(shù),如果分配給域的存儲(chǔ)器超過(guò)max_size字節(jié),則它指示armlink生成錯(cuò)誤。

⑥ -length如果指定的長(zhǎng)度為負(fù)值,則base_address是域的結(jié)束地址。它通常與EMPTY一起使用,以表示在存儲(chǔ)器中變小的棧。

當(dāng)確定執(zhí)行域?qū)傩詴r(shí),注意以下幾點(diǎn)。

① PI、OVERPLAY、FIXED和ABSOLUTE為并列關(guān)系屬性,某一個(gè)執(zhí)行域只能為這4種屬性之一。如果沒(méi)有指定,ABSOLUTE為其默認(rèn)屬性。

② 使用+offset格式的base_designator的執(zhí)行區(qū)繼承前一個(gè)執(zhí)行區(qū)的屬性(如果它是加載域中的第一個(gè)執(zhí)行區(qū),則繼承所在加載域的屬性,),或者具有ABSOLUTE屬性。

③ 不能為執(zhí)行域顯式指定RELOC屬性。該屬性只能從前面的執(zhí)行域或父區(qū)繼承才能具有RELOC屬性。

④ 被指定了PI或OVERLAP屬性的執(zhí)行域,不能有重疊的地址范圍。但對(duì)于ABLOUTE和FIXED屬性的執(zhí)行域,ARM編譯器不允許有重疊的地址范圍。

⑤ RW段默認(rèn)使用壓縮屬性。如果不想鏈接器對(duì)該段進(jìn)行壓縮,必須在Scatter文件中使用NOCOMPRESS顯示聲明。

⑥ UNINIT指定執(zhí)行區(qū)中的ZI輸出節(jié)(如果有)不被初始化為0。使用它可以創(chuàng)建包含未初始化數(shù)據(jù)或存儲(chǔ)器映射I/O的執(zhí)行區(qū)。

5.輸入段描述符

輸入段由以下部分組成。

·? 模塊名稱,如目標(biāo)文件名稱、庫(kù)成員名稱或庫(kù)文件名稱。模塊名稱可以使用通配符。

·? 輸入段名稱,或輸入節(jié)屬性,如READ-ONLY或CODE。

圖13.13顯示了輸入段描述符的基本組成。

BNF語(yǔ)法為:

input_section_description ::=

? ?module_select_pattern

?? ????["("

??? ???????("+" input_section_attr | input_section_pattern)

???? ??????([","] "+" input_section_attr | "," input_section_pattern))*

????? ??")"]

其語(yǔ)法說(shuō)明如下。

① module_select_pattern

這是由文字文本構(gòu)成的模式?!?”通配符匹配0個(gè)或多個(gè)字符,而“?”匹配任何單個(gè)字符。匹配不區(qū)分大小寫。

使用*.o可以匹配所有對(duì)象。使用*可以匹配所有目標(biāo)文件和庫(kù)。

當(dāng)滿足下列條件之一時(shí),鏈接器認(rèn)為module_selector_pattern與輸入段匹配。

·? 包含輸入段的目標(biāo)文件與module_selector_pattern匹配。

·? 包含輸入段的庫(kù)成員名稱(不帶路徑名)與module_selector_pattern匹配。

·? 從其中提取段的庫(kù)全名(包含路徑名)。如果名稱包含空格,使用通配符可以簡(jiǎn)化搜索。例如,使用*libname.lib匹配C:lib dirlibname.lib。

另外,ARM鏈接器支持特殊的模塊選擇程序模式“.ANY”,允許將輸入節(jié)分配給執(zhí)行區(qū),而無(wú)需考慮其父模塊。使用.ANY以任意分配方式填充執(zhí)行區(qū)。

注意

最好不要依賴編譯程序生成的或ARM庫(kù)代碼使用的輸入段名。因?yàn)椋@些名稱在每次編譯之間可以變化,例如編譯選項(xiàng)的改變或編譯器版本發(fā)生變化,都可能引起輸入段名稱的變化。

② input_section_attr

輸入段屬性符定義了一個(gè)用逗號(hào)隔開(kāi)的模式類別。該類表中的每個(gè)模式定義了輸入段名稱或輸入段屬性匹配方式。當(dāng)匹配模式使用輸入段名稱時(shí),它前面必須使用符號(hào)“+”,而符號(hào)“+”前面緊接的逗號(hào)可以省略。

輸入段屬性不區(qū)分大小寫。可以是下列屬性之一:

·? RO-CODE;

·? RO-DATA;

·? RO,同時(shí)選擇RO-CODE和RO-DATA;

·? RW-DATA;

·? RW-CODE;

·? RW,同時(shí)選擇RW-CODE和RW-DATA;

·? ZI;

·? ENTRY,包含ENTRY點(diǎn)的節(jié)。

可以識(shí)別以下同義詞:

·? CODE代表RO-CODE;

·? CONST代表RO-DATA;

·? TEXT代表RO;

·? DATA代表RW;

·? BSS代表ZI。

可以識(shí)別以下偽屬性:

·? FIRST;

·? LAST。

?

如果對(duì)輸入段的排列順序有特殊的要求,如特定的輸入段必須是域中的第一個(gè)輸入節(jié),而包含校驗(yàn)和的輸入段必須是最后一個(gè)輸入段,可以使用FIRST和LAST標(biāo)記執(zhí)行區(qū)中的第一個(gè)和最后一個(gè)段。

FIRST或LAST偽屬性必須放在屬性列表的最后。

特殊的模塊選擇程序模式“.ANY”允許在不考慮其父模塊的情況下,將輸入段分配給執(zhí)行域。使用一個(gè)或多個(gè)“.ANY”模式以任意分配方式填充執(zhí)行域。在大多數(shù)情況下,使用單個(gè)“.ANY”相當(dāng)于使用“*”模塊選擇屬性。

在分散載入描述文件中不能使用兩個(gè)“*”選擇屬性。但是,可以使用兩個(gè)變形的選擇程序,例如,*A和*B,也可以將.ANY選擇屬性與模塊選擇屬性一起使用。*模塊選擇屬性的優(yōu)先級(jí)比.ANY高。如果刪除了文件中包含*選擇屬性的部分,.ANY選擇屬性才能在鏈接時(shí)起作用。

在解析所有其他(非.ANY)輸入段描述并且將輸入段分配給最匹配的執(zhí)行區(qū)之后,才解析使用.ANY模塊選擇程序模式的input_section_descriptions。如果有一個(gè)以上.ANY模式,則鏈接程序盡可能多地填充第一個(gè).ANY,然后開(kāi)始填充下一個(gè).ANY。

每個(gè)未被分配的剩余輸入段將被分配給具有以下特性的執(zhí)行區(qū):

·? 最大的剩余空間(由max_size的值和已分配給該區(qū)的輸入段的尺寸確定);

·? 匹配.ANY的input_section_description;

·? 與輸入段的存儲(chǔ)器屬性相匹配的存儲(chǔ)器訪問(wèn)屬性(如果有);

·? input_section_pattern。

13.4.3? Scatter文件典型用法

1.創(chuàng)建啟動(dòng)域

所謂啟動(dòng)域就是加載地址和執(zhí)行地址相同的域。系統(tǒng)執(zhí)行的初始入口點(diǎn)必須要在啟動(dòng)域中,否則鏈接器將報(bào)告以下錯(cuò)誤。

Entry point (0x00000000) lies within non-root region ER_ROM

在Scatter文件中確定啟動(dòng)域可以使用下面兩種方法。

① 使用ABSOLUTE設(shè)置執(zhí)行區(qū)屬性,并且對(duì)第一個(gè)執(zhí)行區(qū)及其所在的加載區(qū)使用相同的地址。為確保執(zhí)行域地址和加載域地址相同,可以將加載域的起始地址和執(zhí)行域的起始地址設(shè)為相同的值或者將第一個(gè)執(zhí)行域的地址偏移量設(shè)為0。

下面的例子,指定了一個(gè)啟動(dòng)域。

BOOT ?0x0000??????????? ;加載域的起始地址在0x0

{

?? EXER ?0x0000????????? ;指定加載域和執(zhí)行域的地址相同

??? {

?????? * (+RO)?????????? ;必須將啟動(dòng)域包含在內(nèi)

??? }

?? ;其他執(zhí)行域

}

② 使用FIXED執(zhí)行域?qū)傩?,確保指定域的載入地址和執(zhí)行地址相同。

下面的例子顯示了使用FIXED屬性,將執(zhí)行域的起始地址固定在ROM中。

BOOT ?0x0000???????????? ;加載域的起始地址在0x0

{

?? EXER ?0x0000?????????? ;指定加載域和執(zhí)行域的地址相同

?? {

?????? * (+RO)??????????? ;必須將啟動(dòng)域包含在內(nèi)

?? }

?? EXER_INIT? 0x8000? FIXED

?? {

???? init.o(+RO)

?? }

}

③ 如果使用分散加載,負(fù)責(zé)創(chuàng)建執(zhí)行域的代碼和數(shù)據(jù)不能將其自身復(fù)制到另一位置,因此啟動(dòng)域必須包含以下內(nèi)容。

·? _main.o和_scatter*.o:包含復(fù)制代碼和數(shù)據(jù)的代碼。

·? Region$$Table和ZISection$$Table段:包含要復(fù)制代碼和數(shù)據(jù)的地址。

·? _dc*.o:執(zhí)行代碼壓縮。

可以使用armlinker產(chǎn)生的InRoot$$Sections符號(hào)放置啟動(dòng)代碼。因?yàn)檫@些代碼被定義為只讀屬性,所有如果Scatter文件中包含了“* (+RO)”,則表示啟動(dòng)域中包含了這些代碼?;蛘唢@式的使用InRoot$$Sections符號(hào)在Scatter文件中對(duì)以上代碼進(jìn)行配置。

下面的例子顯示了如何在Scatter文件中使用InRoot$$Sections鏈接符號(hào),放置啟動(dòng)域。

LOADREG 0x8000???????????????????? ;

{

??? ROOT ?0x8000

??? {

??????????? * (InRoot$$Sections)?????? ;放置啟動(dòng)域

??? }

??? OTHER ?0x100000

??? {

??????????? * (RO,+RW,+ZI)

??? }

???????????????????????????????? ;其他Scatter文件描述

}

?

2.為執(zhí)行域確定固定地址

可以在執(zhí)行區(qū)分散加載描述中使用FIXED屬性來(lái)創(chuàng)建根區(qū),該根區(qū)在固定地址載入和執(zhí)行。

FIXED可以用于在單一加載域內(nèi)(因此通常用于單個(gè)ROM設(shè)備)創(chuàng)建多個(gè)根區(qū)。

例如,使用FIXED屬性將函數(shù)或數(shù)據(jù)塊(如常數(shù)表或校驗(yàn)和)放在ROM中的固定地址,這樣就可以使用指針很方便的對(duì)其進(jìn)行訪問(wèn)。

下面的例子顯示了如何放置單個(gè)目標(biāo)內(nèi)容。

LOADREG1 0x0 0x10000

{

??? EXECREG1 0x0 0x1000????????????? ;啟動(dòng)域,包含初始化代碼

??? {????????????????????????????? ;將初始化代碼放在0x0地址

??????? init.o (Init, +FIRST)?

??????? * (+RO)????????????????????? ;隨后排放余下的只讀數(shù)據(jù)?

??? }

??? RAM? 0x400000? 0x2000???????????? ;將可讀可寫數(shù)據(jù)放在0x400000地址

??? {

??????? * (+RW +ZI)

??? }

??? DATABLOCK 0x4FF00 FIXED 0xFF????? ;執(zhí)行域放在 0x4FF00地址

??? {????????????????????????????? ;限制該域的最大長(zhǎng)度為 0xFF

??????? data.o(+RO-DATA)????????????? ;將只讀數(shù)據(jù)放在0x1FF00 和 0x1FFFF之間

??? }

}

通過(guò)上面的Scatter文件,可以將初始化代碼放在0x0處,其后是其他RO代碼和除了data.o對(duì)象中的RO數(shù)據(jù)之外的所有RO數(shù)據(jù);所有全局的RW變量放在RAM中0x400000處;最好將data.o的RO-DATA只讀數(shù)據(jù)表放在地址0x4FF00處,并指定其最大長(zhǎng)度為0xFF。

上例將代碼或數(shù)據(jù)對(duì)象放在其各自的源文件中,然后放置目標(biāo)文件域,這些操作方式是ARM公司建議的標(biāo)準(zhǔn)編碼方式。為方便起見(jiàn),可以使用編譯指示#pragma和分散載入描述文件放置已命名的域。下面的例子創(chuàng)建模塊dump.c并顯式命名域。

// file dump.c

? ?????int a = 10;?????????????????????????? // 放入數(shù)據(jù)域

? ?????short b[100];???????????????????????? // 放入bss段

??? ???int const c[3] = {1,2,3};?????????????? // 放入.constdata段

?? ????int func1(int a) {return a*1;}????????? // 放入.text段

?? ????#pragma arm section rwdata = "foo", code ="foo"

?? ????int x = 5;?????????????????????????? // 在foo的數(shù)據(jù)域

?? ????char *s = "abc";????????????????????? // s3在code段, "abc" 在 .constdata

? ?????int func2(int x)? {return x+1;}????????? // 放入foo的.text段

?? ????#pragma arm section code, rwdata???????? // 返回

使用下面的Scatter文件指定上面的代碼在內(nèi)存中的放置位置。如果代碼和數(shù)據(jù)段的名稱相同,則首先放置代碼段。

FLASH 0x10000000 0x2000000

{

??? FLASH 0x10000000 0x2000000

??? {

??????? init.o (Init, +First)???????????????? ; 放置初始化代碼

??????? * (+RO)???????????????????????????? ;

??? }

??? RAM 0x0000

??? {

?????? ?vectors.o (Vect, +First)?????????????? ; 放置向量表

??????? * (+RW,+ZI)????????????????????????? ;

??? }

??? DUMP 0x08000000

??? {

??????? dump.o (foo)???????????????????????? ;

??? }

}

通過(guò)上面的Scatter文件,將init中的初始化段放在0x10000000地址,并將除foo外的只讀數(shù)據(jù)func1和c[]放在該初始段的后面;接下來(lái)的執(zhí)行域RAM放置向量表;最后的DUMP域放置由#pragma指定的段dump。

?

3.在代碼映像中保留空白域

可以在Scatter中使用 EMPTY 屬性為棧保留一個(gè)空白存儲(chǔ)器塊。該存儲(chǔ)塊不構(gòu)成載入?yún)^(qū)的一部分,但指定在執(zhí)行時(shí)使用。由于它創(chuàng)建為虛 ZI區(qū),所以 armlink 使用以下符號(hào)訪問(wèn)它:

·? Image$$region_name$$ZI$$Base;

·? Image$$region_name$$ZI$$Limit;

·? Image$$region_name$$ZI$$Length。

如果指定的長(zhǎng)度為負(fù)值,則Image$$region_name$$ZI$$Limit被視為域的結(jié)束地址。它是絕對(duì)地址,不是相對(duì)地址。下面例子顯示了如何在Scatter文件中預(yù)留一個(gè)空白區(qū)域。

LOADREGION ?0x700000?????????????????? ; 加載域的起始地址在0x700000

{?????????????????????????????????? ;

??? STACK 0x7000000 EMPTY –0x10000?????? ; 該域的結(jié)束地址為0x700000,因?yàn)槠溟L(zhǎng)度為負(fù)

??????????????????????????????????? ;

region

??????????????????????????????????? ;

??? {

??????????????????????????????????? ; 預(yù)留空白區(qū)放置棧

??? }

??? HEAP +0 EMPTY 0x10000?????????????? ; 棧的起始地址在上個(gè)預(yù)留區(qū)域介紹地址

??????????????????????????????????? ;

??????????????????????????????????? ;

??? {

??????????????????????????????????? ; 預(yù)留空白區(qū)域放置堆

??? }

??? ; rest of scatter description...

}

在上面的例子中定義了一個(gè)執(zhí)行域STACK 0x7000000 EMPTY -0x10000,它從地址 (0x7000000-0x1000)開(kāi)始,在地址0x7000000結(jié)束。

在此示例中,鏈接程序生成符號(hào):

Image$$STACK$$ZI$$Base????? = 0x6ff0000

Image$$STACK$$ZI$$Limit???? = 0x7000000

Image$$STACK$$ZI$$Length??? = 0x1000

Image$$HEAP$$ZI$$Base?????? = 0x7000000

Image$$HEAP$$ZI$$Limit????? = 0x7010000

Image$$HEAP$$ZI$$Length???? = 0x1000

EMPTY屬性僅適用于執(zhí)行區(qū)。如果在載入?yún)^(qū)定義中使用EMPTY屬性,則鏈接程序生成警告信息并忽略該屬性。鏈接程序檢查用于EMPTY區(qū)的地址空間不與任何其他執(zhí)行區(qū)重疊。

4.使用OVERLAY關(guān)鍵字

在ARM以前的編譯器中,沒(méi)有提供地址空間的重疊管理。如果有運(yùn)行時(shí)域地址空間重疊,需要用戶自己提供地址空間重疊的管理機(jī)制。但在RVDS的編譯器中,提供了運(yùn)行時(shí)域?qū)傩躁P(guān)鍵字OVERLAY,用戶可以使用該關(guān)鍵字生成自己的重疊空間。

下面例子顯示了如何使用OVERLAY關(guān)鍵字,生成運(yùn)行時(shí)域的重疊空間。

LOADREG 0x8000

{

???????????????????????????????????? ;

??? STATIC_RAM 0x0????????????????????? ; 靜態(tài)RAM區(qū),包含大部分的RW和ZI

??? {

??????????? * (+RW,+ZI)

??? }

??? OVERLAY_A_RAM 0x1000 OVERLAY????????? ; 重疊區(qū)...

??? {

??????????? module1.o (+RW,+ZI)

??? }

??? OVERLAY_B_RAM 0x1000 OVERLAY

??? {

??????????? module2.o (+RW,+ZI)

??? }

???????????????????????????????????? ;

}

5.在Scatter文件中使用預(yù)處理偽操作

可用在Scatter文件的第一行加上需要編譯器進(jìn)行預(yù)處理的操作。語(yǔ)法格式如下所示。

#! <preprocessor> [pre_processor_flags]

LOAD_FLASH ( 0x8000 + ( 0x2 * 0x400 ))? ;

例如:

#! armcc ?-E

聯(lián)接器可以對(duì)預(yù)處理的表達(dá)式進(jìn)行簡(jiǎn)單的計(jì)算,可以識(shí)別簡(jiǎn)單的運(yùn)算符如+、-、×、/、AND和OR,如:

#define AN_ADDRESS (BASE_ADDRESS+(ALIAS_NUMBER*ALIAS_SIZE))

同時(shí),也可以在Scatter文件頭加一些預(yù)處理的偽操作,如:

#define ADDRESS 0x20000000

#include "include_file_1.h"

#define BASE_ADDRESS 0x8000

#define ALIAS_NUMBER 0x2

#define ALIAS_SIZE 0x400

在Scatter文件中,使用預(yù)處理的更詳細(xì)的信息,請(qǐng)參見(jiàn)ARM相關(guān)文件。

?

13.4.4? 等效的簡(jiǎn)單映像分散載入描述

前面介紹了分散加載的命令行選項(xiàng),如-ro-base、-rw-base、-reloc、-split、-ropi和-rwpi。但在實(shí)際編程時(shí),因?yàn)槭褂肧catter文件可以產(chǎn)生更清晰的內(nèi)存映像視圖,所以最好使用Scatter文件對(duì)映像進(jìn)行加載。

本節(jié)詳細(xì)介紹如何將各分散加載的命令行選項(xiàng),替換為Scatter文件。

1.-ro-base address選項(xiàng)的替換

使用-ro-base address命令行鏈接產(chǎn)生的內(nèi)存映像由一個(gè)加載域和三個(gè)執(zhí)行域組成。執(zhí)行域放在存儲(chǔ)器映像中的相鄰位置。

選項(xiàng)中的address指定了加載域和第一個(gè)執(zhí)行域的起始地址(加載域和第一個(gè)執(zhí)行域的起始地址相同)。

下面的例子顯示了與“-ro-base? 0x8000”命令行選項(xiàng)等價(jià)的Scatter文件。

LOADREG 0x8000????? ;定義加載域的起始地址0x8000

{???????????????? ;

??? ROM ?+0????????? ;定義第一個(gè)執(zhí)行域的起始地址,該地址與加載域的起始地址相同,為0x8000

????????????????? ;

??? {

??????? *(+RO)?????? ;該域放置所有的RO段

??? }

??? RAM_RW ?+0?????? ;定義第二個(gè)執(zhí)行域,起始地址為0x8000+ROM段大小

????????????????? ;

??? {

??????? *(+RW)?????? ;將所有的RW代碼放置在該段

??? }

??? RAM_ZI +0??????? ;定義ZI段

????????????????? ;ZI段的起始地址為0x8000+ROM段的大小+RAM_RW段的大小

????????????????? ;

??? {

??????? *(+ZI)?????? ;放置所有的ZI段

??? }

}

上例中的Scatter文件創(chuàng)建的映像由一個(gè)加載域和三個(gè)執(zhí)行域組成。加載域的起始地址為0x8000。三個(gè)執(zhí)行域分別為ROM、RAM_RW和RAM_ZI,它們分別包含RO、RW和ZI輸出段。RO和RAM_RW為啟動(dòng)域,RAM_ZI在執(zhí)行時(shí)動(dòng)態(tài)創(chuàng)建。ROM的執(zhí)行地址是0x8000,通過(guò)對(duì)執(zhí)行區(qū)描述使用+offset格式的基址指定程序,所有三個(gè)執(zhí)行域在存儲(chǔ)器映射中相鄰放置,即前一個(gè)執(zhí)行域的末尾放置后一個(gè)執(zhí)行域。

如果鏈接程序時(shí),將-ro-base選項(xiàng)和-ropi混合使用,則可以生成位置無(wú)關(guān)代碼。

下面的例子顯示了與-ro-base 0x8000 -ropi等效的Scatter文件。

LOADREG ?0x8000 ?PI???????? ;加載域的地址為0x8000,并指定該加載域的屬性為PI

{

??? ROM ?+0??????????????? ;第一執(zhí)行域的地址為0x8000,而且該執(zhí)行域繼承了加載域的PI屬性

???????????????????????? ;所有該域的執(zhí)行地址是可變的

??? {

??????? *(+RO)????????????? ;放置所有的RO段

??? }

??? RAM_RW +0 ABSOLUTE????? ;使用ABSOLUTE屬性代替PI屬性

??? {

??????? *(+RW)????????????? ;放置RW段

??? }

??? RAM_ZI +0

??? {

??????? *(+ZI)

??? }

}

執(zhí)行域ROM從LOADREG加載域繼承 PI 屬性。下一個(gè)執(zhí)行域 RAM_RW 被標(biāo)記為 ABSOLUTE 所以其不再具有PI屬性。另外,因?yàn)镽AM_ZI 域使用了+0的偏移量,所以它從 RAM_RW域繼承 ABSOLUTE 屬性。

2.-ro-base和-rw-base選項(xiàng)的替換

使用-ro-base和-rw-base選項(xiàng)鏈接的映像也由一個(gè)加載域和三個(gè)執(zhí)行域組成,它與類型1生成的映像十分相似,只是此類映像的RW執(zhí)行區(qū)與RO執(zhí)行區(qū)不相鄰。

在-ro-base選項(xiàng)中指定加載域的起始地址,在-rw-base選項(xiàng)中指定執(zhí)行域的地址。

下面的例子顯示與使用-ro-base 0x8000 -rw-base 0x040000等效的分散載入描述。

LOADREG ?0x8000????????? ;定義加載域的起始地址為0x8000

{

??? ROM_RO +0??????????? ;定義第一個(gè)執(zhí)行域的起始地址為0x8000

??? {

??????? * (+RO)?????????? ;在該域中放置所有的RO段

??? }

??? RAM_RW 0x040000?????? ;第二個(gè)執(zhí)行域名為RAM_RW,起始地址為0x40000

??? {

??????? * (+RW)?????????? ;放置所有的RW段

??? }

??? RAM_ZI +0

??? {

??????? * (+ZI)?????????? ;放置所有的ZI段

??? }

}

該Scatter文件創(chuàng)建的映像有一個(gè)名為L(zhǎng)OADREG的加載域,載入地址是0x8000。該映像有3個(gè)執(zhí)行區(qū),分別為ROM、RAM_RW和RAM_ZI,它們分別包含RO、RW和ZI輸出段。其中,RO域是啟動(dòng)域,執(zhí)行地址是0x8000,RAM_RW執(zhí)行域與第一個(gè)執(zhí)行域RAM_RW不相鄰。其執(zhí)行地址是0x040000。緊隨其后的執(zhí)行區(qū)RAM_ZI放置所有的ZI數(shù)據(jù)。

另外,也可以將-rw-base和位置無(wú)關(guān)選項(xiàng)-rwpi配合使用,將RW輸出節(jié)的執(zhí)行區(qū)標(biāo)記為位置獨(dú)立。

下面的例子顯示了使用-ro-base 0x8000 -rw-base 0x40000 -rwpi等效的Scatter文件。

LOADREG ?0x0x8000????????????? ;定義加載域的起始地址為0x8000

{

??? ROM ?+0?????????????????? ;定義第一執(zhí)行域,其起始地址為0x8000

??? {

??? ????*(+RO)???????????????? ;放置所有RO段

??? }

??? RAM_RW ?0x40000 ?PI???????? ;設(shè)置第二執(zhí)行域的屬性為PI屬性

??? {

??????? *(+RW)

??? }

??? ER_ZI +0????????????????? ;繼承了PI屬性

??? {

??????? *(+ZI)

??? }

}

第一個(gè)執(zhí)行域ROM從加載域LOADREG繼承ABSOLUTE屬性。第二個(gè)執(zhí)行區(qū)RAM_RW標(biāo)記為PI屬性。另外,因?yàn)镋R_ZI區(qū)的偏移為+0,所以它從RAM_RW區(qū)繼承PI屬性。

?

3.-reloc -split選項(xiàng)的替換

使用-split選項(xiàng)生成的映像由兩個(gè)加載域和三個(gè)執(zhí)行域組成。

使用以下的鏈接選項(xiàng)重新分割并定位加載域。

·? -reloc

組合使用-reloc -split生成具有兩個(gè)加載域的映像,并且使加載域具有RELOC屬性。

·? -ro-base address1

指定包含RO輸出段的域的載入地址和執(zhí)行地址。

·? -ro-base address2

指定包含RW輸出段的域的載入地址和執(zhí)行地址。

·? -split

將默認(rèn)的單一加載域(包含RO和RW輸出段的加載域)分成兩個(gè)加載域。一個(gè)載入域包含RO輸出段,另一個(gè)包含RW輸出段。

下面的例子顯示了與使用-ro-base 0x8000 -rw-base 0x040000 -split等效的Scatter文件。

LOADREG1 ?0x8000??????????? ;指定第一個(gè)加載域的起始地址為0x8000

{???

??? ROM ?+0

??? {

??????? *(+RO)

??? }

}

LOADREG2 ?0x040000????????? ;第二個(gè)加載域的起始地址為0x40000

{

??? RAM_RW +0

??? {

??????? *(+RW)?????????????? ;放置所有的RW段

??? }

??? RAM_ZI +0?????

??? {

??????? *(+ZI)???

??? }

}

使用上例中的Scatter文件創(chuàng)建的內(nèi)存映像有兩個(gè)加載域,分別為L(zhǎng)OADREG1和LOADREG2,它們的起始地址分別為0x8000和0x040000。

該映像文件有三個(gè)執(zhí)行域,分別為ROM、RAM_RW和RAM_ZI,它們分別包含RO、RW和ZI輸出段。ROM的執(zhí)行地址是0x8000。

RAM_RW執(zhí)行域與ROM不相鄰。其執(zhí)行地址是0x040000。

執(zhí)行域RAM_ZI緊隨RAM_RW域放置。

可以使用-reloc選項(xiàng)和-split選項(xiàng)配合使用,指定兩個(gè)加載域具有RELOC屬性。

下面的例子顯示與使用-ro-base 0x8000 -rw-base 0x040000 -reloc -split等效的Scatter文件。

LOADREG ?0x010000 RELOC

{

???? ROM ?+ 0

???? {

???????? * (+RO)

???? }

}

LOADREG ?0x040000 RELOC

{

???? RAM_RW + 0

???? {

???????? * (+RW)

? ???}

???? RAM_ZI +0

???? {

???????? * (+ZI)

???? }

}

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(jiàn)(www.farsight.com.cn)是國(guó)內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國(guó)北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營(yíng)分公司。華清遠(yuǎn)見(jiàn)除提供嵌入式相關(guān)的長(zhǎng)期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開(kāi)出版70余本嵌入式/移動(dòng)開(kāi)發(fā)/物聯(lián)網(wǎng)相關(guān)圖書。企業(yè)理念:專業(yè)始于專注 卓識(shí)源于遠(yuǎn)見(jiàn)。企業(yè)價(jià)值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。