Linux asm(“int $ 0x0”)与零除

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

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

 int i = 5/0; 

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

 asm volatile ("int $0x00") 

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

int 0h与由于除零而产生陷阱0 的CPU不同

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(只能从环0调用)。

当你除以零时, CPU首先转换到Ring 0,内核用divide_error处理异常。 但是,如果使用int 0x00显式调用它,则仍处于(当前权限级别)CPL = 3。

有关非常低级别的细节,请参阅“英特尔软件开发人员手册”。 第2卷介绍了int指令,并概述了CPU决定如何处理陷阱/中断的所有决策步骤。 第3卷描述了IDT,陷阱门等的细节

具体来说, 表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 

其他参考:

  • 中断描述符表 (osdev.org)
  • 英特尔®64和IA-32架构软件开发者手册 (intel.com)

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