[ArmCompiler6--armlink]Keil-MDK中scatter load机制
Posted 苏导
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ArmCompiler6--armlink]Keil-MDK中scatter load机制相关的知识,希望对你有一定的参考价值。
简述
Keil MDK工具中,Armlink使用scatter加载机制来描述一份image在memory map中的划分。
image的memory map由regions和output sections组成。
Scatter加载
需要使用Scatter加载的场景
- 复杂的memory map,比如各种切分等
- 不同类别的memory设备,RAM, ROM, SRAM,外设等
- 固定函数放在指定位置
- 使用symbols来识别heap和stack
当使用scatter file时,如下的符号将未被定义
- Image–RO–Base.
- Image–RO–Limit.
- Image–RW–Base.
- Image–RW–Limit.
- Image–XO–Base.
- Image–XO–Limit.
- Image–ZI–Base.
- Image–ZI–Limit.
使用scatter file时,如果没有为stack和heap使用特定region,或没有重新实现__user_setup_stackheap(), 将会产生错误信息。
scatter file指定stack和heap
ARM C库为__user_setup_stackheap()提供了多种实现,并会根据statter file情况自动选择合适的一种实现。当然如果自己实现了user_setup_heap()的话,ARM C库提供的所有实现都会被覆盖。
另外在scatter file中定义两个特别的execution regions(ARM_LIB_HEAP和ARM_LIB_STACK)来选择两种region内存模式,这两种region都有EMPTY属性,一旦使用了这两种region内存模式,ARM C库提供的所有实现也会被无效掉,因为ARM C库中的user_setup_heap()使用了如下的synbols:
- Image–ARM_LIB_STACK–Base.
- Image–ARM_LIB_STACK–ZI–Limit.
- Image–ARM_LIB_HEAP–Base.
- Image–ARM_LIB_HEAP–ZI–Limit.
需要确保只有一个ARM_LIB_STACK或ARM_LIB_HEAP region的指定,且必须分配空间,因为user_setup_heap()会使用这些数据:
LOAD_FLASH …
…
ARM_LIB_STACK 0x40000 EMPTY -0x20000 ; Stack region growing down
ARM_LIB_HEAP 0x28000000 EMPTY 0x80000 ; Heap region growing up
…
另外也可以只在scatter file中定义ARM_LIB_STACKHEAP,这样user_setup_stackheap()将使用如下symbol的值:
- Image–ARM_LIB_STACKHEAP–Base
- Image–ARM_LIB_STACKHEAP–ZI–Limit
复杂image scatter file示例
与此图对应的scatter file如下:
LOAD_ROM_1 0x0000 ; Start address for first load region (0x0000)
EXEC_ROM_1 0x0000 ; Start address for first exec region (0x0000)
program1.o (+RO) ; Place all code and RO data from
; program1.o into this exec region
DRAM 0x18000 0x8000 ; Start address for this exec region (0x18000),
; Maximum size of this exec region (0x8000)
program1.o (+RW, +ZI) ; Place all RW and ZI data from
; program1.o into this exec region
LOAD_ROM_2 0x4000 ; Start address for second load region (0x4000)
EXEC_ROM_2 0x4000
program2.o (+RO) ; Place all code and RO data from
; program2.o into this exec region
SRAM 0x8000 0x8000
program2.o (+RW, +ZI) ; Place all RW and ZI data from
; program2.o into this exec region
这里是比较复杂的例子,即将program1和program2分别放在两个load region中。在一些不这么复杂的情况下,ARM推荐 *或.ANY 来指代剩下的code和data。
Root execution region的情况
Root region指的是load address和execution address相同的region。
image的初始化entry point必须在root region之内。
ABSOLUTE属性
ABSOLUTE属性可以用来指定root region。
为了使execution region address和load region address一样,如下条件满足其中之一即可:
条件 | 说明 |
---|---|
一 | 为execution region和load region设置相同的基地址(base address) |
二 | 在load region中的第一个execution region添上+0,另外如果该load region中的其余所有execution region都添上+0,除了ZI之后的execution region都是root regions |
ABSOLUTE属性用法示例如下:
LR_1 0x040000 ; load region starts at 0x40000
; start of execution region descriptions
ER_RO 0x040000 ABSOLUTE ; load address = execution address
* (+RO) ; all RO sections (must include section with
; initial entry point)
… ; rest of scatter-loading description
FIXED属性
FIXED属性用于创建固定地址的root regions。
对应的scatter file如下:
LR_1 0x040000 ; load region starts at 0x40000
; start of execution region descriptions
ER_RO 0x040000 ; load address = execution address
* (+RO) ; RO sections other than those in init.o
ER_INIT 0x080000 FIXED ; load address and execution address of this
; execution region are fixed at 0x80000
init.o(+RO) ; all RO sections from init.o
… ; rest of scatter-loading description
可以使用该属性将某个函数,或一块数据(如常数表、校验值)放置在固定的地址。
例如一些初始化代码需要放在ROM的开头,校验码可能要放在ROM的末尾,那么一些memory内容可能是无用的。使用*或.ANY将其余的code或data填满初始化代码和校验码之间的memory空间。
为维护和调试方便,Keil建议在scatter file中只使用必要的指定地址防止,将大部分的都交给linker来做。
在固定地址放置函数或数据
armlinker允许在固定地址放置一个section,具体如下:
方法 | 说明 |
---|---|
一 | 在指定地址定义一个execution region,指定其section描述,且该execution region只包含这一个section |
二 | 对于特殊名字的section,linker能从section名字获取其地址,这些特殊名字的section称为__at sections |
为将一个函数或变量放在指定地址,该函数或变量必须放在它自己的section中:
步骤 | 说明 |
---|---|
一 | 将函数或数据item放在其所属的源文件中 |
二 | 使用attribute((section(“name”))),将函数或数据放在自己命名的section中 |
三 | 在汇编语言中使用.section指令,汇编语言中.section是最小的memory放置单元 |
四 | 使用-ffunction_sections编译器选项,该选项会为源文件中的每个函数都产生一个ELF section。该选项对于一些函数而言会增加code size,因为一些共享地址、数据和字符串没有被减去。但是可以在链接时使用armlink –remove将这部分再减去 |
不使用scatter file而实现函数or数据放置在固定地址
- 创建main.c
#include <stdio.h>
extern int sqr(int n1);
const int gValue __attribute__((section(".ARM.__at_0x5000"))) = 3; // Place at 0x5000
int main()
int squared;
squared=sqr(gValue);
printf("Value squared is: %d\\n", gSquared);
- function.c
int sqr(int n1)
return n1*n1;
- 编译与链接
armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --map function.o main.o -o squared.axf
使用scatter的命名section实现函数or数据放置在固定地址
- main.c
#include <stdio.h>
extern int sqr(int n1);
int gSquared __attribute__((section("foo"))); // Place in section foo
int main()
gSquared=sqr(3);
printf("Value squared is: %d\\n", gSquared);
- function.c
int sqr(int n1)
return n1*n1;
- scatter file
LR1 0x0000 0x20000
ER1 0x0 0x2000
*(+RO) ; rest of code and read-only data
ER2 0x8000 0x2000
main.o
ER3 0x10000 0x2000
function.o
*(foo) ; Place gSquared in ER3
; RW and ZI data to be placed at 0x200000
RAM 0x200000 (0x1FF00-0x2000)
*(+RW, +ZI)
ARM_LIB_STACK 0x800000 EMPTY -0x10000
ARM_LIB_HEAP +0 EMPTY 0x10000
- 编译与链接
armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --map --scatter=scatter.scat function.o main.o -o squared.axf
使用scatter的指定地址实现函数or数据放置在固定地址
- main.c
#include <stdio.h>
extern int sqr(int n1);
// Place at address 0x10000
const int gValue __attribute__((section(".ARM.__at_0x10000"))) = 3;
int main()
int squared;
squared=sqr(gValue);
printf("Value squared is: %d\\n", squared);
- function.c
int sqr(int n1)
return n1*n1;
- scatter file
LR1 0x0
ER1 0x0
*(+RO) ; rest of code and read-only data
ER2 +0
function.o
*(.ARM.__at_0x10000) ; Place gValue at 0x10000
; RW and ZI data to be placed at 0x200000
RAM 0x200000 (0x1FF00-0x2000)
*(+RW, +ZI)
ARM_LIB_STACK 0x800000 EMPTY -0x10000
ARM_LIB_HEAP +0 EMPTY 0x10000
- 编译与链接
armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --no_autoat --scatter=scatter.scat --map function.o main.o -o squared.axf
以上是关于[ArmCompiler6--armlink]Keil-MDK中scatter load机制的主要内容,如果未能解决你的问题,请参考以下文章
[ArmCompiler6--armlink]Keil-MDK中scatter file语法
markdown 重写模块apache di .htaccess untuk melakukan redirect non https ke https dan non www ke www