In this lesson, you will learn how to quantify your application’s memory usage by analyzing the individual sections of an ELF binary to identify exactly where your SRAM and Flash resources are being consumed.
Understanding the ELF Layout
When you compile code for an embedded system, your toolchain produces an Executable and Linkable Format (ELF) file. This file acts as a map, dividing your program into specific segments:
.text: Contains your executable machine instructions (Flash)..data: Stores initialized global or static variables (copied from Flash to RAM at startup)..bss: Holds uninitialized global or static variables (zeroed in RAM at startup).
Using the size Utility
To gain visibility into these segments, we use the size tool provided by the GNU Binutils suite. While running size firmware.elf gives a quick summary, using the -A (System V format) flag provides a detailed breakdown of each section's size in bytes:
$ arm-none-eabi-size -A firmware.elf
firmware.elf :
section size addr
.text 8192 0x08000000
.data 128 0x20000000
.bss 1024 0x20000080
...
Total 9344
In this output, you can immediately see the memory footprint:
- Flash Usage: Calculate
.text+.data. The.datavalues reside in Flash (as initial values) before being moved to RAM. - RAM Usage: Calculate
.data+.bss. This is the exact amount of volatile memory your program requires at runtime.
Why This Matters
By analyzing these segments, you can identify "bloat" candidates. If your .bss section is unexpectedly large, you might have allocated massive static arrays that could be moved to dynamic memory or reduced in size. Conversely, a rapidly growing .text segment might indicate that your compiler is inlining too many functions or including unnecessary library dependencies.
Regularly monitoring these values during your build pipeline prevents "memory creep," ensuring your firmware stays within the strict hardware constraints of your target MCU.
Key Takeaway: Precise memory management starts with using the size tool to decompose your ELF file into its constituent sections, allowing you to differentiate between static storage requirements and dynamic runtime consumption.