I'm fooling around with c++ on arm cortex m3 with latest available arm-none-eabi-gcc 6.3. I made a dummy class and created a global object of that class:
class B
{};
class A : B
{
public:
A()
{
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH = 1;
GPIOC->ODR |= 1<<8;
}
virtual void foo()
{}
virtual ~A()
{}
};
A a;
int main(void) { while(1); }
This code compiles to 1620 bytes. If I remove virtual dtor it compiles to 1304 bytes. That's a palpable difference.
I went and looked into assembly and .map file and saw that many different runtime functions are being linked to my binary if I use virtual dtor. There's malloc and free and _static_initialization_and_destruction and so on.
The strange thing is: I do not understand how are they called? Main is called like this:
8000260: d3f9 bcc.n 8000256 <FillZerobss>
8000262: f000 f89f bl 80003a4 <SystemInit>
8000266: f000 f957 bl 8000518 <__libc_init_array>
800026a: f000 f865 bl 8000338 <main>
800026e: 4770 bx lr
After return from main (which never happens, by the way) execution just sits there on bx lr, it keeps jumping to the same address.
So I can't see a path for static object deinitialization to be called. Why isn't it optimized away as unreachable code?
I compile like this:
arm-none-eabi-g++ -c -fmessage-length=0 -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections -fno-rtti -fno-exceptions -fno-threadsafe-statics
and link like this arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb --specs=nosys.specs --specs=nano.specs -Wl,--gc-sections -T "${ProjDirPath}/src/Startup/STM32F100XB_FLASH.ld" -ffreestanding
I tried adding -fno-use-cxa-atexit or making a dummy __cxa_atexit - and it does make binary slightly smaller (which is even weirder than no effect at all).
Is there any way to disable destruction of static objects completely?
UPDATE:
- adding -Os made code shrink but there is still a difference with/without virtual dtor (1244 vs 1040 bytes ) so the question remains.
- here's the output of compiling with -S with dtor, without dtor