__attribute__((section))可将const数组放入自定义段,再通过链接脚本中“.flash_lut (noload) : { . = 0x08004000; *(.flash_lut) } > flash”将其精确定位到flash指定地址,并需确保地址合法、对齐且未被预留。

用 __attribute__((section)) 指定数组在 Flash 中的绝对地址
嵌入式 C++ 中无法直接用 0x08004000 这样的地址“赋值”给数组,必须靠链接器脚本 + 编译器属性协同实现。最常用且可靠的方式是把数组放进自定义段(section),再在链接脚本中把该段映射到目标 Flash 地址。
例如,要把一个常量查找表放在 0x08004000(常见于 STM32F1 的 Flash 起始偏移):
const uint16_t my_lut[256] __attribute__((section(".flash_lut"))) = {0, 1, 4, 9, /* ... */};
注意:__attribute__((section)) 必须紧跟在变量声明后、初始化前;const 很关键——非常量数据不能放 Flash,否则编译会报错或链接失败。
链接脚本里必须显式定位 .flash_lut 段
仅加 section 属性不够,链接器不知道这个段该放哪。你得修改 .ld 文件,在 SECTIONS 块中插入明确位置:
.flash_lut (NOLOAD) : ALIGN(4)
{
. = 0x08004000;
*(.flash_lut)
} > FLASH
关键点:
-
NOLOAD表示该段不加载进 RAM(只保留在 Flash 映像中),避免启动时被复制 -
ALIGN(4)确保数组按字对齐,防止读取异常(尤其在 Cortex-M 上访问未对齐地址可能触发 HardFault) -
. = 0x08004000是绝对定位起点,不是偏移量;若此处已有其他段占用,链接会报region `FLASH' overflowed -
> FLASH指定内存区域,需确保链接脚本中已正确定义FLASH区域(起始地址和长度)
别忘了检查 Flash 页边界和写保护
单片机 Flash 写入以页(page)为单位,但这里只是**读取**常量数组,所以无需擦写。不过仍要确认两点:
- 目标地址
0x08004000是否落在合法 Flash 区间内(比如 STM32F103 是0x08000000–0x0801FFFF) - 该地址是否已被 Bootloader、固件升级区或 IAP 功能预留——强行覆盖会导致设备变砖
- 某些芯片(如 GD32)默认启用 Flash 读保护(RDP),虽然不影响运行时读取,但调试器可能无法读出该区域内容,导致 JTAG/SWD 下载失败或调试异常
验证是否真的落到目标地址:查 .map 文件
编译后生成的 .map 文件是最权威依据。搜索 my_lut 或 .flash_lut,你会看到类似:
.flash_lut 0x08004000 0x200
0x08004000 my_lut
如果地址不对,常见原因有:
- 链接脚本里
.flash_lut段没写. = 0x08004000,而是依赖上一段末尾自动对齐 - 数组定义漏了
const,导致编译器把它当成可读写数据,试图塞进 RAM 段(如.data) - 链接脚本中
FLASH区域定义错误,比如起始地址写成0x08000000但长度只有0x4000,而0x08004000已超界
实际地址不以代码注释或 IDE 预览为准,只认 .map 输出。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











