
Реализация модульной архитектуры прошивки методом ручной динамической линковки на примере STM32
RomanBashmakov 11 минут назад Реализация модульной архитектуры прошивки методом ручной динамической линковки на примере STM32 Уровень сложности Простой Время на прочтение 5 мин Охват и читатели 116 C * Занимательные...
Anthropic — What company has the best second artificial intelligence model at the end of June?
В сфере искусственного интеллекта произошло заметное событие. RomanBashmakov 11 минут назад Реализация модульной архитектуры прошивки методом ручной динамической линковки на примере STM32 Уровень сложности Простой Время на прочтение 5 мин Охват и читатели 116 C * Занимательные задачки Программирование микроконтроллеров * Системное программирование * Туториал Рассмотрен подход к созданию управляемого "бэкдора", позволяющего подгружать функции без остановки и перезагрузки. С помощью манипуляций с линкер-скриптом и средств языка C создаются "точки расширения" в прошивке, позволяющие в будущем внедрять новые функциональные модули без пересборки и перезаписи всей программы. Такой подход может быть полезен при разработке отказоустойчивых систем для оптимизации жизненного цикла встроенного ПО, так как позволяет заложить гибкость при непредвиденных модификациях.
Метод Разделение памяти Метод заключается в разделении адресного пространства прошивки: фиксируется положение базового кода и выделяются отдельные секции для динамически загружаемых блоков кода, которые объявляются с attribute((section(". my_patchable_func"))) , что позволяет размещать код функции/переменных в заданной области ОЗУ/ПЗУ, описываемой линкер-скриптом. В некотором смысле этот подход представляет собою внедрение микро-бутлоадера, который выполняет свою функцию не ДО основного кода, а ОДНОВРЕМЕННО с ним.
Технические детали
Как обновляемый код будет общаться с базовой частью? Глобальные переменные : Чтобы обновляемая функция «видела» глобальные данные ядра, необходимо использовать таблицу указателей или фиксированные адреса (абсолютную адресацию). Ядро экспортирует таблицу адресов своих функций и данных, а модуль обращается к ним как к внешним API.
Статические переменные : Лучше полностью избегать использования static внутри динамических функций. Вместо этого все необходимые данные должны передаваться в функцию через аргументы или указатели на структуры, выделенные в «ядре». Это делает функцию позиционно-независимой и упрощает управление памятью.
Задачи, решаемые в рамках реализации Создание базовой прошивки: Проектирование ядра системы, которое содержит таблицу экспорта функций и переменных и загрузчик. Формирование патча: Он должен уметь получать от базовой части все необходимые ресурсы и работать в сложившихся ограничениях (патч пользуется только остатками памяти, которые к тому же могут быть фрагментированы, а выполнение кода патча не должно ломать логику базовой части в том числе по таймингам). Протокол передачи: Базовая часть должна уметь принимать патч, проверять целостность, а сам процесс инъекции кода должен быть по возможности неблокирующим.
Пример Код проекта примера можно найти в репозитории . Для демонстрации подхода сконфигурирован проект в CubeMX для платы на STM32F103C8T6 ( blue pill ) с USB в режиме виртуального COM -порта. В полученный стандартный линкер-скрипт добавлен сегмент RAM_PATCH в посередине ОЗУ (по адресу 0x20002800 ): /* RAM (20K) */ MEMORY { RAM_MAIN (xrw) : ORIGIN = 0x20000000, LENGTH = 10K /* Main part (.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





