簡體   English   中英

在WIN32與WIN64中配置浮點單元上下文

[英]Configuring floating point unit context in WIN32 vs WIN64

我試圖編寫一個未處理的異常過濾器(請參閱SetUnhandledExceptionFilter())以與Windows SEH一起使用來報告無效的浮點運算。 我想捕獲異常,打印堆棧跟蹤,然后禁用浮點異常並使用生成的非限定或非數字值繼續執行。

我編寫了下面的簡單程序來演示捕獲異常並恢復執行的能力。 注意使用#ifdef _WIN64,因為ContextRecord的定義根據目標體系結構而變化(WIN32使用“FloatSave”,WIN64使用“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運行時,上面的程序按預期運行,輸出:

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

但是,當作為WIN64 .exe運行時,程序進入無限循環,不斷重新捕獲浮點異常:

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

這似乎表明我沒有成功配置浮點單元,我想這與WIN32和WIN64之間的ContextRecord的不同定義有關,但是我還沒有找到任何關於如何的相關文檔。設置浮點上下文。

有關如何正確設置WIN64浮點上下文的任何想法?

提前致謝

我現在有一個工作的例子。 感謝@IInspectable指出我正確的方向(SSE)。 問題是需要在ExecutionContext中設置MxCsr寄存器(s?)。 請注意,調用controlfp DID確實正確設置了MxCsr寄存器,但是當過濾器函數返回時,所有寄存器都會重置為ExceptionInfo中給出的上下文。 訣竅是在該上下文中覆蓋MxCsr,下面的代碼就是這樣做的。

對於上下文中MxCsr的兩個位置,我仍然有點困惑。 controlfp()似乎將BOTH一起設置為相同的值(在調試器中觀察到)。

#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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM