您的位置:首页 > 其它

CPU访问字节对齐

2012-04-10 12:48 239 查看
编写可移植代码,需要考虑的一个问题是如何存取不对齐的数据。

例如, 如何读取一个存储于一个不是 4 字节倍数的地址的4字节值. i386 用户常常存取不对齐数据项, 但是不是所有的体系允许这个,很多现代的CPU体系会产生异常。

可以采用以下的函数,进行字节对齐。

#include <asm/unaligned.h>

get_unaligned(ptr);

put_unaligned(val, ptr);

这些宏是无类型的, 并且用在每个数据项, 不管它是 1 个, 2 个, 4 个, 或者 8 个字节长.

关于对齐的另一个问题是跨平台的数据结构移植性. 同样的数据结构可能在不同的平台上编译方式不同,编译器根据各个平台不同的惯例来安排结构成员对齐。

为了编写可以跨不同CPU体系使用的数据结构,你应当一直强制自然的数据项对齐, 加上对一个特定对齐方式的标准化. 自然对齐意味着存储数据项在是数据项大小的整数倍的地址上(例如, 8-byte 项在 8 的整数倍的地址上)。

为了阻止编译器以不希望的方式调整成员变量存储位置,你应当使用填充成员来避免在数据结构中留下空洞。

为展示编译器如何强制对齐, dataalign 程序在源码的 misc-progs 目录中发布, 并且一个对等的 kdataalign 模块是 misc-modules 的一部分. 这是程序在几个平台上的输出以及模块在 SPARC64 的输出:

arch Align: char short int long ptr long-long u8 u16 u32 u64
i386        1    2     4   4    4   4         1  2   4   4
i686        1    2     4   4    4   4         1  2   4   4
alpha       1    2     4   8    8   8         1  2   4   8
armv4l      1    2     4   4    4   4         1  2   4   4
ia64        1    2     4   8    8   8         1  2   4   8
mips        1    2     4   4    4   8         1  2   4   8
ppc         1    2     4   4    4   8         1  2   4   8
sparc       1    2     4   4    4   8         1  2   4   8
sparc64     1    2     4   4    4   8         1  2   4   8
x86_64      1    2     4   8    8   8         1  2   4   8

kernel: arch Align: char short int long ptr long-long u8 u16 u32 u64
kernel: sparc64     1    2     4   8    8   8         1  2   4   8

有趣的是注意不是所有的平台对齐 64-位值在 64-位边界上, 因此你需要填充者成员来强制对齐和保证可移植性。

最后, 需要知道编译器可能自己悄悄地插入填充成员到数据结构中,用来保证每个成员是对齐的。

为了目标处理器的良好性能. 自动填充可能妨碍你的企图. 解决这个问题的方法是告诉编译器这个结构必须是"紧凑的", 不能增加填充者。

例如, 内核头文件 <linux/edd.h> 定义几个与 x86 BIOS 接口的数据结构,定义如下:

struct
{
u16 id;
u64 lun;
u16 reserved1;
u32 reserved2;
}
__attribute__ ((packed)) scsi;

在64-位CPU平台上编译这个结构时,如果没有使用__attribute__ ((packed)),在lun 成员前面,可能添加 2 个或者6 个字节进行填充。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: