x86異常處理與中斷機制(2)中斷向量表

補充:事件不僅包含中斷和異常,還包含系統調用,這個屬于用戶主動請求的事件。

上一節,只有一個溢出異常,那么,如果很多異常、中斷呢?(中斷向量表)

另外,之前0號地址只能存儲兩條指令,如果需要更多指令怎么辦?(地址的位置以及對應程序大小應該更靈活)

注意,中斷服務程序包含(保存現場,調用處理方法(主體),恢復現場)

我們在遇到中斷之后,需要執行的步驟,我們簡化一下

  1. CPU做一些硬件處理工作(識別中斷源,關中斷,當前指令(或下一條指令)地址壓棧,FLAGS寄存器壓棧)
  2. 到處理中斷的程序地址(這里的程序是中斷服務程序)
  3. 執行中斷服務程序(包含保護現場,執行處理程序(這個才是主體部分),恢復現場,返回原程序)
  4. 繼續執行原有程序

在不同的時代,中斷的處理都是這個過程,只不過每個過程具體的執行發生了變化,且越來越復雜,我們依次看一下。

1 時代1:UNIVAC時代,僅有固定地址中斷處理

在最初的計算機時代,只有很少的內部中斷和外部中斷。
在這里插入圖片描述內個時候的中斷服務程序,是固定的地址,并且程序的大小也相對受限。

例如出現了算數溢出,那么就會跳轉到地址0執行中斷服務程序

在這里插入圖片描述
不僅如此,這個時候的中斷服務程序幾乎是

  • 固定地址
  • 固定大小

因此靈活性很差,不過由于很少,所以還好。

到了后來,中斷越來越多,因此就有了中斷向量表,下面看看8086時代吧。

2 時代2:8086時代,實模式 + 中斷向量表

這個時代,中斷已經較多了,管理中斷的方式也更加靈活了。

在這里插入圖片描述
8086采用的是實模式,也就是說,進入CPU指令中的地址,就是實際的物理地址。

在8086的1MB內存中,有專門的中斷向量表區,從地址0開始的1K字節,它用于存放中斷服務程序的地址,也就是存放CS:IP

每對CS:IP占用4個字節,因此1KB的空間,最多可以支持256種中斷
在這里插入圖片描述
CS:IP,CS在前,IP在后,因此CS在高地址,IP在低地址,又因為是小端模式,因此IP的高字節是高位,低字節是低位;CS同理。

這樣一來,實際的中斷服務程序的位置,是根據這些CS:IP的值確定的,而它們在內存中是可以修改的,因此

  • 中斷服務程序的位置可變
  • 程序的大小可改

并且這些中斷服務程序的位置是任意的,只要能夠與中斷向量表對應上即可。

同時,不同的中斷服務程序,位置沒有關聯,放哪里都行。在實模式的8086之下,只需要CS:IP就可以確定實際內存的位置。
在這里插入圖片描述
在這個時代,中斷服務程序的位置了大小更加靈活,變成了間接獲取,因為加了一個中斷向量表。

在這里插入圖片描述
注意,這個時候有5種類型的中斷,并不是5個中斷,這個時候涉及到的內部中斷有4個,外部中斷有1個,而這個外部中斷,是8259A芯片發出的,該芯片外面可以連接很多個外設。

在這里插入圖片描述
我們來看看這個時代中斷處理的示意圖。

在這里插入圖片描述

3 時代3:80386時代,保護模式 + 中斷向量表

這個時代就有點復雜了,引入了保護模式,同時增加了一些中斷類型,這也是Linux 0.11內核對應的CPU。

在這里插入圖片描述圈住的部分是80386支持的中斷類型,int0 ~ int16,其中int15未定義,可以在手冊中查到。
在這里插入圖片描述

3.1 保護模式下的尋址方式

首先,保護模式下,依然是CS:EIP的形式,但是由于EIP已經足夠尋址4GB,因此CS不再作為位數擴展的功能了,它的功能發生了改變。

在這里插入圖片描述
在保護模式下,段寄存器依然是16位,它們變成了段選擇子寄存器,先從最簡方式描述地址的生成方法

  1. 通過段選擇子寄存器找到8字節大小的段描述符
  2. 根據段描述符的內容獲取段基址(32位)
  3. 段基址EIP組合(==應該就是相加吧?==基址 + 偏移地址),得到地址
  4. 注意: 目前可以知到這個地址是給CPU看的,它應該是虛擬地址,現在先不管,先當成通過這個地址就能夠訪問到內存的指定位置。

是不是比實模式復雜多了,下面,進一步展開細節

通過段選擇子寄存器(此后均以CS舉例說明),怎么找到對應的段描述符?在這里插入圖片描述

  1. 計算機啟動進入實模式
  2. 填好GDT
  3. 設置好GDT的初始地址放入GDTR寄存器中

在保護模式下, CS + GDTR獲取對應的描述符(0~8191),這樣,我們就獲取了代碼段的描述符了。

接下來我們看看這個描述符

  1. 這個描述符有8192個,也就是2^13,而一個描述符有2^3 = 8個字節,因此一共占用了2^16個內存單元,也就是64KB,CS寄存器是16位的,這是它能夠訪問的極限,這樣,通過GDTR基址 + CS偏移的方式,能夠訪問到每一個描述符表。
  2. 再看每一個描述符的結構
    在這里插入圖片描述
    它有8個字節的大小,其中有四個字節是段基址,就是這個段基址與EIP組合,形成最終的要訪問內存的(虛擬)地址。其他的自己還涉及到權限以及界限,先不管是干啥的。

段描述符的內容是什么,怎么獲取段基址

上面已經說明了。

3.2 保護模式下的中斷操作

上面一小節,經歷了一系列復雜過程,終于說明了保護模式下如何尋址,真的很復雜啊……下面說明一下中斷操作過程。其實最主要說明的還是中斷服務程序位置這個過程。

在這里插入圖片描述
在保護模式下,也有一個IDTR中斷描述符表寄存器,還有一個IDT中斷描述符。

這個IDT同樣是支持256種類型的中斷的,每個描述符表項占8個字節,因此一共占用2KB。

IDTR提供的是IDT的基址,然后CPU獲取中斷號之后,根據中斷號 * 8 + IDTR定位對應的描述符。

對于中斷描述符

  • 字節0167四個字節對應的是32位地址,也就是EIP的值
  • 字節23對應的是CS的值
  • 有了CS:EIP就可以通過上一小節的方式找到對應的地址,從而找到中斷服務程序入口地址
    (這個過程其實與CS:IP類似,只不過麻煩了點)

折騰了這么一大圈,終于找到中斷服務程序了……

3.3 小結

這個太復雜了,我們簡單總結一下吧。

首先,保護模式下的尋址方式更復雜了,引入了全局描述符表,雖然依然是CS:EIP,但是其計算方式更加復雜了。

其次,保護模式下的中斷處理更復雜了

  • 以前固定位置的中斷向量表,變成了任意位置的中斷描述符表IDT,通過IDTR中斷類型號計算得到中斷描述符
  • 再通過中斷描述符的內容獲取CS:EIP,再獲取對應中斷服務程序的入口地址

我們可以看到,模式越來越復雜間接程度越來越高,設置的自由度提高,安全性也提高了。

在這里插入圖片描述

思想:太固定死板怎么辦?加個固定的中轉站!通過改變中轉站,來實現靈活地分配目標

這幾個時代的發展過程,可以說中轉站越來越多,越來越復雜,靈活度越來越高。

小結

本篇內容,貫徹的是中斷處理的找中斷服務程序的過程。

可以看到

  1. UNIVAC時代非常直接地找到地址
  2. 8086時代提供了固定位置中斷向量表,間接地找到CS:IP,尋址方式是直接的
  3. 80386時代提供了任意位置的中斷描述符表,間接地獲取CS:EIP,尋址方式也是間接的,需要通過全局描述符表GDT獲取段基址,從而獲取內存地址

不管怎樣,時代的發展使得根據中斷類型號,找到中斷服務程序這個過程越來越復雜,靈活度也越來越高。

后面會介紹中斷處理的其他過程,最后結合Linux 0.11內核源代碼,使得軟硬件對應上。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384611.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384611.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384611.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

x86異常處理與中斷機制(3)中斷處理過程

上一節講完了根據中斷類型號找中斷服務程序的過程,現在著重說明一下更加完整的中斷處理過程吧。 本節以8086時代的中斷處理過程為例進行說明,主要分兩大部分 硬件處理軟件處理 需要注意,這不是絕對的,得看實際情況,…

Linux 0.11 內核解析:中斷相關(1)asm.s文件中斷處理分析

0 源代碼 有兩個版本的,一個是帶中文注釋,Intel格式的;一個是不帶注釋是AT&T格式的。 Linux 0.11 中文注釋版 Linux 0.11 源碼,基于《Linux內核完全注釋》趙炯 1 asm.s 文件 我們先假設該文件處理的中斷是無特權過渡的情況…

【精華文】C語言結構體特殊情況分析:結構體指針 / 基本數據類型指針,指向其他結構體

參考鏈接:Structure pointer pointing to different structure instance 注:可以查看此篇的問題和唯一的回復,那是相對正確的,不要看comment,有很多錯誤。 我是拒絕分析這種問題的,因為似乎沒有人會這么亂用…

enum in c language

今天說說C語言中的枚舉。 參考:Enumeration (or enum) in C 1 定義 定義一個枚舉類型很容易: enum aa { a1, a2, a3 };這里 enum是關鍵字aa是枚舉變量,也就是我們自定義類型a1,a2,a3是枚舉成員 然后怎么使用呢? 首先&#…

