在什么情况下,我需要为x86-64汇编函数设置SEH展开信息?

64位的Windows ABI定义了一个通用的exception处理机制 ,我相信这个机制是跨C ++exception和结构化exception共享的,即使在其他语言中也是如此。

如果我正在编写x86-64汇编程序以在nasm编译并链接到C或C ++库,那么在生成展开信息等方面,我需要在Windows上进行哪些调整?

我不打算直接在汇编代码中生成任何exception,但我想如果用户提供的缓冲区是无效的,代码可能会得到访问冲突。

我希望尽可能最less的写这个工作,特别是因为看起来nasm对生成展开信息的支持很差,使用MASM不是这个跨平台项目的一个选项。 我确实需要使用(因此保存和恢复)非易失性寄存器。

作为一般规则,Windows x64需要所有功能来提供展开信息。 唯一的例外是不修改rsp叶函数,也不修改任何非易失性寄存器。

从您的问题的上下文来看,您真正想知道的是不为您的x64 Windows上的非叶装配函数提供展开信息的实际后果。 由于C ++异常是基于SEH异常实现的,所以当我讨论下面的异常时,我的意思是所有的“本地”(访问冲突,抛出使用RaiseException等等)和C ++异常。 这是我头顶的一个列表:

  • 例外将无法通过您的功能

请注意,这一点很重要,不是抛出异常,或者直接在函数中发生访问冲突。 假设你的汇编代码调用了一个C ++函数,它引发了一个异常。 即使你的程序集函数的调用者有一个匹配的catch块,它也将永远无法捕捉异常,因为在没有展开数据的情况下,展开将停止在你的函数中。

  • 在走栈时,栈走会停在函数而没有展开数据(或者误入歧途;重点是,你会得到一个无效的调用栈)

基本上,如果你的函数出现在调用堆栈上(调试器在显示调用栈,分析器等时)

  • 注册的Unhandled Exception Filters将不会被回调,如果一个异常被抛出,并且你的汇编函数在调用堆栈上

这干扰了任何依赖于UEFs的东西。 自定义的崩溃处理程序,例如。 或者更相关的东西: std::terminate在这种情况下不会被调用,如果你的程序抛出了一个C ++异常,那是未处理的(因为它是由C ++标准决定的)。 MSVC运行时使用UEF来实现这一点,所以这不会工作。


你在开发第三方库吗? 如果是这样的话,以上几点的重要性将取决于客户的使用情况。