我的目标设备是基于EFM32 Cortex-M3的设备。我的工具链是ARM GNU官方工具链gcc-arm-none-eabi-8-2018-q4-major。
没有LTO,一切都可以正常工作,但是要使LTO工作,我必须用-fno-lto
标记所有中断处理程序代码。我想摆脱这种解决方法。
问题是,每个中断处理程序都将从最终二进制文件中删除。 (我正在与arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out
进行检查),这将导致二进制崩溃。
深入挖掘并搜索类似问题之后:
__attribute__((used))
,__attribute((interrupt))
之类的功能标记为无效-尽管具有这些属性,但中断处理程序仍被删除。 (与Prevent GCC LTO from deleting function相关) startup_efm32gg.c
中的示例代码定义了默认的中断处理程序,如下所示:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
常规中断处理程序定义也会发生相同的问题(例如,没有别名且不弱)
这可能是相关的,但似乎弱符号在LTO模式下的行为也相同。
预先感谢您的任何想法!
编辑:查看我对已标记答案的答复以获取完整解决方案!
答案 0 :(得分:3)
从哪里引用您的中断处理程序?就像将未引用的静态函数和对象从单个转换单元中删除一样,在LTO期间将删除未使用的外部函数和对象。为了防止这种情况(并且为了使您的程序在抽象模型中仍然有效),需要从入口点开始到功能和对象的引用链。如果不存在,则说明您实际上没有在程序中使用它们。
如果引用来自链接脚本或asm源文件,则很可能是LTO中的错误,并且没有看到应有的引用。在这种情况下,您可以将__attribute__((__used__))
之类的hack应用于受影响的函数定义。或者,您可以对它们进行虚假引用,例如通过将其地址存储到虚拟易失对象中,或在输入约束中使用其地址来清空内联asm块。作为另一种选择,也许有一种方法可以重做您使用asm源文件或链接脚本所做的任何事情,以在C级创建中断表,并在特殊部分中使用适当的结构/数组,以便编译器可以实际看到引用,而无需伪造它们。