惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
MongoDB | Blog
MongoDB | Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
aimingoo的专栏
aimingoo的专栏
B
Blog
博客园 - 聂微东
博客园_首页
D
DataBreaches.Net
F
Fortinet All Blogs
小众软件
小众软件
M
MIT News - Artificial intelligence
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
The GitHub Blog
The GitHub Blog
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
F
Full Disclosure
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 【当耐特】
Simon Willison's Weblog
Simon Willison's Weblog
云风的 BLOG
云风的 BLOG
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
G
Google Developers Blog
B
Blog RSS Feed
Attack and Defense Labs
Attack and Defense Labs
W
WeLiveSecurity
N
News | PayPal Newsroom
Recent Announcements
Recent Announcements
AI
AI
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V2EX - 技术
V2EX - 技术
TaoSecurity Blog
TaoSecurity Blog
S
Security Affairs
Martin Fowler
Martin Fowler
Webroot Blog
Webroot Blog
P
Palo Alto Networks Blog
S
Schneier on Security
Latest news
Latest news

博客园 - yinsua

OpenBCI调试记录 Qt QML/Quick程序部署 一种CAN接口电路的隔离方案 【转载】0-5V转4-20mA电路以及Howland电流源分析与仿真 【转载】外置USB供电与内置锂电池供电自动切换电路 模块的电气隔离的例子(音频采集电路) 【转载】EMC 共模电感选型 RS485的电路防护设计 ubuntu 20.04 安装VMware Tools Linux常用操作 MOS管随笔 RTX V4随笔 lua语言 简单类测试 Git 加入gitignore文件后应用 git报错error: could not lock config file RT-Thread速览——内核 ARM MDK开发中的\$Super\$\$main与\$Sub\$\$main - yinsua - 博客园 cpolar(内网穿透工具)安装 VSCode + EIDE开发记录
【转载】Keil MDK的sct分散加载文件详解
yinsua · 2024-12-03 · via 博客园 - yinsua

原文链接:https://blog.csdn.net/weixin_44788542/article/details/127537956

sct 分散加载文件简介

MDK 生成一个以工程名命名的后缀为 *.sct 的分散加载文件 (Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置。
工程构建时, MDK 会根据我们选择的芯片型号,获知芯片的内部 FLASH 及内部SRAM 存储器概况。这里我选择的是STM32F103VET6型号, 这款单片机有 64 KB 的 SRAM,512 KB的 ROM 内存,可以通过规格书查到。

当选好型号后,Target页面的ROM和RAM设置就已经按默认的自动配置好了。

ROM size为0x80000即512k字节,RAM size为0x10000即64k字节,与规格书一致。

默认情况下,Linker页面的Usw Menory Layout from Target Dialog是勾选上的,意思是以前面Target页面的内存布局为准。可以看到下图中的Scatter File是没有文件的,因为这时候内存布局是依靠前面Target页面设置为准,这里有没有这个分散加载文件无所谓。

现在这样操作可以让KEIL自动生成一个sct文件:
1.去掉勾选Usw Menory Layout from Target Dialog,这时Scatter File自动生成一个sct文件在obj文件的输出路径下
2.重新勾选Usw Menory Layout from Target Dialog,编译工程
3.编译成功后就生成了一个默认的sct文件,其配置与Target页面的内存布局含义一样,再回到Options->Linker就可以点击Edit打开该sct文件

打开后如下图所示:

如果把其与之前的Target页面的内存布局来对比,不难理解这里面几个数字表示的含义。
其按每行对应的含义如下:

加载域名  起始地址 大小{;加载区域大小 (分号后面是注释)
        运行域名 起始地址 大小   ;执行地址
        {
                中断向量表起始地址, +First表示强制放到首地址

                ARM相关库,InRoot$$Sections即ARM库的链接器标号,主要作用COPY RW区到RAM,
                然后再RW区后面创建ZI区。 库函数__main函数中有这个段。 它是__main()的一部分。

                编译文件RO只读在该区域
        }
        运行内存名字 起始地址 大小
        {
                编译可读可写,静态区
        }
}

sct 文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。同等级的域之间使用花括号“{}”分隔开,最外层的是加载域(LR_IROM1),第二层“{}”内的是执行域 (ER_IROM1, RW_IRAM1)

选中某个文件,右键选第一个选项

打开对应文件的设置项,其中有Memory Assignment项,三个设置分别对应RO ZI RW数据放在内存哪个位置。
+RO表示只读,代码或者只读数据,一般用来表示代码,+RW表示可读可写的数据,+ZI表示初始化为0的数据。
举例:
如果我在led.c文件的设置项里设置Other Data放到IRAM1

重新编译后再打开工程的sct文件就会看到已经同步更新了,在RW_IRAM1执行域里多了一句led.o (+RW)

sct文件格式

load_region_name  start_address | "+"offset  [attributes] [max_size]
{
    execution_region_name  start_address | "+"offset  [attributes][max_size]
    {
        module_select_pattern  ["("
                                    ("+" input_section_attr | input_section_pattern)
                                    ([","] "+" input_section_attr | "," input_section_pattern)) *
                               ")"]
    }
} 
load_region:       加载区,用来保存永久性数据(程序和只读变量)的区域;
execution_region:  执行区,程序执行时,从加载区域将数据复制到相应执行区后才能被正确执行;
load_region_name:  加载区域名,用于“Linker”区别不同的加载区域,最多31个字符;
start_address:     起始地址,指示区域的首地址;
+offset:           前一个加载区域尾地址+offset 做为当前的起始地址,且“offset”应为“0”或“4”的倍数;
attributes:        区域属性,可设置如下属性:
                    PI       与地址无关方式存放;
                    RELOC    重新部署,保留定位信息,以便重新定位该段到新的执行区;
                    OVERLAY  覆盖,允许多个可执行区域在同一个地址,ADS不支持;
                    ABSOLUTE 绝对地址(默认);
