浅析 Keil 中的 sct 文件

sct分散加载文件格式与应用 介绍了sct分散加载文件格式,并给出了具体应用以及一些自己总结的细节问题。 阅读详情
AI摘要

本文围绕Keil中的sct文件展开,先介绍程序存储与运行时不同数据域的状态及加载过程,指出sct文件可定义各区域起始地址和大小。接着详细阐述sct文件,包括简介、格式(加载域、执行域、输入节区描述),还说明了设置堆栈的方法及配置文件的方式。


一、程序的存储与运行

1、存储

程序编译后,应用程序中所有具有同一性质的数据(包括代码)被归到一个域,程序在存储或运行的时候,不同的域会呈现不同的状态,这些域的意义如下:

  • Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到 ROM 区。
  • RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在 ROM 区,因而程序不能修改其内容。
    • 例如 C 语言中 const 关键字定义的变量就是典型的 RO-data。
  • RW-data:Read Write data,即可读写数据域,它指初始化为"非0值"的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。
    • 例如 C 语言中使用定义的全局变量,且定义时赋予"非 0 值"给该变量进行初始化。
  • ZI-data:Zero Initialie data,即 0 初始化数据,它指初始化为"0 值"的可读写数据域,它与 RW-data 的区别是程序刚运行时这些数据初始值全都为 0,而后续运行过程与 RW-data 的性质一样,它们也常驻在 RAM 区,因而应用程序可以更改其内容。
    • 例如 C 语言中使用定义的全局变量,且定义时赋予"0 值"给该变量进行初始化
    • 若定义该变量时没有赋予初始值,编译器会把它当 ZI-data 来对待,初始化为 0;
  • ZI-data 的栈空间(Stack)及堆空间(Heap):
    • 在 C 语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。
    • 使用 malloc 动态分配的变量属于堆空间。
    • 在程序中的栈空间和堆空间都是属于 ZI-data 区域的,这些空间都会被初始值化为 0 值。编译器给出的 ZI-data 占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用 malloc 动态申请堆空间,编译器会优化,不把堆空间计算在内)。

详细内容可以参考如下文章:
STM32 map 文件浅析 、单片机内存区域划分

总结如下:

程序组件所属类别
机器代码指令Code
常量RO-data
初值非0的全局变量RW-data
初值为0的全局变量ZI-data
局部变量ZI-data 栈空间
使用malloc动态分配的空间ZI-data 堆空间

2、加载、运行

RW-data 和 ZI-data 它们仅仅是初始值不一样而已,为什么编译器非要把它们区分开?原因如下:

应用程序具有静止状态和运行状态。静止态的程序被存储在非易失存储器中,如 STM32 的内部 FLASH,因而系统掉电后也能正常保存。但是当程序在运行状态的时候,程序常常需要修改一些暂存数据,由于运行速度的要求,这些数据往往存放在内存中(RAM),掉电后这些数据会丢失。因此,程序在静止与运行的时候它在存储器中的表现是不一样的,见下图。


程序在存储状态时,RO section 及 RW Section 都被保存在 ROM 区。当程序开始运行时,内核直接从 ROM 中读取代码,并且在执行主体代码前,会先执行一段加载代码,它把 RW Section 数据从 ROM 复制到 RAM,并且在 RAM 加入 ZI Section,ZI Section 的数据都被初始化为 0。加载完后 RAM 区准备完毕,正式开始执行主体程序。

编译生成的 RW-data 的数据属于图中的 RW Section,ZI-data 的数据属于图中的 ZI Section。是否需要掉电保存,这就是把 RW-data 与 ZI-data 区别开来的原因:
- 因为在 RAM 创建数据的时候,默认值为 0,
- 但如果有的数据要求初值非 0,那就需要使用 ROM 记录该初始值,运行时再复制到 RAM。

STM32 的 RO 区域不需要加载到 SRAM,内核直接从 FLASH 读取指令运行。计算机系统的应用程序运行过程很类似,不过计算机系统的程序在存储状态时位于硬盘,执行的时候甚至会把上述的 RO 区域(代码、只读数据)加载到内存,加快运行速度,还有虚拟内存管理单元(MMU)辅助加载数据,使得可以运行比物理内存还大的应用程序。而 STM32 没有 MMU,所以无法支持 Linux 系统。

当程序存储到 STM32 芯片的内部 FLASH 时(即 ROM 区),它占用的空间是 Code、RO-data 及 RW-data 的总和,所以如果这些内容比STM32 芯片的 FLASH 空间大,程序就无法被正常保存了。当程序在执行的时候,需要占用内部 SRAM 空间(即 RAM 区),占用的空间包括RW-data 和 ZI-data。应用程序在各个状态时各区域的组成见下表。

程序状态与区域组成
程序执行时的只读区域(RO)Code + RO data
程序执行时的可读写区域(RW)RW data + ZI data
程序存储时占用的ROM区Code + RO data + RW data

而这些区域的起始地址和大小,以及各个函数变量应该放在哪个存储器区域中就是由本文要讲的 sct 文件定义的。

二、sct 分散加载文件

1、简介

当工程按默认配置构建时,MDK 会根据我们选择的芯片型号,获知芯片的内部 FLASH 及内部 SRAM 存储器概况,生成一个以工程名命名的后缀为 *.sct 的分散加载文件(Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置。

  • 可以设置源文件中定义的所有变量自动按地址分配到外部 SDRAM,这样就不需要再使用关键字 __attribute__ 按具体地址来指定了;
  • 利用它还可以控制代码的加载区与执行区的位置,例如可以把程序代码存储到单位容量价格便宜的 NAND-FLASH 中,但在 NAND-FLASH 中的代码是不能像内部 FLASH 的代码那样直接提供给内核运行的,这时可通过修改分散加载文件,把代码加载区设定为 NAND-FLASH 的程序位置,而程序的执行区设定为 SDRAM 中的位置,这样链接器就会生成一个配套的分散加载代码,该代码会把 NAND-FLASH 中的代码加载到 SDRAM 中,内核再从 SDRAM 中运行主体代码,大部分运行 Linux 系统的代码都是这样加载的。

2、文件格式

下面是一个由 MDK 默认生成的 sct 文件:

我使用的是 STM32F407,不同的芯片型号内存不一样

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region(加载域,基地址空间大小)
  ER_IROM1 0x08000000 0x00040000  {  ; load address = execution address(加载地址 = 执行地址)
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data(可读写数据)
   .ANY (+RW +ZI)
  }                             
}

在默认的 sct 文件配置中仅分配了 Code、RO-data、RW-data 及 ZI-data 这些大区域的地址,链接时各个节区(函数、变量等)直接根据属性排列到具体的地址空间。

sct 文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。同等级的域之间使用花括号"{}“分隔开,最外层的是加载域,第二层”{}"内的是执行域,其整体结构见下图。

2.1 加载域

sct 文件的加载域格式如下:

加载域名 (基地址 | ("+"地址偏移)) [属性列表] [最大容量]
"{"
	执行区域描述+
"}"

本例中为:
LR_IROM1 0x08000000 0x00080000  {
	...
}
  • 加载域名: 在 map 文件中的描述会使用名称 LR_IROM1 来标识空间。
  • 基地址 + 地址偏移:基地址为 STM32 内部 FLASH 的基地址 0x08000000,地址偏移可选
  • 属性列表: 指出当前加载域的属性列表。加载域可以继承先前加载域的属性。主要有以下这些(多个使用时以空格间隔开):
    • ABSOLUTE : 指定将内容放置在链接后不会更改的基地址所表示的固定地址上。 这是默认值 ,除非使用了 PI 或 RELOC 。
    • ALIGN alignment : 指定对齐约束。alignment 为阿拉伯数字,最小为 4,必须是 2 的整数次幂。例如, ALIGN 4 。基地址的值必须符合该对齐约束。如果使用了 +offset ,连接器将计算并使用对齐后的地址。
    • NOCOMPRESS : RW 数据压缩默认情况下处于启用状态。 使用 NOCOMPRESS 关键字可以指定在最终镜像中不得压缩加载域的内容。
    • OVERLAY : 使用 OVERLAY 关键字可以在同一地址具有多个加载域。 ARM 工具不提供覆盖机制。 要在同一地址使用多个加载域,必须提供自己的叠加层管理器。 该属性不能被继承。
    • PI : 表示当前域与位置无关。 内容不依赖于任何固定地址,并且在链接后无需任何额外处理即可移动。(如果镜像中包含 XO,则不支持此属性。)
    • PROTECTED : 该关键字将阻止以下情况:
      • Overlapping of load regions
      • Veneer sharing
      • String sharing with the --merge option.
    • RELOC : 指出当前域是可重定位的。 内容取决于固定地址。 输出重定位信息,以使内容可以通过另一个工具移动到另一个位置。(如果镜像中包含 XO,则不支持此属性。)
  • 最大容量: 最大容量说明了这个加载域可使用的最大空间,该配置也是可选的,如果加上这个配置后,当链接器发现工程要分配到该区域的空间比容量还大,它会在工程构建过程给出提示。STM32 内部 FLASH 的大小 0x00080000(512KB)

