使用arm-none-eabi-gcc编译,如何让ELF支持自定义.sram段替代默认段?
解决ARM嵌入式编译自定义.sram段及链接器缺.bss的问题
核心问题原因
链接器提示缺少.bss段,是因为arm-none-eabi-gcc默认会生成与.bss相关的符号(如__bss_start、__bss_end),即使你的代码里没有用到.bss变量,链接器也会检查这些符号对应的段是否存在。另外,ARM EABI5 ELF格式完全支持自定义段名,a.out的限制对你的场景不适用。
具体实现步骤
1. 编写正确的链接脚本
在链接脚本中,需要同时定义自定义的.sram段,以及保留空的.bss段(或处理默认段依赖),示例如下:
/* 定义内存区域:根据你的硬件调整起始地址和长度 */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } SECTIONS { /* 保留.text段存放启动代码和默认编译生成的代码(如果不需要可后续通过选项清理) */ .text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) } > FLASH /* 自定义.sram段:将需要加载到SRAM的初始化数据放在这里 */ .sram : { __sram_start = .; /* 定义段起始符号,方便启动代码初始化 */ *(.sram) /* 匹配代码中标记为.sram的变量 */ *(.sram.*) /* 匹配.sram.xxx这类子段 */ __sram_end = .; /* 定义段结束符号 */ } > SRAM AT > FLASH /* AT > FLASH表示初始化数据存放在FLASH,启动时复制到SRAM */ /* 必须保留.bss段:即使没有变量,也要定义空段满足链接器的符号检查 */ .bss : { __bss_start = .; *(.bss) *(.bss.*) *(COMMON) __bss_end = .; } > SRAM }
2. 在代码中标记变量到.sram段
用GCC属性__attribute__((section(".sram")))指定变量存放到自定义段:
// 初始化数据会先存在FLASH,启动时复制到SRAM uint32_t my_sram_buffer __attribute__((section(".sram"))) = {0x11, 0x22, 0x33, 0x44}; // 如果是未初始化数据,也可以放.sram(但通常未初始化用.bss,这里仅示例) uint8_t my_uninit_sram_var __attribute__((section(".sram")));
3. 解决.bss缺失的两种可选方案
方案一(推荐):保留空.bss段
像上面的链接脚本一样,即使没有.bss变量,也定义空的.bss段,链接器就不会报错。这种方式兼容编译器的默认行为,不需要修改编译选项。方案二:禁用默认.bss相关符号
如果确实不需要.bss段,可以在编译时添加以下选项,告诉编译器不要生成默认的COMMON段和标准库依赖:arm-none-eabi-gcc -c -fno-common -ffreestanding your_code.c -o your_code.o这种方式需要你完全自定义启动代码,避免依赖标准库的初始化逻辑,适合极简嵌入式场景。
4. 链接命令与选项
链接时指定你的自定义脚本,可选添加--gc-sections去掉未使用的段:
arm-none-eabi-gcc -T your_script.ld --gc-sections obj/*.o -o app.elf
验证结果
编译链接完成后,用readelf -S app.elf查看段信息,应该能看到.sram段,同时不会有.bss缺失的错误。
内容的提问来源于stack exchange,提问作者zupoluzu
相关产品推荐
相关产品推荐

