原由:
不知為什麼,總是有人來問我這個問題。
Q:怎樣將一個global varible(RW/RO)指定到其一特定位置上?
所以,雖然我目前沒有用到這個功能。
這一項好像大多用到有外部記憶体裝置(SDRAM)的系統上,而SOC本身並沒有RAM/或不夠時
才需要這項功能。
但也有人是將特定資訊(版本控制、加密)等....,而使用的。總之,我也試著實作了。
1.what is linker (scatter)
請參照:
https://sourceware.org/binutils/docs-2.18/ld/Scripts.html#Scripts
2.為什麼要用這個
我們編輯出的程式在ROM/Flash長怎樣(先不管格式);
而在執行又長怎樣?
3.how to do this on keil C
在keil C中Project中的Options for …Linker Tab可以找到(Scatter.ld)
p.s: 你也必須注意到,下面的Misc control 及Liker control string(不可改寫, 但你可以由Misc control中去改)
在某些project不知為何scatter file不能改。
4.
在這個linker scatter中內容(注意的是它的格式,函空格/Tab 對齊等)
A.目前的(標準的,大致都長的像這樣)
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x00014000 0x0002B000 { ; load region size_region
ER_IROM1 0x00014000 0x0002B000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20002000 0x00002000 { ; RW data
.ANY (+RW +ZI)
}
}
可以很簡單的看其它的section及配置
5.
A.在某個 *.c /*.s中宣告你要的變數,但一定要是全域(非static)才可以讓在object中可見symbol
(一般可以nm去看,但keil C好像沒看到)
在這裡只簡單地以 *.s實作.
可以參考,原本的寫法(注意它的格式及format)
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
SPACE Heap_Size
__heap_limit
B.加入我們自己的
AREA STEVEN_DATA, DATA, READWRITE
EXPORT __TEST_STEVEN
DCD 0;
C.修改原本的,加入
TEST_IRAM1 0x2002000 0x00000004 {
*.o (STEVEN_DATA, +First)
}
D.指定其linker Scatter(若在scatter中不能指定時,直接在misc controls 覆寫設定。
E. 去看它的map file(同在project 中listing Tab打開它)
F.compiler後,檢查
我目標是將它(TEST_STEVEN)放在第一個位置上。
Execution Region TEST_IRAM1 (Base: 0x02002000, Size: 0x00000004, Max: 0x00000004, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x02002000 0x00000004 Data RW 4 STEVEN_DATA arm_startup_nrf51.o
I.
那要如何使用它,這裡我舉出一個方法。理應有好幾種方式處理
macro
#define STEVEN (*((volatile unsigned int*) 0x20002000))
這樣子就可以把它當作一個register來使用了,同mcu中去存取control register一樣
STEVEN=11;
----------------------------------------------------------------------------------------------------------------------
上個範例是指定RW(即可變的)
而這次是另外一個案子(不同系統的),但改為RO(read only)
其前面的步驟,是類似的。
檢查其
在keil C中Project中的Options for …Linker Tab可以找到(Scatter.ld)
及其相關設定Misc control 及Liker control string
打開這個project的linker scripter
#!armcc -E --device=DARMCM1
#define ROM_SIZE 0x23400
#define SRAM_START 0x20000000
#define SRAM_SIZE 0x3000
_ROM 0x00000 ROM_SIZE
{
_RESET +0
{
boot_ISD9xx.o
}
_CODE +0
{
* (+RO)
}
_SRAM SRAM_START ALIGN 4
{
* (+RW, +ZI)
}
_Overlap_1 +0 ALIGN 4 OVERLAY
{
featurex.o(+RW,+ZI)
audioadccontrol.o(+RW,+ZI)
VR.o(+RW,+ZI)
Recording.o(+RW,+ZI)
}
_Overlap_2 +0 ALIGN 4 OVERLAY
{
ShareRam.o(+RW,+ZI)
}
}
和前面的不同了,若要修改還是應詢問相關人員(看起來還滿像是gnu的寫法,可能由那改過的)。這裡我們先不去管它。
其misc control
--map --first='boot.o(vectors)' --datacompressor=off --info=inline --entry Reset_Handler
相同地,都是必須要將VIC(interrupt vector)放在第一位(0x0000)。
所以我們可將其固定RO data放在它的後面。
1.這次我們改以 *.C 來作。
所以create a c file (test.c)
const unsigned int TEST=0xA5A5A5;
2.因為keil c ,會幫你最佳化動作。
所以,你必須先把這個拿去用。(即被其它人參照)
在這裡我將它的compiler設定成:(最少動作)
ps .在mian.c(或其它file中,把它參照到)
目前其optimzation 必須設O0
3.改寫linker scripter
加入
_RESET +0
{
boot_ISD9xx.o
boot.o(vectors)
}
_ABC +0
{
test.o(+RO)
}
最後變成
#!armcc -E --device=DARMCM1
#define ROM_SIZE 0x23400
#define SRAM_START 0x20000000
#define SRAM_SIZE 0x3000
_ROM 0x00000 ROM_SIZE
{
_RESET +0
{
boot_ISD9xx.o
boot.o(vectors)
}
_ABC +0
{
test.o(+RO)
}
_CODE +0
{
* (+RO)
}
_SRAM SRAM_START ALIGN 4
{
* (+RW, +ZI)
}
_Overlap_1 +0 ALIGN 4 OVERLAY
{
featurex.o(+RW,+ZI)
audioadccontrol.o(+RW,+ZI)
VR.o(+RW,+ZI)
Recording.o(+RW,+ZI)
}
_Overlap_2 +0 ALIGN 4 OVERLAY
{
ShareRam.o(+RW,+ZI)
}
}
先把boot.o(vectors)載入(VIC內容),再把我們要的固定值加入
4.檢查:
打開*.map
A.變數有存在?
在Image Symbol Table中可見
test.c 0x00000000 Number 0 test.o ABSOLUTE
.constdata 0x000000c0 Section 4 test.o(.constdata)
Global Symbols
TEST 0x000000c0 Data 4 test.o(.constdata)
B.其memory map
最後產生的hex file內容:(可能非執行時內容)
Memory Map of the image
Image Entry point : 0x0000cfd9
Load Region _ROM (Base: 0x00000000, Size: 0x0001245c, Max: 0x00023400, ABSOLUTE)
Execution Region _RESET (Base: 0x00000000, Size: 0x000000c0, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000000 0x000000c0 Data RO 96 vectors boot.o
Execution Region _ABC (Base: 0x000000c0, Size: 0x00000004, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x000000c0 0x00000004 Data RO 2335 .constdata test.o
C.看其*hex內容:
p.s:
最後,我想說的。這二種RW/RO,都是必須去修改linker scripter(新增一個section放)。
若沒必要還是不要去動比較好。
2.可用來使其不被Optimail
--keep='boot.o(SysInfo)