有关属性的继承,参考:

LR1 0x8000 PI    ; 默认为 ABSOLUTE
{
    …
}
LR2 +0             ; LR2 从 LR1 继承 PI 属性
{
    …
}
LR3 0x1000         ; LR3 不继承 LR2 的任何属性,因为它没有相对基地址,恢复默认为 ABSOLUTE
{
    …
}
LR4 +0             ; LR4 继承 LR3 的  ABSOLUTE 属性
{
    …
}
LR5 +0 RELOC       ; LR5 不继承 LR4 的任何属性,因为它显式设置了 RELOC
{
    …
}
LR6 +0 OVERLAY     ; LR6 不继承 LR5 的任何属性,因为它显式设置了 OVERLAY
{
    …
}
LR7 +0             ; LR7 无法继承 OVERLAY,恢复默认为 ABSOLUTE
{
    …
}

2.2 执行域

执行域名 (基地址 | "+"地址偏移) [属性列表] [最大容量 ]
"{"
	输入节区描述
"}"

本例中为:
ER_IROM1 0x08000000 0x00040000  {  ; load address = execution address(加载地址 = 执行地址)
   ...
}
RW_IRAM1 0x20000000 0x00020000  {  ; RW data(可读写数据)
	...
}    

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

属性列表:

  • ABSOLUTE :指定将内容放置在链接后不会更改的 base_address 所表示的固定地址上。
  • ALIGN alignment :指定对齐约束。alignment 为阿拉伯数字,最小为 4,必须是 2 的整数次幂。例如, ALIGN 4 。 base_address 的值必须符合该对齐约束。如果使用了 +offset ,连接器将计算并使用对齐后的地址。(执行域上的 ALIGN 属性将导致加载地址和执行地址都对齐)
  • ALIGNALL value :增加执行域中各节的对齐方式。value 的值必须是 2 的正幂,并且必须大于或等于 4。
  • ANY_SIZE max_size :指定 armlink 可以用未分配的节填充的执行域内的最大大小。max_size 必须小于或等于域的大小。
  • EMPTY [–]length :在执行域中保留给定大小的空内存块,通常由堆或堆栈使用。 带有 EMPTY 属性的域中不能放置任何节。
  • FILL value :创建包含 value 值的链接器生成的区域(例如,FILL 0xFFFFFFFF )。FILL 属性可以替换以下组合: EMPTY ZEROPAD PADVALUE 。
  • FIXED :固定地址。 链接器会尝试使执行地址等于加载地址。 这使得该域成为根区域。 如果不可能,则链接器会产生错误。
  • NOCOMPRESS :RW 数据压缩默认情况下处于启用状态。 使用 NOCOMPRESS 关键字,可以指定执行域中的 RW 数据不得在最终镜像中压缩。
  • OVERLAY :用于地址范围重叠的节。 如果连续的执行域具有相同的 +offset ,那么它们将被赋予相同的基地址。
  • PADVALUE value :定义用于填充的值。例如, EXEC 0x10000 PADVALUE 0xFFFFFFFF EMPTY ZEROPAD 0x2000 表示创建一个大小为 0x2000 且使用 0xFFFFFFFF 填充的域。
  • PI :该域仅包含与位置无关的节。 内容不依赖于任何固定地址,并且在链接后无需任何额外处理即可移动。(如果镜像中包含仅执行节(XO),则不支持此属性)
  • SORTTYPE algorithm :指定执行域的排序算法,例如 ER1 +0 SORTTYPE CallTree 。该属性的优先级高于通过连接器参数 --sort 算法 的方式。
  • UNINIT :用于创建包含未初始化数据或内存映射 I/O 的执行域。
  • ZEROPAD :零初始化的段作为零填充块写入 ELF 文件。只有根执行域可以使用 ZEROPAD 属性进行零初始化。在非根执行域中使用 ZEROPAD 属性会生成警告,并忽略该属性。

