5
votes

My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.

Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto. I would like to get rid of this workaround.

The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out) This makes the resulting binary crash.

Digging deeper and after googling for similar problems:

Sample code from startup_efm32gg.c defines default interrupt handlers as such:

void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }

The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)

It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.

Thank you in advance for any ideas!

Edit: See my reply to the marked answer for a full solution!

1

1 Answers

3
votes

Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.

If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__)) to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.