There is a time in every developer’s life when the program memory is running out. If you have already experienced this problem or you are about to this article is for you!
There are at least three ways to reduce program size:
- code optimization,
- compiler optimization,
- discarding unreferenced code.
Code optimization is a process in which you reduce output code size by changing program in a way that the functionality is maintained. However, in this article I will cover the last two.
First things first. Why should you care about code size? There are a few reasons. The firmware is obviously getting smaller. Having this in mind, the flashing time can be, thus reduced drastically. Also you are bounded by the size of your MCU which can not be easily extended.
One way of reducing output code size is to let compiler to do the job for you. All what is required is simply passing -Os option in parameter list to the compiler during compilation process.
What exactly is going on when you decide to use compiler optimization? When you pass -Os (optimization for size) to the compiler it is equivalent to passing -O2 and a few other options. The compiler is actually doing some pattern matching. It is looking for certain chunks of code which can be translated differently, thus the size is drastically reduced. However, this has serious consequences. The compiler is not analysing the code, therefore it can decide to skip whole loops if it appears that the piece of code is doing nothing useful. This is pretty dangerous! That is why I do not recommend this path unless you know exactly what are you doing. There are certain techniques which can make compiler to behave in a certain way thus it won’t perform optimization on a crucial piece of code.
Discarding unreferenced code
This practice is safer in comparison to previous one. It works in two stages.
The first stage is to tell compiler to put stuff like functions, classes (for C++) and external variables and variables into separate sections. This allows to perform a code fragmentation which is handled in next stage by linker. To make compiler to put above into sections you have to pass to it to options:
The second step is to tell linker to actually discard unreferenced sections and therefore reduce the output size of the code. This can be done by passing below flags to linker
Depending upon which type of optimization you decide to use the code size may differ. For example, if you have a big project passing –Os to compiler may significantly reduce the size. However, if you go for discarding unreferenced code the result can be very poor. It strongly depends on the amount of code you actually use. But if you are using third-party libraries like HAL, SPL, FatFS, U8glib loosing references to unused code can reduce the code drastically! As a representative example I will introduce you to quadrocopter project. I use there HAL and FatFS libraries. After using the third method, discarding unreferenced code, I reduced the output code size by almost two times. And that is something!