中斷和異常
中斷和異常是強制性的執行流的轉移,從當前正在執行的任務或程序轉移到一個特殊的例程或任務。
當硬件發生信號時,便產生中斷。中斷的產生和正在執行的程序之間是異步的,即中斷的產生是隨機的。
異常是處理器執行指令的過程中發現錯誤而產生的。
處理器的中斷和異常處理機制使中斷和異常的處理對於應用程序和操作系統或可執行程序而言是透明的。
當處理器收到中斷信號或者檢測到異常的時候,便掛起正在進行的進程或任務,轉而去處理中斷或異常處理例程。
中斷或異常處理例程處理完成後,處理器繼續被中斷的進程或程序。被中斷的程序繼續執行。
因此異常處理程序需要記錄一些狀態信息,以便在異常處理完成後繼續執行後面的程序。這些信息也都是通過壓棧和出棧進行操作。
為什麼當異常發生時會停止當前的程序?
這是因為正常程序的優先級沒有異常程序的優先級高。同樣對於異常和中斷,又有很多優先級可以設置。當一個低優先級的異常發生後,它仍然可以被一個高優先級的異常所打斷。這就是異常的嵌套。
異常的優先級有的是固定的,有些則可以被軟件來設置。下表顯示了各類異常和中斷源的優先關係。
只有兩種情況例外:無法從產生的異常恢復、中斷使當前的程序終止。
異常的處理流程:
當異常發生以後,系統會停止增在發生的程序,轉而去訪問向量表,然後從向量表中加載異常處理函數的入口地址。
IDT表
int 0x80中斷的處理
這條指令就是去IDT表中取出中斷處理函數,然後執行完後進行下面的代碼。
int 0x80去哪個中斷處理函數去處理?
系統初始化的時候已經設置好的:set_system_gate(0x80,&system_call)
#include\asm-x86_64\desc.h
static void __init set_system_gate(unsigned int n, void *addr)
{
_set_gate(idt_table+n, 15, 3, addr);
}
n 就是中斷號,addr就是中斷的地址。
idt_table 是一個全局變量,就是idt表的起始地址。然後用n就找到80對應的那個表項
中斷描述符表的初始化工作主要通過宏_set_gate來完成,它定義於include/asm/system.h中
#define _set_gate(gate_addr,type,dpl,addr)\
__asm__("movw %%dx,%%ax\n\t"\
"movw %0,%%dx\n\t"\
"movl %%eax,%1\n\t"\
"movl %%edx,%2"\
:\
:"i"((short)(0x8000+(dpl<<13)+(type<<8))),\
"o"(*((char *)(gate_addr))),\
"o"(*(4+(char *)(gate_addr))),\
"d"((char *)(addr)),"a"(0x00080000))
註釋:
%0、%1、%2、%3:0、1、2、3可以看作變量,這些變量在程序的":"之後,程序的兩個":",是定義輸入、輸出項的。針對這段程序這些變量的前 面都加了明確的限定,例如"i"(輸入項)、"o"(輸出項),剩下的"d"(edx的初始值),"a"(eax的初始值)。而0、1、2、3的概念就是 指第幾個變量,這裡輸入項、輸出向、寄存器初始混合編號;相應的0("i"((short)(0x8000+(dpl<<13)+ (type<<8)))));1((*((char *)(gate_addr))));2((*(4+(char *)(gate_addr))));3("d"((char *)(addr)));4("a"(0x00080000))
進入彙編程序段後
"d"((char *)(addr)) 代表把偏移地址addr值放入edx中,一共32位(高16位,低16位)
"a"(0x00080000) 代表把0x00080000值放入eax中,一共32位(高16位就是0x0008是段選擇符,低16位會被放在edx中的過程偏移低16位代替)
"i"((short)(0x8000+(dpl<<13)+(type<<8))) 中斷或者陷進的屬性及dpl ,0x8000指示存在,一共32位(高16位為0x0000,低16位放前邊說的,會被放入地址的低16位中)
另外兩條用於輸出
"o"(*((char *)(gate_addr)))
"o"(*(4+(char *)(gate_addr))) 放入對應的IDT[]中
movw %%dx,%%ax movw只移動低16位,高16位不變 eax中的0x00080000變成了0x008和低16位地址
movw %0,%%dx 把第一個參數(%0)低16位放入dx
閱讀更多 有理想的代碼dog 的文章