首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在x64上为我的进程启用对齐异常?

如何在x64上为我的进程启用对齐异常?
EN

Stack Overflow用户
提问于 2018-03-29 00:47:18
回答 2查看 0关注 0票数 0

我很好奇,看看我的64位应用程序是否存在对齐错误。

IPF,x86和x64上的Windows数据对齐

在Windows中,生成对齐错误的应用程序会引发异常,EXCEPTION_DATATYPE_MISALIGNMENT

  • 在x64体系结构中,默认情况下,对齐例外是禁用的,并且修复由硬件完成。应用程序可以通过设置一对寄存器位来启用对齐异常,在这种情况下,除非用户使用操作系统屏蔽异常,否则将引发异常SEM_NOALIGNMENTFAULTEXCEPT。(有关详细信息,请参阅AMD体系结构程序员手册第2卷:系统编程。

[编者按:强调我的]

  • 在x86架构上,操作系统不会使对齐错误对应用程序可见。在这两个平台上,对齐错误也会出现性能下降,但与Itanium相比,它将严重不那么严重,因为硬件会使多次访问内存来检索未对齐的数据。
  • 在Itanium上,默认情况下,操作系统(OS)会使该异常对应用程序可见,并且在这些情况下终止处理程序可能会有用。如果你没有设置处理程序,那么你的程序会挂起或崩溃。在清单3中,我们提供了一个示例,显示如何捕获EXCEPTION_DATATYPE_MISALIGNMENT异常。

忽略了参考AMD体系结构程序员手册的方向,我会参考英特尔64和IA-32体系结构软件开发人员手册

5.10.5检查对齐 当CPL为3时,可通过设置CR0寄存器中的AM标志和EFLAGS寄存器中的AC标志来检查内存引用的对齐情况。未对齐的内存引用会生成对齐异常(#AC)。在特权级别0,1或2下运行时,处理器不会生成对齐异常。有关启用对齐检查时对齐要求的说明,请参阅表6-7。

优秀。我不确定那是什么意思,但很好。

那么还有:

2.5控制寄存器 控制寄存器(CR0,CR1,CR2,CR3和CR4;参见图2-6)确定处理器的工作模式和当前正在执行的任务的特性。这些寄存器在所有32位模式和兼容模式下均为32位。 在64位模式下,控制寄存器扩展为64位。MOV CRn指令用于操作寄存器位。这些指令的操作数大小前缀将被忽略。 控制寄存器总结如下,并且这些控制寄存器中每个架构定义的控制字段都是单独描述的。在图2-6中,64位模式下寄存器的宽度用括号表示(CR0除外)。- CR0 - 包含控制处理器工作模式和状态的系统控制标志

在这里输入图像描述
在这里输入图像描述

AM 对齐掩码(CR0的第18位) - 设置时启用自动对齐检查; 在清除时禁用对齐检查。只有当AM标志置位,EFLAGS寄存器中的AC标志置位,CPL为3,处理器工作在保护模式或虚拟8086模式时,才进行对齐检查。

我试过了

我实际使用的语言是Delphi,但假装它是语言不可知的伪代码:

代码语言:javascript
复制
void UnmaskAlignmentExceptions()
{
   asm
      mov rax, cr0; //copy CR0 flags into RAX
      or  rax, 0x20000; //set bit 18 (AM)
      mov cr0, rax; //copy flags back
}

第一条指令

代码语言:javascript
复制
mov rax, cr0;

特权指令异常失败。

如何在x64上为我的进程启用对齐例外?

PUSHF

我发现x86有这样的说明:

  • PUSHFPOPF:在堆栈上打开/关闭首个16位EFLAGS
  • PUSHFDPOPFD:按下/弹出所有32位EFLAGS的开/关堆栈

在这里输入图像描述
在这里输入图像描述

然后,这导致我的x64版本:

  • PUSHFQPOPFQ:在堆栈上打开/关闭RFLAGS quad

(在64位的世界里,EFLAGS它们被重新命名RFLAGS)。

所以我写道:

代码语言:javascript
复制
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;
}

它没有崩溃或触发保护例外。我不知道它是否符合我的要求。

EN

回答 2

Stack Overflow用户

发布于 2018-03-29 09:24:50

在x64上运行的应用程序可以访问标志寄存器(有时称为EFLAGS)。此寄存器中的位18允许应用程序在发生对齐错误时获得异常。所以从理论上讲,所有的程序都必须这样做才能使对齐错误的异常是修改标志寄存器。

然而

为了实际工作,操作系统内核必须设置cr0的位18来允许它。而Windows操作系统并没有这样做。为什么不?谁知道?

应用程序不能在控制寄存器中设置值。只有内核可以做到这一点。设备驱动程序在内核中运行,所以他们也可以设置它。

可以通过创建一个设备驱动程序来解决这个问题,并尝试通过它来工作(请参阅http://blogs.msdn.com/b/oldnewthing/archive/2004/07/27/198410.aspx#199239以及注释以下)。请注意,这篇文章已经超过十年了,所以一些链接已经死了。

票数 0
EN

Stack Overflow用户

发布于 2018-03-29 10:03:18

这适用于64位Intel CPU。某些AMD可能会失败

代码语言:javascript
复制
pushfq
bts qword ptr [rsp], 12h ; reset AC bit of rflags
popfq

它在32位CPU中不会立即工作,它们将首先需要内核驱动程序来更改CR0的AM位,然后

代码语言:javascript
复制
pushfd
bts dword ptr [esp], 12h
popfd
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100007852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档