Конфликт типа раздела для идентично определенных переменных

Этот вопрос возник в контексте этого вопроса: Найти неисполненные строки кода 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;
}

что приводит к 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 правильно...).

Есть ли способ получить больше информации об этом? Видите, что это за точный конфликт? Или это просто ошибка...?

1 ответ

Сообщение действительно очень плохое, но это не ошибка. Проблема здесь возникает со встроенной функцией foo() и происходит потому, что встроенные функции должны быть определены в каждом контексте перевода, где они используются. В этой ссылке мы можем прочитать об атрибуте раздела:
"..uninitialized переменные ориентировочно попадают в раздел common (или bss) и могут быть многократно" определены ". Использование атрибута section изменяет раздел, в который входит переменная, и может привести к тому, что компоновщик выдаст ошибку, если неинициализированная переменная имеет несколько определений... "

Таким образом, когда функция foo должна быть "определена" в функции main, компоновщик находит переменную cov, ранее определенную во встроенной функции foo, и выдает ошибку.

Давайте сделаем работу препроцессора и расширим определение 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();

Чтобы облегчить рассуждение, давайте изменим атрибут section определения в встроенной функции foo на cov.2 просто для компиляции кода. Теперь у нас нет ошибки, поэтому мы можем проверить объект (.o) с помощью objdump:

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

Мы видим, что компилятор делает foo:: cov, в разделе cov.2 GLOBAL (подписано буквой 'u'). Когда мы используем одно и то же имя раздела (cov), компилятор, пытающийся "определить" foo в главном блоке, обнаруживает предыдущий глобально определенный cov и выдает ошибку.

Если вы делаете встроенный foo статическим (inline static void foo(),,.), который не позволяет компилятору выдавать код для встроенной функции и просто копирует его во время раскрытия, вы увидите, что ошибка исчезает, потому что нет глобального foo::cov.

Другие вопросы по тегам