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

链接错误:构造虚表定义于已丢弃段——定位GCC/Clang/Gold的Bug

结论:这个Bug出自Gold链接器

我可以明确告诉你,你遇到的链接错误确实是Gold链接器的Bug,而非GCC或Clang的问题。咱们来一步步拆解这个问题:

问题场景重现

你的SSCCE代码和编译流程可以完整复现问题,先整理清晰:

头文件 a.hpp

struct A { int i; ~A() { asm("" : "=r"(i)); } };
struct B : public virtual A { };
struct C : public B { };
struct D { D(C); };

源文件 a.cpp

#include "a.hpp"
void f(C) { }
D::D(C c) { f(c); }

源文件 main.cpp

#include "a.hpp"
int main() { C c; D d(c); }

编译链接命令

g++ -O3 -fPIC -c a.cpp
clang++ -O3 -fPIC -c main.cpp
clang++ -fuse-ld=gold main.o a.o -o main

链接时触发的错误:

a.o:a.cpp:function D::D(C) [clone .cold]: error: relocation refers to global symbol "construction vtable for B-in-C", which is defined in a discarded section
section group signature: "_ZTV1C"
prevailing definition is from main.o
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)

Bug原因分析

这个问题的核心是Gold链接器在处理跨编译器生成的section group时的逻辑缺陷:

  1. 虚继承场景下,编译器会生成特殊的「构造vtable」(construction vtable),用于对象构造阶段的虚函数调用,这类vtable会被归到以类的完整vtable(_ZTV1C即vtable for C)为签名的section group中。
  2. GCC和Clang对于这类section group的生成细节(比如符号命名、section标记)存在细微差异。
  3. Gold链接器在合并两个编译器生成的目标文件时,错误地认为Clang生成的_ZTV1C section group是「主导定义」,进而丢弃了GCC生成的、属于同一组的构造vtable符号,但GCC编译的a.o中还有代码需要引用这个被丢弃的符号,最终导致重定位错误。

为什么你的调整能解决问题?

你提到的几种有效调整,本质上都是避开了Gold的缺陷触发条件:

  • 统一用同一编译器编译所有文件:此时两个目标文件的section group生成逻辑一致,Gold能正确识别并合并相关符号,不会出现误丢弃。
  • 改用ld而非gold链接:传统GNU ld的section group处理逻辑和Gold不同,不会触发这个错误判断。
  • 去掉main.cpp的-O3或-fPIC:改变了Clang生成的符号或section结构,使得Gold不再将其视为「主导定义」,或者避免了构造vtable的特殊section标记。
  • 交换目标文件顺序:Gold会优先处理排在前面的目标文件的section group,此时GCC生成的符号会被保留,不会被后续Clang的文件覆盖丢弃。

后续建议

你完全可以把这个Bug提交给GNU Binutils项目(Gold链接器的维护方),提交时记得附上你的SSCCE、编译链接命令和错误日志,这些信息能帮助开发者快速定位修复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:48:11