c – Linux asm(“int $0x0”)vs除以零

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

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

int i = 5/0;

然后我打破断点(如预期).然而,

asm volatile ("int $0x00")

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

由于除以零,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可以从用户空间调用,因为内核将其陷阱门限设置为(描述符权限级别)DPL = 3.

其他处理器异常向量具有DPL = 0(只能从环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

附加参考:

> Interrupt Descriptor Table(osdev.org)
> Intel® 64 and IA-32 Architectures Software Developer Manuals(intel.com)

翻译自:https://stackoverflow.com/questions/23926143/linux-asmint-0x0-vs-division-by-zero

转载注明原文:c – Linux asm(“int $0x0”)vs除以零