In many embedded applications, it is mandatory that memory allocation is static and not dynamic. Means that no calls to things like malloc() or free() shall be used in the application, because they might fail at runtime (out of memory, heap fragmentation).
But when linking with 3rd party libraries or even with the C/C++ standard libraries, how to ensure no dynamic memory is used? The problem can occur as well for C++ objects, or a simple call to printf() which internally requires some dynamic memory allocated.
Zero Heap Size?
An easy (and rather naive) approach is to set the heap size to zero. Most linker script or linker environments have the ability to set the heap size to zero, as below:
However, this won’t help, as most linker scripts just uses the free space between the stack space and the variables (bss): So setting the heap size to zero just assumes a zero reservation, but the _sbrk() of the library will continue to use dynamic memory, potentially crashing into the stack space.
Bottom line: with most linker scripts heap size set to zero will not help anything. It even increases the chances that the heap will crash into the stack as the linker assumes zero usage of heap. But it won’t prevent that the heap is used.
Heap in Linker File
This can be seen from the linker file shown below:
To make sure that no heap is used, the easiest way is to simply remove the .heap allocation in above linker file. Check your linker file for ‘heap’ or something similar, and make sure no memory is allocated for it. Especially make sure that no symbol ‘__prvHeapStart‘ or ‘__prvHeapLimit‘ is used, as they usually are required by the newlib/newlib-nano library dynamic memory allocation.
Linker FreeMarker Scripts
Some environments like the NXP MCUXpresso IDE is using an automatic generation of linker files. But it is easy to deal with this, if you know about the FreeMarker Scripts used by this. The Scripts are located in
<MCUXpresso IDE Installation Path>\ide\Wizards\linker
So I can easily disable the .heap using my modified FreeMarker Script:
With the heap and its symbols removed, any usage of malloc() should give a linker error, similar to this one:
Invoking: MCU Linker arm-none-eabi-gcc -nostdlib -Xlinker -Map="AEMBS_tinyK22_HS22.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -Xlinker --sort-section=alignment -Xlinker --cref -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -T "AEMBS_tinyK22_HS22_Debug.ld" -o "AEMBS_tinyK22_HS22.axf" ./utilities/fsl_assert.o ... ./McuLib/FreeRTOS/FreeRTOShooks.o arm-none-eabi/bin/ld.exe: arm-none-eabi/lib/thumb/v7e-m+fp/hard\libcr_newlib_semihost.a(_cr_sbrk.o): in function `_sbrk': _cr_sbrk.c:(.text._sbrk+0x38): undefined reference to `_pvHeapStart'
Linker Cross Reference
In case it is not clear what is using memory allocation or causing the error, the linker cross reference can be used. For this the GNU linker –cref option has to be added to the linker options:
This generates an information like below in the linker .map file:
Cross Reference Table Symbol File ADC0_DriverIRQHandler ./startup/startup_mk22f51212.o ADC0_IRQHandler ./startup/startup_mk22f51212.o ADC16_ClearStatusFlags ./drivers/fsl_adc16.o ADC16_Deinit ./drivers/fsl_adc16.o ... main ./source/main.o ./startup/startup_mk22f51212.o malloc arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-malloc.o) arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-rand.o) ./drivers/fsl_common.o mcgConfig_BOARD_BootClockRUN ./board/clock_config.o
This gives a list of modules which are using things like malloc().
Another way to find out the dependencies is using the ‘Image Information’ view in Eclipse/MCUXpresso, see Listing Code and Data Size for all Files with the GNU size Utility in a Post-Build Action:
FreeRTOS static memory allocation
More on a side-note: FreeRTOS by default is using its own dynamic heap allocation. But it is possible to run the RTOS in a static way (no dynamic memory allocation), see FreeRTOS V9.0.0 with Static Memory Allocation.
Dynamic memory allocation and usage is not desired in many applications. To prevent usage of malloc() and free(), it is best to remove any heap definition in the linker file, to cause a linker error. Then the GNU linker cross reference table or the image information can be very useful.
Happy linking 🙂
- Example using FreeMarker Scripts: Tutorial: Porting BLE+NRF Kinetis Design Studio Project to MCUXpresso IDE
- Bootloader with FreeMarker Scripts: Linking Bootloader Applications with Eclipse and FreeMarker Scripts
- FreeMarker scripts: https://freemarker.apache.org/