Ошибка GCC "<переменная> вызывает конфликт типов раздела"
Почему возникает ошибка компилятора при попытке поместить две (RAM) переменные, которые отличаются только значениями инициализации, в один и тот же раздел?
проблема
Источник C:
int __attribute__((section(".in_my_data"))) _foo = 1;
int __attribute__((section(".in_my_data"))) _bar = 0;
Соответствующий вывод компилятора GCC:
mcve/main.c:75:45: error: _bar causes a section type conflict
Сценарий компоновщика содержит следующую строку в SECTIONS
определение, но (фатальная) ошибка от компилятора, а не от компоновщика.
.my_data : { *(.in_my_data) } > data
Дальнейшая информация
Изменение источника C, чтобы позволить компилятору использовать два раздела, позволяет компиляции проходить, но компоновщик генерирует ошибку, если два входных раздела отображаются в один и тот же выходной раздел.
Источник C:
int __attribute__((section(".in_my_data_nonzero"))) _foo = 1;
int __attribute__((section(".in_my_data_zero"))) _bar = 0;
Сценарий компоновщика:
.my_data : { *(.in_my_data*) } > data
(Соответствующий) выход компоновщика:
Link Error: attributes for input section '.in_my_data_nonzero' conflict
with output section '.my_data'
Изменение порядка строк в источнике C только изменяет, какой раздел (второй появляется в источнике C) содержит ошибку.
Вопрос
Какой атрибут (ы) требуется компилятору GCC для секции для переменной, которая инициализируется с нуля, а не для той, которая инициализируется с ненулевым значением, или наоборот?
Компилятор пытается поместить переменные, которые инициализируются в ноль в .bss
раздел, а не .data
раздел для инициализированных данных? Или есть другой раздел для данных, которые инициализируются на ноль?
Смежные вопросы
Подобные вопросы касаются проблем с конфликтами между типами памяти (ПЗУ или ОЗУ):
- "Конфликт типов разделов" в руку встроен, что это?
- Как решить проблему с "конфликтом типов разделов" и рекомендации по использованию атрибута section с gcc
- Получение "конфликта типа раздела" с использованием M2tklib и glcd
... или положить инициализированный const
данные в выходных разделах NOLOAD:
... или остаются загадкой относительно причины и могут быть связаны:
Насколько я могу судить, ни один из вышеперечисленных вопросов не имеет ответа, который я могу применить для решения этого вопроса.
2 ответа
Предупреждение: этот ответ может относиться только к компилятору Microchip XC16.
Исследование
Компилятор присваивает атрибуты переменным C так, чтобы они были распределены по определенным разделам следующим образом (см. Примечание 1 ниже для конкретной информации XC16).
int a = 1;
- назначен.data
,int b = 0;
- назначен.bss
,int c;
- назначен.bss
,
Первый и последний из них имеют смысл: .data
используется для инициализированных данных и .bss
используется для неинициализированных данных. Тем не мение, .bss
данные также устанавливаются в ноль при запуске ANSI C (см. Примечание 2).
Ответ
Может показаться, что компилятор включает в себя переменные, которые инициализированы, но со значением, равным всем битам 0 в .bss
раздел, а также все те, которые вообще не инициализированы.
Согласно википедии:
Реализация также может назначать статически распределенные переменные и константы, инициализированные значением, состоящим только из битов с нулевым значением, для секции BSS.
Временное решение
GCC имеет опцию -fno-zero-initialized-in-bss
который может быть использован, чтобы заставить все переменные, которые инициализируются с нуля в .data
раздел, как указано в этом ответе. Это может быть применено к файлу на основе источника, но не к отдельным переменным.
Желаемое за действительное
Было бы неплохо, если бы __attribute__((**doload**))
это может быть применено, чтобы заставить компилятор поместить инициализированную нулем переменную в .data
вместо .bss
,
Заметки
Примечание 1: компилятор XC16 может использовать .ndata
а также .nbss
указать рядом данные под адресом 0x8000.
Примечание 2: Маркировка переменной с помощью __attribute__((noload))
приведет к исключению переменной из .bss
раздел. XC16 генерирует определенный выходной раздел с уникальным именем (GUID?) Для каждой переменной, помеченной как таковая.
По умолчанию GCC размещает классы объектов в разных разделах, исполняемый код переходит в.text, инициализированные данные в.data, статические данные в.bss и некоторые более неясные.
Если вы попытаетесь заставить два объекта разных классов принадлежать одному и тому же разделу, GCC вызовет ошибку этого раздела.
Решение состоит в том, чтобы разместить их в разных разделах и, наконец, сказать компоновщику, чтобы в конечном итоге объединить эти объекты в одном разделе, например:
.boot : { // target ELF section will contain....
*(.boot) // executable code
*(.boot_rodata) // constant data
*(.boot_bss) // static data
} > BOOT // to finally be place in this area