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

间接使用GNU链接器链接失败:ld成功g++报错问题咨询

问题原因分析与解决办法

当你用arm-none-eabi-g++替代直接调用ld时,核心问题在于g作为C编译链的前端工具,会自动注入一系列默认的启动目标文件和链接规则,而这些是直接调用ld时不会自动添加的,这就导致了两个报错:

1. 多重定义__dso_handle

  • g默认会链接crtbegin.o——这个文件是GCC用来处理C全局对象的构造/析构(动态初始化)的辅助模块,它内部已经定义了__dso_handle符号。
  • 你的代码中(具体是main.cpp里的std::__ioinit相关逻辑)也生成了__dso_handle的定义,两者冲突。而直接调用ld时你没有手动添加crtbegin.o,所以不会触发这个重复定义问题。

2. 未定义__bss_start__和__bss_end__

  • g++还会自动链接crt0.o——这是标准C的启动文件,包含程序的入口_start函数,这个函数依赖__bss_start__和__bss_end__这两个符号来完成BSS段的清零初始化。
  • 但你的自定义链接脚本game.ld里应该只定义了常规的__bss_start和__bss_end(或者_bss_start/_bss_end),符号名和crt0.o期望的不匹配,导致链接时找不到。直接调用ld时你没加crt0.o,自然不会有这个依赖问题。

解决办法

如果你想继续用g++来完成链接(好处是它能自动处理C的一些链接依赖逻辑),最简单的方式是**禁用g自动添加的启动文件**,添加-nostartfiles选项即可:

arm-none-eabi-g++ -nostartfiles -L/home/th/opt/arm-none-eabi/lib/ -L/home/th/opt/lib/gcc/arm-none-eabi/8.2.0/ -T /home/th/autoreverse/game/game.ld main.cpp.obj init.cpp.obj syscalls.cpp.obj queue.cpp.obj echange.cpp.obj echangeur.cpp.obj startup.s.obj -lstdc++ -lc -lgcc -o game.elf

这个选项会让g++表现得和直接调用ld类似,只链接你明确指定的目标文件和库,不会自动注入crt0.o、crtbegin.o这些启动模块——而你已经提供了自己的startup.s.obj,完全不需要依赖默认的启动文件。

如果你的场景确实需要依赖crt0.o的启动逻辑,那就要修改game.ld链接脚本,添加符号别名:

__bss_start__ = __bss_start;
__bss_end__ = __bss_end;

让crt0.o能找到它需要的符号,但嵌入式开发中一般更推荐使用自定义的启动文件,所以第一种方法更常用。

内容的提问来源于stack exchange,提问作者bitmap.kid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:00:35