0

I am currently playing around with embedded C++ programming, I am trying to understand the C HAL provided by ST, rework it in modern C++, optimize some stuff away, etc.

I got to the point where I can blink an LED. The size of my current binary is 1800 bytes, but along the way, it occurred more than once that my binary size grew significantly because of very small changes. Significant means that I got an 6144 bytes binary instead of my 1800 bytes one, which is more than a 3x increase. My goal is of course to keep the binary size small.

Every time that this happened, I looked into the disassembled elf file and I noticed that the compiler included some kind of stack unwinding stuff, and that is what caused the increase of the binary size. In the disassembled file, I can see symbols like __gnu_unwind_get_pr_addr, __gnu_Unwind_Restore_VFP, _Unwind_DebugHook, __gnu_Unwind_RaiseException, etc.

First time this happened, I was using some shady pointer stuff, so I can understand that because of that some exception could happend and then this stack unwinding stuff is needed. Last time I copied over a function and forgot to remove the __attribute__((weak)) attribute. Even though I found that this was causing it, I don't really see what the problem is there, I thought that if I don't implement a strong function, then the weak one will be used without any problems.

Question: what exactly is this unwinding stuff that gets added to the binary, what is its purpose, and what causes it generally speaking?

My assumption is that if I write code that could potentially cause an exception to happen, then stack unwinding is a necessary component of the exception mechanism, so that is why this extra code is added. But I am just guessing here, it is hard to find anything about this online.

Marcell Juhász
  • 528
  • 3
  • 9
  • 4
    Yes, it's for exceptions. Does your code actually use exceptions (`try/throw/catch`)? If not, try compiling with `-fno-exceptions` and see if it goes away. – Nate Eldredge Oct 26 '22 at 14:08
  • Note that "pointer stuff" does not throw C++ exceptions; it may cause a CPU exception, which is an entirely different mechanism with the same name. CPU exceptions have nothing to do with stack unwinding. – Nate Eldredge Oct 26 '22 at 14:09
  • 1
    It sounds like you don't have any specific size requirements, in which case you are performing the worst kind of premature optimization. Basically you need to understand that "keep the binary small" and "use modern C++" are contradictory requirements. If the modern C++ can do something that you can't do *as easily* in C then you are swapping the binary size for developer convenience. Don't fight it unless you know you aren't going to have room for your program. If you can guess at this early stage that this may be the case, then just use C to begin with. – Tom V Oct 26 '22 at 16:35
  • define "binary"...what file format is this binary? elf? intel hex? motorola srecord? other? overhead can multiply as much as if not more than actual code/data. – old_timer Oct 26 '22 at 22:57
  • @TomV With all due respect, I think that you are wrong about modern C++ and binary size. With language features like consteval, constexpr and concepts, I can push many things into compile time rather than runtime. Of course this is application specific, but when programming for embedded devices, the role of a GPIO for example is pretty static, it does not really change during runtime, hence every if-else statement and bitmask calculation can be executed at compile time in the GPIO init function. And that is only one of many such places. And again, my goal is to use C++, not C – Marcell Juhász Oct 27 '22 at 13:44
  • @old_timer raw binary, that can be written directly into the flash of an MCU for execution – Marcell Juhász Oct 27 '22 at 13:46
  • @NateEldredge thanks for the suggestion, I will try that flag the next time I encounter this behavior. – Marcell Juhász Oct 27 '22 at 13:50
  • 1
    @MarcellJuhász: the experience of many embedded engineers (including yorself, according to the numbers you have posted above) prove you wrong. C++ always introduces more overhead, especially in small projects. – Tom V Oct 27 '22 at 13:51
  • 1
    @TomV It is entirely possible to use C++ and avoid the overheads if you understand the tools and language. This is like saying you can not build an embedded FORTH system (or any language). It is actually impossible to build an embedded 'C' system. You need assembler to do it and no one actually builds a 'C' embedded system. An equally ridiculous argument. – artless noise Oct 29 '22 at 13:06
  • 1
    More on topic, modern C compilers actually include the exception tables, for 'C' code as [this question shows](https://stackoverflow.com/questions/21527256/when-is-arm-exidx-is-used). – artless noise Oct 29 '22 at 13:08

0 Answers0