Win32 EXCEPTION_INT_OVERFLOW与EXCEPTION_INT_DIVIDE_BY_ZERO

时间:2011-02-15 01:52:19

标签: windows exception assembly x86

我对EXCEPTION_INT_OVERFLOW和EXCEPTION_INT_DIVIDE_BY_ZERO例外有疑问。

Windows将捕获IDIV指令生成的#DE错误,并最终使用这两个代码之一生成SEH异常。

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

我快速浏览了intel手册第3卷中#DE错误的部分,我能收集的最好的是操作系统必须解码DIV指令,加载除数参数,然后比较它为零。

但这对我来说似乎有点疯狂。为什么芯片设计者不会使用某种标志来区分错误的两个原因?我觉得我一定错过了什么。

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

2 个答案:

答案 0 :(得分:6)

您的假设似乎是正确的。 #DE上唯一可用的信息是CS和EIP,它提供指令。由于两个状态代码不同,OS必须解码指令以确定哪个。

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

至于“确切知道”它是如何区分的,所有知道的人都可能不被允许透露它,要么是为了阻止人们利用它(不完全确定如何,但跳进内核模式是一个好地方开始寻求利用)或根据可能在不另行通知的情况下改变的实施细节做出假设。


编辑:玩过kd之后我至少可以说在我可以访问的特定版本的Windows XP(32位)(及其运行的处理器){{ 1}}中断处理程序似乎解码指令的ModRM值,以确定是否返回nt!Ki386CheckDivideByZeroTrapSTATUS_INTEGER_DIVIDE_BY_ZERO

(显然这是原始研究,任何地方的任何人都不能保证,并且恰好与基于英特尔手册的扣除相匹配。)

答案 1 :(得分:1)

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

但你不能依赖于例程正确选择代码。

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

  • 如果操作数(除数)是内存操作数,则无论参数值如何,它总是引发EXCEPTION_INT_DIVIDE_BY_ZERO。
  • 如果操作数是一个寄存器且下面的双字为零,则无论上半部分是否为零,都会引发EXCEPTION_INT_DIVIDE_BY_ZERO。

我花了一天时间才发现这一点...希望这会有所帮助。