当在x86上以保护模式触发中断时,是否可以找出触发的中断号?例如,假设我调用了int 0xFF。在处理程序中,我可以找到int 0xFF被调用吗?
答案 0 :(得分:5)
如果您有独特的中断处理程序(或者至少是唯一的入口点和序言代码),那么,当然,您可以将int 0xFF
与int 0x30
区分开来。 ISR地址存储在IDT
中,因此,这就是区分开始的地方。
没有非常好的替代独特的ISR。这就是为什么......
在ISR中,您可以检查调用者的堆栈,查看返回地址并检查返回地址之前的代码,看它是否为2字节int n
指令(编码为字节:0xCD,n)或别的。问题是,还有int 3
和into
1字节指令(分别编码为0xCC和0xCE)。你如何区分0xCD + 0xCC(int 0xCC
)或0xCD + 0xCE(int 0xCE
)和简单的0xCC(int 3
)或0xCE(into
)?在0xCC或0xCE之前可能有任何内容。可变长度的指令不允许我们轻松可靠地分析/反汇编代码。
其他触发中断/异常的方式如ud2
?或触发#GP,#PF的指令?这些可以是任意指示。
另外,您应该记住,异常不会以完全相同的方式处理。其中一些在进入ISR之前带有CPU保存在堆栈上的额外信息,这是错误代码。其他人没有此错误代码,您的ISR需要在执行iret
之前将其删除。确定异常向量时出错会导致代码崩溃或挂起。
现在,关于硬件中断......您可以确定正在处理哪个硬件中断。 PIC
具有in-service register
(ISR
),其中设置为1(AFAIR)的位表示IRQ
,但是如果您让更高优先级的中断抢占ISR处理中断优先级较低(通过启用ISR内部的中断),中断识别很快变得比必要的复杂。
因此,只需使用独特的ISR来处理所有IRQ,异常和系统调用。或者使用一个常见的ISR但具有多个唯一的入口点,每个入口点在堆栈上保存唯一的编号(=向量编号)。之后的公共代码将提取该数字并执行该中断向量所需的操作。
答案 1 :(得分:2)
创建将值推送到堆栈的存根是处理这个问题的一种巧妙方法,并在James Molloy tutorial上使用:
%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 */
答案 2 :(得分:0)
我不是中断处理程序的专家,但他们必须在某处有一个返回地址,以便原始代码可以继续执行。如果您可以使用此地址,那么您可以检查以前的地址,该地址可能包含中断号码。