对于相同定义的变量,段类型冲突

exa*_*ple 18 c++ gcc c++11

这个问题出现在这个问题的背景下:找到未执行的c ++代码行

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

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;
}
Run Code Online (Sandbox Code Playgroud)

结果与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();
                              ^
Run Code Online (Sandbox Code Playgroud)

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

        .section        cov,"aw",@progbits
Run Code Online (Sandbox Code Playgroud)

我不明白为什么下一个定义应与此冲突("aw",@ progbits是正确的......).

有没有办法获得更多相关信息?看看确切的冲突是什么?或者这只是一个错误......?

小智 1

该消息确实非常糟糕,但它不是一个错误。\n这里的问题发生在内联函数 foo()\n 上,因为内联函数必须在它们使用的每个翻译上下文中定义。在此链接中,我们可以阅读有关节属性的信息:\n
“..未初始化的变量暂时进入公共(或 bss)节,并且可以乘以 \xe2\x80\x98define\xe2\x80\x99。使用节属性会更改什么如果未初始化的变量有多个定义,则变量进入的部分和\n可能会导致链接器发出错误...”

\n\n

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

\n\n

让 xe2x80x99s 使预处理器工作并扩展 COV() 定义以帮助澄清问题:

\n\n
inline  void foo()\n{\n    do { static unsigned cov[2] __attribute__((section("cov"))) = { 40, cover() }; } while(0);\n}\n\nint main(int argc, char *argv[]) {\n    do { static unsigned cov[2] __attribute__((section("cov"))) = { 44, cover() }; } while(0);\n\n    if (argc > 1)\n        do { static unsigned cov[2] __attribute__((section("cov"))) = { 47, cover() }; } while(0);\n\n    if (argc > 2)\n             foo();\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了方便推理,让\xe2\x80\x99s将foo内联函数中定义的section属性修改为cov.2,以便编译代码。现在我们没有\xe2\x80\x99t错误,因此我们可以使用objdump检查对象(.o):

\n\n
objdump -C -t -j cov ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o\n\n./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o:     file format elf64-x86-64\n\nSYMBOL TABLE:\n0000000000000000 l    d  cov    0000000000000000 cov\n0000000000000000 l     O cov    0000000000000008 main::cov\n0000000000000008 l     O cov    0000000000000008 main::cov\n\nobjdump -C -t -j cov.2 ./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o \n\n./cmake-build-debug/CMakeFiles/stkovf.dir/main.cpp.o:     file format elf64-x86-64\n\nSYMBOL TABLE:\n0000000000000000 l    d  cov.2  0000000000000000 cov.2\n0000000000000000 u     O cov.2  0000000000000008 foo()::cov\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们可以看到编译器将foo::cov,在 cov.2 节中设为 GLOBAL (由 \xe2\x80\x98u\xe2\x80\x99 字母签名)。\n当我们使用相同的节名称 (cov) 时,编译器,尝试在主块中 \xe2\x80\x98define\xe2\x80\x99 foo 遇到先前全局定义的 cov 并发出错误。

\n\n

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

\n