armlink 第四章 scatter文件舉例
在前面學習了基本術語和概念之後,本章是加強scatter編寫能力的章節。
4.1 什麼時候使用scatter文件
scatter文件通常用於嵌入式系統中,因爲這些系統含有ROM,RAM,還有一些內存映射的外設。下面的場景常使用scatter文件:
-
複雜的內存映射:放在不同內存區域的section,需要使用scatter文件來更精細的操控放置的位置
-
不同的存儲類型:許多系統包含各種各樣的存儲設備,如flash,ROM,SDRAM,SRAM等。這時可以使用scatter文件,將更適合的存儲區域放置更適合的代碼。例如:中斷代碼放置在SRAM中,已達到快速響應的目的;而不頻繁訪問的配置信息可以放置在flash存儲中。
-
內存映射的外設:在內存映射機制下,scatter文件可以在一個精確的地址放置數據section。這樣訪問這個數據section就相當於訪問對應的外設。
-
在固定地址存放函數:即使修改並重新編譯了應用程序,而跟應用程序緊密相關的函數還是可以放置在一個固定的位置。這個對於跳轉表的實現非常有用。
-
使用符號標記堆和棧:當應用被鏈接時,可以爲堆和棧定義符號
4.2 在scatter文件中指定堆和棧
在c語言中,常常需要兩個存儲區域,堆和棧。在所有的內存都由我們分配的情況下,堆和棧也需要我們進行分配。
在程序開始運行之前,會調用__user_setup_stackheap()函數,它負責初始化堆和棧。而這個函數根據我們在scatter文件中的設置來初始化。
要想正確的初始化堆和棧。我們需要在scatter文件中定義兩個特殊的執行region。分別叫做ARM_LIB_HEAP 和ARM_LIB_STACK。這兩段內存由c庫進行初始化,所以不能放置任何輸入section,此時應該設置EMPTY屬性。同時也可以給這兩個內存區域設置基址和大小。如下:
LOAD_FLASH …
{
…
ARM_LIB_STACK 0x40000 EMPTY -0x20000 ; 棧區,向下增長
{ }
ARM_LIB_HEAP 0x28000000 EMPTY 0x80000 ; 堆區向上增長
{ }
…
}
當然還有更簡單的用法,只需要定義一個特殊的執行region,叫做ARM_LIB_STACKHEAP,同樣他需要有EMPTY屬性,並設置基址和大小
4.3 使用scatter文件描述一個簡單的鏡像
如下圖,是一個簡單的鏡像內存視圖。
下面根據這個圖,來寫一個scatter文件
LOAD_ROM 0x0000 0x8000 ; 加載region的名字叫LOAD_ROM
; 基址0x0000
; 最大大小0x8000
{
EXEC_ROM 0x0000 0x8000 ; 第一執行region的名字叫做EXEC_ROM
; 基址0x000
; 最大大小0x8000
{
* (+RO) ; 放置所有的代碼和RO數據
}
SRAM 0x10000 0x6000 ; 第二個執行region叫SRAM
; 基址 0x10000
; 最大大小 0x6000
{
* (+RW, +ZI) ; 放置所有的RW數據和ZI數據
}
}
4.4 使用scatter文件描述一個稍微複雜的鏡像
如下圖
下面的例子展示了上圖對應的scatter描述
LOAD_ROM_1 0x0000 ; 第一個加載region的基址爲0x0000
{
EXEC_ROM_1 0x0000 ; 第一個執行region的基址爲0x0000
{
program1.o (+RO) ; 放置programe1.o中的所有的代碼和RO數據
}
DRAM 0x18000 0x8000 ; 這個執行region的基址爲0x18000,最大大小爲0x8000
{
program1.o (+RW, +ZI) ; 放置program1.o中的所有的RW數據和ZI數據
}
}
LOAD_ROM_2 0x4000 ; 第二個加載region的基址爲0x4000
{
EXEC_ROM_2 0x4000
{
program2.o (+RO) ; 放置programe2.o中的所有的代碼和RO數據
}
SRAM 0x8000 0x8000
{
program2.o (+RW, +ZI) ; 放置program2.o中所有的RW數據,和ZI數據
}
}
注意:在上面這個例子中,如果再次新增一個program3.o文件。我們需要將program3.o也放置進去。當然,你也可以使用通配符*,或者.ANY來匹配剩下的所有文件。
4.5 在指定地址放置函數和數據
爲了單獨放置函數和數據,需要將這些函數和數據與源文件中的剩下的部分分開來對待。
鏈接器有兩種方法使我們能夠在指定位置放置section:
- 在scatter文件中定義一個指定位置的執行region,然後在這個region中放置需要的section。
- 定義"__at" section .這些特殊section能夠根據名字而獲得放置地址。
爲了將函數或者數據放置在一個特殊位置,他們必須放置在某個section中。下面幾種方式可以達到此目的:
- 放置函數和數據在他們自己單獨的源文件中
- 使用__attribute__((at(address)))將變量放置在指定位置的section中
- 使用__attribute__((section(“name”)))將函數或者變量放置在指定名字的section中。
- 在彙編代碼中,使用AREA僞指令。因爲AREA僞指令是彙編當中最小的可定位的單元
- 使用–split_sectoins 編譯選項,爲每個源文件中的函數生成一個section
下面舉例說明。
4.5.1 不使用scatter,在指定的地址放置變量
- 創建main.c源文件包含下面的代碼
#include <stdio.h>
extern int sqr(int n1);
int gSquared __attribute__((at(0x5000))); //放在0x5000
int main()
{
gSquared=sqr(3);
printf("Value squared is: %d\n", gSquared);
}
- 創建function.c源文件包含下面的代碼
int sqr(int n1)
{
return n1*n1;
}
- 編譯並連接源文件:
armcc -c -g function.c
armcc -c -g main.c
armlink --map function.o main.o -o squared.axf
--map表示顯示內存映射。
在上面例子中,__attribute__((at(0x5000)))指示全局變量gSquared放置於絕對地址0x5000處。
內存映射如下:
…
Load Region LR$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000000, Max: 0x00000004,ABSOLUTE)
Execution Region ER$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000004, Max:0x00000004, ABSOLUTE, UNINIT)
Base Addr Size Type Attr Idx E Section Name Object
0x00005000 0x00000004 Zero RW 13 .ARM.__at_0x00005000 main.o
4.5.2 使用scatter,在一個命名的section中放置變量
- 創建main.c包含如下源文件
#include <stdio.h>
extern int sqr(int n1);
int gSquared __attribute__((section("foo"))); //放置在名字叫foo的section中
int main()
{
gSquared=sqr(3);
printf("Value squared is: %d\n", gSquared);
}
- 創建functio.c包含下面代碼
int sqr(int n1)
{
return n1*n1;
}
- 創建scatter文件scatter.scat 包含如下配置
LR1 0x0000 0x20000
{
ER1 0x0 0x2000
{
*(+RO) ; 餘下的代碼和只讀數據放置在此處
}
ER2 0x8000 0x2000
{
main.o
}
ER3 0x10000 0x2000
{
function.o
*(foo) ; 將gSquared放置在此處
}
; RW和ZI數據放置在0x200000處
RAM 0x200000 (0x1FF00-0x2000)
{
*(+RW, +ZI)
}
ARM_LIB_STACK 0x800000 EMPTY -0x10000
{
}
ARM_LIB_HEAP +0 EMPTY 0x10000
{
}
}
ARM_LIB_STACK 和 ARM_LIB_HEAP region是必須的,因爲程序和c庫進行鏈接
- 編譯並鏈接源文件
armcc -c -g function.c
armcc -c -g main.c
armlink --map --scatter=scatter.scat function.o main.o -o squared.axf
上例,__attribute__((section(“foo”))) 指示了gSquared 被放置在名字叫foo的section中。scatter文件也說明了將foo section放置在ER3執行region中。
內存映射如下:
Load Region LR1 (Base: 0x00000000, Size: 0x00001570, Max: 0x00020000, ABSOLUTE)
…
Execution Region ER3 (Base: 0x00010000, Size: 0x00000010, Max: 0x00002000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00010000 0x0000000c Code RO 3 .text function.o
0x0001000c 0x00000004 Data RW 15 foo main.o
…
4.5.3 在指定位置放置變量
- 創建main.c文件,如下;
#include <stdio.h>
extern int sqr(int n1);
// 在0x10000處放置
const int gValue __attribute__((section(".ARM.__at_0x10000"))) = 3;
int main()
{
int squared;
squared=sqr(gValue);
printf("Value squared is: %d\n", squared);
}
- 創建functon.c源文件,如下:
int sqr(int n1)
{
return n1*n1;
}
- 創建scatter文件scatter.scat如下:
LR1 0x0
{
ER1 0x0
{
*(+RO) ; 剩下的只讀代碼
}
ER2 +0
{
function.o
*(.ARM.__at_0x10000) ; 放置gValue在0x10000
}
; RW和ZI放置在0x200000
RAM 0x200000 (0x1FF00-0x2000)
{
*(+RW, +ZI)
}
ARM_LIB_STACK 0x800000 EMPTY -0x10000
{
}
ARM_LIB_HEAP +0 EMPTY 0x10000
{
}
}
- 編譯並鏈接源文件
armcc -c -g function.c
armcc -c -g main.c
armlink --no_autoat --scatter=scatter.scat --map function.o main.o -o squared.axf
從內存映射圖中,可以看到變量在ER2中的0x10000處
…
Execution Region ER2 (Base: 0x00001578, Size: 0x0000ea8c, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00001578 0x0000000c Code RO 3 .text function.o
0x00001584 0x0000ea7c PAD
0x00010000 0x00000004 Data RO 15 .ARM.__at_0x10000 main.o
…
在這個例子中,ER1的大小未知。因此,gValue可能被放置ER1也可能放置在ER2中。
爲了保證放在ER2中,你必須在ER2中包含對應的section匹配文字。並且在鏈接的時候,還必須指定--no_autoat命令行選項。
如果忽略了--no_autoat選項,gValue將被單獨放置,對應於
LR$$.ARM.__at_0x10000加載region。
該region包含的執行region爲
ER$$.ARM.__at_0x10000
注意:at形式的縮寫。
//放置 variable1 在 .ARM.__AT_0x00008000處 int variable1 __attribute__((at(0x8000))) = 10; //放置 variable2 在.ARM.__at_0x8000處 int variable2 __attribute__((section(".ARM.__at_0x8000"))) = 10;
上面的section名字,忽略大小寫
__at具有如下的限制:
- __at section的地址範圍內不能覆蓋。
- __at section不準放在位置無關的執行region中
- __at section不能引用鏈接器定義的這些符號:
$$Base,$$Limit,$$Length.
- __at section 不準用在SysV,BPABI,以及BPABI的動態鏈接庫上。
- __at section 的地址必須是對齊的整數倍
- __at section 忽略+FIRST後者+LAST
4.6 __at section的自動放置
鏈接器自動放置__at section。當然也可以手動放置,在下一小節中介紹
鏈接器通過--autoat指示鏈接器自動放置__at setcion。這個選項默認是打開的。
當使用--autoat鏈接時,__at section 不會被放置在scatter文件中的與section模式字符串匹配的region中。而是將這個section放在一個兼容的region中。如果沒有兼容的region,則創建兼容的region。
帶有--autoat選項的所有鏈接器,創建的region都有UNINIT屬性。如果需要將這個__at section放置在一個ZI region中,則必須放置在兼容region中。
兼容region滿足如下條件:
-
__at 的地址剛好處在執行region的地址範圍內。如果一個region沒有設置最大大小,鏈接器將排除__at section之後,計算大小,這個大小再加上一個常量作爲其最後的大小。這個常量默認值爲10240字節。他可以通過--max_er_extension命令行選項來調整。
-
這個執行region還需要滿足如下的條件:
- 具有模式字符串,並能夠匹配這個section
- 至少有一個section和__at section 具有相同的類型(RO,RW,ZI)
- 沒有EMPTY屬性
來個例子:
//放置RW變量在叫做.ARM.__at_0x02000的section中
int foo __attribute__((section(".ARM.__at_0x2000"))) = 100;
//放置ZI變量在.ARM.__at_0x4000的section中
int bar __attribute__((section(".ARM.__at_0x4000"),zero_init));
//放置ZI變量在.ARM.__at_0x8000的section中
int variable __attribute__((section(".ARM.__at_0x8000"),zero_init));
對應的scatter文件如下:
LR1 0x0
{
ER_RO 0x0 0x2000
{
*(+RO) ; .ARM.__at_0x0000 lies within the bounds of ER_RO
}
ER_RW 0x2000 0x2000
{
*(+RW) ; .ARM.__at_0x2000 lies within the bounds of ER_RW
}
ER_ZI 0x4000 0x2000
{
*(+ZI) ; .ARM.__at_0x4000 lies within the bounds of ER_ZI
}
}
; 鏈接器爲.ARM.__at_0x8000創建一個加載和執行region。因爲它超出了所有候選region的大小。
4.7 手動放置__at section
使用--no_autoat命令行選項,然後使用標準的模式匹配字符串去控制__at section的放置。
舉例如下:
//放置RO變量在.ARM.__at_0x2000
const int FOO __attribute__((section(".ARM.__at_0x2000"))) = 100;
//放置RW變量在.ARM.__at_0x4000
int bar __attribute__((section(".ARM.__at_0x4000")));
對應的scatter文件如下:
LR1 0x0
{
ER_RO 0x0 0x2000
{
*(+RO) ; .ARM.__at_0x0000 is selected by +RO
}
ER_RO2 0x2000
{
*(.ARM.__at_0x02000) ; .ARM.__at_0x2000 is selected by the section named
; .ARM.__at_0x2000
}
ER2 0x4000
{
*(+RW +ZI) ; .ARM.__at_0x4000 is selected by +RW
}
}
4.8 使用__at 映射一個外設寄存器
爲了將一個未初始化的變量映射爲一個外設寄存器。可以使用ZI __at section。
假設這個寄存器的地址爲0x10000000,定義一個section叫做.ARM.__at_0x10000000.如下:
int foo __attribute__((section(".ARM.__at_0x10000000"),zero_init))
手動放置的scatter文件如下:
ER_PERIPHERAL 0x10000000 UNINIT
{
*(.ARM.__at_0x10000000)
}
4.9 使用.ANY 來放置未分配的 section
在大多數情況下,單個.ANY 等價於使用*。但是,.ANY 可以出現在多個執行region中。
4.9.1 多個.ANY 的放置規則
當使用多個.ANY時,鏈接器有自己默認的規則來組織section。
當多個.ANY 存在於scatter文件中時,鏈接器以section的大小,從大到小排序。
如果多個執行region都有相同特性(後文稱爲等價)的.ANY,那麼這個section會被分配到具有最多可用空間的region中。
例如:
- 如果有兩個等價的執行region,一個大小爲0x2000,另一個沒有限制。那麼.ANY匹配的section會放置在第二個中。
- 如果有兩個等價的執行region,一個大小爲0x2000,另一個爲0x3000. 那麼.ANY匹配的section會先放置在第二個中,直到第二個的大小小於第一個。
相當於這個兩個執行region在交替放置。
4.9.2 命令行選項控制多個.ANY的放置
可以通過命令行選項,控制.ANY的排序,下面的命令行選項是可用的:
-
--any_placement=algorithm algorithm是如下之一:first_fit,worst_fit,best_fit,或者next_fit
-
--any_sort_order=order.此處order是如下之一:cmdline或者descending_size
當你想要按照順序填充region時,使用first_fit
當你想要填滿整個region時,使用best_fit
當你想要均勻填充region時,使用worst_fit
當你想要更精確的填充時,使用next_fit
因爲,鏈接器會產生veneer代碼以及填充數據,而這些代碼的是在.ANY匹配之後產生的。所以,如果.ANY將region填滿,則很有可能導致整個regoin無法放置,鏈接器產生的代碼。鏈接器會產生如下的錯誤。
Error: L6220E: Execution region regionname size (size bytes) exceeds limit (limit bytes)
--any_contingency選項防止鏈接器將region的大小填滿。它保留region的一部分空間。當鏈接器產生的代碼沒有空間時,就使用這部分保留的空間。
first_fit和best_fit 默認打開這個選項。
4.9.3 優先級
.ANY 還可以指定優先級。
優先級通過後面接一個數字來表示,從0開始遞增。數字越大優先級越高。
例子如下:
lr1 0x8000 1024
{
er1 +0 512
{
.ANY1(+RO) ; 優先級較低,和er3交替均勻填充
}
er2 +0 256
{
.ANY2(+RO) ; 優先級最高,先填充這個
}
er3 +0 256
{
.ANY1(+RO) ;優先級較低,和er1交替均勻填充
}
}
4.9.4 指定.ANY的最大大小
使用ANY_SIZE max_size 指定最大大小。
例子如下:
LOAD_REGION 0x0 0x3000
{
ER_1 0x0 ANY_SIZE 0xF00 0x1000
{
.ANY
}
ER_2 0x0 ANY_SIZE 0xFB0 0x1000
{
.ANY
}
ER_3 0x0 ANY_SIZE 0x1000 0x1000
{
.ANY
}
}
上面例子中:
- ER_1 有0x100的保留空間,該保留空間用於鏈接器產生的內容
- ER_2 有0x50的保留空間
- ER_3 沒有保留空間。region將會被填滿。應該將ANY_SIZE的大小,限制在region大小的98%以內。以預留2%用於鏈接器產生的內容。
4.9.5 例子1
有6個同樣大小的section。如下:
名字 | 大小 |
---|---|
sec1 | 0x4 |
sec2 | 0x4 |
sec3 | 0x4 |
sec4 | 0x4 |
sec5 | 0x4 |
sec6 | 0x4 |
對應的scatter文件如下:
LR 0x100
{
ER_1 0x100 0x10
{
.ANY
}
ER_2 0x200 0x10
{
.ANY
}
}
- 對於first_fit: 首先分配所有section到ER_1中,然後再是ER_2中
- 對於next_fit:跟first_fit一樣,但是ER_1會被填滿,然後被標記爲FULL。
- 對於best_fit: 首先sec1分配到ER_1中,然後ER_2和ER_1優先級相同,且ER_2空間比ER_1空間大,接着分配sec2到ER_1中。直到ER_1填滿
- 對於worst_fit:首先分配sec1到ER_1中,然後ER_2空間比ER_1大,接着分配sec2到ER_2中。剩下的兩個region空間一樣大,且優先級相同,然後選擇scatter的第一個,將sec3分配到ER_1中,依次類推。
4.9.6 例子2——使用next_fit
有下面的section:
名字 | 大小 |
---|---|
sec1 | 0x14 |
sec2 | 0x14 |
sec3 | 0x10 |
sec4 | 0x4 |
sec5 | 0x4 |
sec6 | 0x4 |
對應的scatter如下:
LR 0x100
{
ER_1 0x100 0x20
{
.ANY1(+RO-CODE)
}
ER_2 0x200 0x20
{
.ANY2(+RO)
}
ER_3 0x300 0x20
{
.ANY3(+RO)
}
}
詳細步驟如下:
- 首先sec1 被分配給ER_1.因爲ER_1有更佳的匹配。ER_1現在還剩下0x6個字節
- 鏈接器嘗試將sec2分配給ER_1,因爲它有更佳的匹配。但是ER_1沒有足夠的空間。因此ER_1被標記爲FULL,並且在後續的過程中再也不會考慮給ER_1分配section。鏈接器選擇ER_3,因爲它有更高的優先級
- 鏈接器嘗試將sec3分配給ER_3,但是無法放入,因此被標記爲FULL,接着鏈接器將sec3放在ER_2中。
- 鏈接器現在處理sec4.它大小爲0x4,適合ER_1和ER_3.但是這兩個在前面步驟中被標記爲FULL。因此剩下的section被放置在ER_2中。
- 如果還有一個section叫做sec7,且大小爲0x8.他將鏈接失敗。
4.9.7 例子三
有兩個文件sections_a.o和sections_b.o,如下:
名字 | 大小 |
---|---|
seca_1 | 0x4 |
seca_2 | 0x4 |
seca_3 | 0x10 |
seca_4 | 0x14 |
名字 | 大小 |
---|---|
secb_1 | 0x4 |
secb_2 | 0x4 |
secb_3 | 0x10 |
secb_4 | 0x14 |
使用如下命令:
--any_sort_order=descending_size sections_a.o sections_b.o --scatter scatter.txt
排序之後,如下:
名字 | 大小 |
---|---|
seca_4 | 0x14 |
secb_4 | 0x14 |
seca_3 | 0x10 |
secb_3 | 0x10 |
seca_1 | 0x4 |
seca_2 | 0x4 |
secb_1 | 0x4 |
secb_2 | 0x4 |
如果使用如下命令:
--any_sort_order=cmdline sections_a.o sections_b.o --scatter scatter.txt
排序之後如下:
名字 | 大小 |
---|---|
seca_1 | 0x4 |
secb_1 | 0x4 |
seca_2 | 0x4 |
secb_2 | 0x4 |
seca_3 | 0x10 |
secb_3 | 0x10 |
seca_4 | 0x14 |
secb_4 | 0x14 |
4.10 控制venner的放置
在scatter文件中,還可以放置venner代碼。使用Venner$$Code來匹配venner代碼。
4.11 帶有OVERLAY屬性的放置
可以在同一個地址中,放置多個執行region。因此在某一個時刻,只有一個執行region被激活。
如下面的例子:
EMB_APP 0x8000
{
...
STATIC_RAM 0x0
{
*(+RW,+ZI)
}
OVERLAY_A_RAM 0x1000 OVERLAY
{
module1.o (+RW,+ZI)
}
OVERLAY_B_RAM 0x1000 OVERLAY
{
module2.o (+RW,+ZI)
}
...
}
被OVERLAY標記的region,在啓動的時候,不會被c庫初始化。而這部分內存的內容由overlay 管理器負責。如果這部分region包含有初始化數據。需要使用NOCOMPRESS屬性來阻止RW 數據的壓縮。
OVERLAY 屬性還可以用在單個執行region中,因此,這個region可以被用作:防止c庫初始化某個region
OVERLAY region也可以使用相對基址。如果他們有相同的偏移,則連續放置在一起。
如下例子:
EMB_APP 0x8000{
CODE 0x8000
{
*(+RO)
}
# REGION1 的基址爲 CODE的結尾
REGION1 +0 OVERLAY
{
module1.o(*)
}
# REGION2 的基址爲REGION1的基址
REGION2 +0 OVERLAY
{
module2.o(*)
}
# REGION3 的基址和REGION2的基址相同
REGION3 +0 OVERLAY
{
module3.o(*)
}
# REGION4 的基址爲 REGION3的結尾+4
Region4 +4 OVERLAY
{
module4.o(*)
}
}
4.12 預留一個空region
可以在scatter文件中,預留一個空的內存區域,比如:將此區域用於棧。使用EMPTY屬性可以達到此效果。
爲了預留一個空的內存用於棧。對應的加載region沒有,執行region在執行時被分配。它被當做dummy ZI region對待,鏈接器使用下面的符號訪問它:
1. Image$$region_name$$ZI$$Base
2. Image$$region_name$$ZI$$Limit
3. Image$$region_name$$ZI$$Length
注意:dummy ZI region 在運行時並不會被初始化爲0
如果長度爲負數,給定的地址就是結束地址。
例子如下:
LR_1 0x80000 ;加載region從0x80000開始
{
STACK 0x800000 EMPTY -0x10000 ;region 結束地址爲0x800000,開始地址使用長度進行計算
{
;空region用於放置棧
}
HEAP +0 EMPTY 0x10000 ; region從上一個region結束處開始。
{
}
...
}
下圖展示了這個例子:
4.13 c和c++ 庫代碼的放置
可以在scatter文件中,放置c和c++ 庫代碼。
在scatter文件中使用,*armlib* 或者 *cpplib* 來索引庫名字。一些ARM c c++庫的section必須放在root region中。例如:__main.o,__scatter*.o,__dc*.o,*Region$$Table.
鏈接器可以在InRoot$$Sections中自動的,可靠的,放置這些section。
例子1如下:
ROM_LOAD 0x0000 0x4000
{
ROM_EXEC 0x0000 0x4000 ; 在0x0處的root region
{
vectors.o (Vect, +FIRST) ; 向量表
* (InRoot$$Sections) ; 所有的庫section 必須放置在root region中。如__main.o,__scatter*.o,__dc*.o,*Region$$Table
}
RAM 0x10000 0x8000
{
* (+RO, +RW, +ZI) ; 所有的其他的section
}
}
例子2:arm c庫的例子
ROM1 0
{
* (InRoot$$Sections)
* (+RO)
}
ROM2 0x1000
{
*armlib/c_* (+RO) ; 所有arm支持的c庫函數
}
ROM3 0x2000
{
*armlib/h_* (+RO) ; just the ARM-supplied __ARM_*
; redistributable library functions
}
RAM1 0x3000
{
*armlib* (+RO) ; 其他的arm支持的庫,如,浮點庫
}
RAM2 0x4000
{
* (+RW, +ZI)
}
名稱ARM lib表示位於install_directory\lib\armlib目錄中的ARM C庫文件
例子3:arm c++ 庫代碼的放置
#include <iostrem>
using namespace std;
extern "C" int foo(){
cout << "Hello" << endl;
return 1;
}
爲了放置c++ 庫代碼,定義如下的scatter文件
LR 0x0
{
ER1 0x0
{
*armlib*(+RO)
}
ER2 +0
{
*cpplib*(+RO)
*(.init_array) ; .init_array 必須顯示放置,因爲它被兩個region共享,鏈接器無法決定怎麼放置
}
ER3 +0
{
*(+RO)
}
ER4 +0
{
*(+RW,+ZI)
}
}
名稱install_directory\lib\armlib表示位於armlib目錄中的ARM C庫文件
名稱install_directory\lib\cpplib表示位於cpplib目錄中的ARM c++庫文件
4.14 scatter文件的預處理
在scatter文件的第一行,設置一個預處理命令。然後鏈接器會調用相應的預處理器先處理這個文件。預處理命令的格式如下:
#! preprocessor [pre_processor_flags]
最常見的預處理命令如下:
#! armcc -E
舉例如下:
#! armcc -E
#define ADDRESS 0x20000000
#include "include_file_1.h"
lr1 ADDRESS
{
}
也可以在命令行中,進行預處理,如下:
armlink --predefine="-DADDRESS=0x20000000" --scatter=file.scat
armlink 系列完。
下一篇 從arm彙編到使用匯編點亮一個LED。