如何从x86中的中断处理程序中获取中断编号



当在x86上的保护模式下触发中断时,是否可以确定触发的中断编号?例如,假设我调用int 0xFF。在处理程序中,我能发现int 0xFF被调用了吗?

如果您有唯一的中断处理程序(或者,至少有唯一的入口点和序言代码),那么,当然,您可以区分int 0xFFint 0x30。ISR地址存储在IDT中,因此,这是差异开始的地方。

除了独特的ISR,没有什么好的选择。原因如下。。。

在ISR中,您可以检查调用方的堆栈,查看返回地址,并检查返回地址之前的代码,看看它是2字节的int n指令(编码为字节:0xCD,n)还是其他指令。问题是,还有int 3into的1字节指令(分别编码为0xCC和0xCE)。如何区分0xCD+0xCC(int 0xCC)或0xCD+0xCE(int 0xCE)以及简单的0xCC(int 3)或0xCE(into)?0xCC或0xCE之前可能有任何内容。可变长度的指令不能让我们轻松可靠地向后分析/反汇编代码。

其他触发中断/异常的方式呢,比如ud2?或者触发#GP、#PF的指令?这些指令可以是任意的。

此外,您应该记住,处理异常的方式并不完全相同。其中一些附带了CPU在进入ISR之前在堆栈上保存的额外信息,这是错误代码。其他人没有此错误代码,您的ISR需要在执行iret之前将其删除。异常向量的确定错误将导致代码崩溃或挂起。

现在,关于硬件中断。。。您可以确定正在为哪个硬件中断提供服务。PIC具有in-service registerISR),其中设置为1(AFAIR)的位表示IRQ,但如果您让优先级较高的中断抢先处理优先级较低的中断(通过启用ISR内部的中断),则中断识别很快变得比必要的更复杂。

因此,只需为所有IRQ、异常和系统调用使用唯一的ISR即可。或者使用一个通用ISR,但具有多个唯一入口点,每个入口点在堆栈上保存一个唯一编号(=矢量编号)。之后的公共代码将提取这个数字,并对该中断向量执行必要的操作。

制作将值推送到堆栈的存根是处理此问题的一种巧妙方法,并在James Molloy教程中使用:

%macro ISR_NOERRCODE 1
  global isr%1
  isr%1:
    cli                         ; Disable interrupts firstly.
    push byte 0                 ; Push a dummy error code.
    push byte %1                ; Push the interrupt number.
    jmp isr_common_stub         ; Go to our common handler code.
%endmacro
%macro ISR_ERRCODE 1
  global isr%1
  isr%1:
    cli                         ; Disable interrupts.
    push byte %1                ; Push the interrupt number
    jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE   8
ISR_NOERRCODE 9
ISR_ERRCODE   10
ISR_ERRCODE   11
ISR_ERRCODE   12
ISR_ERRCODE   13
ISR_ERRCODE   14
ISR_NOERRCODE 15
/* More entries */

这也处理错误代码。

我不是中断处理程序的专家,但它们必须在某个地方有一个返回地址,这样原始代码才能恢复执行。如果您可以旧的这个地址,那么您可以检查以前的地址,它可能包含中断的编号。

最新更新