You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC Linker中__bss_start__与__bss_end__符号长度为0的问题

解决__bss_start__/__bss_end__符号异常导致BSS清零跳过的问题

最近我在钻研嵌入式裸机程序的底层运行逻辑时,自己写了配套的C代码和链接脚本,生成的二进制能正常驱动LED闪烁,但调试时碰到了一个头疼的问题:__bss_start__和__bss_end__两个符号的值居然都是0x20000000,导致我的BSS段清零函数因为判断start >= end直接跳过执行了。

我用objdump工具分析目标文件,得到了这样的输出:

20000000 g O .bss 00000004 timer_delayCount

这说明.bss段其实是正常的——长度4字节,起始地址正确落在0x20000000,但为什么链接脚本里定义的__bss_start__和__bss_end__没有正确计算出段的结束地址呢?

结合我的排查经验,给你几个可能的解决方向:

  • 检查链接脚本的符号定义逻辑:这是最常见的出错点。很多人会把__bss_end__的位置写错,正确的写法应该是在.bss段的定义块里,先标记起始,再放段内容,最后标记结束,示例如下:
    .bss :
    {
      __bss_start__ = .;  /* 标记BSS段起始地址 */
      *(.bss)             /* 包含所有目标文件的.bss段 */
      *(COMMON)           /* 包含公共符号 */
      __bss_end__ = .;    /* 标记BSS段结束地址 */
    } > RAM               /* 指定加载到RAM区域 */
    
    要是把__bss_end__写在了.bss段内容之前,那它的值自然会和起始地址一样。
  • 确认RAM内存区域的定义:链接脚本里的RAM区域如果起始地址正确但长度设置过小,或者定义有误,链接器可能无法正确扩展.bss段的结束地址,导致__bss_end__和起始地址重合。
  • 核对符号名的拼写:不同编译器/链接器对BSS段符号的命名可能有差异,比如有些是__bss_start(无末尾下划线)、__end_bss等。如果你的链接脚本里的符号名和C代码里引用的不匹配,或者不符合工具链的约定,就会出现符号值异常。
  • 检查C代码里的符号引用方式:在C代码里声明这些符号时,要用正确的类型,比如:
    extern unsigned char __bss_start__;
    extern unsigned char __bss_end__;
    
    避免用指针类型或者错误的类型转换,防止地址计算出现偏差。

如果以上方法都没解决问题,建议编译链接时加上-Wl,-Map=output.map参数生成链接映射文件,查看__bss_start__和__bss_end__在映射文件里的实际值,能更直观地看到链接器的分配逻辑,帮你快速定位问题。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:41:44