本例中包含了 ER_IROM1 及 RW_IRAM1 两个执行域,它们分别对应描述了 STM32 的内部 FLASH 及内部 SRAM 的基地址及空间大小。而它们内部的“输入节区描述”说明了哪些节区要存储到这些空间,链接器会根据它来处理编排这些节区。

2.3 输入节区描述

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

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

本例中有:
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
.ANY (+RW +ZI)
  • 模块选择样式: 模块选择样式可用于选择 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”。
  • 输入节区属性: 通过在模块选择样式后面加入输入节区属性,可以选择样式中不同的内容,每个节区属性描述符前要写一个“+”号,使用空格或“,”号分隔开,可以使用的节区属性描述符见下表。
节区属性描述符说明
RO-CODE、CODE只读代码段
RO-DATA、CONST只读数据段
RO及TEXT包括 RO-CODE 和 RO-DATA
RW-DATA可读写数据段
RW-CODE可读写代码段
RW、DATA包括 RW-DATA 和 RW-CODE
ZI及BSS初始化为 0 的可读写数据段
XO只可执行的区域
ENTRY节区的入口点

例如,示例文件中使用".ANY(+RO)“选择剩余所有节区 RO 属性的内容都分配到执行域 ER_IROM1 中,使用”.ANY(+RW +ZI)"选择剩余所有节区 RW 及 ZI 属性的内容都分配到执行域 RW_IRAM1中。

* 和 .ANY 的区别

* 和 .ANY 大部分情况下都是通用的,不过它们有一个很细节的区别,那就是如果使用的是 .ANY,比如上面的例子中 ER_IROM1 里的,如果这个 ROM 的数据满了,那它就会从下面的 RAM 中去申请内存来存储数据;而如果定义为了 *(+RO) 和 *(+XO),该 ROM 区内存满了之后,则不会继续往下面定义的分区申请内存,如下图:
改成 * 之后报错如下,提示内存不够:

另外,.ANY 还可以设置优先级,其中 .ANY2 的优先级比 .ANY1 的优先级高。

  • 节区特性:节区特性可以使用"+FIRST"或"+LAST"选项配置它要存储到的位置,FIRST 存储到区域的头部,LAST 存储到尾部。通常重要的节区会放在头部,而 CheckSum(校验和)之类的数据会放在尾部。
    • 例如示例文件中使用"(RESET,+First)"选择了 RESET 节区,并要求把它放置到本区域第一个位置,而 RESET 是工程启动代码中定义的向量表,该向量表中定义的堆栈顶和复位向量指针必须要存储在内部 FLASH 的前两个地址,这样 STM32 才能正常启动(详见 STM32 芯片启动过程),所以必须使用 FIRST 控制它们存储到首地址。

总的来说,我们的 sct 示例文件配置如下:

  • 程序的加载域为内部 FLASH 的 0x08000000,最大空间为 0x00100000;程
  • 序的执行基地址与加载基地址相同,其中 RESET 节区定义的向量表要存储在内部 FLASH 的首地址,且所有 o 文件及 lib 文件的 RO 属性内容都存储在内部 FLASH 中;
  • 程序执行时 RW 及 ZI 区域都存储在以 0x20000000 为基地址,大小为 0x00020000 的空间。

链接器根据 sct 文件链接,链接后各个节区、符号的具体地址信息可以在 map 文件中查看。

2.4 设置堆栈

如果使用了分散加载文件,那么有些连接器定义的符号就变成了未定义。这些符号就包含堆栈的定义函数所使用的符号,因此,使用的是分散加载文件时,就必须要手动设置栈和堆。方法主要有以下两种:

  • 在分散文件中使用下列方法之一
    • 定义名为 ARM_LIB_STACK 和 ARM_LIB_HEAP 的单独的栈和单独的堆域。
    • 定义包含堆栈和堆的组合域,名为 ARM_LIB_STACKHEAP。
  • 通过重新实现 __user_setup_stackheap() 来设置堆和堆栈边界。(在 stm32 中的 .s 启动文件中,使用的正是这种方法)

