Ошибка 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 раздел для инициализированных данных? Или есть другой раздел для данных, которые инициализируются на ноль?

Смежные вопросы

Подобные вопросы касаются проблем с конфликтами между типами памяти (ПЗУ или ОЗУ):

... или положить инициализированный 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
Другие вопросы по тегам