微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 对ARM处理器的内存对齐问题

对ARM处理器的内存对齐问题

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

可以对齐或不对齐的内存访问。对齐的内存访问发生时的数据都位于其自然大小边界。例如,如果该数据类型的大小是4个字节,那么它属于被4整除的内存地址是位于其自然大小边界。未对齐的内存访问发生在所有其他情况下(在上面的例子中,内存地址时,是不能被4整除)。ARM处理器的设计有效地访问对齐的数据。在ARM处理器上试图访问未对齐的数据会导致不正确的数据或显着的性能损失(这些不同的症状会在稍后讨论)。与此相反,大多数CISC型处理器(即x86)的访问未对齐的数据是无害的。这份文件将讨论一些比较常见的方式,一个应用程序可能会执行未对齐的内存访问,并提供一些建议的解决方案,以避免这些问题, 。

症状

上述问题,适用于所有ARM架构。然而,根据MMU(内存管理单元)和操作系统支持的可用性,应用程序可能会看到不同的行为在不同的平台上。默认情况下,未对齐的内存访问不会被困住了,会导致不正确的数据。与功能的MMU的平台上,但是,OS捕获非对齐访问,它在运行时进行纠正。其结果将是正确的数据,但在10-20 CPU周期的成本。

常见原因

上述问题的类型转换适用于所有ARM架构。然而,根据MMU(内存管理单元)和操作系统支持的可用性,应用程序可能会看到不同的行为在不同的平台上。默认情况下,未对齐的内存访问不会被困住了,会导致不正确的数据。与功能的MMU的平台上,但是,OS捕获非对齐访问,它在运行时进行纠正。其结果将是正确的数据,但在10-20 CPU周期的成本。

代码:

void my_func(char *a) { int *b = (int *)a; DBGPRINTF("%d", *b); }

这个简单的例子,可能会导致未对齐的内存访问,因为我们不能保证的char * a是一个4字节的边界上对齐。只要有可能,应避免这种类型的施放。

使用数据缓冲区
未对齐的内存访问的最常见的原因源于不正确地处理数据缓冲区。这些数据缓冲区可能包含任何数据从USB端口读取,通过网络,或从一个文件中。这个数据是很常见的包装,有没有插入填充,以确保数据在缓冲区内位于其自然大小边界。在这个例子中,我们会考虑的情况下,从文件加载的Windows BMP和解析的头。的Windows BMP文件包含一个头的像素数据。的标头是由两个结构:

代码:

typedef PACKED struct { unsigned short int type; /* Magic identifier */ unsigned int size; /* File size in bytes */ unsigned short int reserved1, reserved2; unsigned int offset; /* Offset to image data, bytes */ } HEADER; typedef PACKED struct { unsigned int size; /* Header size in bytes */ int width,height; /* Width and height of image */ unsigned short int planes; /* Number of colour planes */ unsigned short int bits; /* Bits per pixel */ unsigned int compression; /* Compression type */ unsigned int imagesize; /* Image size in bytes */ int xresolution,yresolution; /* Pixels per meter */ unsigned int ncolours; /* Number of colours */ unsigned int importantcolours; /* Important colours */ } INFOHEADER;

请注意,在的HEADER和INFOHEADER结构的大小,分别为14和40字节。让我们假设我们要确定在运行时的图像的宽度和高度。的代码来访问这些数据可能看起来像这样:

代码:

#define INFOHEADER_OFFSET (sizeof(HEADER)) #define WIDTH_OFFSET (INFOHEADER_OFFSET + offsetof(INFOHEADER, width)) #define HEIGHT_OFFSET (INFOHEADER_OFFSET + offsetof(INFOHEADER, height)) int imageWidth, imageHeight; void * fileBuf; pMe->mFile = IFILEMGR_OpenFile(pMe->mFileMgr, "test.bmp", _OFM_READ); if (pMe->mFile) { IFILE_GetInfo(pMe->mFile, &fileInfo); fileBuf = MALLOC(fileInfo.dwSize); if (fileBuf) { result = IFILE_Read(pMe->mFile, fileBuf, fileInfo.dwSize); if (result == fileInfo.dwSize) { imageWidth = *((uint32*)(((byte*)fileBuf) + WIDTH_OFFSET)); imageHeight = *((uint32*)(((byte*)fileBuf) + HEIGHT_OFFSET)); } } }

注意的宽度和高度的偏移量。因为他们属于一个半字边界上,以上述方式访问这些值会导致未对齐的内存访问。下面列出的一些推荐的方法来避免这个问题。

推荐的解决方案

使用memcpy

我们的第一个选项是,只需执行MEMCPY从缓冲区中的数据到本地变量:

代码:

if (result == fileInfo.dwSize) { MEMCPY(&imageWidth, (((byte*)fileBuf)+WIDTH_OFFSET), sizeof(uint32)); MEMCPY(&imageHeight, (((byte*)fileBuf)+HEIGHT_OFFSET), sizeof(uint32)); } 

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

网站地图

Top