ARM 编译套件提供了两种内存模型:

  • One-Region Model: 应用程序的栈和堆在相同的内存域中彼此接近,在此运行时内存模型中,当分配了新的堆空间时(例如,在调用 malloc() 时),将根据栈指针的值检查堆。

  • Two-Region Model: 应用程序的栈和堆放置在单独的内存域中。要使用 Two-Region Model,必须导入函数 __use_two_region_memory。在这个运行时内存模型中,当分配新的堆空间时,将根据堆限制检查堆。

注意,在这两种运行时内存模型中,栈的增长都是未检查的。

在 Keil 中,一般都是用的 Two-Region Model。无论哪一种方式,都需要我们自己来定义。在 Keil 项目中,通常会在启动文件(.s) 中指定内存模型。

下面就来看一下这两种方法的实现。

2.4.1 在分散加载文件中实现

ARM C 库提供了 __user_setup_stackheap() 函数的多种实现,该函数会使用在分散加载文件中定义的与堆和栈相关的符号来生成堆栈。

如果要选择 Two-Region Model,则需要在分散文件中定义两个特殊的执行域,分别为 ARM_LIB_HEAP 和 ARM_LIB_STACK 。两个域都有 EMPTY 属性。这样,ARM C 库将不再使用默认的 __user_setup_stackheap() ,而是使用如下符号定义栈:

  • 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 域,并且必须分配一个大小,例如,在自己的分散加载文件中如下来定义栈和堆:

LOAD_FLASH
{
    ...
    ARM_LIB_STACK 0x40000 EMPTY -0x20000  ; Stack region growing down
    { }
    ARM_LIB_HEAP 0x28000000 EMPTY 0x80000 ; Heap region growing up
    { }
    ...
}

如果要选择 One-Region Model,则必须在分散加载文件中定义一个名为 ARM_LIB_STACKHEAP 的执行域,当前域也同样是 EMPTY 属性。这样, __user_setup_stackheap() 将使用以下符号:Image$$ARM_LIB_STACKHEAP$$Base 、 Image$$ARM_LIB_STACKHEAP$$ZI$$Limit 。例如,在自己的分散加载文件中如下来定义栈和堆:

LOAD_FLASH ...
{
    ...
    ARM_LIB_STACKHEAP 0x20000 EMPTY 0x20000  ; Heap and stack growing towards
    { }                                      ; each other in the same region
    ...
}
2.4.2 实现函数 __user_setup_stackheap()

如果我们在自己的代码中重新实现 __user_setup_stackheap() ,则此方法将覆盖所有库中相同的实现。在我们的项目中,一般会在启动文件(例如 STM32 中的 startup_stm32fXXX.s )实现 __user_setup_stackheap() 函数,如下图:

注意,如果要选择 Two-Region Model,则必须要引入函数 __use_two_region_memory

3、配置 sct 文件

通过 Use Memory Layout from Target Dialog 选项可以选择是使用 MDK 生成还是使用用户自定义的 sct 文件。

取消选择后,即可自己设置 sct 文件,点击下面的 Edit 即可编辑 sct 文件:

可以看到,其地址、大小和如下设置是对应的:

现在尝试分配一个变量到 RAM 中:

uint32_t gTest __attribute__((section(".my_data")));

int main(void)
{
	...
	gTest = 10;
	printf("Value gTest == %d is in: %p\r\n", gTest, &gTest);

	...
}

sct 文件修改如下:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00040000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  MY_DATA 0x20000000 0x00005000   {
    .ANY(my_section)
  }
  RW_IRAM1 0x20010000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }                              
}

最终打印出来的结果为:

map 文件:


当然,你如果对分散加载文件的使用并不熟悉或者是配置起来比较麻烦,也可以通过如下方式:


右键单击想要设置的文件,选中 Options for File '...',通过这几个选项就可以很方便地把代码放在我们想要放入的内存区域:

分散加载文件 scatter files 对本文做了一些补充说明

【STM32】sct 分散加载文件的格式与应用 在 MDK 的“Options for Target->Linker->Use Memory Layout from Target Dialog”选项可配置该选择。1.勾选时, 阅读详情

