gcc - gcc 的 -flto 丢弃了什么?

标签 gcc stm32 lto

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

如果我启用链接时优化,它仍然可以编译和启动,并且比不使用 -ftlo 时小约 10kiB,但有一些细微的损坏。

如何调试这个?

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

最佳答案

时间问题

优化代码应该并且将会使其运行得更快,这可能会导致预计其运行速度慢一些的硬件出现问题。

一个例子:

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();
  }
}

按钮.c:

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

void button_pressed() {
  return button_flag;
}

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

关于gcc - gcc 的 -flto 丢弃了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50175117/

相关文章:

c - 尝试通过 bash 脚本中的命令行传递预处理器指令

c++ - 包含 header 的搜索路径因编译器而异

clang, lto, 防止函数删除

c++ - C++ 代码中的 volatile 相关错误

c - 原子比较(不等于)和交换

stm32 - STM32F303 上的引导加载程序 : built in from factory or externally programmed?

c - STM32F4 I2C 无库

c - STM32F0 I2C HAL 保存结构到 I2C EEPROM

c++ - LTO 导致标准库崩溃