Компиляция с -flto и -nostartfiles приводит к отсутствию какой-либо программы.
При разработке собственного загрузчика я столкнулся с проблемой в avr-gcc. Пытаюсь скомпилировать код с флагами компилятора
-flto #для включения оптимизации времени компоновки
-nostartfiles #чтобы исключить таблицу векторов прерываний
Мой загрузчик состоит из нескольких файлов, которые используются в зависимости от флагов компиляции. Все исходники компилируются и линкуются, а путь к коду ведёт только к некоторым их частям. Поэтому я хотел избавиться от мёртвого кода, и -flto (будучи более новой разработкой) создаёт гораздо меньший объём машинного кода, чем -ffunction-sections -fdata-sections с -Wl,--gc-sections -Wl,--print-gc-sections.
Но когда дело доходит до дальнейшего сокращения размера машинного кода путем удаления таблицы векторов прерываний с помощью -nostartfiles, весь код оптимизируется, оставляя мне на выходе нулевой байт.
Сталкивался ли кто-нибудь с такой же проблемой при использовании этой комбинации флагов компилятора?
@Kwasmich, 👍1
Обсуждение1 ответ
Лучший ответ:
Как написал @MaximilanGerhardt в своём комментарии, LTO оптимизировал слишком много кода. Обычные программы начинаются с таблицы векторов прерываний, которая в случае обычного сброса или запуска указывает на функцию main. Поэтому компилятор знает, что у main есть точка входа, и она используется. Сама программа начинается с этой таблицы.
Удаление таблицы векторов прерываний с помощью -nostartfiles приводит к тому, что компилятор вообще не знает об использовании main и оптимизирует ее, убирая.
Чтобы дать компилятору подсказку, __attribute__((used)) должен быть помещен во все методы, которые должны остаться, и в противном случае не должно быть никакого пути кода, ведущего к ним.
Вы наткнулись на что-то работающее, но это не совсем верное решение. Вам следует использовать скрипт линковки (традиционно ld-файл), который помещает ваш стартовый код (желательно обёртку, а не сам main()) по правильному адресу с атрибутом «keep». В случае AVR «векторы» — это на самом деле инструкции перехода, поэтому, если вам нужна поддержка только команды сброса, вы, вероятно, можете просто начать свой код с неё; в других архитектурах векторы — это указатели, поэтому вам потребуется указать адрес стартового кода, а затем сам код., @Chris Stratton
Также следует отметить, что без кода запуска инициализированные переменные ОЗУ работать не будут, поскольку копирование этой инициализации из флэш-памяти в ОЗУ выполняется кодом запуска; однако значения типа PROGMEM будут работать., @Chris Stratton
- Как скомпилировать без добавления загрузчика?
- Как записать загрузчик?
- Как компилировать, загружать и контролировать через командную строку Linux?
- Предупреждение при проверке скетча с кодом VS
- Разница в загрузчике Arduino Nano ATmega328P
- Не удается снова загрузиться после смены платы
- Как добавить гистерезис к пороговым значениям?
- Почему я получаю avrdude: stk500v2_ReceiveMessage(): timeout error when uploading to Arduino Mega?
Я столкнулся с тем, что больше не могу скомпилировать скетч Arduino с помощью LTO, потому что оптимизация была настолько агрессивной, что исключала некоторые обработчики прерываний периферийных устройств. Возможно, GCC считает, что начальная функция загрузки (по адресу 0x0000 или где-то ещё) никогда не вызывается, и всё завершает? Может быть, попробовать добавить
__attribute__ ((used))к некоторым функциям и посмотреть, что получится? (https://gcc.gnu.org/wiki/LinkTimeOptimizationFAQ), @Maximilian GerhardtВот и всё! Теперь он выдаёт результат. Но он больше не меньше, чем версия
--gc-sections. Полагаю, он уже удалил некоторые части, которые должны были остаться. Спасибо!, @KwasmichРад слышать! Было бы здорово, если бы вы сами ответили на вопрос и привели конкретный фрагмент кода, который помог всё это заработать., @Maximilian Gerhardt