相关推荐

[Cortex-M3]-3-分散加载文件解析(.sct)

目录1 分散加载文件.sct 2 如何生成.sct文件3 *(InRoot$$Sections) 说明4 如何修改分散加载文件5 已经初始化变量的初值,存储位置6 +RW +ZI和+RO如何执行 MDK的分散加载主要是通过.sct文件实现的,链接器根据.sct文件的配置分配各个节区地址,生成分散加载代码,因此通过修改该文件可以定制具体节区的存储位置。 那为什么需要分散加载文件呢?不用可以吗? 一般情况下,可以不独自编写分散加载文件,ARM链接器直接按照默认

汽车电子开发 3006

SCT分散文件

定义RAM1的运行时域,使用.ANY进行随意分配变量,这里不能使用*号代替,*表示匹配所有的目标文件,定义RAM2的运行时域,使用.ANY进行随意分配变量,这里不能使用*号代替,*表示匹配所有的目标文件,定义RAM1的运行时域,使用.ANY进行随意分配变量,这里不能使用*号代替,*表示匹配所有的目标文件,定义一个运行时域,域基址:0x10000000,域大小为0x00008000,对应实际RAM大小。定义一个运行时域,第一个运行时域必须和加载时域起始地址相同,否则库不能加载到该时域的错误,

qq_41659556的博客 1819

Keil 中的 sct 文件

Keil 中的 sct 文件

扬帆起航 1074

Keil MDK的sct分散加载文件详解

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

a只如初见的博客 2万+

动态库加载失败终极指南:从libbz2.so.1错误看Linux依赖管理本质

本文以经典的libbz2.so.1加载错误为例,深入剖析Linux动态链接库管理的核心机制。文章不仅提供从ldd检查、符号链接创建到LD_LIBRARY_PATH设置等实战解决方案,更系统性地讲解了动态链接器的寻库路径、版本管理及依赖问题预防策略,帮助开发者从根本上理解和掌握Linux依赖管理本质。

weixin_29212429的博客 446

<202505高项>《【VIP合集】 软考高项(第四版)十大知识域、五大过程组、ITTO输入输出工具、项目绩效域》

软考高项(第四版)十大知识域、五大过程组、ITTO输入输出工具、项目绩效域

Else 的博客 1850

内存分配基础:SCT文件的基本概念

在 Keil MDK(μVision)中,链接器脚本文件(分散加载文件,Scatter-Loading File)用于控制代码和数据在内存中的分布。

weixin_44562404的博客 2343

【YOLO多模态检测顶刊】TGRS 2025范文解读,RGFNet 可见光-红外图像融合目标检测,2026年基于YOLO多模态融合属于发文热点,小论文和大论文通用,通读顶刊了解做实验和论文写作的全流程

🔥本文提出了一种反射率引导的渐进特征对齐网络(RGFNet)用于全天候无人机目标检测。该方法利用Retinex理论从可见光图像中提取光照不变的反射率特征,设计了反射率引导协同对齐模块(RCAM)实现跨模态双向特征对齐,并通过光照感知选择性融合模块(LSFM)在共享状态空间中进行高效特征交互。在DroneVehicle和DVTOD数据集上的实验表明,RGFNet分别达到81.4%和88.5%的mAP,显著优于现有方法。该方法有效解决了低光照条件下可见光-红外图像特征错位问题,为全天候无人机检测提供了新思路。

Ai缝合怪、助力小伙伴高效发论文 1075

分散加载文件 scatter files

当链接器创建镜像文件时,它会创建一些 ARM 预定义的与域或者节相关的符号。这些符号就代表了链接器创建创建镜像的依据。链接器定义了一些 ARM 保留的符号,我们可以在需要时访问这些符号。这些符号是包含$$字符序列的符号以及所有其他包含$$字符序列的外部名称。我们可以导入这些符号地址,并将它们作为汇编语言程序的可重定位地址使用,或者将它们作为 C 或 C++ 源代码中的extern符号来引用。如果使用--strict编译器命令行选项,则编译器不接受包含的符号名称。要重新启用支持,请在编译器命令行中包含。

Projectsauron 的博客 1万+

MATLAB代码实现了一个柱塞泵配流盘过流面积的计算和可视化功能

