c++ - 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) 中作为符号导出。因此,由于某种原因,链接器选择保留弱符号,即使存在同名的强符号。
解决方案
对于那些正在寻找这个的人来说,显然 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
,否则中断会卡在默认无限循环,不执行预期的中断处理程序并从中断返回,允许继续执行其他代码。
推荐阅读
- c# - C# Request.Browser.Type 列表
- javascript - 在 React-native 的异步存储中扩展和显示数组
- javascript - Vue.js 中的财务计算 - 使用计算方法
- r - rgdal 无法识别 GDAL 版本
- react-native - 当键盘在本机反应中打开时,需要点击两次以触发 ListItem 中的 onPress 功能
- python - 来自不同列的 Python Pandas 字符串匹配
- python - 在 csv 文件的同一行上写入 2 个变量
- react-native - React Native - 如果 ScrollView 不在屏幕顶部,则键盘避免不起作用
- docker - 未找到 Docker 可执行文件
- java - 无法单击 Selenium 中的按钮