首页 > 解决方案 > arm-none-eabi-g++ 无法使用 -flto 正确处理弱别名

问题描述

我正在使用 SystemWorkbench 4 stm32 对 STM32F413 微控制器进行编程。中断向量在程序集启动文件中定义为弱别名,如下所示:

.weak   TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler

并在如下对象中引用:

g_pfnVectors:
  .word _estack
  .word Reset_Handler
  .word NMI_Handler
  .....
  .word TIM1_UP_TIM10_IRQHandler
  .....

所以这g_pfnVectors是一个 IRQ Handler 函数的地址列表。它们被声明为弱别名,因此如果用户未定义它们,则使用默认处理程序。

我已经定义了这样的处理程序:

extern "C" {
void TIM1_UP_TIM10_IRQHandler() {
    if (SU_TIM->SR & TIM_SR_UIF) {
        SU_TIM->SR &= ~TIM_SR_UIF;
        ...
    }
}
}

这适用于正常的编译器优化标志,但是我想尝试一下,如果我得到更小和可能更快的代码-flto(主要是为了尝试它,并不真正需要它)。但是当使用 编译时-flto,g++ 会忽略我对处理程序的实现,只使用默认处理程序,我的处理程序根本不在代码中。

所以我试图通过添加__attribute__((used))到函数定义中来强制g++包含该函数,但它仍然没有编译。但是,如果我给它另一个名字,那么它就会包含在二进制文件中。此外,如果我删除了弱别名并且只在启动文件中引用了处理程序,它也可以工作。

所以不知何故,弱别名不适用于 g++ 链接时间优化。也许有人可以告诉我错误是什么以及我在这里做错了什么。

编辑:

我查看了在生成的 .elf 文件中使用 nm 创建了哪些符号,并将其TIM1_UP_TIM10_IRQHandler导出为具有 DefaultHandler 地址的弱符号。但是,当仅查看包含该TIM1_UP_TIM10_IRQHandler函数的编译单元中的 .o 文件时,它会在文本部分 (T) 中作为符号导出。因此,由于某种原因,链接器选择保留弱符号,即使存在同名的强符号。

标签: c++armg++link-time-optimization

解决方案


对于那些正在寻找这个的人来说,显然 GCC 7 中存在与链接时间优化相关的已确认错误(-flto):

https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966

我刚刚再次遇到这个问题,使用 GCC 8(gcc-arm-none-eabi-8-2019-q3-update 版本),行为仍然相同。

也适用于我的解决方法(来自https://github.com/ObKo/stm32-cmake/issues/78)是删除或注释文件末尾的弱定义startup_XXX.s,因此进行更改,例如

    .weak   NMI_Handler
    .thumb_set NMI_Handler,Default_Handler

/*
    .weak   NMI_Handler
    .thumb_set NMI_Handler,Default_Handler
*/

并在源文件中用您自己的实现替换它们:

void NMI_Handler(void)
{
    //...
}

所有被调用的弱处理程序都需要删除,例如如果您UART1_Handler()在 HAL/LL 驱动程序中定义了,则需要从文件中删除相应的.weak条目startup_XXX.s,否则中断会卡在默认无限循环,不执行预期的中断处理程序并从中断返回,允许继续执行其他代码。


推荐阅读