什么被gcc的-flto丢弃了?

时间:2018-05-04 12:35:59

标签: gcc stm32 lto

我正在使用arm-none-eabi-gcc 6.3.1为stm32构建我们的固件。

如果我启用链接时优化,它仍然可以编译和启动,并且比没有-ftlo小~10kiB但是有一些微妙的破坏。

我该如何调试?

有没有办法让gcc告诉我在链接时优化期间丢失了什么(错误地)?

1 个答案:

答案 0 :(得分:1)

时间问题

优化代码应该并且会使它运行得更快,这可能会导致硬件出现问题,因为它会使速度慢一点。

一个例子:

void GPIO_Test() {
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_SET);
    GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

这在没有-lto的情况下有效,但在启用-lto时无法将输出设置为高。为什么?因为在大多数STM32型号上,在启用RCC中的时钟和使用外设之间需要一个小的延迟(这在勘误表中提到)。调用函数将提供所需的延迟,但使用-lto,编译器可以在另一个模块中内联函数,从而减少延迟。

缺少volatile

-lto的一个常见问题是,它可以优化对应该声明为volatile的变量的访问,但不是,即使访问被封装在一个变量中也是如此函数调用在另一个模块中。

让我们看一个简单的例子。

MAINLOOP.C:

while(1) {
  if(button_pressed()) {
    do_stuff();
  }
}

button.c的:

int button_flag;
void button_interrupt_handler() {
    button_flag = GPIOx->IDR & SOME_BIT;
}

void button_pressed() {
  return button_flag;
}

如果没有-lto,则在另一个模块中调用函数会被视为具有可能副作用的黑盒子,始终会生成调用,并始终评估结果。换句话说,对另一个模块的每个函数调用都充当隐式内存屏障。使用-lto屏障不再存在,编译器可以有效地内联或以其他方式优化其他模块中的函数。