简介
当工程按默认配置构建时,MDK 会根据我们选择的芯片型号,获知芯片的内部FLASH 及内部 SRAM 存储器概况,自动生成一个以工程名命名的后缀为*.sct 的分散加载文件(Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置。
一般情况下,不需要编写分散加载文件,由编译器自动生成,将某些数据放到默认位置。但是在某些场合,希望将某些数据放在指定的位置。
例如可以设置源文件中定义的所有变量自动按地址分配到外部 SRAM,这样就不需要再使用关键字“attribute”按具体地址来指定了;
复杂内存映射:如果必须将代码和数据放在多个不同的内存区域中,则需要使用详细指令指定将哪些数据放在哪个内存空间中。
不同类型的内存:许多系统都包含多种不同的物理内存设备,如闪存、 ROM、 SDRAM 和快速 SRAM。分散加载描述可以将代码和数据与最适合的内存类型相匹配。例如,可以将中断代码放在快速 SRAM 中以缩短中断等待时间,而将不经常使用的配置信息放在较慢的闪存中。
位于固定位置的函数:可以将函数放在内存中的固定位置,即使已修改并重新编译周围的应用程序。
使用符号标识堆和堆栈:链接应用程序时,可以为堆和堆栈位置定义一些符号。
利用它还可以控制代码的加载区与执行区的位置,例如可以把程序代码存储到单位容量价格便宜的 NAND-FLASH 中,但在NAND-FLASH 中的代码是不能像内部 FLASH 的代码那样直接提供给内核运行的,这时可通过修改分散加载文件,把代码加载区设定为 NAND-FLASH 的程序位置,而程序的执行区设定为 SRAM 中的位置,这样链接器就会生成一个配套的分散加载代码,该代码会把NAND-FLASH 中的代码加载到 SRAM 中,内核再从 SRAM 中运行主体代码,大部分运行Linux 系统的代码都是这样加载的。
sct文件的格式

在默认的 sct 文件配置中仅分配了 Code、RO-data、RW-data 及 ZI-data 这些大区域的地址,链接时各个节区(函数、变量等)直接根据属性排列到具体的地址空间。
sct 文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。同等级的域之间使用花括号“{}”分隔开,最外层的是加载域,第二层“{}”内的是执行域。


; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00020000 {
//定义一个加载域,域地址0x08000000,域大小为0x00020000
//load region size_region 所有代码需要下载到0x08000000 开始的区域中,且这个区域大小只有0x00020000
ER_IROM1 0x08000000 0x00020000 {
//load address = execution address 第一个运行时域必须和加载域起始地址相同,其大小一般也相同
//只能是只读的代码段和只读数据段
*.o (RESET, +First) //启动代码的首次执行地址,RO执行域名称为ER_IROM1,
//将 RESET 段最先加载到本域的起始地址外
//首次执行的地址为RESET标号所表示的地址,RESET 存储的是向量表
//对应启动文件中的AREA RESET, CODE, READONLY
*(InRoot$$Sections) //稍后文件中会单独讲到
.ANY (+RO) //加载所有匹配目标文件的只读属性数据,包含:Code、 RW-Code、 RO-Data。
}
RW_IRAM1 0x20000000 0x00005000 {
//再定义一个运行时域,域基址0x20000000
//RW data 执行域是以0x20000000 开始的长度为0x00004000 一段区域
.ANY (+RW +ZI) //其中包括的是哪些文件
}
}
加载区描述
加载域名 (基地址 | ("+" 地址偏移)) [属性列表] [最大容量]
{
执行区域描述
}
LR_IROM1 0x08000000 0x00080000 {
; load region size_region
......
}
加载域名:名称,在 map 文件中的描述会使用该名称来标识空间。如本例中只有一个加载域,该域名为 LR_IROM1。
基地址+地址偏移:这部分说明了本加载域的基地址,可以使用+号连接一个地址偏移,算进基地址中,整个加载域以它们的结果为基地址。如本例中的加载域基地址为 0x08000000,刚好是 STM32 内部 FLASH 的基地址。
属性列表:属性列表说明了加载域的是否为绝对地址、N 字节对齐等属性,该配置是可选的。本例中没有描述加载域的属性。
最大容量:最大容量说明了这个加载域可使用的最大空间,该配置也是可选的,如果加上这个配置后,当链接器发现工程要分配到该区域的空间比容量还大,它会在工程构建过程给出提示。本例中的加载域最大容量为 0x00080000,即 512KB,正是本型号 STM32 内部 FLASH 的空间大小。
执行域
执行域名 (基地址 | "+" 地址偏移) [属性列表] [最大容量 ]
{
///输入节区描述
}
执行域的格式与加载域是类似的,区别只是输入节区的描述有所不同
输入节区描述 .o .ANY (+RO)等的用法
配合加载域及执行域的配置,在相应的域配置“输入节区描述”即可控制该节区存储到域中
//除模块选择样式部分外,其余部分都可选选填
模块选择样式"("输入节区样式","

本文围绕STM32的分散加载文件(sct)展开,介绍了其格式,包括加载区和执行域描述、输入节区用法。还说明了通过MDK配置选项和手动两种方式修改sct文件的方法,并给出自动分配变量到指定SRAM空间、优先使用内部SRAM并分配堆区到指定空间的实例。
最低0.47元/天 解锁文章
2万+





