Статьи

Заполнение неиспользуемой памяти с помощью GNU Linker

Во многих моих приложениях я использую контрольную сумму CRC / контрольную сумму, чтобы убедиться, что код / ​​флэш-память на цели не изменена. Для этого учитывается не только код / ​​данные во флэш-памяти, но и все неиспользуемые пробелы в карте памяти. Вместо того, чтобы оставить его до флешера / отладчика (который обычно стирает его до 0xFF), я хочу заполнить его своим шаблоном. Линкер GNU использует шаблон 0 × 00 для неиспользуемых байтов внутри секций. Итак, этот пост собирается использовать линкер GNU для «заполнения» неинициализированной флэш-памяти шаблоном.

FLASH с шаблоном DeadBeef

FLASH с шаблоном DeadBeef

= заполнить команду файла компоновщика

У линкера GNU есть способ заполнить раздел. Документация компоновщика GNU перечисляет синтаксис SECTIONS как:

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill
...
}

Интересная вещь — это = fil l в конце: здесь я могу указать выражение, которое затем используется для заполнения раздела:

=fill

Включение =fillв определение раздела указывает начальное значение заполнения для этого раздела. Вы можете использовать любое выражение для указания заполнения. Любые нераспределенные дыры в текущем выходном разделе при записи в выходной файл будут заполнены двумя младшими байтами значения, при необходимости повторяющимися. Вы также можете изменить значение заполнения с помощью FILLоператора в содержании определения раздела.

Например

.text :
  {
  . = ALIGN(4);
  *(.text)  /* .text sections (code) */
  *(.text*)  /* .text* sections (code) */
  *(.rodata)  /* .rodata sections (constants, strings, etc.) */
  *(.rodata*)  /* .rodata* sections (constants, strings, etc.) */
  *(.glue_7)  /* glue arm to thumb code */
  *(.glue_7t)  /* glue thumb to arm code */
  *(.eh_frame)

  KEEP (*(.init))
  KEEP (*(.fini))

  . = ALIGN(4);

  _etext = .;  /* define a global symbols at end of code */
  } > m_text =0xEE

Заполнит мой раздел шаблоном байта 0xEE. Я могу убедиться в этом, сравнивая сгенерированные файлы S19 (см. « Двоичные (и S19) файлы для загрузчика mbed с плагинами Eclipse и GNU ARM Eclipse »):

Вставленный байт заполнения

Вставленный байт заполнения

❗ = Fill применяется только * внутри * выходного раздела, поэтому не заполняет пространство между выходными разделами!

FILL () Команда компоновщика

Заполнение = применяется к разделу вывода. Но если я хочу заполнить разные части в секции вывода, то следует использовать команду FILL:

FILL(expression)

Укажите «шаблон заполнения» для текущего раздела.
Любые неопределенные области памяти внутри раздела (например, области, которые вы пропускаете, назначая новое значение счетчику местоположений ‘.’), Заполняются двумя младшими байтами из аргумента выражения.
FILLУтверждение охватывает ячейку памяти
после точки это происходит в определении раздела; Включая более одного
FILLоператора, вы можете иметь разные шаблоны заполнения в разных частях выходного раздела.

Моя любимая команда FILL такая:

FILL(0xDEADBEEF)

или же

FILL(0xDEADC0DE)

🙂

Заполнение памяти * Снаружи * Разделы

Хотя примеры выше = fill и FILL () хороши, они только заполняют * внутри * раздела.

Например, для моего KL25Z у меня есть следующая ПАМЯТЬ, определенная в файле компоновщика:

MEMORY {
  m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x000000C0
  m_cfmprotrom  (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
  m_text  (RX) : ORIGIN = 0x00000410, LENGTH = 0x0001FBF0
  m_data  (RW) : ORIGIN = 0x1FFFF000, LENGTH = 0x00004000
}

Компоновщик поместит мой код и постоянные данные в секцию вывода m_text. Я не заполнит все 128 Кбайт FLASH, так что к концу m_text будет не наполнится выше примеров. Так как же заполнить остаток m_text до адреса 0 × 1’FFFF (конец флэш-памяти)?

Хитрость заключается в том, чтобы добавить специальный раздел вывода в конце, который затем заполняется шаблоном. Для этого мне нужно найти последний раздел, вставленный в m_text. Глядя на мой файл сценария компоновщика, это:

  .fini_array :
  {
  PROVIDE_HIDDEN (__fini_array_start = .);
  KEEP (*(SORT(.fini_array.*)))
  KEEP (*(.fini_array*))
  PROVIDE_HIDDEN (__fini_array_end = .);

   ___ROM_AT = .;
  } > m_text

Таким образом .fini_array — это последнее, что нужно для m_text, и он определяет символ компоновщика ___ROM_AT, который обозначает конец ПЗУ. Теперь я создаю новый выходной раздел .fill и перемещаем символ ___ROM_AT:

  .fini_array :
  {
  PROVIDE_HIDDEN (__fini_array_start = .);
  KEEP (*(SORT(.fini_array.*)))
  KEEP (*(.fini_array*))
  PROVIDE_HIDDEN (__fini_array_end = .);

   /*___ROM_AT = .; */
  } > m_text
  
  .fill :
  {
  FILL(0xDEADBEEF);
  . = ORIGIN(m_text) + LENGTH(m_text) - 1;
  BYTE(0xAA)
   ___ROM_AT = .;
  } > m_text

  • Использование команды FILL для определения шаблона (0xdeadbeef)
  • Установка курсора текущего раздела ( . ) На последний байт области M_text MEMORY
  • Запись значения в это местоположение с помощью команды BYTE (). Обратите внимание, что этот байт технически необходим, так как компоновщик должен иметь что-то в разделе вывода.
  • Определение символа ___ROM_AT . Мой файл компоновщика использует этот символ позже. Если ваш файл компоновщика не нуждается в этом, вам не нужна эта строка.

После этого я получаю неиспользованную FLASH, заполненную шаблоном DEADBEEF:

Заполненная флэш-память с 0xdeadbeef

Заполненная флэш-память с 0xdeadbeef

И конец имеет, как и ожидалось, при 0x1FFFF байт 0 × 00:

0x1FFFF заполнено 0xAA

0x1FFFF заполнено 0xAA

Резюме

Заполнение неиспользуемой флэш-памяти определенным шаблоном — очень полезная вещь: она определяет память, например, для вычисления контрольной суммы. Кроме того, это может повысить надежность приложения: я могу заполнить флэш-память недопустимой инструкцией или инструкцией HALT: поэтому, когда мое приложение перейдет в неопределенную память, я смогу остановить работу системы.

Использовать шаблон заполнения внутри раздела очень просто с помощью компоновщика GNU (ld). Чтобы заполнить неиспользуемую память за пределами выходных разделов, я использую выделенный раздел .fill, как показано в этом посте.

Happy FILL ing 🙂

Ссылки: