搜索
bottom↓
回复: 34

好郁闷,编译器默认开O3优化,竟然会让程序流程错乱

[复制链接]

出0入0汤圆

发表于 2019-10-30 22:54:06 | 显示全部楼层 |阅读模式

之前一直没意识到,开了优化后会有C语言程序正确,编译之后汇编指令乱跑的情况。

开发环境:
MDK 5.28,编译器v5(ARM Compiler 5.06 update 6 build 750),编译器选项开启了C99模式和GNU扩展,优化水平是O3;

工程环境:
STM32F051,使用了开源的FreeRTOS系统、Letter-Shell命令行外壳、SPIFFS文件系统和SPIFlash驱动层。

写好底层驱动后测试SPIFFS文件系统,mount步骤就开始出错,但底层检查不出问题。
动态调试的时候发现文件系统句柄指向的配置结构体都被改写了。
然后又进行了两天的艰苦跟踪,发现在SPIFlash驱动层的switch分支里程序竟然乱跳。
https://github.com/pellepl/spifl ... ster/src/spiflash.c  ,从153行switch跳到某个case中间的165行,应该跳转到253行case)

把优化等级从O3调到O0就正常了。

给大家提个醒吧,有时候出bug了还真不是源代码的问题 :'(

出0入4汤圆

发表于 2019-10-30 23:17:10 | 显示全部楼层
代码开最高优化不正常的情况下,多数是代码写的不严谨。 我们的代码一直要求开最高编译能通过。

出0入0汤圆

发表于 2019-10-30 23:25:35 | 显示全部楼层
是这样子的

出0入0汤圆

发表于 2019-10-30 23:43:15 | 显示全部楼层
个人建议 case 里面的 return改成break,   return最后返回  

出140入158汤圆

发表于 2019-10-31 01:43:57 来自手机 | 显示全部楼层
wajlh 发表于 2019-10-30 23:17
代码开最高优化不正常的情况下,多数是代码写的不严谨。 我们的代码一直要求开最高编译能通过。 ...

正解            

出0入93汤圆

发表于 2019-10-31 06:24:15 | 显示全部楼层
把优化等级从O3调到O0就正常了。
绝大多数原因就是该用volatile时而你又不肯用然后甩锅给编译器。

分支里程序竟然乱跳
这不是非常非常正常么,要不怎么叫优化呢。

出0入442汤圆

发表于 2019-10-31 06:35:15 来自手机 | 显示全部楼层
takashiki 发表于 2019-10-31 06:24
绝大多数原因就是该用volatile时而你又不肯用然后甩锅给编译器。

这不是非常非常正常么,要不怎么叫优化呢 ...

不要过于相信编译器,否则你死都不知道怎么死的。比如cypress api在vc上编译,开lto之后内部底层一个buffer指针会在内部返回时错乱,插拔usb设备大概率崩溃,关掉lto正常。你可以看看gcc maillist,几乎每天都有人提交bug。包括mips elf 6.2,编译时如果switch非常大,则偶尔会有case被优化没了!!!我对着汇编一个case一个case分析,最终确认那个case没了。mips elf 8.2也是同样的问题。riscv gcc还没遇到过这种情况,主要还是看社区支持力度。对了,gcc我都是os+lto,vc都是o2,现在通通不开lto了,以防多线程编译器bug。

出0入0汤圆

发表于 2019-10-31 06:37:41 来自手机 | 显示全部楼层
What is lto?

出0入93汤圆

发表于 2019-10-31 06:47:15 | 显示全部楼层
wye11083 发表于 2019-10-31 06:35
不要过于相信编译器,否则你死都不知道怎么死的。比如cypress api在vc上编译,开lto之后内部底层一个buff ...

我照样也发现过编译器的BUG,不是过于相信,而是一般在坛子里发帖指责编译器问题的绝大多数都是自己的问题。
STM8的cosmic,逗号表达式Release模式无法按照C语言标准从左至右依次计算而是按它自己的喜好选择性的计算。虽然这个不符合MISRA,但毕竟是编译器的BUG。

出0入12汤圆

发表于 2019-10-31 06:48:55 | 显示全部楼层

Link-time optimization.

我觉得最开始开发的时候最好就开 O3,至少是 Os,看具体情况稍微调整。

出130入129汤圆

发表于 2019-10-31 07:03:43 来自手机 | 显示全部楼层
fatfs的格式化函数,记得o3时候会死掉,不过没去深究,水平有限

出0入0汤圆

发表于 2019-10-31 07:42:42 来自手机 | 显示全部楼层
了解一些优化的知识是必要的,这不能说是编译器的问题

出0入0汤圆

发表于 2019-10-31 07:44:22 来自手机 | 显示全部楼层
要开O3优化,我们一般推荐开始就开,代码庞大后,写的如果不规范,最后开O3会要人命的

出0入0汤圆

发表于 2019-10-31 07:46:21 | 显示全部楼层
iar也會有bug,8.32.2運算uint32_t * uint32_t的值會少一部分,開不開優化都一樣
但是8.40這bug就修正了

出0入0汤圆

 楼主| 发表于 2019-10-31 08:19:32 | 显示全部楼层
qidaimengxing 发表于 2019-10-30 23:43
个人建议 case 里面的 return改成break,   return最后返回

还有这个说法,我去试试看

出0入0汤圆

 楼主| 发表于 2019-10-31 08:21:25 | 显示全部楼层
takashiki 发表于 2019-10-31 06:24
绝大多数原因就是该用volatile时而你又不肯用然后甩锅给编译器。

这不是非常非常正常么,要不怎么叫优化呢 ...

这次不是volatile的锅。

case分支进入某个case中间代码,没有从case入口执行,改变了源码功能,这也算优化?

出0入0汤圆

 楼主| 发表于 2019-10-31 08:23:46 | 显示全部楼层
wajlh 发表于 2019-10-30 23:17
代码开最高优化不正常的情况下,多数是代码写的不严谨。 我们的代码一直要求开最高编译能通过。 ...

github上搬来的文件系统代码,也没意识到会有这个问题,O3还是默认开的

出0入0汤圆

发表于 2019-10-31 08:24:07 来自手机 | 显示全部楼层
乱跳可能不是编译器的问题,而是调试器的问题,编译等级高了导致每条汇编无法对应到一行C了

出0入22汤圆

发表于 2019-10-31 08:28:40 | 显示全部楼层
O3不能跑多数是自己代码问题,O3后调试单步不正常是正常现象,我自己的代码也是要求O3必须能正常跑,调试的话就开O0,最终发布必须O3

出0入0汤圆

发表于 2019-10-31 08:43:57 来自手机 | 显示全部楼层
编译器也会有问题的,我一般不开启优化,自己优化时间较长的算法

出0入0汤圆

发表于 2019-10-31 08:53:25 | 显示全部楼层
wajlh 发表于 2019-10-30 23:17
代码开最高优化不正常的情况下,多数是代码写的不严谨。 我们的代码一直要求开最高编译能通过。 ...

老哥有没有单片机代码规范方面的书推荐学习下?
以前遇到过几次优化后,运行不正常的现象,不管是51还是ARM,像上面有人说volatile关键字,改加的也都加了,有时能解决,有时怎么都解决不了,现在索性所有的程序都不开优化了,好在还没出现过程序空间不够用的情况。

出100入113汤圆

发表于 2019-10-31 08:55:19 | 显示全部楼层
zxzx8059 发表于 2019-10-31 07:46
iar也會有bug,8.32.2運算uint32_t * uint32_t的值會少一部分,開不開優化都一樣
但是8.40這bug就修正了 ...

还有这种低级错误?目前使用 8.32.3 暂时没遇到这种问题。

出0入79汤圆

发表于 2019-10-31 08:56:57 | 显示全部楼层
我也认为是代码写的问题,开不开优化,差别很大的。

出0入8汤圆

发表于 2019-10-31 09:00:11 | 显示全部楼层
本帖最后由 kebaojun305 于 2019-10-31 09:04 编辑
fnems 发表于 2019-10-31 08:21
这次不是volatile的锅。

