微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 关于arm 的字节对齐

关于arm 的字节对齐

时间:11-09 来源:互联网 点击:

ARM中字节对齐的深入探讨

ARM中字节对齐的深入探讨
阅读了yos的文章《内存对齐问题学习小结》,深有体会,看来在进行指针操作时,必须进行强制类型转换,否则可能出现预想不到的错误。

在我的一个项目中,需要进行数据包解码,同样出现数据对齐的问题,却没能找到好的解决方法问题如下
CPU ARM7 ,编译环境 Keil RVCT3.0

#pragma pack(1)
typedef struct {
uint8 u8a[3];
uint8 u8b[4];
uint16 u16c;
uint32 u32d;
uint32 u32e;
} TSTBLK,* PTSTBLK;

主程序
main
{
uint16 i;
PTSTBLKpTST;

uint16 u16k;
uint32 u32m,u32l;
uint8DBUF[200];

for(i= 0 ;i<200;i++)DBUF[i]=i;

pTST=(PTSTBLK)DBUF;// 1
u16k = (pTST->u16c);// 2
u32m = pTST->u32d;// 3
u32l = pTST->u32e;// 4
//以下语句是避免 u16k,u32m,u32l被优化掉
i = u16k;
i = (uint16)u32m;
i = (uint16)u32l;
}

运行语句1 后, 结构体中的
u8a[] = 0x00~0x02
u8a[] = 0x03~0x06
u16c = 0x0807
u32d = 0x0C0B0A09
u32e = 0x100F0E0D
显然以上结果是我们所需要的,正确!
但继续运行 2,3,4得到
u16k = 0x0706
u32m = 0x080B0A09
u32l = 0x0C0F0E0D
字节对齐发生了问题,乱了!
乱得还不轻 u32m 没有等于0x0B0A0908
u32m 没有等于0x0B0A0908
u32m 也没有等于0x0F0E0D0C
why?

我试图用u16k = (uint16)(pTST->u16c);
u32m = (uint32)pTST->u32d;
去修改,但无效!
其实pTST->u16c本身就是16位的,强制转到16位自然没有任何意义。

你说的情况对于ARM CPU确实存在,但对于其它体系结构就不会出现
这是一个典型的ARM非对齐访问的问题。#pragma pack(1)能保证你的结构体中的数据是紧缩对齐的(在内存中是依次排列的)。那么对于
#pragma pack(1)
typedef struct {
uint8 u8a[3];
uint8 u8b[4];
uint16 u16c;
uint32 u32d;
uint32 u32e;
} TSTBLK,* PTSTBLK;
假设该结构体存放的基地址为0,则u8a[3]位于0-2字节, u8b[4]位于3-6字节,u16c位于7-8字节,依次类推。那么当我们去访问u16c时编译器会编译成一条访问地址为7的半字读的汇编语言,而地址为7对于半字读来说是一个非对齐访问,CPU就自动会把地址变成把最低位忽略,也是说CPU读的实际地址为6,于是读u16c得到的是6 、7两个字节即u16c=0x0706。对于字的访问CPU会忽略低两位地址,分析方法与前相同。你的两个32位数我不能理解,你怎么可能得到那样的结果,是不是写错了哦??我觉得你应该分别得到0x0B0A0908 0x0F0E0D0C才对。当然还涉及一个字节序的问题。
这一个问题在ARM CPU中会出现,但对于POWERPC的CPU或X86的CPU你的代码就不会出现问题,这都是CPU对非对齐访问采用的处理方式不同造成,POWERPC X86 会把非半字的非对齐访问变成两个字节访问,因为不会出现上面问题。MIPS我没有去研究过。
对于ARM CPU把结构体改为:
#pragma pack(1)
typedef struct {
uint8 u8b[4];
uint32 u32d;
uint32 u32e;
uint16 u16c;
uint8 u8a[3];
} TSTBLK,* PTSTBLK;
整个结构体仍然只占23个字节,但应该不会出现前面的问题。

__packed 能解决问题
谢谢大家,用__packed 可以解决问题,但我没理解__packed 和#pragma pack(1)的区别,请问谁能再解释得清楚些?

我先前的实验结果确实是 u32m = 0x080B0A09u32l = 0x0C0F0E0D
为什么不是0x0B0A0908 和0x0F0E0D0C,原因不详

我不同意更改结构体,因为数据结构是规定死了,不能随意改
对于ARM CPU把结构体改为:
#pragma pack(1)
typedef struct {
uint8 u8b[4];
uint32 u32d;
uint32 u32e;
uint16 u16c;
uint8 u8a[3];
} TSTBLK,* PTSTBLK;

uboot中,ARM体系下,设置变量4字节对齐

调试程序遇到由于buffer地址不是4字节对齐,所有底层去:

u32 *p =(u32 *)buf;

使得数据拷贝有误。所以,去参考了uboot中其他人的做法:

\board\s1845\flash.c中的:

#define __align__ __attribute__ ((aligned (8)))
static __align__ ulong precmd0[2]= { 0x00aa00aa, 0x00aa00aa };

所以,此处就可以这么做,使一个字符数组变量4字节对齐的:

static__attribute__ ((aligned (4)))unsigned char data_buf[MAX_PAGE_SIZE];

ARM 的 RealView中的解释:

4.4.2.__attribute__((aligned))

aligned类型属性指定类型的最低对齐要求。

Note

此类型属性是 ARM 编译器支持的 GNU 编译器扩展。

Copyright 2007-2009 ARM Limited. All rights reserved.ARM DUI 0348BC
Non-Confidential, Unrestricted Access

4.5.3 __attribute__((aligned))
aligned 变量属性指定变量或结构字段的最低对齐要求(按字节计算)。
注意
此变量属性是 ARM 编译器支持的 GNU 编译器扩展。
示例
int Variable_Attributes_aligned_0 __attribute__ ((aligned (16)));

short Variable_Attributes_aligned_1[3] __attribute__ ((aligned));

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top