2010-11-04 47 views
1

我发现this MSDN上:数据对齐

在32位Windows平台上,操作系统自动修复内核模式内存定位错误,使他们看不到的应用。它为调用进程和任何后代进程执行此操作。这个功能通常会显着降低性能,但在64位Windows中尚未实现。因此,如果您的32位驱动程序包含错位错误,则在移植到64位Windows时需要修复它们。

我对此有些害怕。任何人都可以给我看一个错位错误的例子吗?

编辑:我基本上知道对齐的概念和它的原因。我只是想在win32和win64之间根据“自动修复”对齐和对我的驱动程序的影响找出差异。

回答

2

考虑以下结构,其中ac是32位字,b是一个字节。

|-----------a-----------|--b--|-----------c-----------| 
|  :  :  :  :  :  :  :  |  : 

如果您分配一个64位的边界上这个结构,那么ab都将被正确对齐,但c不会,因为它跨越了64位字边界。事实上,如果不将ac推到这样的边界上,就不可能布置这个结构。

在实践中,编译器通常会采取的定义是这样的:

struct { 
    int a; 
    char b; 
    int c; 
}; 

,并安排它像这样:

|-----------a-----------|--b--|  padding  |-----------c-----------| 
|  :  :  :  :  :  :  :  |  :  :  :  : 

所以,没有任何价值的跨越对齐边界。但是在驱动程序编程中,结构通常必须打包(即没有填充),以匹配线上或磁盘上的数据结构格式。那时你可以进入争斗,除非你手动解开字边界。

+0

感谢您的图形和文学解释相关。我很好奇“自动修复”的一点。这是否意味着win32会自动添加填充到结构中,而win64不会?如果我同时使用#pragma pack(1)会怎么样? – solotim 2010-11-05 07:25:36

+0

填充由编译器完成,无论体系结构如何,都不受任何给定的Windows版本/体系结构的影响。您可以使用'#pragma pack(1)'来压缩编译器的默认行为,从而强制打包,这通常是协议编码所必需的,但是当故障开始时。简而言之,如果你坚持编译器的默认行为,那么你大多会忘记对齐问题。 – 2010-11-05 11:18:51

+0

@solotim访问未对齐的数据将导致硬件异常。我想“自动修复”所做的是通过将未对齐的内存访问分解为几个对齐的内存访问来处理这种异常,然后返回重建的值。这意味着有几条指令会在故障后执行,这会降低性能。再一次,这只是我的猜测,我自己并没有证实。 – 2011-03-17 15:22:38

1

我没有一个例子,但问题很简单,只能在64位边界上访问64位数据。如果数据是32位(或更小)对齐,则不能以64位值的形式可靠地访问此数据,因为每个第二个值不会位于64位边界上,并且此访问将生成一个异常。

WIntel机器非常容忍这些故障,但大多数其他架构(如ARM)在所有对齐问题上都会抛出异常,因此所有指针都会以极度怀疑的方式查看。小心谨慎是唯一的出路,使用静态分析工具如Lint和Klocwork可以提供很多帮助。万一有人

+0

谢谢,我已经更新了这个问题。顺便说一下,Lint是否可用于Windows驱动程序代码? – solotim 2010-11-04 09:50:44

+1

原则上Lint对于代码的功能是不可知的,并且在所有平台上都可以使用,无论是Windows还是其他操作系统,或Intel,ARM或任何其他处理器。你需要小心,确保它为你的平台正确配置,然后离开你。 – 0xDEADBEEF 2010-11-04 09:55:00

0

报价this文档具有相同的关注:

如果处理器试图读取或写入 对准不当数据,可以发生 对齐错误。在x86 硬件上,对齐错误为 ,用户不可见。硬件 按照前面段落 中的描述修复了故障。在x64硬件上, 对齐错误由 默认禁用,而类似硬件 修复错误。但是,在Intel Itanium 体系结构中,如果在运行64位内核模式 代码时发生对齐 错误,则硬件会使 出现异常。 (对于用户模式代码, 这是默认设置,一个 单独的应用可以改变, 虽然上 禁用对准故障安腾会严重降低 性能。)