跳到主要内容

2. 内存区域与布局控制

链接脚本通过 MEMORY 命令描述芯片的物理内存区域,通过 SECTIONS 命令描述各输出段的摆放规则。本章介绍两者的语法与 KF32 的区域划分。

2.1 MEMORY 命令​

MEMORY 用于声明目标芯片的内存区域(名称、起始地址、长度),供后续段布局通过 > region 引用。以 KF32A158MQVSF(512K PFlash / 64K RAM / 32K DFlash)为例,链接脚本的 MEMORY 配置如下:

MEMORY
{
flash : ORIGIN = 0x00000000, LENGTH = 512K /* chip flash */
ram : ORIGIN = 0x10000000, LENGTH = 64K /* chip ram */
da_mem : ORIGIN = 0x00200000, LENGTH = 32K /* Flash Data Limit */

mode_mem : ORIGIN = 0x0C001420, LENGTH = 0x00000004 /* mode config*/
pro_mem : ORIGIN = 0x0C001000, LENGTH = 0x00000004 /* protect config */
}

2.1.1 区域职责说明​

编程相关空间为代码 flash 和变量 ram;其余空间用于定义 HEX 文件内容下的地址偏移与大小:

区域起始地址长度职责
flash0x00000000512KPFlash:程序代码与常量运行空间(VMA),同时承载 .data 初值的装载区(LMA)
ram0x1000000064K变量、堆栈运行空间;前 32K 为低功耗保持区(以产品规格书为准)
da_mem0x0020000032KDFlash:数据存储区域
mode_mem0x0C0014204模式配置区域(.debugormode 段)
pro_mem0x0C0010004加密保护区域(.protectmode 段)

2.2 SECTIONS 与布局控制​

SECTIONS 中每个输出段的配置格式为:

输出段名 (修饰符): { 输入段规则 } > 运行区域 [AT > 装载区域]
  • > region:指定输出段的运行地址 VMA;
  • AT > region:指定输出段的装载地址 LMA(未指定时 LMA = VMA);
  • (NOLOAD):标记该段不装载,不占用 HEX 内容。

链接脚本的整体布局框架如下:

SECTIONS
{
.text : { … } > flash /* 代码、常量、C++ 函数表 */
.data : { … } > ram AT > flash /* 已初始化数据,初值存 flash */
.bss (NOLOAD) : { … } > ram /* 未初始化数据 */
.heap (NOLOAD) : { … } > ram /* 堆 */
.stack (NOLOAD) : { … } > ram /* 栈,锚定 RAM 顶部 */
.flashdata : { … } > da_mem /* Flash Data */
.debugormode : { … } > mode_mem /* 模式配置字 */
.protectmode : { … } > pro_mem /* 加密保护配置字 */
… /* 调试段收集与 /DISCARD/ 丢弃 */
}

2.2.1 输入段匹配规则​

段配置格式为 文件名(输入段),其中 * 为通配符:

写法含义
*(.text*)匹配任意文件中以 .text 起始的段
vector.o(.text*)仅匹配 vector.o 文件下的 .text 起始段
KEEP (*(.init_array*))匹配且豁免死段优化(--gc-sections)
SORT(.init_array.*)按段名排序后依次并入(保证构造优先级)
备注

编译器默认按函数/变量拆分段(-ffunction-sections / -fdata-sections),每个函数或变量拥有独立段名(如 .text.main、.data.foo)。因此自定义数据段名匹配规则必须以 * 结尾(如 *(.UserRAMData*)),函数代码段则不需要。

2.2.2 定位计数器与符号赋值​

脚本中 = 运算里的 . 为当前定位计数器,符号 = . 将当前地址记录到符号中,供 startup 代码与调试分析使用。为 . 或符号赋绝对地址时,需注意 LLD 的绝对地址语义;仅做相对推进(. = . + 长度;)不受影响(见 4.1 定位计数器 . 的语义)。