Win32 EXCEPTION_INT_OVERFLOW vs EXCEPTION_INT_DIVIDE_BY_ZERO

我有一个关于EXCEPTION_INT_OVERFLOW和EXCEPTION_INT_DIVIDE_BY_ZEROexception的问题。

Windows将捕获IDIV指令产生的#DE错误,并最终以这两个代码之一产生SEHexception。

我的问题是如何区分这两个条件? 英特尔手册中关于idiv的信息表明它将在“除以零”和“下溢情况”中生成#DE。

我快速浏览了intel手册第3卷中的#DE错误一节,我可以收集的最好的结果是操作系统必须解码DIV指令,加载除数参数,然后将其与零比较。

虽然这对我来说似乎有点疯狂。 为什么芯片devise人员不会使用某种标志来区分错误的两个原因? 我觉得我一定会错过一些东西。

有没有人知道操作系统如何区分2种不同的失败原因?

你的假设似乎是正确的。 #DE上唯一可用的信息是CS和EIP,它给出了指令。 由于两个状态码不同,操作系统必须对指令进行解码才能确定哪一个。

我还建议芯片制造商在这种情况下实际上不需要两个单独的中断,因为除以零的任何东西都是无穷大的,这太大而无法放入目标寄存器。

至于“明确地知道”它是如何区分的,所有那些知道的人可能不被允许透露它,要么阻止人们利用它(不完全确定如何,而是跳入内核模式是一个开始寻找的好地方利用),或基于可能会改变的实现细节做出假设,恕不另行通知。


编辑:玩过KD我至少可以说,在特定版本的Windows XP(32位)我有权访问(和它正在运行的处理器) nt!Ki386CheckDivideByZeroTrap中断处理程序似乎解码ModRM值该指令确定是否返回STATUS_INTEGER_DIVIDE_BY_ZEROSTATUS_INTEGER_OVERFLOW

(显然这是原创性的研究,不是任何人都能保证的,而且恰巧与基于英特尔手册的扣除相匹配。)

Zooba的回答总结了Windows解析指令以找出要提出的内容。

但是你不能依赖程序正确选择代码。

我在64位DIV指令的64位Windows 7上观察以下内容:

  • 如果操作数(除数)是内存操作数,则不管参数值如何,它总是会引发EXCEPTION_INT_DIVIDE_BY_ZERO。
  • 如果操作数是一个寄存器,并且较低的dword是零,则不管上半部分是否为零,都会引发EXCEPTION_INT_DIVIDE_BY_ZERO。

花了我一天的时间找到这个…希望这有助于。