我很好奇,看看我的64位应用程序是否存在alignment错误。
从IPF,x86和x64上的Windows数据alignment :
在Windows中,生成alignment错误的应用程序将引发exception
EXCEPTION_DATATYPE_MISALIGNMENT
。
- 在x64体系结构中 ,默认情况下,alignment例外是禁用的,而修复由硬件完成。 应用程序可以通过设置一对寄存器位来启用alignmentexception ,在这种情况下,除非用户操作系统用
SEM_NOALIGNMENTFAULTEXCEPT
屏蔽exception,否则将引发exception。 (有关详细信息,请参阅“ AMD体系结构程序员手册”卷2:系统编程。 )[编者按: 强调我的]
在x86体系结构上 ,操作系统不会使alignment错误对应用程序可见。 在这两个平台上,alignment错误也会出现性能下降,但是与Itanium相比,性能会降低很多,因为硬件会使多次访问内存来检索未alignment的数据。
在Itanium上 ,默认情况下,操作系统(OS)会使此例外对应用程序可见,并且在这些情况下终止处理程序可能会有用。 如果你没有设置处理程序,那么你的程序将挂起或崩溃。 在清单3中,我们提供了一个示例,显示如何捕获EXCEPTION_DATATYPE_MISALIGNMENTexception。
忽略了查阅“ AMD体系结构程序员手册”的方向,我将参考“ 英特尔64和IA-32体系结构软件开发人员手册”
5.10.5检查alignment
当CPL为3时,可以通过设置CR0寄存器中的AM标志和EFLAGS寄存器中的AC标志来检查内存引用的alignment情况。 未alignment的内存引用会生成alignmentexception(#AC)。 在特权级别0,1或2下运行时,处理器不会产生alignmentexception。请参阅表6-7,了解启用alignment检查时alignment要求的说明。
优秀。 我不确定那是什么意思,但很好。
那么还有:
2.5控制寄存器
控制寄存器(CR0,CR1,CR2,CR3和CR4;见图2-6)确定处理器的工作模式和当前正在执行的任务的特性。 这些寄存器在所有32位模式和兼容模式下均为32位。
在64位模式下,控制寄存器扩展到64位。 MOV CRn指令用于操作寄存器位。 这些指令的操作数前缀被忽略。
控制寄存器总结如下,并且这些控制寄存器中的每个架构定义的控制字段都是单独描述的。 在图2-6中,64位模式下的寄存器宽度用括号表示(CR0除外)。 – CR0 – 包含控制处理器工作模式和状态的系统控制标志
上午
校准掩码(CR0的第18位) – 设置时启用自动校准检查; 清除时禁用alignment检查。 只有当AM标志置位,EFLAGS寄存器中的AC标志置位,CPL为3,处理器工作在受保护模式或虚拟8086模式时,才进行alignment检查。
我实际使用的语言是delphi,但假装它是语言不可知的伪代码:
void UnmaskAlignmentExceptions() { asm mov rax, cr0; //copy CR0 flags into RAX or rax, 0x20000; //set bit 18 (AM) mov cr0, rax; //copy flags back }
第一条指令
mov rax, cr0;
特权指令exception失败。
如何在x64上为我的进程启用alignment例外?
我发现x86有这样的说明:
PUSHF
, POPF
:按下/popup首个16位的EFLAGS开/关堆栈 PUSHFD
, POPFD
:按下/popup所有32位的EFLAGS开/关堆栈 然后,这导致我的x64版本:
PUSHFQ
, POPFQ
:在堆栈上打开/closuresRFLAGS quad (在64位的世界里, EFLAGS
被重新命名为RFLAGS
)。
所以我写道:
void EnableAlignmentExceptions; { asm PUSHFQ; //Push RFLAGS quadword onto the stack POP RAX; //Pop them flags into RAX OR RAX, $20000; //set bit 18 (AC=Alignment Check) of the flags PUSH RAX; //Push the modified flags back onto the stack POPFQ; //Pop the stack back into RFLAGS; }
它没有崩溃或触发保护例外。 我不知道它是否做到了我想要的。
在x64上运行的应用程序可以访问标志寄存器(有时称为EFLAGS )。 该寄存器中的位18允许应用程序在发生对齐错误时获得异常。 所以从理论上说,所有的程序都要做到使对齐错误的异常是修改标志寄存器。
为了实际工作,操作系统内核必须设置cr0的位18来允许它。 而Windows操作系统不这样做。 为什么不? 谁知道?
应用程序不能在控制寄存器中设置值。 只有内核可以做到这一点。 设备驱动程序在内核中运行,所以他们也可以设置它。
可以通过创建一个设备驱动程序来解决这个问题,并尝试使用它(参见http://blogs.msdn.com/b/oldnewthing/archive/2004/07/27/198410.aspx#199239和注释以下)。 请注意,这篇文章已经超过十年了,所以有些链接已经死了。
你也可能会发现这个评论(和这个问题中的其他一些答案)是有用的:
Larry Osterman – 07-28-2004 2:22 AM
我们实际上构建了一个x86版本的对齐例外(你可以像Skywing所说的那样做)。
我们很快就把它关闭了,因为有多少应用程序打破了:)