该MATLAB代码实现了一个柱塞泵配流盘过流面积的计算和可视化功能。输出曲线可直接用于验证设计的合理性(如是否存在过流面积突变或不足)。的不同范围,选择对应的几何模型计算过流面积。通过分段逻辑计算柱塞腔在不同旋转角度(过流面积在特定条件下会被限制(如。),确保结果符合物理实际。条件分支,根据旋转角度。

huanghm88的专栏 579

在Simulink中构建永磁同步电机的网络化控制模型,并分析通信网络对系统性能的影响

核心优势通过仿真验证了网络延迟和丢包对PMSM控制性能的影响。提供了改进PI参数或引入自适应控制的解决方案。扩展方向抗干扰控制:结合卡尔曼滤波或滑模控制抑制网络噪声。时间敏感网络(TSN)建模:参考知识库[2]的中断触发方式,实现确定性通信。网络安全仿真:模拟恶意攻击(如数据篡改)对控制系统的威胁。

xiaoheshang_123的博客 167

浅析keil的scf分散加载文件-基于STM32的例程

浅析keil的scf分散加载文件-基于STM32的例程关于分散加载文件分散加载文件.sct 关于分散加载文件 keil编译器的链接的时候,是根据分散加载(.scf后缀的文件)来确定程序的加载域和运行域的。加载域就是程序运行前在flash中具体分区情况,执行域就是程序运行后,程序在flash和ram中的分区情况。这里引用野火关于加载视图和执行视图的对比图: 可以看到,左边是加载视图,RW段和RO段对应的存储空间我们称为加载域。当程序运行后,RW段中的数据会被复制到RAM中,同时还会初始化一个ZI段用来存放没有

小胡的博客 2531

【ESD专题】从原理上分析TVS管PCB Layout的经验法则

我们常常会听到的一些经验法则,按这些经验法则去做,一般也不会有什么问题,但是到底是为什么呢? 没有从原理上分析和证明的时候,往往在Layout之后还要担心实际测试结果怎么样。或是在实际测试出问题后,根本无法进行分析,难道说修改一个版本就好了?那要从哪里修改呢?也无从下手呀。...

一点硬件 1446

STM32开发入门:从零搭建Keil5工程模板与标准外设库配置详解

嵌入式开发中,集成开发环境(IDE)是连接开发者与硬件的重要桥梁,它集成了编译器、调试器和项目管理器,负责将高级语言代码翻译成机器码。Keil MDK作为ARM Cortex-M系列微控制器的主流IDE,其工程配置的准确性直接决定了后续开发的效率与稳定性。对于STM32这类基于Cortex-M内核的MCU,标准外设库(SPL)提供了贴近寄存器的硬件抽象层,是理解底层原理和进行高效嵌入式编程的基础。通过合理配置工程目录结构、头文件路径、全局宏定义(如STM32F10X_MD)以及Flash下载算法,可以构建一

weixin_33714884的博客 291

PCL Super4PCS算法实现点云粗配准(版本一)【2025最新版】

Win11系统下实现[Super4PCS: Fast Global Pointcloud Registration via Smart Indexing一文中的配准算法。

点云侠的博客 3377

原理和代码解读:用Diffusion Models高清图像修复(Image Inpainting)

在最近的Diffusion Models应用中,Image Inpainting+ControlNet/Lora等工作在模特衣服生成、家居场景重建等场景中得到了广泛的应用。这篇博客主要介绍Diffusion Models如何在修复高清图像的。

沉迷单车的追风少年 2494

第六日学习日志

1、了解学习DM1160的主控两个CPU的地址映射,以及不同种类memory和registers的特点,用途。 2、学习分散加载文件浅析,同时对应项目的.sct文件,理解其中的代码含义,不过目前对照只能理解基本的语法含义,还暂时未能完全搞懂各个部分的功能。 3、了解FW.BIN文件的生成流程,经keil编译生成.axf文件,然后根据.sct文件将不同的code 、data放入不同类别的memory里,映射关系和大小在memamp.h文件里可以找到。然后生成不同种类的bin文件,最终再由AfterBuild.

electrical_engineer0的博客 225

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

嵌入式内存管理:从物理介质到链接脚本与运行时优化

内存是计算机系统中程序运行时数据和指令的存储空间,其管理效率直接影响系统性能与稳定性。从原理上看,内存分为ROM、RAM等物理介质,软件通过链接脚本规划其布局,将代码与数据分配到不同段(如.text、.data、.bss)。在嵌入式等资源受限场景,精细的内存管理技术价值凸显,能有效避免内存不足和泄漏问题。应用时,开发者需理解堆栈机制、内存分配器原理,并掌握如将关键函数复制到RAM执行(Copy the functions to RAM)等优化手段,以提升实时性。本文围绕嵌入式开发,深入探讨了内存布局、链接脚

weixin_33860553的博客 488

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Keil中sct分散加载文件学习

分散加载文件是一个文本文件,通过编写一个分散加载文件来指定ARM连接器在生成映像文件时如何分配RO/RW/ZI等数据的存放地址。如果不用SCATTER文件指定,那么ARM连接器会按照默认的方式来生成映像文件,一般情况下我们是不需要使用分散加载文件的。分散加载区域分为两类:加载区:该映像文件开始运行前存放的区域,即当系统启动或加载时应用程序存放的区域。执行区:映像文件运行时的区域,即系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行是可以有一个或多个执行块。

weixin_42663633的博客 1628

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

分散加载(3)---sct文件说明

1)分散加载文件由加载域Load region和执行域Execution region组成,一个分散加载文件中可以定义多个加载域Load region,一个加载域Load region中可以定义多个执行域Execution region,一个执行域Execution region可以定义多个输入节input section。2)区域单位名称: 域region,节section。2.1)加载域的构成:定义一个加载域,由以下几个部分组成:加载域名称,基地址,属性,最大内存空间,至少一个执行域。

