The Easiest Way to Calculate Function Size in C

Unfortunately calculating function size is not as easy of finding variable size using sizeof() compile-time operator. There are numerous ways to calculate the size in run-time but to keep things simple, it’s better to check that information from linker, as for sure must knows it.

Let’s talk about what things we are going to use:

 

1- “.map” file generated by GCC/G++ linker:

 

This file has the symbols we have in the code/firmware either in flash, RAM or any other defined memory section. The following snippet is taken from compiling one of the examples of nRF52 SDK. If you want to try just run make default inside the following directory examples\peripheral\gpiote\pca10040\blank\armgcc. The first column is the symbol start address, the second column is the function size in HEX and the third one is the object file name containing that symbol.

.text.bsp_board_led_invert
                0x00000380       0x24 _build/nrf52832_xxaa/boards.c.o
                0x00000380                bsp_board_led_invert
 .text.bsp_board_init
                0x000003a4       0x5c _build/nrf52832_xxaa/boards.c.o
                0x000003a4                bsp_board_init  

You can scan this file until you find the function you’re looking for and find its length and start address. For instance bsp_board_led_invert takes 36 bytes in Flash.

 

2- “.out” file generated by GCC/G++ and NM GNU tool

 

Sometimes it’s hard to search a symbol in the .map file here comes nm tool found with GCC tool-chain to list all symbols in an object file. To list all your code symbols then use the .out file with nm or .elf file should also do the job too. This tool can list the symbols and also sort the symbols according to the size. I have the .out file from the first step, so simply to list the symbols by size run the following command (make sure you’re using the right command as I’m using ARM GCC here)

arm-none-eabi-nm -S --size-sort -t d nrf52832_xxaa.out

And here is a snippet from output

00001024 00000030 T app_error_handler_bare
00000896 00000036 T bsp_board_led_invert
00003460 00000040 T exit
00000720 00000040 T Reset_Handler
00001056 00000052 W app_error_fault_handler
00000780 00000052 t gpioIntHandler
00000832 00000064 T main
00003500 00000076 T __libc_init_array
536871056 00000076 b m_cb
00000932 00000090 T bsp_board_init
536870916 00000096 d impure_data
00001108 00000136 T nrfx_gpiote_init
00001568 00000196 T nrfx_gpiote_in_event_enable
00002448 00000200 T TIMER0_IRQHandler
00001244 00000324 T nrfx_gpiote_in_init
00000000 00000512 T __isr_vector
00001764 00000684 T GPIOTE_IRQHandler
00002648 00000812 T SystemInit
536871144 00008192 N __HeapBase

The first column is the start address in decimal, then the length and the symbol name.

 

Weird Symbols Names ?

 

If you found strange names as symbols, and mostly strange characters added as suffix and prefix to a function or variable name you know, then this comes from what is called name mangling. For example, get_event function could become something like that:

__ZN2os9get_eventENS_17enum_task_id_typeE

Why? This is because the compiler needs unique names for variables, functions, …etc and while we can have static variables or functions with same names in different source files, then the compiler need to distinguish between them. The same thing is applicable to c++ for overloading also.

To de-mangle the name, C++filt is the tool used to produce the original name, for example running the following to de-mangle the past example:

arm-none-eabi-c++filt __ZN2os9get_eventENS_17enum_task_id_typeE
Exit mobile version