Я хотел реорганизовать мой объект, используемый для хранения системного времени в миллисекундах для моего проекта STM32F030, в одноэлементную схему (раньше это был просто обычный глобальный объект).Я сделал это, и, к моему удивлению, компоновщик больше не может связывать код, потому что он не помещался ни в мою флэш-память, ни в ОЗУ (раньше у меня было достаточно свободного места).Почему это происходит?Я подозреваю, что компилятор GCC добавляет тонну кода обработки исключений, но я не понимаю, почему это произойдет.
Я использую G ++, предоставляемый System Workbench для STM32 IDE.Я решил сократить код до наименьшего нерабочего фрагмента и обнаружил, что раздувание кода происходит всякий раз, когда существует метод статического класса, который возвращает ссылку или объект этого класса И есть явный конструктор для этого класса (даже если это простообъявление с пустым телом).Как ни странно, если я удаляю конструктор и позволяю компилятору предоставить мне конструктор, то раздувание кода исчезает.Не имеет значения, является ли конструктор общедоступным или закрытым.
class Singleton {
public:
//if I remove the next line the project links!
Singleton(){}
static Singleton& instance() {
static Singleton singleton;
return singleton;
}
};
int main(void)
{
auto temp = Singleton::instance();
for(;;) {
}
}
Как видите, программа вообще ничего не делает, за исключением ленивой инициализации экземпляра singleton, поэтому код должен быть таким маленьким, каквозможный.Я компилирую код с оптимизацией -fno-exceptions
, -fno-rtti
, -Oz
и все еще получаю следующий результат:
/../arm-none-eabi/bin/ld.exe: test.elf section `.text' will not fit in region `FLASH'
/../arm-none-eabi/bin/ld.exe: region `FLASH' overflowed by 12012 bytes
Я подозреваю, что GCC добавляет вызовы обработки исключений, потому что похожая вещьслучалось со мной раньше (объявление чисто виртуальной функции также увеличивало размер кода на ~ 50 КБ), но, возможно, я что-то упустил.Есть ли способ обойти эту проблему?
РЕДАКТИРОВАТЬ : Следуя предложению из комментариев, я отредактировал скрипт компоновщика, увеличив размер флеш-памяти, чтобы программа связывалась.Вот соответствующая часть сгенерированного файла карты: pastebin
Кажется, что действительно есть некоторая обработка исключений, вставленная в сгенерированный код (вызовы отмены, ___Unwind_RaiseException
, __cxa_allocate_exception
,__cxa_throw
std::exception::~exception()
и т. Д.).
Я думал, что это может быть проблемой, связанной с компилятором, поэтому я скомпилировал код с ARMCLANG, предоставленным Keil IDE, и размер результирующего кода был меньше 1 КБ..
РЕДАКТИРОВАТЬ 2 : Я нашел решение проблемы с раздуванием кода (передача флага -fno-threadsafe-statics
компилятору значительно уменьшает размер кода), но это происходит за счет безопасности потоков,Проект, над которым я работаю, не является однопоточным, так как использует прерывания, поэтому я думаю, что я просто воспользуюсь явно инициализированным подходом к глобальным переменным, с которого я начинал.
EDIT 3 Похоже, что статическая инициализация потока безопасности потока инициализации была лишь симптомом проблемы, и реальным виновником была библиотека Newlib , которая является реализацией стандартной библиотеки C / C ++ для встроенных систем.Использование newlib-nano вместо стандартного newlib значительно сокращает размер кода (теперь стоимость потоковой безопасной статической инициализации составляет всего дюжину или около того байтов вместо прежних 70 КБ).Можно включить newlib-nano , передав флаг --specs=nano.specs
компоновщику.