【问题标题】:Section type conflict for identically defined variables相同定义变量的节类型冲突
【发布时间】:2015-07-12 09:36:44
【问题描述】:

这个问题出现在这个问题的上下文中:Find unexecuted lines of c++ code

在搜索这个问题时,大多数人都试图将代码和变量添加到同一部分 - 但这绝对不是这里的问题。这是一个最小的工作示例:

unsigned cover() { return 0; }

#define COV() do { static unsigned cov[2] __attribute__((section("cov"))) = { __LINE__, cover() }; } while(0)

inline void foo() {
        COV();
}

int main(int argc, char* argv[])
{
        COV();

        if (argc > 1)
                COV();

        if (argc > 2)
                foo();

        return 0;
}

导致g++ -std=c++11 test.cpp (g++ (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)) 出现以下错误:

test.cpp:6:23: error: cov causes a section type conflict with cov
  COV();
                       ^
test.cpp:11:30: note: ‘cov’ was declared here
         COV();
                              ^

虽然这个错误不是很有帮助,因为它没有说明为什么这应该是一个冲突。 .ii 和 .s 临时文件都没有提示可能是什么问题。实际上.s文件中只有一个节定义

        .section        cov,"aw",@progbits

我不明白为什么下一个定义应该与这个冲突(“aw”,@progbits 是正确的......)。

有什么方法可以获取更多信息吗?看看具体是什么 冲突是什么?或者这只是一个错误......?

【问题讨论】:

  • 这个问题与Inline static data causes a section type conflict 完全相同,我写了接受的答案并附有详细解释,the OP's own subsequent solution 更好。 GCC 不支持在问题中使用__attribute__。
  • @MikeKinghan 建议:1/ 从副本中总结您的出色答案。 2/ 赚取赏金。 3/关闭问题重复。
  • @YSC 很受诱惑,但我觉得为我以前的答案提升 295 个代表然后通过总结它再提升 100 个左右的代表是不合适的 - 当我只有机会由于在获得赏金之前没有及时注意到这个骗局并对其进行近距离投票!
  • @Mike - 据我所知,您其他答案中的分析是正确的。然而,这个问题与识别问题部分有关。这就是为什么:“此赏金试图通过查明违规者来获得解决冲突的规范答案”。 (我们也有同样的问题。我们有将近 200 个目标文件,我们不知道是哪些符号导致了失败。我们无法从数百个目标文件中手动检查数十万个符号)

标签: c++ c++11 gcc


【解决方案1】:

消息确实很糟糕,但这不是错误。 这里的问题发生在内联函数 foo() 并且发生是因为必须在它们使用的每个翻译上下文中定义内联函数。在这个link 中,我们可以读到section 属性:
"..未初始化的变量暂时进入公共(或 bss)部分,可以多次“定义”。使用 section 属性可以更改变量进入的部分和 如果未初始化的变量有多个定义,可能会导致链接器发出错误...".

因此,当 foo 函数需要在函数 main 中“定义”时,链接器会找到先前在内联函数 foo 中定义的 cov 变量并发出错误。

让我们进行预处理器的工作并扩展 COV() 定义以帮助澄清问题:

inline  void foo()
{
    do { static unsigned cov[2] __attribute__((section("cov"))) = { 40, cover() }; } while(0);
}

int main(int argc, char *argv[]) {
    do { static unsigned cov[2] __attribute__((section("cov"))) = { 44, cover() }; } while(0);

    if (argc > 1)
        do { static unsigned cov[2] __attribute__((section("cov"))) = { 47, cover() }; } while(0);

    if (argc > 2)
             foo();

为了方便推理,我们把foo内联函数中definition的section属性改成cov.2来编译代码。现在我们没有错误了,所以我们可以使用 objdump 检查对象 (.o):

objdump -C -t -j cov ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o

./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    d  cov    0000000000000000 cov
0000000000000000 l     O cov    0000000000000008 main::cov
0000000000000008 l     O cov    0000000000000008 main::cov

objdump -C -t -j cov.2 ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o 

./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    d  cov.2  0000000000000000 cov.2
0000000000000000 u     O cov.2  0000000000000008 foo()::cov

我们可以看到编译器在 cov.2 GLOBAL 部分中生成了 foo::cov(由“u”字母签名)。 当我们使用相同的节名 (cov) 时,编译器尝试在主块中“定义” foo 会遇到先前全局定义的 cov 并发出错误。

如果你将 inline foo 设为静态 (inline static void foo() . . .),这样可以避免编译器为内联函数发出代码并在扩展时复制它,你会看到错误消失了,因为没有全局foo::cov。

【讨论】:

  • 我认为这是对 Mike 在引用问题中的回答的重述。然而,这个问题与识别问题部分有关。这就是为什么:“此赏金试图通过查明违规者来获得解决冲突的规范答案”。 (我们也有同样的问题。我们有将近 200 个目标文件,我们不知道是哪些符号导致了失败。我们无法从数百个目标文件中手动检查数十万个符号)
猜你喜欢
  • 2022-08-16
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 1970-01-01
  • 2018-04-17
  • 2018-12-12
  • 1970-01-01
  • 2018-11-23
相关资源
最近更新 更多