max_size:          该区域的大小; 
execution_region_name:执行区域名;
start_address:     该执行区的首地址,必须字对齐;
+offset:           同上;
attributes:        同上;
                    PI          与地址无关,该区域的代码可任意移动后执行;
                    OVERLAY     覆盖;
                    ABSOLUTE    绝对地址(默认);
                    FIXED       固定地址;
                    UNINIT      不用初始化该区域的ZI段;
module_select_pattern: 目标文件滤波器,支持通配符“*”和“?”;
                        *.o匹配所有目标,* (或“.ANY”)匹配所有目标文件和库。
input_section_attr:    每个input_section_attr必须跟随在“+”后;且大小写不敏感;
                        RO-CODE 或 CODE
                        RO-DATA 或 CONST
                        RO或TEXT, 包括 RO-CODE 和 RO-DATA
                        RW-DATA
                        RW-CODE
                        RW 或 DATA, 包括 RW-CODE 和 RW-DATA
                        ZI 或 BSS
                        ENTRY, that is a section containing an ENTRY point.
                        FIRST,用于指定存放在一个执行区域的第一个或最后一个区域;
                        LAST,同上;
input_section_pattern: 段名; 

sct 文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。同等级的域之间使用花括号“{}”分隔开,最外层的是加载域,第二层“{}”内的是执行域。
还是举之前的例子:

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
    led.o (+RW)
   .ANY (+RW +ZI)
  }
}

【加载域】

• 加载域名: 在 map 文件中的描述会使用该名称LR_IROM1来标识空间。

• 基地址 + 地址偏移:
基地址为 STM32 内部 FLASH 的基地址 0x08000000,地址偏移可选

• 属性列表: 属性列表说明了加载域的是否为绝对地址 N 字节对齐等属性

• 最大容量: 最大容量说明了这个加载域可使用的最大空间,STM32 内部 FLASH的大小0x00080000(512KB)

【执行域】
执行域的格式与加载域是类似的,区别只是输入节区的描述有所不同。

包含了 ER_IROM1 及 RW_IRAM1两个执行域,它们分别对应描述了 STM32 的内部 FLASH及内部 SRAM 的基地址及空间大小。

而它们内部的“输入节区描述”说明了哪些节区要存储到这些空间,链接器会根据它来处理编排这些节区。

【输入节区描述】
模块选择样式 “(“输入节区样式”,” “+“输入节区属性”)”

模块选择样式 “(“输入节区样式”,” “+“节区特性”)”

模块选择样式 “(“输入符号样式”,” “+“输入节区属性”)”

