使用arm-none-eabi-gcc链接时出现`.bss`段内存区域未指定错误
链接阶段报错:
no memory region specified for loadable section '.bss' 问题描述
手动使用arm-none-eabi-gcc构建嵌入式应用,编译过程正常,但链接阶段仅抛出以下错误:
error: no memory region specified for loadable section `.bss'
已尝试最简链接脚本仍无法解决,脚本内容如下:
MEMORY { foo : ORIGIN = 0x50000000, LENGTH = 0xF0000000 } SECTIONS { .sram : { __sram_bss_start = .; *(.bss) *(.bss*) *(.text) __sram_bss_end = .; } > foo }
从脚本可见.bss已被明确分配到foo内存区域,无法理解报错原因。
编译链接命令
... SOURCES := source1.c SOURCES += source2.c ... OBJECTS := $(SOURCES:$(MYSRCDIR)/%.c=$(MYOBJDIR)/%.o) LD_FLAGS := -nostartfiles LD_FLAGS += -T linkerScript.ld LD_FLAGS += --entry=Reset_Handler LD_FLAGS += -Wl,-Map,"memoryMap.map" LD_FLAGS += -mcpu=cortex-m7 LD_FLAGS += -mthumb LD_FLAGS += -mlittle-endian LD_FLAGS += -mfloat-abi=hard LD_FLAGS += -mfpu=fpv5-sp-d16 LD_FLAGS += -specs=nano.specs LD_FLAGS += -specs=nosys.specs LD_FLAGS += -lc LD_FLAGS += -lm LD_FLAGS += -lgcc LD_FLAGS += --sysroot="/usr/lib/arm-none-eabi/newlib" #LD_FLAGS += --verbose all: $(BIN) $(BIN): $(OBJECTS) $(CC) -o $@ $^ $(LD_FLAGS) $(OBJDIR)/%.o : $(SRCDIR)/%.c @mkdir -p $(@D) $(CC) $(INC) $(CFLAGS) -o $@ -c $< $(DEFS)
工具版本
$ arm-none-eabi-gcc -v ... gcc version 9.2.1 20191025 $ arm-none-eabi-ld -v GNU ld (2.34-4ubuntu1+13ubuntu1) 2.34
更新测试结果
测试发现以下链接脚本可正常通过:
MEMORY { foo : ORIGIN = 0x50000000, LENGTH = 0xF0000000 } SECTIONS { /* 可正常工作 */ .sram : { *(.text) } > foo .bss : { *(.bss) } > foo /* 无法工作 */ /* .text : { *(.text) } > foo .sram : { *(.bss) } > foo */ }
怀疑是自定义段名.sram的问题,但根据资料,链接脚本段名应支持自定义,无需依赖项目其他定义。
问题原因及解决方法
这个错误的核心是链接器对标准段名和自定义段名的属性处理逻辑不同:
- 标准段名(如
.text、.bss、.data)会被链接器自动赋予对应属性:比如.bss默认是NOLOAD(无需加载到内存),.text默认是LOAD(需要加载)。 - 自定义段名(如
.sram)默认无任何属性,需显式指定。
当你把.bss(NOLOAD段)放入自定义的.sram段时,链接器会将.sram默认视为LOAD段,导致.bss的NOLOAD属性被覆盖,最终触发"未指定内存区域"的误报。
可行解决方式
方式一:给自定义段显式添加NOLOAD属性
修改初始链接脚本,给.sram段标记NOLOAD,明确告诉链接器该段无需加载:
MEMORY { foo : ORIGIN = 0x50000000, LENGTH = 0xF0000000 } SECTIONS { .sram (NOLOAD) : { __sram_bss_start = .; *(.bss) *(.bss*) *(.text) __sram_bss_end = .; } > foo }
注意:这种方式将LOAD属性的.text和NOLOAD属性的.bss放在同一段,虽能解决报错,但不符合嵌入式系统通常的内存布局规范,建议尽量分开处理。
方式二:分开定义标准段并分配内存
按照测试中正常工作的逻辑,将.text和.bss分别定义为独立段,或给自定义段赋予对应属性:
MEMORY { foo : ORIGIN = 0x50000000, LENGTH = 0xF0000000 } SECTIONS { .text : { *(.text) } > foo .bss (NOLOAD) : { *(.bss) } > foo // 或使用自定义段名时显式指定属性 // .sram_text : { *(.text) } > foo // .sram_bss (NOLOAD) : { *(.bss) } > foo }
测试差异说明
你更新中的两种测试情况差异原因:
- 正常工作的脚本中,
.bss是标准段名,链接器自动识别为NOLOAD属性,因此即使和自定义.sram段共存也无冲突。 - 无法工作的脚本中,
.bss被放入自定义.sram段,.sram默认LOAD属性覆盖了.bss的NOLOAD属性,链接器误判为该段未分配内存区域。
内容的提问来源于stack exchange,提问作者zupoluzu
相关产品推荐
相关产品推荐

