我正在研究本地纤程/协程实现 - 相当标准,对于每个纤程,分配一个单独的堆栈,并且为了切换上下文,寄存器被推入源上下文堆栈并从目标堆栈弹出。它运行良好,但现在我遇到了一个小问题:
我需要 SEH 在纤程内工作(如果程序终止或奇怪的事情开始发生,直到纤程的最后一个堆栈帧之前未处理异常,它都不会)。只需在上下文切换期间保存/恢复
FS:[0]
(显然,还有 FS:[4]
和 FS:[8]
),并初始将新分配的纤程的 FS:[0] 设置为 0xFFFFFFFF
(以便在上下文之后设置异常处理程序) switch 将成为链的根)几乎有效。
准确地说,它适用于我测试的所有非服务器 Windows 操作系统 - 问题是 Windows Server 2008 和 2008 R2 默认启用了异常链验证(SEHOP、SEH 覆盖保护)功能,这使得
RaiseException
检查如果原始处理程序(ntdll.dll 中的某处)仍然是链的根,则立即终止程序,就像没有安装任何处理程序一样。
因此,我面临着在堆栈上构造适当的根框架以使验证代码满意的问题。是否有任何(隐藏的?)API 函数我可以调用来做到这一点,或者我是否必须弄清楚需要什么才能让
RtlDispatchException
和朋友们满意并自己构建适当的 _EXCEPTION_REGISTRATION
条目?我不能只重用创建线程中 Windows 提供的地址,因为它会位于错误的地址(SEH 实现还会检查处理程序地址是否在 FS:[4]
和 FS:[8]
给出的边界内,并且可能还如果地址顺序一致)。
哦,我强烈建议不诉诸
CreateFiber
WinAPI 系列函数。
我在评论中提到的方法,生成一个指向
EXCEPTION_REGISTRATION
的假 ntdll!FinalExceptionHandler
条目,似乎在实践中确实有效 - 至少,这就是我们现在在 D 运行时中所拥有的,并且到目前为止还没有任何报告问题:
查看您的 github.com 链接中的代码,@dnadlinger,我不太清楚您的 64 位 Windows 代码是否缺少您为 32 位 Windows 描述的解决方案,或者实际上是否缺少针对 64 位 Windows 的相应解决方案Windows 更简单。
假设是后者,我尝试调整Boost.Context 64位Windows fcontext masm实现以在每次上下文切换时保存和恢复
GS:[0]
处的三指针块,这就是我推断D语言的64位Windows Fiber上下文切换代码正在做。
不幸的是,即使有了链接的更改,我用来在异常处理期间执行上下文切换的测试程序(在 PR 中链接)的行为与未修改的 Boost.Context 相同。
我错过了什么?