信號量SIGCHLD的使用,如何讓父進程得知子進程執行結束,如何讓父進程區分多個子進程的結束

本教程基于 Ubuntu 20.10 gcc 10.2.0. 示例程序如果不能正常編譯和執行,說明您系統和工具版本與我的不匹配,請自行查閱資料。 0 概述 先給出該信號的描述: SignalValueDescriptionSIGCHLD17Child status has changed (POSIX). Signal sent …

使用gdb調試多進程程序、同時調試父進程和子進程

參考: [1] GDB debugging multi-process programs [2] Debugging programs with multiple processes 根據這兩篇參考鏈接,完全可以實現使用gdb同時調試父進程和子進程。 接下來說明一下可能遇到的坑 gdb8.1版本有bug,設置完set detach-fork-on off&…

Linux安裝Ncurses庫

參考:How To Install Ncurses Library In Linux 針對Ubuntu說明一下: wget https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.2.tar.gz,至于最新版本,自己看官網,修改一下版本號即可。tar xzf ncurses-6.2.tar.gzcd nc…

gdb 10.2的安裝

參考 [1] GDB-10.2 [2] README for GDB release 個人系統 Ubuntu20.10。 注意gdb10.2需要c11語法,需要安裝g 下載安裝包wget https://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.xz解壓縮tar -xvzf gdb-10.2.tar.xz進入解壓之后的目錄mkdir buildcd build配置,…

gdb tui的使用

[1] GDB Text User Interface [2] GDB Text User Interface 簡單來說,進入gdb之后,使用ctrl x 2就足夠了。其他細節請參考上述鏈接,選一個就可以。

C語言中信號函數(signal)的使用

先來簡單談談C語言中的信號(signal) 首先,signal是C語言庫中的函數,它實際上是軟中斷,也就是軟件發出的終端,本質來說,類似于int n。 對于接收到該軟中斷信號的進程,就會停下手頭的…

UNIX哲學

參考: 對比Linux與Windows 使用Linux想要做某些事情的時候,就拆開想,想想我需要哪些功能,需要哪些工具,依次怎么執行,然后用管道建立連接,讓數據依次流過不同的工具,從而得到最終結果…

fork創建多個子進程

references: [1] how to create two processes from a single Parent [2] fork() in C [3] linux中fork同時創建多個子進程的方法 fork的本質,就是復制,把當前進程復制一份,然后兩個進程并發地執行fork后面的語句,區別就是&#x…

wait系統調用

reference:Wait System Call in C 只強調幾點,剩下的直接看參考鏈接內容就好了,不是偷懶,而是里面內容寫的很好了,沒必要再寫一遍了,這種東西就是單純的系統調用而已,理解了功能,就完事了&#…

Linux進程間通信:共享內存與管道

references: [1] IPC through shared memory [2] Inter Process Communication (IPC) [3] https://www.geeksforgeeks.org/pipe-system-call/ [4] watch command in Linux with Examples 參考鏈接1和2是介紹了共享內存IPC的簡單原理和相關系統調用的使用參考鏈接3是介紹了管道通…

find command基本使用

find命令通常用于根據文件名查找文件,這是最基本用法。 find [path] -name/-iname [filename] path寫要查找的路徑,自動遞歸查找filename寫文件名,可以使用通配符*還有其他什么的表達式 具體細節請man find查閱文檔。

正則表達式特別需要注意的點:“空“字符的匹配

在正則表達式中,[...]代表1個字符,不管里面有多少字符,最終這個東西的結果都是1個字符。 對于表達式[^a]表達的匹配除了a之外的字符,并且是1個字符。 需要注意的是,有些特殊字符是不會被匹配的。 我們看一個示例&am…

vim多列操作--插入/刪除

插入 How to insert text at beginning of a multi-line selection in vi/VimVim Commands 刪除 ctrl v使用上下左右鍵選中一片區域按d刪除

vim進行行內某部分的復制剪切粘貼

ctrl v使用方向鍵選中你要復制的部分 按d(剪切)或者按y(復制)再移動到你的目標位置,按p粘貼(在正常模式下才行,如果不是,先按esc) 這個過程與你操作word文檔的復制粘貼…

函數調用堆棧

基于孟寧老師的Linux內核分析 1 int g(int x){ 2 int y x 3;3 return y;4 }5 6 int f(int x){7 int z x 10;8 return g(z);9 }10 11 int main(){12 int a f(8) 1;13 return 0;14…

gdb調試的幾點提示(1)

GDB debugger Examining Memory Continuing and Stepping How to translate a virtual memory address to a physical address? s和n是C語言的下一步 si和ni是匯編語言下一步 gdb能夠查看的都是虛擬地址,不能查看物理地址,應用程序都不能查看物理地址…