g++ compiler flag to minimize binary size
Asked Answered
P

3

21

I'm have an Arduino Uno R3. I'm making logical objects for each of my sensors using C++. The Arduino has very limited on-board memory 32KB*, and, on average, my compiled objects are coming out around 6KB*.

I am already using the smallest possible data types required, in an attempt to minimize my memory footprint. Is there a compiler flag to minimize the size of the binary, or do I need to use shorter variable and function names, less functions, etc. to minimize my code base?

Also, any other tips or words of advice for minimizing binary size would be appreciated.

*It may not be measured in KB (as I don't have it sitting in front of me), but 1 object is approximately 1/5 of my total memory size, which is prompting my concern.

Padishah answered 9/3, 2013 at 18:53 Comment(7)
gcc -o3 , -o2 O for optimizeAnoxia
@Grijesh No... -O3 will make binaries larger in general.Cronk
@Padishah The gcc option that optimizes for size is -Os. You can also strip the symbols for your binaries after linking.Cronk
@Cronk Really! I thought 3 for better level what its for?Anoxia
Are you using templates, from the standard library or your own inventions? These tend to introduce additional code for every type they're instantiated with. Function and variable name size has no effect whatsoever on binary size (if you strip debug info and such, which you should anyway).Steamtight
variable names do not affect the size of generated machine code. but if you leave debugging information in the executable, remove that. the g++ option for that is -s. with only 32K to play around with I would seriously consider using hand-crafted assembly language rather than C++. just sayin'. ;-)Moffatt
@Grijesh Execution speed and binary size do not necessarily correlate. Things like loop unrolling and frequent inlining may make the program faster, but increase the size of the binaries...Cronk
T
49

There are lots of techniques to reduce binary size in addition to what us2012 and others mentioned in the comments, summing them up with some points of my own:

  • Use -Os to make gcc/g++ optimize for size.
  • Use -ffunction-sections -fdata-sections to separate each function or data into distinct sections within the translation unit. Combine it with the linker option -Wl,--gc-sections to get rid of any unreferenced sections.
  • Run strip with at least the following options: -s -R .comment -R .gnu.version. It can be combined with --strip-unneeded to remove all symbols that are not necessary for relocation processing.
Thermoplastic answered 9/3, 2013 at 19:21 Comment(0)
X
20

If your code does not contain c++-exception-handling you can save a lot of space (up to 30k after all optimize steps mentioned by Tuxdude). Therefore you have to provide the following flag: -fno-exceptions

But even if you don't use exceptions, the exception handling can be included! Check the following steps:

  1. no usage of new, delete. If you really need it replace them by malloc/free wrappers. For an example search for "tinynew.cpp"

  2. provide function for pure virtual call, e.g.extern "C" void __cxa_pure_virtual() { while(1); }

  3. overwrite __gnu_cxx::__verbose_terminate_handler(). It handles unhandled exceptions and does name demangling, which is quite large! (e.g d_print_comp.part.10 with 9.5k or d_type with 1.8k)

Cheers Flo

Xever answered 27/12, 2014 at 14:47 Comment(1)
Point 3 helped a lot! Thanks!Iodous
M
0

For debug where you want fast builds and good error messages, use -Og -g3 -fsanitize=address -fno-omit-frame-pointer -Wall -Werror

For production where you want the smallest fastest binaries:

  1. Let's start with only -Os -fwrapv -fomit-frame-pointer -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables, which are very safe. Separately add -Wl,--gc-sections -fwhole-program -s -Wl,--build-id=none _only_ to the very last gcc step which links everything together. (If you added that to intermediary steps, things would fall apart and not work.)
  2. ONLY if grep -rnwe throw -e catch shows you use no exceptions, add -fno-exceptions
  3. ONLY if grep -rnwe dynamic_cast -e virtual shows you use no virtual methods or dynamic_cast, add -fno-rtti
  4. ONLY if grep -rnwe errno -e virtual shows you don't use errno, add -fno-math-errno
  5. ONLY if grep -rnwe std: shows you don't use dynamic standard library methods (macro-like std such as std::max are fine to use), add -nodefaultlibs -lc -lgcc_s

You should now have the smallest binary you can get for-free/minimal-effort.

Mcknight answered 21/6 at 20:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.