硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1942|回复: 22
收起左侧

[IAR] 关于非对齐内存访问异常的问题

  [复制链接]

38

主题

291

回帖

405

积分

高级会员

积分
405
发表于 2022-10-10 10:01:44 | 显示全部楼层 |阅读模式
最近工程软件运行中崩溃,分析原因是: An unaligned access error has occurred (CFSR.UNALIGNED)

2022-10-10_8-36-11.png

找到这个技术笔记:
Accessing Unaligned Data | IAR Systems

提到了通过 SCB->CCR的控制位UNALIGN_TRP,可以启停该异常生成(HardFault)

如果程序中有非对齐内存访问,并关闭了该异常使能,程序的运行逻辑能保证正常吗?

备注:起源是大量使用了 #pragma pack(1)定义的结构体


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106974
QQ
发表于 2022-10-10 10:22:45 | 显示全部楼层
不能,像硬件浮点什么的,都是不支持非对齐访问的。
回复

使用道具 举报

38

主题

291

回帖

405

积分

高级会员

积分
405
 楼主| 发表于 2022-10-11 10:55:43 | 显示全部楼层
硬汉你好:
针对这个议题,我做了个Test Case:

1) 清理  SCB->CCR的控制位UNALIGN_TRP,关闭异常生成(HardFault)
2) 设计非对齐结构体

typedef __packed struct
{
    uint8_t  b1;
    float    f1;
    uint16_t s1;
    float    f2;
} TestType;

3)测试非对齐访问

_test[0].f1 = 123.456f;
_test[1].f2 = 123.456f;
calc_res = _test[0].f1 * _test[1].f2;

测试结果是正常的,截图如下:
非对齐数据访问测试.png



回复

使用道具 举报

39

主题

929

回帖

1051

积分

至尊会员

积分
1051
发表于 2022-10-11 11:04:44 | 显示全部楼层
不知道编译器能不能设置对齐长度,这样方便很多。
回复

使用道具 举报

38

主题

291

回帖

405

积分

高级会员

积分
405
 楼主| 发表于 2022-10-11 11:11:21 | 显示全部楼层
ghslfgkkl88 发表于 2022-10-11 11:04
不知道编译器能不能设置对齐长度,这样方便很多。

我的使用场景是禁止编译做对齐优化,但必须保证逻辑正确,
对齐、填充这是编译器的常规优化,没有特殊指定编译器做得很好了
回复

使用道具 举报

73

主题

1198

回帖

1417

积分

至尊会员

积分
1417
发表于 2022-10-11 11:14:38 | 显示全部楼层
干嘛非要非对齐操作呢?直接傻瓜式的读取字节信息然后合并就不会出现这种问题啊
回复

使用道具 举报

39

主题

929

回帖

1051

积分

至尊会员

积分
1051
发表于 2022-10-11 11:28:08 | 显示全部楼层
wdliming 发表于 2022-10-11 11:14
干嘛非要非对齐操作呢?直接傻瓜式的读取字节信息然后合并就不会出现这种问题啊

那是因为你没碰到大数据结构的场合,举个最简单的例子:
struct
{
    u32  u32Data;
    u8    u8Status;
}test[ 5000 ];

对齐和非对齐,内存占用相差接近15K,单片机有多少个15K?当然,你可能会杠为什么要放到结构体里面?每个数据单独放就好了。这个就是数据结构的领域了
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2022-10-11 11:29:02 | 显示全部楼层
__packed结构体的使用场景,一般用于多机通讯,传输数据的非本地环境
1. 数据串行化,将结构体打包成数组(__packed没有填充位)
2. MCU1发送一个数组,MCU2接收一个数组,具体硬件传输是UART串口,Ethnet,或者SPI什么的,
3. 发送跟接收不是本机,MCU构架也不一样,可能是arm,avr,c51什么的,
4. 接收时,用memcpy函数,配合offsetof结构体赋值,把数组还原成结构体,
5. 注意打包/还原时的大小端问题,一般默认是MSB
回复

使用道具 举报

38

主题

291

回帖

405

积分

高级会员

积分
405
 楼主| 发表于 2022-10-11 11:40:45 | 显示全部楼层
h_007 发表于 2022-10-11 11:29
__packed结构体的使用场景,一般用于多机通讯,传输数据的非本地环境
1. 数据串行化,将结构体打包成数组 ...

总结的对,这就是我的使用场景,概括之,基于字节流的序列化和反序列化
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2022-10-11 11:54:03 | 显示全部楼层
对于大型结构体的offsetof用法,不熟悉的朋友,可以参考Linux Kernel的list.h,足够详细,网上也有大量注释
回复

使用道具 举报

73

主题

1198

回帖

1417

积分

至尊会员

积分
1417
发表于 2022-10-12 17:49:23 | 显示全部楼层
h_007 发表于 2022-10-11 11:29
__packed结构体的使用场景,一般用于多机通讯,传输数据的非本地环境
1. 数据串行化,将结构体打包成数组 ...

写的非常好
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106974
QQ
发表于 2022-10-12 17:58:05 | 显示全部楼层
wanglehui_12 发表于 2022-10-11 10:55
硬汉你好:
针对这个议题,我做了个Test Case:


