4

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

4

3 回答 3

5

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

除了独特的 ISR,没有很好的替代方案。这就是为什么...

在 ISR 中,您可以检查调用者的堆栈、查看返回地址并检查返回地址之前的代码,以查看它是否是 2 字节int n指令(编码为字节:0xCD,n)或其他内容。int 3问题是,还有into1 字节指令(分别编码为 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( ),其中位设置为 1 (AFAIR) 表示in-service register,但是如果您让较高优先级的中断抢占 ISR 处理较低优先级的中断(通过启用 ISR 内部的中断),那么中断识别很快就会变得更加复杂比必要的。ISRIRQ

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

于 2012-09-03T01:40:00.483 回答
2

制作将值推送到堆栈的存根是处理此问题的一种巧妙方法,并且在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 */

这也处理错误代码

于 2015-11-09T12:31:49.607 回答
0

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

于 2012-09-02T23:28:48.537 回答