![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLw0EVPdXSE1UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0gDO0EDMyEjMzITMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
分散加載作用:
可以将代碼放入不同的存儲空間。
1.基本概念
了解分散加載檔案之前,首先需要了解Code、RO-Data、RW-Data、ZI-Data。
- Code:程式代碼
- RO-Data:程式中定義的常量以及const型資料
- RW-Data:已經初始化的靜态變量,變量有初始值
- ZI-Data:沒有初始化的靜态變量,變量沒有初始值
#define num (0x2000) /*RO-Data*/
char const flage = 5; /*RO-Data*/
char str[] = "str"; /*RW-Data*/
char a; /*ZI-Data*/
下圖為keil的map檔案
ROM(Flash)Size = Code + RO-Data + RW-Data
RAM Size = ZI-Data + RW-Data
RW-Data既占ROM,又占RAM原因:(RW-Data與ZI-Data存儲不同原因)
ZI段資料:程式隻需要根據編譯器配置設定給ZI段的基位址以及大小,将對應的RAM全部初始化為0即可。
RW段資料:首先編譯器需要将RW段資料的所有初始值儲存在ROM中,程式在執行時,再将ROM中儲存的資料搬到RAM中。是以,RW段資料兩者都占用空間,并且大小相同。
ZI段與RW段資料初始化
在執行main()函數之前,程式會執行__main()函數。該函數隻要包括_main()與_rt_entry()函數
_main():完成代碼與資料的拷貝,将ZI段資料清零。
- 将代碼拷貝到映射的空間運作。比如:将代碼拷貝到RAM中運作
- 資料拷貝:完成ZI段資料清零與RW段資料指派
_rt_entry():将堆、棧等初始化。之後該函數會跳轉到main()函數
2.分散加載檔案介紹
該檔案用來描述連結器生成映像檔案時需要的資訊。
該可以指定生成映像檔案時Code、RO-Data、RW-DATA、ZI-DATA資料的存放位址。
2.1分散加載檔案文法
分散加載檔案由一個加載時域與多個運作時域構成。基本結構如下圖:
2.1.1加載時域文法:
load_region_name(base_address|("+"offset))[attribute_list][max_size] {
execution_region_description+
}
- load_region_name:該加載時域的名字
-
base_address:該加載時域的起始位址。有兩種書寫方式:
base_address:表示該加載時域中的對象在連接配接時的起始位址,位址必須位元組對齊
+offset:表示本加載時域的中的對象在連接配接時的起始位址是前一個加載時域的結束位址後偏移offset位元組處。若該加載時域為第一個加載時域,則其起始位址為offset。offset數值必須能夠被4整除。
-
attribute_list:指定該加載時域内容的屬性。一般為ABSOLUTE。
ABSOLUTE:絕對位址;
PI:與位置無關;
RELOC:可重定位;
OVERLAY:覆寫;
NOCOMPRESS:不能壓縮;
- max_size:該加載時域的最大尺寸。若該加載時域的實際尺寸超出了max_size,連接配接器将會報錯。
- execution_region_description:運作時域。+表示可以有一個或多個運作時域。
2.1.2運作時域文法:
exec_region_name(base_address|"+"offset)[attribute_list][max_size|" "length]) {
input_section_description*
}
- exec_region_name:該運作時域的名字
- base_address:同加載時域
-
attribute_list:指本運作時域的内容屬性
ABSOLUTE:絕對位址;
PI:與位置無關;
RELOC:可重定位;
OVERLAY:覆寫;
FIXED:固定位址。
ALIGNalignment:将執行區的對齊限制從4增加到alignment。alignment的值必須為2的正數幂。若執行區有base_address,則它需要與alignment對齊。若執行區有offset,則連結器将計算的區基址與alignment邊界對齊。
EMPTY:将執行區中保留一個給定長度的空白記憶體塊,一般提供給堆或棧使用。
ZEROPAD:零初始化的段作為零填充塊寫入ELF檔案。是以,運作時不需要使用零進行填充。
PADVALUE:定義任何填充的值。
NOCOMPRESS:不能進行壓縮。
UNINIT:未初始化的資料。
- max_size:同加載時域。
- length:若指定的長度為負值,則将base_address作為區的結束位址。通常與EMPTY一起使用,用來表示記憶體中變小的堆棧。
- input_section_description:指定輸入段的内容。
2.1.3輸入段描述:
module_select_pattern [ "(" input_section_selector ( "," input_section_selector )* ")" ]
("+" input_section_attr | input_section_pattern | input_symbol_pattern)
-
module_select_pattern :檔案過濾器。支援使用通配符"*“與”?"。字元比對時,不區分大小寫。
*:表示零個或多個字元。
?:表示單個字元。
-
input_section_attr :屬性選擇器與輸入段屬性相比對。每個input_section_attr前都會有+号。緊靠+号前的逗号都可以省略。若要指定一個模式以比對輸入段名稱,則名稱前面需要有+号。選擇器不區分大小寫。可以識别以下選擇器。
RO-CODE(CODE)
RO-DATA(CONST)
RO,包含RO-DATA與 RO-CODE(TEXT)
RW-CODE
RW-DATA
RW,包含RW-DATA與 RW-CODE(DATA)
ZI(BSS)
ENTRY,包含ENTRY之外的段。
通過使用特殊子產品選擇器模式.ANY可以将輸入段配置設定給執行區,而無需考慮其父子產品。可以使用一個或多個.ANY模式以任意配置設定方式填充運作時域。在大多數情況下,使用單個.ANY等效于使用*子產品選擇器。