在WIN32和WIN64中配置浮点单元上下文 [英] Configuring floating point unit context in WIN32 vs WIN64

查看:208
本文介绍了在WIN32和WIN64中配置浮点单元上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试写一个未处理的异常过滤器(请参阅SetUnhandledExceptionFilter())与Windows SEH一起使用来报告无效的浮点运算。我想捕获异常,打印一个堆栈跟踪,然后禁用浮点异常并恢复执行结果的非有限或非数字值。

I am attempting to write an unhandled exception filter ( see SetUnhandledExceptionFilter()) to use with Windows SEH to report invalid floating point operations. I'd like to trap the exception, print a stack trace, then disable floating point exceptions and resume execution with the resulting non-finite or not-a-number value.

我在下面写了简单的程序来演示捕获异常并恢复执行的能力。注意使用#ifdef _WIN64,因为ContextRecord的定义根据目标架构而改变(WIN32使用FloatSave,WIN64使用FltSave)。

I wrote the simple program below to demonstrate the ability to catch the exception and resume execution. Note the use of #ifdef _WIN64, as the definition of the ContextRecord changes depending on the targeted architecture (WIN32 uses "FloatSave", WIN64 uses "FltSave").

#include "stdafx.h"
#include <float.h>
#include <Windows.h>

double zero = 0.0;
LONG WINAPI myfunc(EXCEPTION_POINTERS * ExceptionInfo){
    /* clear the exception */
    unsigned int stat = _clear87();

    /* disable fp exceptions*/
    unsigned int ctrl1 = _control87(_MCW_EM, _MCW_EM);

    /* Disable and clear fp exceptions in the exception context */
    #if _WIN64
        ExceptionInfo->ContextRecord->FltSave.ControlWord = ctrl1;
        ExceptionInfo->ContextRecord->FltSave.StatusWord = 0;
    #else
        ExceptionInfo->ContextRecord->FloatSave.ControlWord = ctrl1;
        ExceptionInfo->ContextRecord->FloatSave.StatusWord = 0;
    #endif

    printf("#########Caught Ya#####!\n");

    return EXCEPTION_CONTINUE_EXECUTION;
}


int _tmain(int argc, _TCHAR* argv[])
{
    double a;

    /* enable fp exceptions*/
    _controlfp(0, _MCW_EM);

    /* Setup our unhandled exception filter */
    SetUnhandledExceptionFilter(myfunc);

    /* do something bad */
    a = 5.0 / zero;

    printf("a = %f\n",a);

    return 0;
}

当作为WIN32 .exe运行时,上述程序按预期运行,输出:

When run as a WIN32 .exe, the above program runs as expected, with the output:

#########Caught Ya#####!
a = -1.#IND00

但是,当作为WIN64 .exe运行时,程序进入无限循环,不断地重新捕捉浮点异常:

However, when run as a WIN64 .exe, the program enters an infinite loop, continuously re-catching the floating point exception:

#########Caught Ya#####!
#########Caught Ya#####!
#########Caught Ya#####!
#########Caught Ya#####!
#########Caught Ya#####!
#########Caught Ya#####!
...

这似乎表明我没有成功配置浮动点单位,我想象的是与WIN32和WIN64之间的ContextRecord的不同定义相关,但是我没有能够找到任何关于如何设置浮点上下文的任何良好的相关文档。

This seems to indicate that I'm not successful at configuring the floating point unit, which I imagine is related to the different definition of ContextRecord between WIN32 and WIN64, but I haven't been able to find any good related documentation on exactly how to set the floating point context.

有关如何正确设置WIN64的浮点上下文的任何想法?

Any thoughts on how to correctly set the floating point context for WIN64?

提前感谢

推荐答案

我现在有一个工作的例子。感谢@IInspectable指出我正确的方向(SSE)。问题是需要在ExecutionContext中设置MxCsr寄存器(s?)。请注意,调用controlfp DID确实正确设置了MxCsr寄存器,但是看起来当过滤器函数返回时,所有寄存器都将重置为ExceptionInfo中给定的上下文。诀窍在于覆盖下面代码中的MxCsr。

I've got a working example now. Thanks to @IInspectable for pointing me in the right direction (SSE). The issue was that the MxCsr register(s?) need to be set in the ExecutionContext. Note that calling controlfp DID indeed set the MxCsr register correctly, however it appears that when the filter function returns, ALL registers are reset to the context given in ExceptionInfo. The trick is to overwrite MxCsr in that context, which the code below does.

在上下文中,我对MxCsr的两个位置仍然有些困惑。 controlfp()似乎将BOTH设置在一起并且具有相同的值(在调试器中观察到)。

I am still a bit confused as to the two locations of MxCsr in the context. controlfp() seems to set BOTH together and to the same value (as observed in debugger).

#include "stdafx.h"
#include <float.h>
#include <Windows.h>
#include <xmmintrin.h>

double zero = 0.0;
LONG WINAPI myfunc(EXCEPTION_POINTERS * ExceptionInfo){
    /* clear the exception */
    unsigned int stat = _clearfp();

    /* disable all fp exceptions*/
    unsigned int ctrlwrd;
    errno_t err =  _controlfp_s(&ctrlwrd, _MCW_EM, _MCW_EM);

    /* Disable and clear the exceptions in the exception context */
    #if _WIN64
        /* Get current context to get the values of MxCsr register, which was
         * set by the calls to _controlfp above, we need to copy these into
         * the exception context so that exceptions really stay disabled.
         * References:
         *    https://msdn.microsoft.com/en-us/library/yxty7t75.aspx
         *    https://software.intel.com/en-us/articles/x87-and-sse-floating-point-assists-in-ia-32-flush-to-zero-ftz-and-denormals-are-zero-daz
         */
        CONTEXT myContext;
        RtlCaptureContext(&myContext);

        ExceptionInfo->ContextRecord->FltSave.ControlWord = ctrlwrd;
        ExceptionInfo->ContextRecord->FltSave.StatusWord = 0;
        ExceptionInfo->ContextRecord->FltSave.MxCsr = myContext.FltSave.MxCsr;
        ExceptionInfo->ContextRecord->FltSave.MxCsr_Mask = myContext.FltSave.MxCsr_Mask;
        ExceptionInfo->ContextRecord->MxCsr = myContext.MxCsr;
    #else
        ExceptionInfo->ContextRecord->FloatSave.ControlWord = ctrlwrd;
        ExceptionInfo->ContextRecord->FloatSave.StatusWord = 0;
    #endif

    printf("#########Caught Ya#####!\n");

    return EXCEPTION_CONTINUE_EXECUTION;
}

int _tmain(int argc, _TCHAR* argv[])
{
    double a;

    /* Enable fp exceptions */
    _controlfp_s(0, 0, _MCW_EM);

    /* Setup our unhandled exception filter */
    SetUnhandledExceptionFilter(myfunc);

    /* do something bad */
    a = 5.0 / zero;

    printf("a = %f\n",a);
    return 0;
}

这篇关于在WIN32和WIN64中配置浮点单元上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