为何要字节对齐?
从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。
TCPIP协议栈一直采用的uip,感觉不是很好,想采用网上的流行的lwip协议,移植中出现了个有趣的问题,找了好半天才找到,是字节对齐问题,用下面这个例子说一下(我用的是KEIL)
在KEIL下测试结构
unsigned long * testzy;
testzy =(unsigned long *)0x0400130e;
* testzy = 0x11223344;//0x0400130C(44 33 22 11)* testzy 真实值变成了 0x00001122
反汇编看
R0=0x11223344;
R1=0x0400130e;
STR R0,[R1] ; 显然由于地址0x0400130e不是4的倍数,数据向前移动了 (R0=0x00001122,而不是0x44332211)
但在IAR测试下,结果又是正确的。
在ADS测试下,也会有问题。
在lwip出现问题的地方,是mem_malloc()分配内存(通过固定数组ram)时候错误,ram起始地址在KEIL下不是4的整数倍,在ADS是(怪异)
所以即使采样了#define MEM_ALIGNMENT4// Must be 4 for ARM system
上面定义只是保证了数组ram存数据保证4的倍数开始??
这样系统通过mem_malloc分配内存的地址并没有按四个字节的倍数来分(KEIL测试下),这样往导致分配好后的地址(该地址不是4的倍数)赋值的时候出错
ARM内存访问的对齐问题
按照ARM文档上的描述,其访问规则如下:
1. 一次访问4字节内容,该内容的起始地址必须是4字节对齐的位置上;
2. 一次访问2字节内容,该内容的起始地址必须是2字节对齐的位置上;
(单字节的没有这个问题,就不用考虑啦。)
计算机主要的架构就分为两类,复杂指令集计算机(CISC)和精简指令集计算机(RISC)。
CISC最有代表性的架构就是x86,RISC最有代表性的架构就是ARM。
不管是什么架构,对要访问的一定长度的数据的地址是有要求的,比如要访问一个32位的整数,那么这个数据必须(最好)存储在以4字节(32/8=4)对齐的地方。
一般来说,RISC对对齐要求的更严格些,非对齐访问可能会带来性能上的损失。
这对程序在不同架构间移植非常重要,因为它极有可能导致你的程序崩溃。