搜索
bottom↓
回复: 11

是编译器的Bug吗?——结构体成员未4字节对齐仍进行优化

[复制链接]

出0入0汤圆

发表于 2015-11-10 14:38:05 | 显示全部楼层 |阅读模式
本帖最后由 LCRPN 于 2015-11-10 20:18 编辑

(编译环境是IAR6.40,for ARM)

这两天重调uCGUI,发现官方Demo竟然不能运行,去年玩得蛮好的啊!那个Debug过程真痛苦,搞得我都开始怀疑人生了。

后来一步一步,硬是找到uCGUI源码里面有一个结构体赋值语句,一执行就HardFault。
仔细看了一下,该成员地址不是4的整数倍,却使用了LDRD(从连续的地址空间加载双字(64位整数)到2个寄存器)指令。(猜想非4字节对齐不能使用该指令)

一张图看懂问题:


其中被赋值的结构体是四个连续的16位有符号整形:



******************************************************************

目前已经发现两处问题,修改为独立成员赋值就好了。
GUIDEV_Auto.c:


GUIDEV.c:


但是uCGUI里面用到这个结构体的地方太多了,其他地方没出问题也许只是侥幸。

******************************************************************

那么问题来了:对于开发者来说,他使用C语言写的程序是完全没有问题的,那么是不是应该怪罪于编译器呢?

另外,我一两年前使用完全相同的环境做这个实验,是没有问题的,因此我怀疑是我的IAR缺少了某个配置文件,导致没能给编译器提供四字节对齐参数,进而导致了这个问题。
那么是不是应该有相应的的配置方法?

有没有大神能告诉我,我的猜想是否正确?


-------------------------------------------------------------

如果所有的结构体成员都使用4字节对齐,对于单片机来说未免太浪费资源。

现在的问题是,应该如何设置编译器,使其在遇到非四字节对齐的量时,不使用LDRD指令。(我认为编译器不分青红皂白地使用LDRD,本身就是一个 硕大无比的 BUG !!!)


-------------------------------------------------------------

写了一段简单测试代码,大家可以运行试试,看会不会进Hardfault。

  1. struct S_child{
  2.         int16_t x0;
  3.         int16_t y0;
  4.         int16_t x1;
  5.         int16_t y1;
  6. };

  7. struct S_Parent{
  8.         struct S_child s1;
  9.         int16_t i;
  10.         struct S_child s2;
  11. };

  12. volatile struct S_Parent gs1;

  13. int main( void )
  14. {        
  15.         gs1.s1 = gs1.s2;                //此处会进Hardfault,因为s2的地址不能被4整除
  16.         for(;;);
  17. }
复制代码


(卧槽,这样完全正确的C语言程序都能导致Hardfault,以后还能不能开心地写结构体了!!!)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2015-11-13 09:11:44 | 显示全部楼层
security 发表于 2015-11-13 08:54
看了你末尾给出的例子,
我想这不是栈的8字节对齐的问题了。
那么,你应该考虑升级编译器了,现在IAR至少 ...

In EWARM 6.40.2:
The LDRD instruction could be used for copying an 8-byte struct with less than 4-byte alignment, which could result in an exception (hard fault) when running the application. This no longer occurs.
[EW23272]

帮你贴上来

出0入0汤圆

 楼主| 发表于 2015-11-10 14:51:10 | 显示全部楼层
hameyou 发表于 2015-11-10 14:47
给编译器配置为4字节对齐!

在哪里配置?

出0入0汤圆

发表于 2015-11-10 15:09:00 | 显示全部楼层
依稀记得有个packed

出0入8汤圆

发表于 2015-11-10 15:29:39 | 显示全部楼层
看看栈地址,是否是8字节对齐。

出0入0汤圆

发表于 2015-11-10 15:42:52 | 显示全部楼层
可能某个头文件里设置了 #pragma pack(1),没有用#pragma pack()恢复默认对齐

出0入0汤圆

 楼主| 发表于 2015-11-10 16:32:37 | 显示全部楼层
ywhbn 发表于 2015-11-10 15:42
可能某个头文件里设置了 #pragma pack(1),没有用#pragma pack()恢复默认对齐

不是,没发现地址都是偶数吗? 对齐还是有的,只不过是2字节的。

出0入0汤圆

发表于 2015-11-12 20:49:49 | 显示全部楼层
#pragma   pack(4) //指定下面的结构体对齐方式为 4 字节对齐   
typedef struct            
{      
    char a;  
    double b;
    int  c;
}test;
其实对齐这种事真不能怪编译器,VS和GCC的编译器对齐方式都不一样,更不用说这些单片机的编译器了。
要规范不出错,就要每个结构体都自己定义对齐方式。

出0入0汤圆

 楼主| 发表于 2015-11-13 00:01:27 | 显示全部楼层
e1ki0lp 发表于 2015-11-12 20:49
#pragma   pack(4) //指定下面的结构体对齐方式为 4 字节对齐   
typedef struct            
{      

试过的,不是同一个问题。我这个是结构体中的结构体对齐问题。

不信请你试着把我最后的例子改对。

出0入8汤圆

发表于 2015-11-13 08:54:44 | 显示全部楼层
LCRPN 发表于 2015-11-13 00:01
试过的,不是同一个问题。我这个是结构体中的结构体对齐问题。

不信请你试着把我最后的例子改对。 ...

看了你末尾给出的例子,
我想这不是栈的8字节对齐的问题了。
那么,你应该考虑升级编译器了,现在IAR至少都7.40了吧
你的6.40版本太低了,要紧跟大佬的步伐啊。

其次,应该是你猜中了,这是编译器的bug
你可见IAR 6.40.2 releasenotes
里面有对LDRD做了说明,你搜一下,或许,这就是你要的答案。

而后更换新的IDE,再试试?

出0入0汤圆

 楼主| 发表于 2015-11-13 10:14:24 | 显示全部楼层
lw32 发表于 2015-11-13 09:11
In EWARM 6.40.2:
The LDRD instruction could be used for copying an 8-byte struct with less than 4- ...

看来这就是答案!解决了,心情舒坦了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-24 11:13

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

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