防止 GCC LTO 删除函数

Posted

技术标签:

【中文标题】防止 GCC LTO 删除函数【英文标题】:Prevent GCC LTO from deleting function 【发布时间】:2016-11-18 06:51:28 【问题描述】:

我使用 GCC-ARM-Embedded 和 FreeRTOS。 FreeRTOS 具有 vTaskSwitchContext() 功能,仅在某些情况下使用 内联汇编代码。

问题是:当我使用 LTO 时,GCC 不考虑内联汇编代码并认为该函数没有被使用,因此将其删除。然后链接器失败,因为内联汇编代码中的函数调用无法解析。

我会申请__attribute__((used)),但我不想接触 FreeRTOS 代码(由 STM32CubeMX 生成)。

我尝试将它放入我的代码中,但实际上 GCC 足够聪明,不允许它工作:

if(false)
    vTaskSwitchContext();

有没有办法在不同的源文件中或通过参数告诉 GCC,这个函数不应该被删除?

示例

// file1.c
void vTaskSwitchContext( void )

    ...


// file2.c
void xPortPendSVHandler( void )

    __asm volatile
    (
    ...
    "   isb                                 \n"
    "   bl vTaskSwitchContext               \n"
    "   mov r0, #0                          \n"
    ...
    );

【问题讨论】:

我想知道这是怎么发生的。链接器查看目标文件及其外部引用。符号是从 C 代码引用还是从内联汇编引用的,这无关紧要。 @undur_gongor:LTO 改变了很多事情,通常会引起意外。 “链接器”实际上并不查看目标文件和外部引用,而是链​​接器充当编译器后端的前端,然后将编译器后端的结果链接起来。 【参考方案1】:

尝试从标记为used 的单独函数调用该函数。

void dummyFunction(void) __attribute__((used));

// Never called.
void dummyFunction(void) 
    vTaskSwitchContext();

【讨论】:

【参考方案2】:

您可以将-Wl,--undefined=vTaskSwitchContext 添加到您的LDFLAGS

【讨论】:

【参考方案3】:

由于某种原因,Dietrich 提出的解决方案对我不起作用。我正在使用 Infineon 的 DAVE 4(基本上是 eclipse,为他们的 XMC 微控制器系列提供了一个花哨的代码生成插件),这可能是它不起作用的原因。对我来说,我不得不在vTaskStartScheduler()之后打电话给vTaskSwitchContext()

int main()

    initializationCode();

    vTaskStartScheduler();

    //Code never reaches here
    vTaskSwitchContext();

【讨论】:

【参考方案4】:

如果您的 FreeRTOS 版本已使用宏 portDONT_DISCARD 代表 vTaskSwitchContext(),您可以在自己的 portmacro.h 中定义 portDONT_DISCARD

#define portDONT_DISCARD __attribute__((used))

基本上是向后移植https://github.com/FreeRTOS/FreeRTOS-Kernel/commit/07e672c448e2a4ea56ae793f1c6dae26d908b16e

【讨论】:

以上是关于防止 GCC LTO 删除函数的主要内容,如果未能解决你的问题,请参考以下文章

gcc有薄lto吗?

GCC LTO 是不是执行跨文件死代码消除?

24 GCC LTO - Link Time Optimization

24 GCC LTO - Link Time Optimization

如何将 GCC LTO 与不同优化的目标文件一起使用?

C++ 在 GCC 上使用已删除的函数,但在 MSVC 上没有