This article will compare the following toolchains:
To compare the generated binaries, we will use the simple Baremetal example from PolyMCU project.
export CROSS_COMPILE=<gcc-toolchain-path>/bin/arm-none-eabi-
cmake -DBOARD=AppNearMe/MicroNFCBoard -DAPPLICATION=Examples/Baremetal -DCMAKE_BUILD_TYPE=Release ../..
make
export CROSS_COMPILE=<gcc-toolchain-path>/bin/arm-none-eabi-
CC=clang-3.x cmake -DBOARD=AppNearMe/MicroNFCBoard -DAPPLICATION=Examples/Baremetal -DCMAKE_BUILD_TYPE=Release ../..
make
Command line for GCC Release:
-DCHIP_LPC11UXX -DCORE_M0 -DNO_BOARD_LIB -D__CORTEX_M0 -D__USE_CMSIS -std=gnu99 -fno-common -fmessage-length=0 -Wall -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer -mcpu=cortex-m0 -mthumb -O3 -DNDEBUG -Wno-unused-but-set-variable -Wno-unused-variable
Command line for LLVM Release:
-DCHIP_LPC11UXX -DCORE_M0 -DNO_BOARD_LIB -D__CORTEX_M0 -D__USE_CMSIS -target arm-none-eabi -std=gnu99 -fno-common -fmessage-length=0 -Wall -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer -fshort-enums -Wno-unknown-attributes -mcpu=cortex-m0 -mthumb -O3 -DNDEBUG -Wno-unused-but-set-variable -Wno-unused-variable
LLVM also uses GCC toolchain linker ld
and share the same linking command as GCC.
Here are the sizes in byte of the different sections and final binaries:
Build | text | data | bss | text+data+bss | final binary |
---|---|---|---|---|---|
GCC 4.9 2014q4 - Debug | 8548 | 184 | 92 | 8824 | 8732 |
GCC 4.9 2014q4 - Release | 5084 | 176 | 92 | 5352 | 5260 |
GCC 4.9 2015q3 - Debug | 8596 | 184 | 92 | 8872 | 8780 |
GCC 4.9 2015q3 - Release | 5136 | 176 | 92 | 5404 | 5312 |
LLVM 3.6 + GCC 4.9 2015q3 - Debug | 9272 | 184 | 96 | 9552 | 9456 |
LLVM 3.6 + GCC 4.9 2015q3 - Release | 5532 | 176 | 96 | 5804 | 5708 |
LLVM 3.8 + GCC 4.9 2015q3 - Debug | 8844 | 184 | 96 | 9124 | 9028 |
LLVM 3.8 + GCC 4.9 2015q3 - Release | 5168 | 176 | 96 | 5440 | 5344 |
We can notice the size of the final binary for LLVM 3.8 release build (ie: 5344 Bytes) is not so far from the size of the final binary built by GCC 4.9 2015q3 (ie: 5312 Bytes).
Let's compare the size of the largest symbols (with the command arm-none-eabi-nm -S --size-sort Baremetal_Example.elf
)
GCC 4_9-2015q3 Release | LLVM 3.8 + GCC 4_9-2015q3 Release |
---|---|
(...) 00000080 T Chip_SystemInit 00000080 t VCOM_bulk_out_hdlr 0000008c T _free_r 000000a0 T leds_init 000000a8 T ARM_USART_Send 000000b0 T _malloc_r 000000b0 T __smakebuf_r 000000b0 T __swbuf_r 000000c0 T g_pfnVectors 000000c0 T vcom_init 000000e8 T __swsetup_r 000000f8 T _puts_r 00000100 T usbd_rom_init 00000112 T __sflush_r |
(...) 00000084 t VCOM_bulk_out_hdlr 00000088 T Chip_SystemInit 0000008c T _free_r 000000a8 T ARM_USART_Send 000000b0 T _malloc_r 000000b0 T __smakebuf_r 000000b0 T __swbuf_r 000000b0 T vcom_init 000000c0 T g_pfnVectors 000000d0 T leds_init 000000e8 T __swsetup_r 000000f0 T usbd_rom_init 000000f8 T _puts_r 00000112 T __sflush_r |
We also noticed LLVM uses __aeabi_memclr*()
, __aeabi_memset*()
while GCC does not.