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

时间:2018-08-21 10:09:07

标签: c++ arm g++ link-time-optimization

我正在用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)中。因此,链接器出于某种原因会选择保留弱符号,即使存在同名的强符号也是如此。

3 个答案:

答案 0 :(得分:1)

对于那些正在寻找这些的人,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(),则需要从{{ 1}}文件,否则该中断将陷入默认的无限循环中,从而导致MCU锁定,而无需执行预期的中断处理程序并从中断返回,从而允许其他代码恢复执行。

答案 1 :(得分:0)

我认为您应该通知编译器它中断 takePhoto(flag) { return new Promise((resolve, reject) => { var sourceType: any; if (flag == "PHOTOLIBRARY") { sourceType = this.camera.PictureSourceType.PHOTOLIBRARY; } else { sourceType = this.camera.PictureSourceType.CAMERA; } const options: CameraOptions = { quality: 50, sourceType: sourceType, destinationType: this.camera.DestinationType.DATA_URL, encodingType: this.camera.EncodingType.JPEG, mediaType: this.camera.MediaType.PICTURE, targetWidth: 450, targetHeight: 450, saveToPhotoAlbum: false, correctOrientation: true, cameraDirection: this.camera.Direction.FRONT }; this.camera.getPicture(options).then( imageData => { resolve(imageData); }) }) ,这通常是不需要的,因为F4的堆栈默认被硬件对齐为8。

如果不起作用,则解决方法是为处理程序分配一个函数指针,这将防止其被丢弃(如果指针本身不会被丢弃,请与调试器联系)。

不得已-用向量表定义更改.s文件

答案 2 :(得分:0)

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

作为另一种解决方法,我发现并没有把startup.s文件弄乱,而是将IRQ处理程序放在单独的.c文件中,并在没有LTO的情况下构建了(并且只有那些)。

对于那些使用CubeIDE并通过CubeMX(也称为“设备配置工具”)生成IRQ / HAL处理程序的人,所有自动生成的处理程序都位于Core\Src\stm32XXXX_it.c中,您只需编辑此文件的属性并删除编译选项中的LTO。

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