Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021)

Материал из 0x1.tv

Докладчик
Антон Бондарев.jpg
Антон Бондарев

Доклад посвящён особенностям работы C++ приложений на микроконтроллерах. В частности рассматриваются причины ограничений С++ по сравнению с десктопными средствами разработки на данном языке. Рассматриваются особенности реализвации поддерки С++ в ОСРВ Embox.

Поскольку данная ОСРВ позволяет избежать ограничений и имеет наиболее полную поддержку С++ для микроконтроллеров.

Видео

Презентация

Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021).pdf

Thesis

Сегодня существует множество средств предоставляющих средства разработки пользовательских приложений на С++ для микроконтроллеров. Однако большинство из них содержать некоторые ограничения. Прежде всего это невозможность перезапуска приложений и невозможноть использования функций из стандарта С++ связанных с потоками.

Embox — открытая операционная система реального времени, позволяет избежать этих ограничений, то есть использовать подобную функциональность на микроконтроллерах. Данная статья посвящена деталям реализации рантайма С++ в ОСРВ Embox.

Базовый синтаксис

Синтаксис языка C++ реализуется компилятором. В рантайм необходимо реализовать несколько базовых сущностей. В компиляторе они включаются в библиотеку поддержки языка libsupc++.a. Наиболее базовой является поддержка конструкторов и деструкторов. Существуют два типа объектов: глобальные и выделяемые с помощью операторов new.

Рассмотрим то как работает C++ приложение. Перед тем как попасть в main(), создаются все глобальные C++ объекты которые присутствуют в коде. Для этого используется специальная секция .init_array.

Также могут использоваться секции .init, .preinit_array, .ctors. Для современных компиляторов ARM, чаще всего секции используются в следующем порядке .preinit_array, .init и .init_array.

С точки зрения LIBC это обычный массив указателей на функции, который нужно пройти от начала и до конца, вызвав соответствующий элемент массива. После этой процедуры управление передаётся в main().

Рассмотрим как устроено завершение C++ приложения, а именно, вызов деструкторов глобальных объектов. Существует два способа.

Наиболее используемый в компиляторах — через __cxa_atexit() (из C++ ABI). С помощью этой функции могут быть зарегистрировать специальные обработчики, которые будут вызваны в момент завершения программы. Когда при старте приложения происходит вызов глобальных конструкторов, как описано выше, кроме того туда включается сгенерированный компилятором код, который регистрирует обработчики через вызов __cxa_atexit. Задача LIBC здесь сохранить требуемые обработчики и их аргументы и вызвать их в момент завершения приложения.

Другим способом является сохранение указателей на деструкторы в специальных секциях .fini_array и .fini. В компиляторе GCC это может быть достигнуто с помощью флага -fno-use-cxa-atexit. В этом случае во время завершения приложения деструкторы должны быть вызваны в обратном порядке (от старшего адреса к младшему). Этот способ менее распространён, но может быть полезен в микроконтроллерах. Ведь в этом случае на момент сборки приложения можно узнать сколько обработчиков потребуется.

Глобальные деструкторы необходимы, чтобы иметь возможность перезапускать C++ приложения. Большинство RTOS для микроконтроллеров предполагает запуск единственного приложения, которое не перезагружается. Старт начинается с пользовательской функции main, единственной в системе. Поэтому в небольших RTOS зачастую глобальные деструкторы пустые.

В компиляторе GCC реализация операторов new/delete находится в библиотеке libsupc++. Можно использовать реализации new/delete из libsupc++.a, но они достаточно простые и могут быть реализованы например, через стандартные malloc/free или аналоги.

Если приложение простое, вам не требуется поддержка исключений и динамическая идентификация типов данных (RTTI). Её можно отключить с помощью флагов компилятора -no-exception -no-rtti. Но если эта функциональность С++ требуется, её нужно реализовать. Сделать это куда сложнее чем new/delete. Но так как эта функциональность на зависит от ОС можно воспользоваться реализацией библиотеки ibsupc++.a из кросс-компилятора. Для использования исключений из кросс-компилятора есть небольшие требования, которые нужно реализовать при добавлении собственного метода загрузки C++ рантайма. В линкер скрипте должна быть предусмотрена специальная секция .eh_frame. А перед использованием рантайма эта секция должна быть инициализирована с указанием адреса начала секции.

Для ARM архитектуры используются другие секции с собственной структурой информации — .ARM.exidx и .ARM.extab. Формат этих секций определяется в стандарте «Exception Handling ABI for the ARM Architecture» — EHABI[2]. .ARM.exidx это таблица индексов, а .ARM.extab это таблица самих элементов требуемых для обработки исключения. Чтобы использовать эти секции для обработки исключений, необходимо включить их в линкер скрипт.

Чтобы GCC мог использовать эти секции для обработки исключений, указывается начало и конец секции .ARM.exidx — __exidx_start и __exidx_end. Эти символы импортируются в libgcc в файле libgcc/unwind-arm-common.inc:

extern __EIT_entry __exidx_start;
extern __EIT_entry __exidx_end;

Стандартная библиотека языка (libstdc++)

В поддержку языка C++ входит не только базовый синтаксис, но и стандартная библиотека языка libstdc++. Её функциональность, так же как и для синтаксиса, можно разделить на разные уровни. Есть базовые вещи типа работы со строками или C++ обёртка setjmp . Они легко реализуются через стандартную библиотеку языка C. А есть более продвинутые вещи, например, Standard Template Library (STL).

При использовании стандартной библиотеки С++ из кросс-компилятора существует особенность. Взглянем на стандартный arm-none-eabi-gcc. Он собран с поддержкой —with-newlib. Newlib реализация стандартной библиотеки языка C. В Embox используется собственная реализация стандартной библиотеки. Так как стандартные библиотеки C отличаются, то для поддержки рантайма нужно реализовать слой совместимости.

Кроме стандартной библиотеки кросс-компилятор имеет модель потоков “Thread model: single”. Когда GCC собран с этой опцией, убирается вся поддержка потоков из STL (например std::thread и std::mutex). И, например, со сборкой такого сложного С++ приложение как OpenCV возникнут проблемы. Иначе говоря, для сборки приложений, которые требуют подобную функциональность, недостаточно этой версии библиотеки.

Решением, которые мы применяем в Embox, является сборка собственного компилятора ради стандартной библиотеки с многопоточной моделью. В случае Embox модель потоков используется posix “Thread model: posix”. В этом случае std::thread и std::mutex реализуются через стандартные pthread_и pthread_mutex_. При этом также отпадает необходимость подключать слой совместимости с newlib.

Embox — свободная ОСРВ, позволяющая запускать сложные С++ приложения на микроконтролерах (Антон Бондарев, OSSDEVCONF-2021)!.jpg

Примечания и ссылки


Plays:14   Comments:0