Linux asm(" int $ 0x0")vs除以零

时间:2014-05-29 05:16:09

标签: c linux assembly x86

有人可以解释汇编指令int $0x00与执行实际除法之间的区别。我在内核中的divide_error()处理程序上设置了断点,该处理程序与IDT中的第0个条目相关联(除法错误)。

当我在C程序中执行此操作时:

int i = 5/0;

然后我点击了断点(如预期的那样)。然而,

asm volatile ("int $0x00")

不会触发处理程序。为什么呢?

2 个答案:

答案 0 :(得分:12)

由于除以0,

int 0h CPU 生成陷阱0不同。

这个article of Phrack很好地解释了IDT以及Linux如何设置它。关键部分是:

DPL=Descriptor Privilege Level

    The DPL is equal to 0 or 3. Zero is the most privileged level (kernel
mode).  The current execution level is saved in the CPL register (Current
Privilege Level). The UC (Unit Of Control) compares the value of the CPL
register against the DPL field of the interrupt in the IDT. The interrupt
handler is executed if the DPL field is greater (less privileged) or equal
to the value in the CPL register. Userland applications are executed in
ring3 (CPL==3). Certain interrupt handlers can thus not be invoked by
userland applications.

...

linux/arch/i386/kernel/traps.c::set_system_gate(n, addr)
        insert a trap gate.
    The DPL field is set to 3.

These interrupts can be invoked from the userland (ring3).

                set_system_gate(3,&int3)
                set_system_gate(4,&overflow)
                set_system_gate(5,&bounds)
                set_system_gate(0x80,&system_call);

linux/arch/i386/kernel/traps.c::set_trap_gate(n, addr)
        insert a trap gate with the DPL field set to 0.
        The Others exception are initialized with set_trap_gate : 

                set_trap_gate(0,&divide_error)
                set_trap_gate(1,&debug)
                set_trap_gate(2,&nmi)
                set_trap_gate(6,&invalid_op)
                set_trap_gate(7,&device_not_available)
                set_trap_gate(8,&double_fault)
                set_trap_gate(9,&coprocessor_segment_overrun)
                set_trap_gate(10,&invalid_TSS)
                set_trap_gate(11,&segment_not_present)
                set_trap_gate(12,&stack_segment)
                set_trap_gate(13,&general_protection)
                set_trap_gate(14,&page_fault)
                set_trap_gate(15,&spurious_interrupt_bug)
                set_trap_gate(16,&coprocessor_error)
                set_trap_gate(17,&alignement_check)
                set_trap_gate(18,&machine_check)

那里的描述完美地解释了它。只能从用户空间调用int 3,4,5和0x80,因为内核将其陷阱门设置为(Descriptor Prvilege Level)DPL = 3.

其他处理器异常向量的DPL = 0(只能从ring 0调用)。

当除以零时, CPU 首先转换为Ring 0,内核使用divide_error处理异常。当您使用int 0x00显式调用它时,您仍处于(当前特权级别)CPL = 3。

对于非常低级的细节,您应该参考英特尔软件开发人员手册。第2卷描述了int指令,并概述了CPU决定如何处理陷阱/中断的所有决策步骤。第3卷描述了IDT,Trap Gates等的私密细节。

具体而言,表3-61决策表准确说明了中断发生的每种可能方式。在您的示例中,调用int 0x00会将您置于第2列,实际上是:

if PE=1                 # protected mode enabled
and DPL < CPL           # DPL=0 - kernel set up trap gate like this
                        # CPL=3 - b/c you're in user-mode
and int type == S/W     # you executed int instruction (s/w interrupt)
then issue #GP          # General Protection fault
                        # -- kernel delivers this to usermode as SIGSEGV

补充参考:

答案 1 :(得分:5)

如果你想要简短的回答,那就是除零中断只能由内核调用。如果您想要更长的答案,请查看ZarathustrA here的答案。