STM32链接脚本:无需指定长度将结构体存至固定内存地址
在STM32链接脚本中固定地址放置结构体(无需指定长度)的实现方法
核心思路
不需要新增MEMORY段,直接利用链接器的段定位功能,结合代码中的section属性标记结构体,让链接器自动计算结构体长度,同时优化段的衔接逻辑以减少不必要的空间浪费。
步骤1:代码中标记目标结构体
在C代码里,给需要固定地址的结构体添加section属性,确保链接器能识别到对应的段,同时避免被编译器优化掉:
// 定义你的结构体 typedef struct { uint32_t magic_code; uint16_t firmware_version; uint16_t checksum; // 其他结构体成员 } SWSystemHeader; // 标记到指定section,并强制保留 __attribute__((section(".SWHEADER_SECTION"), used)) SWSystemHeader g_sw_header = { .magic_code = 0xABCD1234, .firmware_version = 0x0201, // 初始化其他成员 };
步骤2:修改链接脚本
调整链接脚本的SECTIONS部分,实现以下逻辑:
- 中断向量表
.isr_vector正常放在FLASH起始地址 - 普通代码段
.text紧跟向量表,且不超过结构体的固定起始地址 - 将
.SWHEADER_SECTION强制定位到指定地址,链接器自动根据结构体大小分配空间 - 后续代码段从结构体结束地址开始继续排列,避免空间浪费
示例链接脚本代码:
MEMORY { FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K // 保留原有FLASH定义 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } SECTIONS { // 中断向量表,默认放在FLASH起始位置 .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) // 确保向量表不被优化丢弃 } >FLASH // 普通代码/只读数据段,紧跟向量表,上限为结构体固定地址 .text : { . = ALIGN(4); *(.text*) // 所有代码段 *(.rodata*) // 只读数据 *(.rodata.str1.1) // 限制该段不超过结构体固定起始地址,防止重叠 . = MIN(., 0x8000300); } >FLASH // 固定地址放置结构体段,无需手动指定长度 .SWHEADER_SECTION 0x8000300 : { KEEP(*(.SWHEADER_SECTION)) // 强制保留该段内容 } >FLASH // 后续代码段,从结构体结束地址开始继续排列 .text_post : { . = ALIGN(4); *(.text*) // 未在前一段分配的剩余代码 *(.rodata*) // 剩余只读数据 } >FLASH // 数据段和BSS段保持原有逻辑 .data : { . = ALIGN(4); __data_start__ = .; *(.data*) __data_end__ = .; } >RAM AT>FLASH .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) __bss_end__ = .; } >RAM // 栈和堆的定义保持原有设置 _estack = ORIGIN(RAM) + LENGTH(RAM); _Min_Stack_Size = 0x400; _Min_Heap_Size = 0x200; }
关键说明
- 无需指定结构体长度:链接器会自动根据
.SWHEADER_SECTION中的实际内容(即你的结构体大小)分配空间,不需要手动填写长度参数。 - 减少空间浪费:通过限制
.text段的上限,让普通代码尽量填满结构体固定地址前的空间;后续代码从结构体结束地址开始,避免中间出现大块未使用区域(如果普通代码未填满固定地址前的空间,这是固定地址要求导致的必然结果)。 - 防止段重叠:如果普通代码段长度超过了固定地址(0x8000300),链接器会直接抛出重叠错误,提前发现问题。
针对你当前方案的优化说明
你原来的写法重复定义了.text段,且用ALIGN(0x8000300)强制跳转地址,导致中间出现未使用空间。上面的方案通过拆分代码段、限制段范围的方式,最大程度利用了固定地址前后的空间,同时满足结构体固定地址的需求。
内容的提问来源于stack exchange,提问作者Peti634
相关产品推荐
相关产品推荐

