arm-none-eabi-g++ 无法使用 -flto 正确处理弱别名

问题描述 投票:0回答:4

我正在使用 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 处理函数的地址列表。它们被声明为弱别名,因此如果用户未定义它们,则使用默认处理程序。

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

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++ arm g++ link-time-optimization
4个回答
2
投票

我认为你应该通知编译器它是中断

__attribute__ ((interrupt ("IRQ")))
,通常不需要,因为F4默认情况下硬件将堆栈对齐到8。

如果没有帮助,解决方法是为处理程序分配一个函数指针,这将防止它被丢弃(如果指针本身不会被丢弃 - 请与调试器检查)。

最后的手段 - 使用向量表定义更改 .s 文件


2
投票

对于那些寻找此问题的人来说,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)
{
    //...
}

所有正在调用的弱处理程序都需要删除,因此,例如,如果您在 HAL/LL 驱动程序中定义了

UART1_Handler()
,则需要从
.weak
文件中删除相应的
startup_XXX.s
条目,否则中断将通过陷入默认的无限循环来锁定 MCU,而不执行预期的中断处理程序并从中断返回,从而允许其他代码执行恢复。


1
投票

此错误仍然存在于

gcc-arm-none-eabi-9-2020-q3-update
中,但仅适用于 C 处理程序。奇怪的是,用 C++ 编写的处理程序(并使用
extern "C"
链接声明)不再受此错误影响。

作为另一种解决方法,我发现将 IRQ 处理程序放在单独的

startup.s
文件中并在没有 LTO 的情况下构建这些(并且仅那些)即可解决问题,而不是弄乱
.c
文件。

对于使用 CubeIDE 并使用 CubeMX(又名“设备配置工具”)生成 IRQ/HAL 处理程序的用户,所有自动生成的处理程序都在

Core\Src\stm32XXXX_it.c
中,您只需编辑此文件的属性并从编译中删除 LTO选项。

这不是最优的,但它非常适合自动生成的 IRQ/HAL 处理程序:只有第一个调用(从 IRQ 处理程序到 HAL 处理程序)未优化,但 HAL 代码本身已正确优化。


0
投票

到 2023 年它仍然存在,使用 11.2.1-1.2。

因此,如果不破解核心源代码,就不可能使用中断处理程序。

古力克

© www.soinside.com 2019 - 2024. All rights reserved.