我该如何在x86汇编中使用中断来触发除以零错误异常?

5

我正在尝试理解x86汇编中的中断。

我尝试触发一个除以零错误,对应代码为0。

int $0

我原本以为这个行为与除以零相同,但实际上不是。
movl $0, %edx # dividend
movl $0, %eax # dividend
movl $0, %edi # divisor
divl %edi

在前一种情况下,我的程序在Linux上崩溃,并显示“分段错误”和退出码139。而在后一种情况下,我的程序在Linux上崩溃,并显示“浮点异常”和退出码136。
我该如何使用中断来触发与使用零除法器调用div指令相同的错误?

猜测是中断处理程序查看中断源并发现那里没有浮点指令。 - Bo Persson
@BoPersson:不,#DE处理程序不必反汇编任何内容。 POSIX要求,如果整数或FP算术引发信号,则该信号必须是SIGFPE。具有讽刺意味的是,在大多数系统的默认环境中,唯一会引发SIGFPE的事情是整数除法,因为FP异常默认被屏蔽。请参见https://dev59.com/B1oU5IYBdhLWcg3wnoAP。在SIGFPE处理程序中,您可以检查`FPE_INTDIV_TRAP`代码。 - Peter Cordes
1个回答

6
我本以为这会和除以零的行为相同。
原则上这是正确的。
我试图触发一个除以零错误,对应代码0:
int $0
原则上这仍然是正确的。
在前一种情况下,在Linux上我的程序会崩溃,并出现“段错误”和退出码139。在后一种情况下,在Linux上我的程序会崩溃,并出现“浮点异常”和退出码136。
x86 CPU有两种操作模式:实模式和保护模式(64位CPU有第三种模式:长模式)。
在实模式下,您可以执行CPU支持的任何指令。但是实模式通常只允许16位代码和寻址最多1MB的内存。32位操作系统在保护模式下运行。
在保护模式下,cs寄存器中的两个特殊位指示当前正在运行的代码属于操作系统内核还是应用程序。
在保护模式下...
- ...某些指令(例如lmsw)只能由操作系统调用 - ...某些指令(例如cli)只能由应用程序调用,如果操作系统在某些寄存器中设置了一些特殊位;否则只有操作系统才能调用这些指令 - ...某些内存区域的内存访问可能受到操作系统的限制 - ...从应用程序代码跳转到操作系统代码只允许到某些地址... - ...这也适用于中断:操作系统可以决定哪些中断可以由应用程序调用,哪些不能。
如果应用程序尝试执行不允许的操作(例如执行一些指令如lmsw或int $0),CPU将引发“段错误”中断(因为cs寄存器中的两个位指示代码不属于操作系统)。被禁止的指令将不会被执行!
如果您从内核驱动程序调用int $0(在32位Linux上;而不是64位Linux上),这应该具有与除以零相同的效果。

它真的是 cs 寄存器本身中的位吗?而不是由 cs 寄存器中的值选择的段描述符中的位? - Peter Cordes
1
@Peter,是的,当前特权级(CPL)是CS的低两位。请参考第5.2节。 - prl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接