Chinaunix首页 | 论坛 | 博客
  • 博客访问: 11498
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 80
  • 用 户 组: 普通用户
  • 注册时间: 2017-10-31 17:54
文章分类
文章存档

2018年(5)

2017年(2)

我的朋友

分类: 嵌入式

2018-01-12 16:50:12

1.内存对齐

1.1     内存对齐概要


现代计算机中内存空间都是按照byte划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。


1.2     内存对齐作用和原因


各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。

2.ARM平台下内存对齐

在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)      

3.ARM平台下解决方案

上述问题可以修改应用层代码去避免此类问题。如程序清单3.1,我们定义宏如果不是X86平台,直接将uint32_t内存地址强制转换成uint8_t地址,再将数据VAL强制拆分成4个uint8_t型数据分别赋值到对应的uint8_t内存地址上。
          程序清单3.1 ARM平台下避免字节对齐访问


 … 

   #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)

       …




阅读(509) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~