模块选择样式 “(“输入符号样式”,” “+“节区特性”)”

• 模块选择样式: 模块选择样式可用于选择 o 及 lib 目标文件作为输入节区,它可以直接使用目标文件名或“”通配符,也可以使用“.ANY”。
使用语句“.o”可以选择所有 o 文件,使用“.lib”可以选择所有 lib 文件,使用“”或“.ANY”可以选择所有的 o 文件及 lib 文件。
其中“.ANY”选择语句的优先级是最低的,所有其它选择语句选择完剩下的数据才会被“.ANY”语句选中。

• 输入节区样式: 通过输入节区样式可以选择要控制的节区。“(RESET, +First)” 语句的 RESET 就是输入节区样式,它选择RESET 的节区,并使用后面介绍的节区特性控制字“+First”表示它要存储到本区域的第一个地址。

“(InRoot$$Sections)” 是一个链接器支持的特殊选择符号,它可以选择所有标准库里要求存储到 root 区域的节区。

• 输入符号样式: 可以选择要控制的符号,符号样式需要使用“:gdef:”来修饰。例如可以使用“*(:gdef:Value_Test)”来控制选择符号“Value_Test”。

• 输入节区属性: 通过在模块选择样式后面加入输入节区属性,可以选择样式中不同的内容,每个节区属性描述符前要写一个“+”号,使用空格或“,”号分隔开,可以使用的节区属性描述符见表属性描述符及其意义。

sct文件范例

范例1:
通过分散加载文件把代码从flash里拷贝到ram里运行, 基于LPC1788。

LR_IROM1 0x00000000 0x00002000  
{ 
	ER_IROM1 0x00000000 0x00020000  
	{
		*.o (RESET, +First)
		*(InRoot$$Sections)
		startup_lpc177x_8x.o (+RO)
		system_LPC177x_8x.o (+RO)
	}
	
	RW_IRAM1 0x20000000 0x00004000  
	{
		.ANY (+RW +ZI)
	}
}
 
LR_IROM2 0x00002000	0x0007E000
{
	VECTOR 0x10000000 EMPTY 0xE4
	{
	}
	
	ER_IRAM1 +0
	{
		.ANY (+RO)
	}
}

这里有两个加载域(load region)LR_IROM1和LR_IROM2,LR_IROM1是初始化程序,拷贝代码等,从ROM的地址0开始,LR_ROM2是应用程序,从ROM的0x2000开始。+RO表示只读,代码或者只读数据,一般用来表示代码,+RW表示可读可写的数据,+ZI表示初始化为0的数据。大括号里面的为运行域(execution region),一个加载域可以包含几个运行域,LR_ROM2里面有两个运行域,VECTOR和ER_IRAM1,我用VECTOR来表示中断向量区域,ER_IRAM1来表示应用程序区,+0表示紧接着VECTOR排放,EMPTY表示空的,这里空出0xE4的大小,用来放中断向量,.ANY表示除了上面用到的代码之外的代码,官网上有专门解释.ANY的一节。

范例2:
下面是针对LPC2378的USB SRAM作数据RAM使用的配置:

;******************************************************************************
;
; SCATTER LOADING DEION
; ARM
; KEIL's uVision3
; (RealView Microprocessor Developer Kit)
;
; Filename : LPC2378_Flash.scat
;******************************************************************************

LR_IROM1 0x00000000 0x00080000 ;第一个加载域,名字为LR_IROM1,起始
{                  ;地址为0x0,大小为0x80000
	ER_IROM1 0x00000000 0x00080000 ;加载域中的运行时域,名字为ER_IROM1
	{ ;; 起始地址为0x0,大小为0x80000
		vectors.o (VECT, +First)
		init.o (INIT)
		* (+RO)
	}

	RW_IRAM1 0x40000000 0x0000e800
	{
		.ANY(+RW,+ZI)     ; 此处.ANY替换原来的*,是因为下面的一个执行域对指定的模块中的RW,ZI数据指定了存放地址
		;用.ANY就可以把已经被指定的具有RW,ZI属性的数据排除
	} ; The following declarations select the "two region model" ;
}

https://blog.csdn.net/weixin_45829708/article/details/124562053

https://blog.csdn.net/wuhenyouyuyouyu/article/details/71171546
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_44788542/article/details/127537956