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

Можно ли инструктировать C не инициализировать глобальные массивы нулями?

Я пишу встроенное приложение, и почти вся моя оперативная память используется глобальными байтовыми массивами. Когда моя прошивка загружается, она начинается с перезаписывания всей секции BSS в ОЗУ нулями, что совершенно не нужно в моем случае.

Есть ли способ, которым я могу дать указание компилятору, что ему не нужно инициализировать нулевые массивы нулем? Я знаю, что это также можно решить, объявив их в качестве указателей и используя malloc(), но есть несколько причин, по которым я хочу этого избежать.

4b9b3361

Ответ 1

Оказалось, что компоновщик script, включенный в мою toolchain, имеет специальный раздел noinit.

__attribute__ ((section (".noinit")))

/** Заставляет компилятор автоматически не обнулять заданный глобальный переменная при запуске, так что текущее содержимое ОЗУ сохраняется.  В большинстве случаев это значение будет случайным из-за поведение энергозависимой памяти после отключения питания, но может использоваться в некоторых конкретных обстоятельства, такие как передача значений обратно после системного сторожевого таймера reset.

Таким образом, все глобальные переменные, помеченные этим атрибутом, во время загрузки не будут инициализированы нулями.

Ответ 2

Проблема заключается в том, что стандарт C обеспечивает нулевую инициализацию статических объектов. Если компилятор пропустит его, он не будет соответствовать стандарту C.

В компиляторах встроенных систем обычно используется нестандартная опция "компактный запуск" или аналогичный. Когда включено, инициализация статических/глобальных объектов не будет происходить вообще нигде в программе. Как это сделать, зависит от вашего компилятора или в этом случае от вашего порта gcc.

Если вы укажете, какую систему вы используете, кто-то может предоставить решение для этого конкретного порта компилятора.

Это означает, что любая статическая/глобальная (статическая продолжительность хранения), которую вы инициализируете явно, больше не будет инициализирована. Вам придется инициализировать его во время выполнения, то есть вместо static int x=1; вам придется писать static int x; x=1;. Это довольно распространено для записи встроенных программ C таким образом, чтобы сделать их совместимыми с компиляторами, где статическая инициализация отключена.

Ответ 3

В стандарте C REQUIRES глобальные данные должны быть инициализированы до нуля.

Возможно, что некоторые производители встроенных систем предоставляют способ обойти эту опцию, но, безусловно, существует много типичных приложений, которые просто провалились бы, если "инициализировать до нуля" не было сделано.

Некоторые компиляторы также позволяют вам иметь дополнительные разделы, которые могут иметь другие характеристики, чем раздел "bss".

Другой вариант - это, конечно, "сделать свое собственное распределение". Поскольку это встроенная система, я полагаю, вы контролируете, как приложение и данные загружаются в ОЗУ, в частности, какие адреса используются для этого.

Итак, вы можете использовать указатель и просто использовать свой собственный механизм для назначения указателя на область памяти, которая зарезервирована для всех, для чего вам нужны большие массивы. Это позволяет избежать довольно сложного использования malloc - и это дает вам более или менее постоянный адрес, поэтому вам не нужно беспокоиться о том, чтобы найти, где ваши данные будут позже. Это, конечно, будет иметь небольшое влияние на производительность, поскольку оно добавляет еще один уровень косвенности, но в большинстве случаев это исчезает, как только массив используется как аргумент функции, поскольку он в любом случае распадается на указатель в этой точке.

Ответ 4

Есть несколько обходных решений, таких как:

  • Удаление раздела BSS из двоичного файла или установка его размера в 0 или 1. Это не будет работать, если загрузчик должен явно выделить память для всех разделов. Это будет работать, если загрузчик просто копирует данные в ОЗУ.
  • Объявление ваших массивов как extern в коде C и определение символов (вместе с их адресами) либо в коде сборки в отдельных файлах сборки, либо в компоновщике script. Опять же, если память должна быть явно выделена, это не сработает.
  • Исправление или удаление соответствующего кода BSS-обнуления либо в загрузчике, либо в стартовом коде, который выполняется в вашей программе до main().

Ответ 5

Вы уверены, что бинарный формат фактически включает раздел BSS в двоичном формате? В двоичных форматах, с которыми я работал с BSS, это просто целое число, которое сообщает ядру/загрузчику, сколько памяти выделяется и нулевое.

В C определенно нет общего пути, чтобы получить неинициализированные глобальные переменные. Это будет функцией вашей системы компилятора/компоновщика/времени выполнения и очень специфичной для этого.

Ответ 6

Все встроенные компиляторы должны допускать сегмент noinit. С помощью компилятора IAR AVR переменные, которые вы не хотите инициализировать, просто объявляются следующим образом:

__ no_init uint16_t foo;

Самая полезная причина для этого - позволить переменным сохранять свои значения над сторожевым таймером или коричневым цветом reset, что, конечно же, не происходит в компьютерных программах на C, поэтому его упущение со стандартного C.

Просто найдите инструкцию для компилятора для "noinit" или чего-то подобного.

Ответ 7

с gcc, -fno-zero-initialized-in-bss