内联 asm 分配给 'FS:0':处理程序未注册为安全处理程序

Inline asm assigning to 'FS:0': handler not registered as safe handler

我正在尝试关注有关 Win32 结构化异常处理的 this 文章。这篇文章很老了,但仍然被认为是对该主题的一个很好的介绍。

我正在尝试从下面转载的文章中编译代码示例 -

//==================================================
// MYSEH - Matt Pietrek 1997
// Microsoft Systems Journal, January 1997
// FILE: MYSEH.CPP
// To compile: CL MYSEH.CPP
//==================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

DWORD  scratch;

EXCEPTION_DISPOSITION
__cdecl
_except_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void * EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void * DispatcherContext )
    {
    unsigned i;

    // Indicate that we made it to our exception handler
    printf( "Hello from an exception handler\n" );

    // Change EAX in the context record so that it points to someplace
    // where we can successfully write
    ContextRecord->Eax = (DWORD)&scratch;

    // Tell the OS to restart the faulting instruction
    return ExceptionContinueExecution;
    }

int main()
{
    DWORD handler = (DWORD)_except_handler;

    __asm
    {                           // Build EXCEPTION_REGISTRATION record:
        push    handler         // Address of handler function
        push    FS:[0]          // Address of previous handler
        mov     FS:[0],ESP      // Install new EXECEPTION_REGISTRATION
    }

    __asm
    {
        mov     eax,0           // Zero out EAX
        mov     [eax], 1        // Write to EAX to deliberately cause a fault
    }

    printf( "After writing!\n" );

    __asm
    {                           // Remove our EXECEPTION_REGISTRATION record
        mov     eax,[ESP]       // Get pointer to previous record.
        mov     FS:[0], EAX     // Install previous record
        add     esp, 8          // Clean our EXECEPTION_REGISTRATION off stack
    }

    return 0;
}

在使用 "cl" 编译它时,它似乎生成了一个可执行文件,但也会抛出以下错误:

myseh.cpp(42) : warning C4733: Inline asm assigning to 'FS:0': handler not registered as safe handler
myseh.cpp(56) : warning C4733: Inline asm assigning to 'FS:0': handler not registered as safe handler

可执行文件崩溃,自定义异常处理程序似乎无法正常工作。 在互联网上搜索似乎表明我需要将我的自定义异常处理程序函数注册为安全异常处理程序。我不是专业的开发人员。但是我还是想关注这篇文章。我需要一些关于如何获得工作可执行文件的指导。

我在 Windows 10 上使用 Visual Studio 2015。

来自 C4733 警告的描述:

Inline asm assigning to 'FS:0' : handler not registered as safe handler

A function modifying the value at FS:0 to add a new exception handler may not work with Safe Exceptions, because the handler may not be registered as a valid exception handler (see /SAFESEH).

To resolve this warning, either remove the FS:0 definition or turn off this warning and use .SAFESEH to specify the safe exception handlers.

这基本上意味着您正在尝试使用不会在生成的 executable 图像中注册为 安全 SEH 处理程序 的处理程序。
根据您的链接器设置,它可能会或可能不会被执行。

默认情况下,链接器会生成 table 个安全处理程序,但它不知道您的 _except_handler 是异常处理程序,因此它不会将其放入 table 个 安全的 SEH 处理程序。要解决它,您基本上有两个选择:

  • 使用 .safeseh MASM 指令将您的函数标记为安全处理程序。
    您必须将其放入单独的 ASM 文件中,因为内联汇编不支持这些指令。

  • 使用 /SAFESEH:NO 开关指示链接器不创建 table 个安全处理程序。
    这样,您的 executable 中的任何 SEH 处理程序都会被 OS.

    视为安全处理程序

我建议查看 /SAFESEH linker switch and .safeseh MASM 指令文档以获取更多信息。

有关安全 SEH 处理程序的更多信息,请参见此 article:

The general idea is to collect handlers' entry points in a designated read-only table and have each entry point verified against this table for exceptions prior to control being passed to the handler.

经过反复试验,对我有用的是:

cl /c myseh.cpp
link myseh.obj /SAFESEH:NO

尽管如此,我仍然想知道如何将异常处理程序注册为安全的异常处理程序。