遇见一个编译优化导致的 bug
来源:鱼鹰谈单片机 发布时间:2024-08-12 分享至微信
来源:公众号【鱼鹰谈单片机】
作者:鱼鹰Osprey
ID :emOsprey
最近在调试 can 通信,因为 c8t6 flash 很小,而鱼鹰培训工程完成的驱动越来越多,导致 flash 不足,因此把 bsp 的优化级别设置成-O2,谁知道在串口输入数据时直接 hardfault 了:
进一步跟踪发现问题出在这条代码中:
uint32_tcnt=*((uint32_t*)pinfo->pdma_cnt_rx);// 出错代码
.....
pinfo->last_dma_cnt = cnt;
这条代码最开始是这样
uint16_tcnt=*((uint16_t*)pinfo->pdma_cnt_rx);
因为我的last_dma_cnt 变量是 16 bit,我想节省一下 ram 空间,因为实际上 DMA 的计数器也只使用了 16 bit。
uint16_t last_dma_cnt; // used in dma
但是测试时发现出现 hardfault 了,通过汇编分析发现是非四字节对齐访问 dma 外设,后面通过修改代码,强制使用 32 bit 访问,就再也没出现问题了。
uint32_t cnt = *(( uint32_t*)pinfo->pdma_cnt_rx);
但昨天修改完编译优化级别后,又一次出现了,汇编分析发现还是对齐问题,因为0x4002005c 这个地址确实是 DMA 的计数器地址。
只是再优化后,没按我的要求 32bit 访问,而是自作主张使用16bit访问,因为它发现 cnt 这个变量操作的地方都是 16 bit,想当然的给我在取值时也给我直接优化成 16 bit 访问。
这样一来,由于 DMA 不支持 2 字节访问指令,因此直接 hardfault 了。为了解决这个优化问题,可以直接使用 volatile 关键字,保证编译器在取值时按照 4 字节对齐访问,如下:
uint32_t cnt = *((volatile uint32_t*)pinfo->pdma_cnt_rx); // must: volatile uint32_t
汇编代码
0x0800BCA6 6800 LDR r0,[r0,#0x00]
完结撒花!
[ 新闻来源:鱼鹰谈单片机,更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj]
存入云盘 收藏
举报
全部评论
暂无评论哦,快来评论一下吧!
鱼鹰谈单片机
面向软件开发进阶读者的公众号,分享包括但不限于 C 语言、KEIL、STM32、51 等知识。
查看更多
相关文章
一个基于Qt的串口调试工具(代码开源)
2024-08-07
先进封装:半导体行业的下一个蓝海
2024-09-04
用c语言实现一个简单的数据加解密算法
2024-08-12
分享一款适用于 keil 的自动化编译脚本
2024-08-07
刘德音揭秘:谁将是下一个台积电?
2024-09-04
热门搜索