这个测试很有意义,浮点的地址是分别是多少。还有就是硬件浮点是否参与了进来。

如果用户仅通过关闭对齐异常触发,就可以正常使用硬件浮点非对齐,这里里面应该有坑,否则ARM手册会直接表示硬件浮点可以使用非对齐访问。

需要更多场景的批量测试验证才能下结论。
回复

使用道具 举报

38

主题

291

回帖

405

积分

高级会员

积分
405
 楼主| 发表于 2022-10-13 17:20:51 | 显示全部楼层
eric2013 发表于 2022-10-12 17:58
这个测试很有意义,浮点的地址是分别是多少。还有就是硬件浮点是否参与了进来。

如果用户仅通过关闭 ...

(1)我的测试平台是 CortexM7核的
(2)FPU开启了,双精度的
(3)float数据地址是奇数
(4)关闭异常使能,结果是OK

硬汉你好,这是我新测试的结果

非对齐数据FPU测试.png
回复

使用道具 举报

210

主题

1045

回帖

1685

积分

至尊会员

More we do, more we can do.

积分
1685
发表于 2022-10-14 00:24:54 | 显示全部楼层
数据结构等显式的编译器会自动处理,但自己写的部分要避免非对其访问
回复

使用道具 举报

9

主题

81

回帖

113

积分

初级会员

积分
113
发表于 2022-10-14 09:18:47 | 显示全部楼层
从汇编上看,先把奇地址的浮点数读取到R0 R1这样的通用寄存器中,再读取到S0 S1的FPU寄存器中。非字节对齐访问只发生在到R0 R1的地方。不知我的理解是否正确。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106974
QQ
发表于 2022-10-14 11:54:58 | 显示全部楼层
wanglehui_12 发表于 2022-10-13 17:20
(1)我的测试平台是 CortexM7核的
(2)FPU开启了,双精度的
(3)float数据地址是奇数

谢谢测试,也许真的行,后面可以试试多任务等场景下,多个任务刷浮点是否正常。
另个M7有个经典非对齐问题,后面也可以试试。

石锤内存访问不支持非对齐是否STM32H7的硬件bug
https://www.armbbs.cn/forum.php?mod=viewthread&tid=94562


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106974
QQ
发表于 2022-10-14 11:59:26 | 显示全部楼层
WALL_E 发表于 2022-10-14 09:18
从汇编上看,先把奇地址的浮点数读取到R0 R1这样的通用寄存器中,再读取到S0 S1的FPU寄存器中。非字节对齐 ...

对,主要就是LDM, STM, LDRD, STRD等指令的对齐访问。
回复

使用道具 举报

9

主题

16

回帖

43

积分

新手上路

积分
43
发表于 2022-10-14 13:06:04 | 显示全部楼层
保持4字节对齐,养成好习惯吧
回复

使用道具 举报

0

主题

15

回帖

15

积分

新手上路

积分
15
发表于 2022-10-14 14:34:03 | 显示全部楼层
在双机通信中,从规约数据帧中取数据,然后直接强转成结构体指针访问,会出现非对齐访问错误
回复

使用道具 举报

9

主题

16

回帖

43

积分

新手上路

积分
43
发表于 2022-10-14 23:36:30 | 显示全部楼层
cumtjdxcz 发表于 2022-10-14 14:34
在双机通信中,从规约数据帧中取数据,然后直接强转成结构体指针访问,会出现非对齐访问错误

嗯,通信数据前面的控制字节也许很不巧,刚好不是4的整数倍。
这种情况下如果要4字节操作,能想到的一种方法是先malloc一个4字节对齐的数组,复制过去,再操作新数组。操作完后free数组。
不知道有没有别的更好的办法
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2022-10-25 11:38:54 | 显示全部楼层
frank117 发表于 2022-10-14 23:36
嗯,通信数据前面的控制字节也许很不巧,刚好不是4的整数倍。
这种情况下如果要4字节操作,能想到的一种 ...

多机通讯的非本地外来数据,结构体成员一般用memcpy+offset来赋值(注意大小端)
就是说,外来数据一般抽象为n个byte的数组,意味着数组的下标0~(n-1)有特殊的意义,需要仔细设计(需要考虑不同硬件构架,不同的编译器等等),重点是逻辑的正确性:序列化和反序列化结果的一致性
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106974
QQ
发表于 2022-12-18 12:09:53 | 显示全部楼层
今天测试了下H7的,有些情况,屏蔽不了。
SCB->CCR &= ~SCB_CCR_UNALIGN_TRP_Msk;

p=(uint32_t *)0x24000003;
*p = 1000;

查了下,它会强行的弹异常。

image.png
回复

使用道具 举报

26

主题

70

回帖

148

积分

初级会员

积分
148
发表于 2022-12-24 15:14:12 | 显示全部楼层
struct
{
    u32  u32Data;
    u8    u8Status;
} test[5000];
这种非对齐的结构体数组, 先计算出目标成员的内存地址, 然后用memcpy把这个成员拷贝到栈上, 采用(读-修改-写)的操作进行操作, 大家看这样可行不?

我也遇到这种问题, 今天看到有人讨论还是挺高兴的.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-12 15:13 , Processed in 0.307230 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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