一次在STM32F00X 上的诡异Bug排查手记

内核开发
1 1077
LMOS LMOS 2018-05-22
积分:15

问题现象:在一个不操作“任何”硬件的函数onfradrsz_free_blk()中,如下注释则没有问题:

602123921

而这么注释则会出问题:

819333914

一开始以为这是GCC做了特殊优化或者地址对齐问题导致的。为了确定问题,只好对照着汇编抄起J-Link手工调试:

1587233471

295554046

230512007

原来,问题出在_FLASH_PREFETCH_BUFFER_ENABLE()宏内

1508997597

480644477

588820770

198926221

因为在1538行代码中把FLASHPTR地址加载到R2寄存器内了。

但是请注意 1539行 GCC 无视了数据类型宽度 使用了ldrb指令,而这条指令加载[R2]地址处的一个字节到R1寄存器中。

当然gcc这种操作并不会导致运算结果出错,因为我确实就是只改变了那个地址处的低8位即第一个字节,虽然我不知道 GCC是怎么检测到的。

如果这个地址是内存地址当然不会有任何问题,可是这个地址是APB总线上的设备寄存器。然而…… 因为APB协议没有定义传输宽度信号,通常都被默认为字大小, 所以 ……所以异常就这样时不时的发生了。


总结:GCC编译出的指令在常规下并不会影响最终的执行结果 (int 数据类型 gcc用了ldrb 指令 读取了第一个字节 我确实是只操作了int类型的低8位) 但是由于是APB总线上外设寄存器只能4字节访问,所以发生了异常。非常有趣的是,GCC在问题是-O2 参数下用了ldr ,而在-O0下却用了ldrb指令,这也就是为什么编译时指定-O2参数bug不能复现的原因。


  • a133333 a133333
    2018-05-23

    好。把群里记录的,做成文字,整理好。。。方便以后学习讨论

    0 回复