Подтвердить что ты не робот

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

Этот вопрос возник в контексте этого вопроса: Найти неиспользуемые строки кода С++

При поиске этой проблемы большинство людей пытались добавить код и переменные в один и тот же раздел, но это определенно не проблема. Вот минимальный рабочий пример:

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

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

4b9b3361

Ответ 1

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

Таким образом, когда функция 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();

Чтобы облегчить рассуждение, измените атрибут раздела определения в 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 и вызывает ошибку.

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