image
Я работаю над одним проектом, который с большим трудом вмещается в 64к памяти микроконтроллера. И подумалось мне, что возможно, пора взглянуть на разные компиляторы, чтобы выбрать какой более агрессивно может уменьшить размер программы.

Представляю вашему вниманию небольшое сравнение.

Для теста я сделал проект в Cube MX, который включает в себя USB_DEVICE и Mass Storage Class. Это довольно большие библиотеки для теста.

Получившийся main.c выглядит примерно так:

int main() 
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
}

Дефайн USBD_DEBUG_LEVEL установлен в 0, чтобы отладочные сообщения USB стека не требовали наличия printf

Подопытные компиляторы:

  • IAR EWARM 8.32.1
  • arm-none-eab-gcc 7-2018-q2-update 7.3.1 (среда STM32 Cube IDE 1.4.2)
  • ARMCC v5.06 update 7 (среда Keil uVision 5.32)
  • ARMCC v6.14.1 (среда Keil uVision 5.32)

Настройки IAR:

  • Оптимизация по размеру
  • Run-time библиотека NORMAL
  • Без low level IO (отключен printf)
  • Включены оптимизации линкера: Inline small routines, merge duplicate sections

Настройки GCC:

  • Reduced runtime library --specs=nano.specs
  • Optimize for size -Os
  • Place functions in their own sections --ffunction-sections
  • Place data in their own sections --ffdata-sections
  • Discard unused sections -Wl, --gc-sections

Настройки armcc5:

  • Use micro lib
  • Use cross module optimization
  • Optimization -O3
  • One ELF section per function --split_sections

Настройки armcc6:

  • Use micro lib
  • Optimization image size -Oz
  • One ELF section per function --split_sections


GCC armcc5 IAR armcc6
Размер прошивки 14036 13548 12997 12984


Надо отметить, что опция KEIL «Use cross module optimization» Значительно увеличила время компиляции, но ни чуть не уменьшила размер кода.

UPD1
В IAR есть опция multi-file compilation. Если ее включить, то IAR уходит вперед со значительным отрывом. Прошивка уменьшается до 12746 байт.

UPD2
Добавление опций -fsection-anchors и -fno-move-loop-invariants в gcc уменьшило прошивку еще на 12 байт.

UPD3
Спасибо Shturman-0 за подсказку как правильно использовать флаг "-flto".
Итак, -flto ставится и линкеру и компилятору.
В startup_xxx.s надо удалить все weak объявления используемых прерываний
В данном случае
// .weak USB_LP_CAN1_RX0_IRQHandler
// .thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
// .weak SysTick_Handler
// .thumb_set SysTick_Handler,Default_Handler

В результате размер прошивки составил 11772 байта (для gcc 7). Gcc 9.3.1 дает 12148

GCC (-flto) armcc5 IAR armcc6
Размер прошивки 11772 13548 12746 12984

И gcc обходит ближайшего соперника на 10%