【问题标题】:How to export template instantiation as non weak?如何将模板实例化导出为非弱?
【发布时间】:2021-08-02 23:46:01
【问题描述】:

C++ 模板函数作为弱符号导出,以解决单一定义规则 (related question)。在为每个用例显式实例化函数的情况下,有没有办法将符号导出为非弱?

示例用例:

// foo.hpp
template<typename T>
void foo();

// All allowed instantiations are explicitly listed.
extern template void foo<int>();
extern template void foo<short>();
extern template void foo<char>();
// foo.cpp
template<typename T>
void foo()
{
  // actual implementation
}

// All explicit instantiations.
template void foo<int>();
template void foo<short>();
template void foo<char>();

当我用 GCC 或 ICC 编译上面的代码时,它们被标记为弱:

$ nm foo.o
                 U __gxx_personality_v0
0000000000000000 W _Z3fooIcEvv
0000000000000000 W _Z3fooIiEvv
0000000000000000 W _Z3fooIsEvv

有没有办法防止这种情况发生?由于它们实际上是确定的,我不希望它们成为替代品。

【问题讨论】:

  • 您为什么希望其他实例化有所不同?在这种情况下,我们的想法是,符号弱并不重要,因为它们都有相同的定义。
  • 并不意味着“可以替代”。这意味着完全相同的候选人,其中任何一个都与其他任何一个一样好,因为它们是相同的。
  • 您要解决什么问题?为什么要阻止它?
  • 感谢 cmets。我同意最终的二进制文件并不重要。据我所知weak 表示该符号可以在链接期间与另一个同名符号进行切换;不需要相同的实现。它与模板一起使用以避免违反 ODR,因为模板实例化往往出现在许多目标文件中。我试图解决的问题是链接时间太慢,我想将链接器的工作减少到最低限度。

标签: c++ gcc linker elf icc


【解决方案1】:

objcopy 支持--weaken 选项,但您想要相反。

它还支持--globalize-symbol,但这似乎对弱符号没有影响:

gcc -c t.cc
readelf -Ws t.o | grep _Z3fooI

    14: 0000000000000000     7 FUNC    WEAK   DEFAULT    7 _Z3fooIiEvv
    15: 0000000000000000     7 FUNC    WEAK   DEFAULT    8 _Z3fooIsEvv
    16: 0000000000000000     7 FUNC    WEAK   DEFAULT    9 _Z3fooIcEvv

objcopy -w --globalize-symbol _Z3fooI* t.o t1.o && 
readelf -Ws t1.o | grep _Z3fooI

    14: 0000000000000000     7 FUNC    WEAK   DEFAULT    7 _Z3fooIiEvv
    15: 0000000000000000     7 FUNC    WEAK   DEFAULT    8 _Z3fooIsEvv
    16: 0000000000000000     7 FUNC    WEAK   DEFAULT    9 _Z3fooIcEvv

不要被吓倒,我们可以先本地化符号,然后全球化:

objcopy -w -L _Z3fooI* t.o t1.o &&
objcopy -w --globalize-symbol _Z3fooI* t1.o t2.o &&
readelf -Ws t2.o | grep _Z3fooI

    14: 0000000000000000     7 FUNC    GLOBAL DEFAULT    7 _Z3fooIiEvv
    15: 0000000000000000     7 FUNC    GLOBAL DEFAULT    8 _Z3fooIsEvv
    16: 0000000000000000     7 FUNC    GLOBAL DEFAULT    9 _Z3fooIcEvv

Voilà:符号现在被明确定义了。

我试图解决的问题是链接时间太慢,我想将链接器的工作减少到最低限度。

如果这使链接器的工作量减少(我对此表示怀疑),我认为这是链接器中的一个错误——如果符号被定义一次,那么该定义是否强或强对链接器无关紧要弱。

【讨论】:

  • 在进行了一些基准测试之后,当从弱符号切换到强符号时,我确实没有看到链接持续时间有任何差异 :)
猜你喜欢
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多