hill_guo的博客 2165

keil的sct文件_STM32 分散加载文件 .sct 解析

1、STM32 启动文件与 .sct 文件分析1) 定义STACK段,{NOINIT,读写}:分配一段内存大小为0.5K;2) 定义HEAP段, {NOINIT,读写}:分配一段内存大小为1K;3) 定义RESET段,{DATA,只读}:DCD各种中断向量;4) 定义|.text|段,{CODE,只读}:Reset_Handler函数,函数中最后加载了__main;对剩余的中断函数进行了弱定义;在...

weixin_33372672的博客 6260

嵌入式工程师必看!Keil MDK-ARM .sct 文件全解析,掌控内存布局就靠它

在嵌入式开发中,你是否遇到过这些问题:想把关键函数放到 RAM 中提速却不知如何操作?多块 Flash/RAM 的芯片不知如何分配代码?Bootloader 和应用程序共存时总出内存冲突? 其实解决这些问题的核心,就藏在 Keil MDK-ARM 的一个特殊文件里 ——Scatter-Loading 文件(.sct 文件)。今天这篇文章,我们就从基础到实战,手把手教你玩转.sct 文件,彻底掌控单片机的内存布局。

MYLK的博客 2139

深入解析SCT分散加载文件

摘要:分散加载文件(.sct)是ARM Cortex-M芯片的链接控制文件,用于定义程序在Flash和RAM中的存储分配。核心结构包括加载域(定义物理存储地址)和执行域(定义运行时存储)。典型配置包含主程序区(代码和只读数据)和RAM数据区(变量)。通过自定义段(如myflash/myram)可将特定数据分配到指定区域,需配合__attribute__((section))使用。

2402_83411382的博客 2317

keil STM32中sct 分散加载文件学习

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

weixin_45829708的博客 6914

keil 中sct文件的分析

; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x00026000 0x000C7000 { ; load region size_regi...

wanjietiam的博客 2089

Keil MDK的.sct加载文件

Keil MDK(MicroVision Development Kit)中的是链接器(ARM Linker)用于精确控制代码和数据在嵌入式设备内存中布局的关键配置文件。它取代了传统的启动代码内存初始化,允许开发者灵活定义内存分区、地址分配和段(section)的加载/执行位置。RORWZI.oABSOLUTERELOCEMPTY.o.ANY+属性+RO+RW+ZIRESET+First__main.ooffsetALIGN nn。

创新改变世界! 1866
上一篇: FreeRTOS 内存管理源码解析
下一篇: hex 文件和 bin 文件剖析
Projectsauron
博客等级 码龄4年 2587粉丝 100原创
评论 13
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值