keil的sct文件_STM32 分散加载文件 .sct 解析
1、STM32 啟動文件與 .sct 文件分析
1) 定義STACK段,{NOINIT,讀寫}:分配一段內(nèi)存大小為0.5K;
2) 定義HEAP段, {NOINIT,讀寫}:分配一段內(nèi)存大小為1K;
3) 定義RESET段,{DATA,只讀}:DCD各種中斷向量;
4) 定義|.text|段,{CODE,只讀}:Reset_Handler函數(shù),函數(shù)中最后加載了__main;
對剩余的中斷函數(shù)進(jìn)行了弱定義;
在最后還有一段用戶初始化堆棧的代碼__user_initial_stackheap。
那這些代碼都存放在什么位置呢?
5) 分析 .sct 文件:
分散加載文件(即scatter file,后綴為.scf)。
分散加載文件是一個文本文件,通過編寫一個分散加載文件來指定ARM連接器在生成映像文件時如何分配RO,RW,ZI等數(shù)據(jù)的存放地址。
如果不用SCATTER文件指定,那么ARM連接器會按照默認(rèn)的方式來生成映像文件,一般情況下我們是不需要使用分散加載文件的。
但在某些場合,我們希望把某些數(shù)據(jù)放在指定的地址處,那么這時候SCATTER文件就發(fā)揮了非常大的作用。
而且SCATTER文件用起來非常簡單好用。
舉個例子:
比如像LPC2378芯片具有多個不連續(xù)的SRAM,通用的RAM是32KB,可是32KB不夠用,我想把某個.C中的RW數(shù)據(jù)放在USB的SRAM中,那么就可以通過SCATTER文件來完成這個功能。
LR_IROM1 0x08000000 0x00080000? {? ? ; load region size_region
ER_IROM1 0x08000000 0x00080000? {? ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00010000? {? ; RW data
.ANY (+RW +ZI)
}
}
STACK段和HEAP段是RW屬性,存在RAM(0x20000000-0x20010000)中,具體的地址由編譯器在后面鏈接時決定,并不是一定存在RAM的開頭地址。
RESET段存在FLASH(0x08000000-0x08080000)中,而且是FLASH的最開頭,再結(jié)合CORTEX-M3的特性,其上電后根據(jù)啟動引腳來決定PC位置,比如啟動設(shè)置為FLASH啟動,則啟動后PC跳到0x08000000。
此時CPU會先取2個地址(硬件決定),第一個是棧頂?shù)刂?#xff0c;第二個是復(fù)位異常地址,這樣就跳到Reset_Handler,Reset_Handler執(zhí)行到將最后跳轉(zhuǎn)到?庫的__main。
|.text |段是CODE屬性,也存在FLASH區(qū)。
啟動代碼所做的工作如下:
先是建立了堆棧,之后上電后尋找到中斷向量表中的復(fù)位函數(shù)Reset_Handler執(zhí)行,之后跳轉(zhuǎn)到__main執(zhí)行?庫函數(shù),最后由__main調(diào)用main()函數(shù),進(jìn)入C的世界。
2、__user_initial_stackheap
這段代碼位于裸機(jī)啟動文件的末尾:
IF? ? ? :DEF:__MICROLIB
EXPORT? __initial_sp
EXPORT? __heap_base
EXPORT? __heap_limit
ELSE
IMPORT? __use_two_region_memory
EXPORT? __user_initial_stackheap
__user_initial_stackheap
LDR? ? ?R0, =? Heap_Mem
LDR? ? ?R1, =(Stack_Mem + Stack_Size)
LDR? ? ?R2, = (Heap_Mem +? Heap_Size)
LDR? ? ?R3, = Stack_Mem
BX? ? ? LR
若是使用了microlib,則只需要將__initial_sp,__ heap_base的,__ heap_limit三個變量定義成全局變量即可(這三個變量也是固定的可被?庫引用,在庫中需要使用到這三個變量對堆棧進(jìn)行初始化);
否則,就需要自己定義__user_initial_stackheap。
microlib缺省的情況下使用的是Keil C庫。
但是事實上,μVision庫里包含了更多__user_initial_stackheap()的函數(shù)體,這樣編譯器可以根據(jù)開發(fā)人員scatter文件的內(nèi)容自動選擇合適的函數(shù)體。
換句話說,針對RVCT v3.x及之后的版本,使用scatter文件的開發(fā)人員可以不再重新實現(xiàn)__user_initial_stackheap()的函數(shù)體。
也就是說不必再自己寫了__user_initial_stackheap,自己在做實驗驗證時,沒有使用microlib庫,同時也將這部分函數(shù)注釋掉,并沒有產(chǎn)生任何異常。
所以對__user_initial_stackheap在這里就不再做更多深入的研究了,這一部分太燒腦了,就當(dāng)作C庫已經(jīng)為我們準(zhǔn)備好了這個函數(shù)。
3、堆棧的單區(qū)模型和雙區(qū)模型
堆棧分為單區(qū)模型和雙區(qū)模型:
單區(qū)模型堆和棧在同一存儲器區(qū)中互相朝向?qū)Ψ皆鲩L
雙區(qū)模型將堆和棧分別放置在存儲器不同的區(qū)中,__ user_initial_stackheap()建立的專用堆限制來檢查堆,需要設(shè)置堆棧的長度。
1)選擇使用單區(qū)模型,在SCT文件中定義一個特殊的執(zhí)行域,使用符號:
ARM_LIB_STACKHEAP,并使用EMPTY屬性這樣庫管理器就選擇了一個把這個域當(dāng)作堆和棧合并在一起的__user_initial_stackheap()函數(shù)。
在這個函數(shù)中使用了“Image$ $ ARM_LIB_STACKHEAP$ $Base”和“Image$ $ARM_LIB_STACKHEAP$ $ZI$ $Limit”符號。
2)選擇使用雙區(qū)模型,在sct文件中定義兩個特殊的執(zhí)行域,使用符號:
ARM_LIB_STACK和ARM_LIB_HEAP,都要使用EMPTY屬性。這樣庫管理器就會選擇使用符號:“Image$ $ARM_LIB_HEAP$ $Base” ,“Image$ $ARM_LIB_STACK$ $ZI$ $ limit”,“Image$ $ARM_LIB_STACK$ $Base”,“Image$ $ARM_LIB_STACK$ $ZI$ $Limit”的__user_initial_stackheap()函數(shù)。
從裸機(jī)的啟動文件可以看出,裸機(jī)使用的是雙區(qū)模型。
4、Huawei_LiteOS 啟動文件與 sct 文件
啟動文件:
LOS_Heap_Min_Size? ?EQU? ? ?0x400
AREA? ? LOS_HEAP, NOINIT, READWRITE, ALIGN=3
__los_heap_base
LOS_Heap_Mem? ? SPACE? ?LOS_Heap_Min_Size
AREA? ? LOS_HEAP_INFO, DATA, READONLY, ALIGN=2
IMPORT? |Image$$ARM_LIB_STACKHEAP$$ZI$$Base|
EXPORT? __LOS_HEAP_ADDR_START__
EXPORT? __LOS_HEAP_ADDR_END__
__LOS_HEAP_ADDR_START__
DCD? ? ?__los_heap_base
__LOS_HEAP_ADDR_END__
DCD? ? ?|Image$$ARM_LIB_STACKHEAP$$ZI$$Base| - 1
PRESERVE8
AREA? ? RESET, CODE, READONLY
THUMB
IMPORT? ||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit||
IMPORT? osPendSV
EXPORT? _BootVectors
EXPORT? Reset_Handler
_BootVectors
DCD? ? ?||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit||
DCD? ? ?Reset_Handler
Reset_Handler
IMPORT? SystemInit
IMPORT? __main
LDR? ? ?R0, =SystemInit
BLX? ? ?R0
LDR? ? ?R0, =__main
BX? ? ? R0
ALIGN
END
定義LOS_HEAP段,{NOINIT,讀寫}:分配一段內(nèi)存大小為1K;
定義LOS_HEAP_INFO段,{DATA,只讀}:定義__LOS_HEAP_ADDR_START__和__LOS_HEAP_ADDR_END__這兩個全局變量供OS使用;
定義RESET段,{CODE,只讀}:啟動向量,第一個是棧頂?shù)刂?#xff0c;第二個是Reset_Handler;將Reset_Handler主體也寫入了RESET段;
首先,可以看出,分配堆棧的方式與裸機(jī)不同,使用的是單區(qū)模型,從下向上排列
__LOS_HEAP_ADDR_START __ = __ los_heap_base,為堆低地址;
__LOS_HEAP_ADDR_END __ = |Image$ $ARM_LIB_STACKHEAP$ $ZI$ $Base | - 1,為堆頂(不確定的地址);
|Image$ $ARM_LIB_STACKHEAP$ $ZI$ $Base|,為棧底(不確定的地址);
|Image$ $ARM_LIB_STACKHEAP$ $ZI$ $Limit|,為棧頂?shù)刂?
所以,由上文可知,在sct文件中必然會出現(xiàn)ARM_LIB_STACKHEAP這個執(zhí)行域:
LR_IROM1 0x08000000 0x00020000? {? ? ; load region size_region
ER_IROM1 0x08000000 0x00020000? {? ? ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
* (LOS_HEAP_INFO)
}
VECTOR 0x20000000 0x400? {? ? ; Vector
* (.data.vector)
}
RW_IRAM1 0x20000400 0x00004800? {? ? ; RW data
;.ANY (+RW +ZI)
* (.data, .bss)
* (LOS_HEAP)
}
ARM_LIB_STACKHEAP 0x20004C00 EMPTY 0x400? {? ? ;LiteOS MSP
}
}
那么其他的異常中斷向量入口在哪里呢?定義在los_hwi.c文件中被定義成了數(shù)組的形式:
#ifdef __ICCARM__
#pragma? location = ".data.vector"
#elif defined (__CC_ARM) || defined (__GNUC__)
LITE_OS_SEC_VEC
#endif
HWI_PROC_FUNC m_pstHwiForm[OS_VECTOR_CNT] =
{
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [0] Top of Stack
(HWI_PROC_FUNC)Reset_Handler,? ? ? ? // [1] reset
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [2] NMI Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [3] Hard Fault Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [4] MPU Fault Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [5] Bus Fault Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [6] Usage Fault Handler
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [7] Reserved
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [8] Reserved
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [9] Reserved
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [10] Reserved
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [11] SVCall Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [12] Debug Monitor Handler
(HWI_PROC_FUNC)0,? ? ? ? ? ? ? ? ? ? // [13] Reserved
(HWI_PROC_FUNC)osPendSV,? ? ? ? ? ? ?// [14] PendSV Handler
(HWI_PROC_FUNC)osHwiDefaultHandler,? // [15] SysTick Handler
};
這一部分代碼被分散加載文件加載到了VECTOR段,位于RAM的開頭部分。
在內(nèi)核初始化時會進(jìn)行中斷向量表重映射的工作。
總結(jié)
以上是生活随笔為你收集整理的keil的sct文件_STM32 分散加载文件 .sct 解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转载] Linux架构
- 下一篇: art-template提取某个重复字段