
C++23 и компилятор: почему встраиваемые системы всё ещё требуют ассемблера
В статье разбираются ограничения static_assert, concepts и constexpr при сборке под ARM‑Yocto/OpenBMC и предлагается решение на уровне ассемблера.
C++23 обещает разработчикам огромный набор возможностей для проверки кода уже на этапе компиляции: static_assert, концепты, constexpr‑функции, метапрограммирование и даже модульная система. На первый взгляд этого достаточно, чтобы гарантировать корректность любой библиотеки.
Однако в реальных проектах, где код собирается под ARM‑архитектуру с агрессивными флагами -O2 -Os -flto=auto в составе Yocto/OpenBMC, возникают специфические проблемы. При такой оптимизации компилятор может полностью удалить «неиспользуемый» код, даже если он нужен для инициализации тестовой инфраструктуры библиотечных классов. В результате разработчик теряет возможность заставить пользователя вызвать обязательную функцию инициализации.
Автор статьи описывает, как попытка решить задачу чисто средствами C++ не увенчалась успехом: static_assert срабатывает только при компиляции, а constexpr‑функции могут быть полностью оптимизированы‑выброшены. Чтобы гарантировать присутствие кода в финальном бинарнике, он прибегает к небольшому трюку на уровне ассемблера: объявление «примитивного» символа с атрибутом __attribute__((used)) и вставка asm volatile (".global %0\n%0:\n" : : "i" (symbol));. Такой подход заставляет линковщик сохранить символ, а компилятор — не удалять его при оптимизации.
Кроме того, в статье показаны примеры использования #pragma GCC push_options и #pragma GCC optimize ("O0") для изоляции критических участков кода, а также обсуждаются потенциальные риски: рост размера бинарника и необходимость поддерживать ассемблерный код в кросс‑компиляторе. В итоге автор предлагает практический шаблон, который можно адаптировать под любые проекты, где требуется гарантировать выполнение кода инициализации встраиваемых систем.
Ссылка на оригинал: https://habr.com/ru/articles/1058316/
Для разработчиков встраиваемых систем C++23 не избавит от необходимости писать небольшие ассемблерные «заглушки». Пример из статьи поможет быстро добавить обязательный инициализатор без изменения архитектуры проекта, но следует помнить о росте размера бинарника и усложнении CI‑процессов.


