首要说说,什么叫对齐。假如一个数据是从偶地址开端的接连存储,那么它便是半字对齐,不然便对错半字对齐;半字对齐的特征是bit0=0,其他位为恣意 值。字对齐的特征是bit1=0,bit0=1,其他位为恣意值。假如一个数据是以能被4 整除的地址开端的接连存储,那么它便是字对齐,不然便对错字对齐。举例说明四字节对齐: 对内存进行操作时,被拜访的地址有必要为4的倍数。假如分配到的地址的地址不是4的倍数时,CPU实践拜访的地址仍是依照字对齐的方法来操作。也便是主动屏蔽bit1和bit0.
用ADS的ARMC Complier下Optimization Level或许引起问题,其间的一个问题便是字节对齐的问题。下面讲讲问题的现象及本质。
其时问题的现象是:程序使 用一公共变量Buf创立行列,假如ADS编译优化选项选用Minium则软件作业正常;源码不变,假如选用ALL优化,则不正常,数据紊乱且无法作业。为 了发现问题,咱们分别用Minium和ALL编译,在反汇编条件下单步盯梢程序,调查CPU寄存器和内存变量的改变状况。发现在Minium形式下,编译 器把行列内存块Uart0TxBuf分配到的地址是0x400015cc,这个地址是一个4字节对齐的地址,而在ALL形式下,编译器把Buf分配的地址 是0x400015c2,这个地址是一个非4字节对齐的地址。正是因为这个非4字节对齐的地址导致了问题的产生。
问题产生在QueueCreate(void *Buf, uint32 SizeOfBuf, uint8 (* ReadEmpty)(), uint8 (* WriteFull)())这个函数里,问题是怎么产生的,
在了解问题产生的机理前,先了解QueueCreate这个函数的作业原理。QueueCreate作业原理是,首要把buf指向的内存初始化为DataQueue格局的结构体。DataQueue的结构体格局如下:
typedef struct {
QUEUE_DATA_TYPE *Out; /* 指向数据输出方位 */
QUEUE_DATA_TYPE *In; /* 指向数据输入方位 */
QUEUE_DATA_TYPE *End; /* 指向Buf的完毕方位 */
uint16 NData; /* 行列中数据个数 */
uint16 MaxData; /* 行列中答应存储的数据个数 */
uint8 (* ReadEmpty)(); /* 读空处理函数 */
uint8 (* WriteFull)(); /* 写满处理函数 */
QUEUE_DATA_TYPE *Buf; /* 存储数据的空间 */
} DataQueue;
从结构体能够看出,结构体字节类型在内存分配为: 4字节指针变量(*Out)、4字节指针变量(*In)、4字节指针变量(*End)、2字节变量NData、2字节变量MaxData、4字节函数指针 变量ReadEmpty()、4字节函数指针变量 WriteFull()。
调查结构体开始地址放在非对齐时会呈现什么状况。
开始地址为0x400015c2时的由编译器分配得到的地址 实践操作地址
*Out 0x400015c2~0x400015c5 0x40015c0~0x400015c3
*In 0x400014c6~0x400015c9 0x400014c4~0x400015c7
*End 0x400015ca~0x400015cd 0x400015c8~0x400015cb
从表中能够看出,实践操作的地址依照4字节对齐格局得到。例如,当履行*Out进行操作时,主动屏蔽bit1和bit0,因而实践产生改变的是 0x40015c0~0x400015c3,而不是0x400015c2~0x400015c5,因为实践操作地址和编译器分配地址相互掩盖,当对*In 操作时,会导致*Out一同改变,对*End操作时,*In也跟着改变。正是因为非对齐的原因导致创立行列和对列操作彻底过错。
当内存开始地址为4字节对齐地址的状况时,编译器分配地址和实践地址共同,因而不存在上述问题。
结 论:
在ARM嵌入式体系中,当把一个内存区域初始化为某个结构体时,有必要留意字节对齐的状况。假如该内存开始地址为非对齐地址,不只得不到预期的成果,还或许 导致一些很古怪的让人无法了解外表问题。在C层面上不太简单调查到这些问题的本质,只要深化到汇编一层去剖析程序,才或许了解这些现象的深层原因。