在什么情况下我需要为 x86-64 汇编函数设置 SEH 展开信息?
Under what conditions do I need to set up SEH unwind info for an x86-64 assembly function?
64 位 Windows ABI 定义了一个通用的 exception handling mechanism,我相信它在 C++ 异常和结构化异常之间共享,甚至在其他语言(例如 C)中也可用。
如果我正在编写要在 nasm
中编译并链接到 C 或 C++ 库的 x86-64 汇编例程,我需要在 Windows 上进行哪些调整以生成展开信息等等?
我不打算直接在汇编代码中生成任何异常,尽管我认为如果用户提供的缓冲区无效等,代码可能会出现访问冲突。
我希望尽可能少地编写以使其正常工作,尤其是因为似乎 nasm
对生成展开信息的支持很差并且使用 MASM
不是一个选项跨平台项目。我确实需要使用(因此保存和恢复)非易失性寄存器。
作为一般规则,Windows x64 需要 所有 函数来提供展开信息。唯一的例外是不修改 rsp
且不修改任何非易失性寄存器的叶函数。
根据您问题的上下文判断,您真正想知道的是不为 x64 上的非叶程序集函数提供展开信息的实际后果 Windows。由于 C++ 异常是基于 SEH 异常实现的,所以当我在下面谈论异常时,我指的是所有 "native"(访问冲突,使用 RaiseException
抛出的东西等)和 C++ 异常。这是我脑海中的一个列表:
- 异常将无法通过您的函数
重要的是要注意,这一点不是关于抛出异常,或者在您的函数中直接发生访问冲突。假设您的汇编代码调用了一个 C++ 函数,该函数抛出异常。即使您的汇编函数的调用者有匹配的 catch
块,它也永远无法捕获异常,因为展开将在没有展开数据的情况下停止在您的函数处。
- 遍历堆栈时,堆栈遍历将停止在没有展开数据的函数处(或误入歧途;重点是,您将得到无效的调用堆栈)
基本上,如果您的函数出现在调用堆栈上(显示调用堆栈时的调试器、分析器等),任何遍历堆栈的东西都会被搞砸
- 已注册
Unhandled Exception Filters
如果抛出异常将不会被回调,并且您的汇编函数在调用堆栈上
这会干扰任何依赖 UEF 的东西。例如,自定义崩溃处理程序。或者可能更相关的东西: std::terminate
在这种情况下不会被回调,如果你的程序抛出 C++ 异常,这是未处理的(因为它是由 C++ 标准规定的)。 MSVC 运行时使用 UEF 来实现它,所以这不会起作用。
您正在开发第 3 方库吗?如果是这样的话,以上几点的重要性将取决于您的客户的用例。
64 位 Windows ABI 定义了一个通用的 exception handling mechanism,我相信它在 C++ 异常和结构化异常之间共享,甚至在其他语言(例如 C)中也可用。
如果我正在编写要在 nasm
中编译并链接到 C 或 C++ 库的 x86-64 汇编例程,我需要在 Windows 上进行哪些调整以生成展开信息等等?
我不打算直接在汇编代码中生成任何异常,尽管我认为如果用户提供的缓冲区无效等,代码可能会出现访问冲突。
我希望尽可能少地编写以使其正常工作,尤其是因为似乎 nasm
对生成展开信息的支持很差并且使用 MASM
不是一个选项跨平台项目。我确实需要使用(因此保存和恢复)非易失性寄存器。
作为一般规则,Windows x64 需要 所有 函数来提供展开信息。唯一的例外是不修改 rsp
且不修改任何非易失性寄存器的叶函数。
根据您问题的上下文判断,您真正想知道的是不为 x64 上的非叶程序集函数提供展开信息的实际后果 Windows。由于 C++ 异常是基于 SEH 异常实现的,所以当我在下面谈论异常时,我指的是所有 "native"(访问冲突,使用 RaiseException
抛出的东西等)和 C++ 异常。这是我脑海中的一个列表:
- 异常将无法通过您的函数
重要的是要注意,这一点不是关于抛出异常,或者在您的函数中直接发生访问冲突。假设您的汇编代码调用了一个 C++ 函数,该函数抛出异常。即使您的汇编函数的调用者有匹配的 catch
块,它也永远无法捕获异常,因为展开将在没有展开数据的情况下停止在您的函数处。
- 遍历堆栈时,堆栈遍历将停止在没有展开数据的函数处(或误入歧途;重点是,您将得到无效的调用堆栈)
基本上,如果您的函数出现在调用堆栈上(显示调用堆栈时的调试器、分析器等),任何遍历堆栈的东西都会被搞砸
- 已注册
Unhandled Exception Filters
如果抛出异常将不会被回调,并且您的汇编函数在调用堆栈上
这会干扰任何依赖 UEF 的东西。例如,自定义崩溃处理程序。或者可能更相关的东西: std::terminate
在这种情况下不会被回调,如果你的程序抛出 C++ 异常,这是未处理的(因为它是由 C++ 标准规定的)。 MSVC 运行时使用 UEF 来实现它,所以这不会起作用。
您正在开发第 3 方库吗?如果是这样的话,以上几点的重要性将取决于您的客户的用例。