分类: 嵌入式
2018-01-12 16:50:12
现代计算机中内存空间都是按照byte划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
在ARM中,有ARM和Thumb两种指令。ARM指令:每执行一条指令,PC的值加4个字节(32bits),一次访问4字节内容,该字节的起始地址必须是4字节对齐的位置上,即地址的低两位为bits[0b00],也就是说地址必须是4的倍数。Thumb指令:每执行一条指令,PC的值加2个字节(16bits),一次访问2字节内容,该字节的起始地址必须是2字节对齐的位置上,即地址的低两位为bits[0b0],也就是说地址必须是2的倍数。
遵循以上方式叫对齐(aligned)存储访问操作,不遵守这样方式称为非对齐(unaligned)存储访问操作。SylixOS下的ARM平台遵守对齐方式。
ARM平台下由于内存对齐产生的问题,如程序清单 2.1,是一段由于ARM平台下遵守内存对齐访问产生问题的代码,代码是一个简单的宏定义将VAL值赋值到DATA地址上。在程序中我们无法保证传进的参数DATA是4的整数倍,所以导致了会出现内存访问异常的现象。程序在运行中出现地址访问错误后退出。
程序清单2.1 平台下问题代码
… #define EC_WRITE_U32(DATA, VAL) \ do { \ *((uint32_t *) (DATA)) = cpu_to_le32((uint32_t) (VAL)); \ } while (0) … |
… #ifdef X86_PLATFORM #define EC_WRITE_U32(DATA, VAL) \ do { \ *((uint32_t *) (DATA)) = cpu_to_le32((uint32_t) (VAL)); \ } while (0) #else #define EC_WRITE_U32(DATA, VAL) \ do { \ *((uint8_t *) (DATA)) = (cpu_to_le32((uint32_t) (VAL))) & 0xff *(((uint8_t *) (DATA)) + 1) =(cpu_to_le32((uint32_t)(VAL)) >> 8) & 0xff; \ *(((uint8_t *) (DATA)) + 2) = (cpu_to_le32((uint32_t) (VAL)) >> 16) & 0xff; \ *(((uint8_t *) (DATA)) + 3) = (cpu_to_le32((uint32_t) (VAL)) >> 24) & 0xff; \ } while (0) … |