case分支进入某个case中间代码,没有从case入口执行,改变了源码功能,这也算优 ...


肯定的告诉你 这就是优化,我的程序一直都是开03优化的。 调试的时候看起来确实是有乱跳的,就是优化了程序,但是功能没问题的。  我建立工程的时候 都是开到03的  如果03的程序功能不正常 优化调整到00  功能也不正常的。

出100入113汤圆

发表于 2019-10-31 09:02:20 | 显示全部楼层
调试时开O3,你看着是乱跳,而实际不是乱跳,因为不同的 case ,可能有重复的代码,被优化到一段当中了。所以开O3看功能是否正常,通过打印日志分析问题,仿真看不出正常执行流程的。O3编译后功能有问题,的确很有可能是代码不规范导致,不过也许有时也跟编译器有点关系。比如前两年用 LWIP 协议栈,IAR老版本开了最高级优化,发送函数很容易阻塞死进程,最后只能中级优化。后来IAR升级到 8.32.3 后,使用 LWIP 协议栈这个问题没有了。

出0入33汤圆

发表于 2019-10-31 09:18:52 | 显示全部楼层
我记得当时搞SPIFFS的时候有个字节对齐的问题,找了好久才找出问题来。

出0入0汤圆

发表于 2019-10-31 09:25:24 | 显示全部楼层
作为经常使用STM32CUBEmx的我是深有体会,配置好默认的工程是O3的最优级别,通常写完代码去单步调试,只要函数嵌套多层(大概三层左右吧)就跳转不了,程序也不会正常跑起来。

出0入0汤圆

发表于 2019-10-31 09:35:44 | 显示全部楼层
乱跳是优化后c和汇编不能直接对应  结果并不一定错误  不然就不叫优化

出0入0汤圆

发表于 2019-10-31 09:36:22 | 显示全部楼层
乱跳是优化后c和汇编不能直接对应  结果并不一定错误  不然就不叫优化

出0入0汤圆

发表于 2019-10-31 09:48:08 来自手机 | 显示全部楼层
感觉IAR的最高优化问题少点,一开始设置最高,逐步添加代码逐步测试。C单步会乱,汇编单步看不懂,只能先0优化调完再设最高继续,工程进度慢也是没办法的事,能力所限

出0入0汤圆

发表于 2019-10-31 09:56:19 | 显示全部楼层
wajlh 发表于 2019-10-30 23:17
代码开最高优化不正常的情况下,多数是代码写的不严谨。 我们的代码一直要求开最高编译能通过。 ...

出0入42汤圆

发表于 2019-10-31 10:21:04 | 显示全部楼层
这种情况一般还真是源代码的问题.

出0入0汤圆

 楼主| 发表于 2019-10-31 12:54:55 | 显示全部楼层
kebaojun305 发表于 2019-10-31 09:00
肯定的告诉你 这就是优化,我的程序一直都是开03优化的。 调试的时候看起来确实是有乱跳的,就是优化了程 ...


乱跳没关系,前提是不改变源码功能。改变了功能就不能算优化了

出0入0汤圆

发表于 2019-11-1 14:29:17 | 显示全部楼层
saccapanna 发表于 2019-10-31 08:55
还有这种低级错误?目前使用 8.32.3 暂时没遇到这种问题。

用gcc時很簡單就
uint64_t x
x*=x;
就能算出來,iar 8.32.2我得分開算
    x=(x & 0x00000000ffffffff);
    s1=(x>>16) & 0x000000000000ffff;
    b1=((x<<48)>>48) & 0x000000000000ffff;
    s2=(s1 * s1)& 0x00000000ffffffff;
    b2=(b1 * b1) & 0x00000000ffffffff;
    c1=(s2<<32)& 0xffffffff00000000;
    s3=(s1 * b1 *2) & 0x00000000ffffffff;
    b3=(s3<<16)& 0x0000ffffffff0000;
    s4=c1+b2+b3;

我遇到程序跑出來的值跟gcc與python算出來的不一樣時,debug看了好一陣子才發現他少算s3部分,後面版本x*=x都沒事
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 15:52

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表