1. 程式人生 > >換種方法學作業系統,輕鬆入門Linux核心

換種方法學作業系統,輕鬆入門Linux核心

​​​​計算機已成為現代人日常工作、學習和生活中必不可少的工具。作業系統是計算機之魂,作為使用者使用計算機的介面,它負責排程執行各個使用者程式,使計算機完成特定的任務;作為計算機硬體資源的管理者,它負責協調計算機中各類裝置高效地工作。作業系統的重要性不言而喻。

對於軟體工程師,理解作業系統的工作原理和關鍵機制是設計高質量應用程式的前提,但要做到這一點是十分困難的。

一方面,作業系統設計涉及電腦科學與工程學科的方方面面,包括資料結構與演算法、計算機組成與系統結構、計算機網路,甚至程式設計語言與編譯系統等核心知識,以及併發、同步和通訊等核心概念。

另一方面,作為一個複雜龐大的軟體產品,理解作業系統更需要理論與實踐深度結合。

作業系統的相關學習資料十分豐富。有闡述基本原理者,有剖析典型系統者,還有構造示例系統者;有面向專業理論者,亦有面嚮應用實踐者。角度多種多樣,內容簡繁不一。

​本書的最大特點在於作者結合其多年的Linux作業系統實際教學經驗編撰而成。作為一位經驗豐富的高階軟體工程師和專業教師,本書作者基於自己學習和研究Linux的心得,創新性地以一個mykernel和MenuOS為基礎實驗平臺進行教學和實驗組織,實現了理論學習與工程實踐的自然融合,達到了事半功倍的效果。

同時,書中設計了豐富的單元測試題和實驗,引導讀者循序漸進地掌握所學知識,並有效地促進讀者深入思考和實踐所學內容。

作者基於本書開設的作業系統課程,其教學形式涉及面對面的課堂教學和線上慕課教學,選課物件既包括軟體工程碩士,又包括一般工程實踐者,學習人數已數以萬計。本書的出版體現了作者認真吸收大量的學員反饋,不斷優化課程的教學內容和過程組織的成果。

本文重點介紹計算機的工作原理,具體涉及儲存程式計算機工作模型、基本的組合語言,以及C語言程式彙編出來的彙編程式碼如何在儲存程式計算機工作模型上一步步地執行。其中重點分析了函式呼叫堆疊相關彙編指令,如call/ret和pushl/popl。

儲存程式計算機工作模型

儲存程式計算機的概念雖然簡單,但在計算機發展史上具有革命性的意義,至今為止仍是計算機發展史上非常有意義的發明。一臺硬體有限的計算機或智慧手機能安裝各種各樣的軟體,執行各種各樣的程式,這在人們看起來都理所當然,其實背後是儲存程式計算機的功勞。

儲存程式計算機的主要思想是將程式存放在計算機儲存器中,然後按儲存器中的儲存程式的首地址執行程式的第一條指令,以後就按照該程式中編寫好的指令執行,直至程式執行結束。

相信很多人特別是學習計算機專業的人都聽說過圖靈機和馮·諾依曼機。圖靈機關注計算的哲學定義,是一種虛擬的抽象機器,是對現代計算機的首次描述。只要提供合適的程式,圖靈機就可以做任何運算。基於圖靈機建造的計算機都是在儲存器中儲存資料,程式的邏輯都是嵌入在硬體中的。

與圖靈機不同,馮·諾依曼機是一個實際的體系結構,我們稱作馮·諾依曼體系結構,它至今仍是幾乎所有計算機平臺的基礎。我們都知道“庖丁解牛”這個成語,比喻經過反覆實踐,掌握了事物的客觀規律,做事得心應手,運用自如。馮·諾依曼體系結構就是各種計算機體系結構需要遵從的一個“客觀規律”,瞭解它對於理解計算機和作業系統非常重要。下面,我們就來看看什麼是馮·諾依曼體系結構。

在1944~1945年期間,馮·諾依曼指出程式和資料在邏輯上是相同的,程式也可以儲存在儲存器中。馮·諾依曼體系結構的要點包括:

馮·諾依曼體系結構如圖1-1所示,其中運算器、儲存器、控制器、輸入裝置和輸出裝置5大基本型別部件組成了計算機硬體;

圖1-1  馮·諾依曼體系結構

計算機內部採用二進位制來表示指令和資料; 

將編寫好的程式和資料先存入儲存器中,然後啟動計算機工作,這就是儲存程式的基本含義。

計算機硬體的基礎是CPU,它與記憶體和輸入/輸出(I/O)裝置進行互動,從輸入裝置接收資料,向輸出裝置傳送資料。

CPU由運算器(算術邏輯單元ALU)、控制器和一些暫存器組成。有一個非常重要的暫存器稱為程式計數器,在IA32(x86-32)中是EIP,指示將要執行的下一條指令在儲存器中的地址。

C/C++程式設計師可以將EIP看作一個指標,因為它總是指向某一條指令的地址。CPU就是從EIP指向的那個地址取過來一條指令執行,執行完後EIP會自動加一,執行下一條指令,然後再取下一條指令執行,CPU像“貪吃蛇”一樣總是在記憶體裡“吃”指令。

CPU、記憶體和I/O裝置通過匯流排連線。記憶體中存放指令和資料。

“計算機內部採用二進位制來表示指令和資料”表明,指令和資料的功能和處理是不同的,但都可以用二進位制的方式儲存在記憶體中。

上述第3個要點指出了馮·諾依曼體系結構的核心是儲存程式計算機。

我們用程式設計師的思維來對儲存程式計算機進行抽象,如圖1-2所示。 

圖1-2  儲存程式計算機工作原理示意圖

我們可以把CPU抽象成一個for迴圈,因為它總是在執行next instruction(下一條指令),然後從記憶體裡取下一條指令來執行。從這個角度來看,記憶體儲存指令和資料,CPU負責解釋和執行這些指令,它們通過匯流排連線起來。這裡揭示了計算機可以自動化執行程式的原理。

這裡存在一個問題,CPU能識別什麼樣的指令,我們這裡需要有一個定義。學過程式設計的讀者基本都知道API,也就是應用程式程式設計介面。

而對於程式設計師來講,還有一個稱為ABI的介面,它主要是一些指令的編碼。在指令編碼方面,我們不會涉及那麼具體的細節,而只會涉及和彙編相關的內容。

至於這些指令是如何編碼成二進位制機器指令的,我們不必關心,有興趣的讀者可以查詢指令編碼的相關資料。此外,這些指令會涉及一些暫存器,這些暫存器有些約定,我們約定什麼樣的指令該用什麼暫存器。

同時,我們也需要了解暫存器的佈局。還有,大多數指令可以直接訪問記憶體,對於x86-32計算機指令集來講,這也是一個重要的概念

對於x86-32計算機,有一個EIP暫存器指向記憶體的某一條指令,EIP是自動加一的(不是一個位元組,也不是32位,而是加一條指令),雖然x86-32中每條指令佔的儲存空間不一樣,但是它能智慧地自動加到下一條指令,它還可以被其他指令修改,如call、ret、jmp等,這些指令對應C語言中的函式呼叫、return和if else語句。

現在絕大多數具有計算功能的裝置,小到智慧手機,大到超級計算機,基本的核心部分可以用馮·諾依曼體系結構(儲存程式計算機)來描述。因此,儲存程式計算機是一個非常基本的概念,是我們理解計算機系統工作原理的基礎。

x86-32彙編基礎

Intel處理器系列也稱為x86,經過不斷的發展,體系結構經歷了16位、32位和64位幾個關鍵階段。32位的體系結構稱為IA32,64位體系結構稱為x86-64,但為了明確區分兩者,本書中把32位體系結構稱作x86-32。本書與Linux核心採用的彙編格式保持一致,採用AT&T彙編格式。

1.x86-32 CPU的暫存器

為了便於讀者理解,下面先來介紹16位的8086 CPU的暫存器。8086 CPU中總共有14個16位的暫存器:AX、BX、CX、DX、SP、BP、SI、DI、IP、FLAG、CS、DS、SS和ES。這14個暫存器分為通用暫存器、控制暫存器和段暫存器3種類型。

通用暫存器又分為資料暫存器、指標暫存器和變址暫存器。

AX、BX、CX和DX統稱為資料暫存器。

qAX(Accumulator):累加暫存器,也稱為累加器。

qBX(Base):基地址暫存器。

qCX(Count):計數器暫存器。

qDX(Data):資料暫存器。

SP和BP 統稱為指標暫存器。

qSP(Stack Pointer):堆疊指標暫存器。

qBP(Base Pointer):基指標暫存器。

SI和DI統稱為變址暫存器。

qSI(Source Index):源變址暫存器。

qDI(Destination Index):目的變址暫存器。

控制暫存器主要分為指令指標暫存器和標誌暫存器。

qIP(Instruction Pointer):指令指標暫存器。

qFLAG:標誌暫存器。

段暫存器主要有程式碼段暫存器、資料段暫存器、堆疊段暫存器和附加段暫存器。

qCS(Code Segment):程式碼段暫存器。

qDS(Data Segment):資料段暫存器。

qSS(Stack Segment):堆疊段暫存器。

qES(Extra Segment):附加段暫存器。

以上資料暫存器AX、BX、CX和DX都可以當作兩個單獨的8位暫存器來使用,如圖1-3所示,以AX暫存器為例。

圖1-3  AX 暫存器示意圖

qAX暫存器可以分為兩個獨立的8位的AH和AL暫存器。

qBX暫存器可以分為兩個獨立的8位的BH和BL暫存器。

qCX暫存器可以分為兩個獨立的8位的CH和CL暫存器。

qDX暫存器可以分為兩個獨立的8位的DH和DL暫存器。

除了上面4個數據暫存器以外,其他暫存器均不可以分為兩個獨立的8位暫存器。注意,每個分開的暫存器都有自己的名稱,可以獨立存取。程式設計師可以利用資料暫存器的這種“可分可合”的特性,靈活地處理字/位元組的資訊。

瞭解了16位的8086 CPU的暫存器之後,我們再來看32位的暫存器。

IA32所含有的暫存器包括:

q4個數據暫存器(EAX、EBX、ECX和EDX)。

q2個變址和指標暫存器(ESI和EDI)。

q2個指標暫存器(ESP和EBP)。

q6個段暫存器(ES、CS、SS、DS、FS和GS)。

q1個指令指標暫存器(EIP)。

q1個標誌暫存器(EFlags)。

32位暫存器只是把對應的16位暫存器擴充套件到了32位,如圖1-4所示為EAX暫存器示意圖,它增加了一個E。所有開頭為E的暫存器,一般是32位的。

EAX累加暫存器、EBX基址暫存器、ECX計數暫存器和EDX資料暫存器都是通用暫存器,程式設計師在寫彙編碼時可以自己定義如何使用它們。EBP是堆疊基址指標,比較重要;ESI、EDI是變址暫存器;ESP也比較重要,它是堆疊棧頂暫存器。

這裡可能會涉及堆疊的概念,學過資料結構課程的讀者應該知道堆疊的概念,本書後面會具體講到push指令壓棧和pop指令出棧,它是向一個堆疊裡面壓一個數據和從堆疊裡面彈出一個數據。這些都是32位的通用暫存器。

圖1-4  EAX暫存器示意圖

值得注意的是在16位CPU中,AX、BX、CX和DX不能作為基址和變址暫存器來存放儲存單元的地址,但在32位CPU中,32位暫存器EAX、EBX、ECX和EDX不僅可以傳送資料、暫存資料儲存算術邏輯運算結果,還可以作為指標暫存器,因此這些32位暫存器更具通用性。

除了通用暫存器外,還有一些段暫存器。雖然段暫存器在本書中用得比較少,但還是要了解一下。除了CS、DS、ES和SS外,還有其他附加段暫存器FS和GS。

常用的是CS暫存器和SS暫存器。我們的指令都儲存在程式碼段,在定位一個指令時,使用CS:EIP來準確指明它的地址。

也就是說,首先需要知道程式碼在哪一個程式碼段裡,然後需要知道指令在程式碼段內的相對偏移地址EIP,一般用CS:EIP準確地標明一個指令的記憶體地址。還有堆疊段,每一個程序都有自己的堆疊段(在Linux系統裡,每個程序都有一個核心態堆疊和一個使用者態堆疊)。

標誌暫存器的功能細節比較複雜煩瑣,本書就不仔細介紹了,讀者知道標誌暫存器可以儲存當前的一些狀態就可以了。

現在主流的計算機大多都是採用64位的CPU,那麼我們也需要簡單瞭解一下x86-64的暫存器。實際上,64位和32位的暫存器差別也不大,它只是從32位擴充套件到了64位。前面帶個“R”的都是指64位暫存器,如RAX、RBX、RCX、RDX、RBP、RSI、RSP,還有Flags改為了RFLAGS,EIP改為了RIP。

另外,還增加了更多的通用暫存器,如R8、R9等,這些增加的通用暫存器和其他通用暫存器只是名稱不一樣,在使用中都是遵循呼叫者使用規則,簡單說就是隨便用。

2.資料格式

在Intel的術語規範中,字表示16位資料型別;在IA32中,32位數稱為雙字;在x86-64中,64位數稱為四字。圖1-5所示為C語言中基本型別的IA32表示,其中列出的彙編程式碼字尾在彙編程式碼中會經常看到。 

圖1-5  C語言中基本型別的IA32表示

3.定址方式和常用匯編指令

彙編指令包含操作碼和運算元,其中運算元分為以下3種:

(1)立即數即常數,如$8,用$開頭後面跟一個數值;

(2)暫存器數,表示某個暫存器中儲存的值,如%eax;而對位元組操作而言,是8個單位元組暫存器中的一個,如%al(EAX暫存器中的低8位);

(3)儲存器引用,根據計算出的有效地址來訪問儲存器的某個位置。

還有一些常見的彙編指令,我們來看它們是如何工作的最常見的彙編指令是mov指令,movl中的l是指32位,movb中的b是指8位,movw中的w是指16位,movq中的q是指64位。我們以32位為主進行介紹。

首先介紹暫存器定址。所謂暫存器定址就是操作的是暫存器,不和記憶體打交道,如%eax,其中%開頭後面跟一個暫存器名稱。

movl %eax,%edx

上述程式碼把暫存器%eax的內容放到%edx中。如果把暫存器名當作C語言程式碼中的變數名,它就相當於:

edx = eax;

立即定址(immediate)是用一個$開頭後面跟一個數值。例如:

movl $0x123, %edx

就是把0x123這個十六進位制的數值直接放到EDX暫存器中。如果把暫存器名當作C語言程式碼中的變數名,它就相當於:

edx = 0x123;

立即定址也和記憶體沒有關係。

直接定址(direct)是直接用一個數值,開頭沒有$符號。開頭有$符號的數值表示這是一個立即數;沒有$符號表示這是一個地址。例如:

movl 0x123, %edx

就是把十六進位制的0x123記憶體地址所指向的那塊記憶體裡儲存的資料放到EDX暫存器裡,這相當於C語言程式碼:

edx = *(int*)0x123;

把0x123這個數值強制轉化為一個32位的int型變數的指標,再用一個*取它指向的值,然後放到EDX暫存器中,這就稱為直接定址。

換句話說,就是用記憶體地址直接訪問記憶體中的資料。

間接定址就是暫存器加個小括號。舉例說明,%ebx這個暫存器中存的值是一個記憶體地址,加個小括號表示這個記憶體地址所儲存的資料,我們把它放到EDX暫存器中:

move (%ebx), %edx

就相當於:

edx = *(int*)ebx;

把這個EBX暫存器中儲存的數值強制轉化為一個32位的int型變數的指標,再用一個*取它指向的值,然後放到EDX暫存器中,這稱為間接定址。

變址定址比間接定址稍微複雜一點。例如:

movl 4(%ebx), %edx

讀者會發現程式碼中“(%ebx)”前面出現了一個4,也就是在間接定址的基礎上,在原地址上加上一個立即數4,相當於: 

edx = *(int*)(ebx+4)

把這個EBX暫存器儲存的數值加4,然後強制轉化為一個32位的int型別的指標,再用一個*取它指向的值,然後放到EDX暫存器中,這稱為變址定址。

如上所述的CPU對暫存器和記憶體的操作方法,都是比較基礎的知識,需要牢固掌握。

x86-32中的大多數指令都能直接訪問記憶體,但還有一些指令能直接對記憶體操作,如push/pop。它們根據ESP暫存器指向的記憶體位置進行壓棧和出棧操作,注意這是指令執行過程中預設使用了特定的暫存器。

還需要特別說明的是,本書中使用的是AT&T彙編格式,這也是Linux核心使用的彙編格式,與Intel彙編格式略有不同。

我們在搜尋資料時可能會遇到Intel彙編程式碼,一般來說,全是大寫字母的一般是Intel彙編,全是小寫字母的一般是AT&T彙編。

本書中的程式碼用到的暫存器名稱都遵守AT&T彙編格式採用全小寫的方式,而正文中需要使用暫存器名稱一般使用大寫,因為它們是首字母縮寫。

還有幾個重要的指令:pushl/popl和call/ret。pushl表示32位的push,如:

pushl %eax

就是把EAX暫存器的值壓到堆疊棧頂。它實際上做了這樣兩個動作,其中第一個動作為:

subl $4, %esp

把堆疊的棧頂ESP暫存器的值減4。因為堆疊是向下增長的,所以用減指令subl,也就是在棧頂預留出一個儲存單元。第二個動作為:

movl %eax, (%esp)

把ESP暫存器加一個小括號(間接定址),就是把EAX暫存器的值放到ESP暫存器所指向的地方,這時ESP暫存器已經指向預留出的儲存單元了。

接下來介紹popl指令,如:

popl %eax

就是從堆疊的棧頂取一個儲存單元(32位數值),從堆疊棧頂的位置放到EAX暫存器裡,這稱為出棧。出棧同樣對應兩個操作:

movl (%esp), %eax

addl $4, %esp

第一步是把棧頂的數值放到EAX暫存器裡,然後用指令addl把棧頂加4,相當於棧向上回退了一個儲存單元的位置,也就是棧在收縮。每次執行指令pushl棧都在增長,執行指令popl棧都在收縮。

call指令是函式呼叫,呼叫一個地址。例如:

call 0x12345

上述程式碼實際上做了兩個動作,如下兩條偽指令,注意,這兩個動作並不存在實際對應的指令,我們用“(*)”來特別標記一下,這兩個動作是由硬體一次性完成的。出於安全方面的原因,EIP暫存器不能被直接使用和修改。

pushl %eip (*)

movl $0x12345, %eip (*)

上述偽指令先是把當前的EIP暫存器壓棧,把0x12345這個立即數放到EIP暫存器裡,該暫存器是用來告訴CPU下一條指令的儲存地址的。

把當前的EIP暫存器的值壓棧就是把下一條指令的地址儲存起來,然後給EIP暫存器又賦了一個新值0x12345,也就是CPU執行的下一條指令就是從0x12345位置取得的。

再看與call指令對應的指令ret,ret指令是函式返回,例如:

ret

上述程式碼實際上做了一個動作,如下一條偽指令,注意,這個動作並不存在實際對應的指令,我們用“(*)”來特別標記一下,這個動作是由硬體一次性完成的。出於安全方面的原因,EIP暫存器不能被直接使用和修改。

popl %eip(*)

也就是把當前堆疊棧頂的一個儲存單元(一般是由call指令壓棧的內容)放到EIP暫存器裡。上述pushl/popl和call/ret彙編指令對應執行的動作彙總如圖1-6所示。

圖1-6  pushl/popl和call/ret彙編指令

總結一下,call指令對應了C語言裡我們呼叫一個函式,也就是call一個函式的起始地址。ret指令是把呼叫函式時壓棧的EIP暫存器的值(即call指令的下一條指令的地址)還原到EIP暫存器裡,ret指令之後的下一條指令也就回到函式呼叫位置的下一條指令。

換句話說就是函式呼叫結束了,繼續執行函式呼叫之後的下一條指令,這和C語言中的函式呼叫過程是嚴格對應的。但是需要注意的是,帶個“(*)”的指令表示這些指令都是不能被程式設計師直接使用的,是偽指令。

因為EIP暫存器不能被程式設計師直接修改,只能通過專用指令(如call、ret和jmp等)間接修改。

若程式設計師可以直接修改EIP暫存器,那麼會有嚴重的安全隱患。讀者可以思考一下為什麼?我們就不展開討論了。

4.彙編程式碼範例解析

我們已經對指令和暫存器有了大致的瞭解,下面做一個練習來驗證我們的理解。在堆疊為空棧的情況下,執行如下彙編程式碼片段之後,堆疊和暫存器都發生了哪些變化?

1    push   $8

2    movl    %esp, %ebp

3    subl    $4, %esp

4    movl    $8, (%esp)

我們分析這段彙編程式碼每一步都做了什麼動作。首先在堆疊為空棧的情況下,EBP和ESP暫存器都指向棧底。 

第1行語句是將立即數8壓棧(即先把ESP暫存器的值減4,然後把立即數8放入當前堆疊棧頂位置)。

第2行語句是把ESP暫存器的值放到EBP暫存器裡,就是把ESP暫存器儲存的內容放到EBP暫存器中,把EBP暫存器也指向當前ESP暫存器所指向的位置。

換句話說,在堆疊中又新建了一個邏輯上的空棧,這一點理解起來並不容易,讀者暫時理解不了也沒有關係。本書後面會將C語言程式彙編成彙編程式碼來分析函式呼叫是如何實現的,其中會涉及函式呼叫堆疊框架。

第3行語句中的指令是subl,是把ESP暫存器儲存的數值減4,也就是說,棧頂指標ESP暫存器向下移了一個儲存單元(4個位元組)。

最後一行語句是把立即數8放到ESP暫存器所指向的記憶體地址,也就是把立即數8通過間接定址放到堆疊棧頂。 

本例是關於棧和暫存器的一些操作的,我們可以對照上述文字說明一步一步跟蹤堆疊和暫存器的變化過程,以便更加準確地理解指令的作用。

再來看一段彙編程式碼,同樣在堆疊為空棧的情況下,執行如下彙編程式碼片段之後,堆疊和暫存器都發生了哪些變化?

1  pushl  $8

2  movl   %esp, %ebp

3  pushl  $8

同樣我們也分析一下這段彙編程式碼每一步都做了什麼動作。首先在堆疊為空棧的情況下EBP和ESP暫存器都指向棧底。

第1行語句是將立即數8壓棧,即堆疊多了一個儲存單元並存了一個立即數8,同時也改變了ESP暫存器。

第2行語句把ESP暫存器的值放到EBP暫存器裡,堆疊空間沒有變化,但EBP暫存器發生了變化。

第3行語句將立即數8壓棧,即堆疊多了一個儲存單元並存了一個立即數8。

讀者會發現,這個例子和上一個例子的實際效果是完全一樣的。

小試牛刀之後,再看下面這段更加複雜一點的彙編程式碼:

1  pushl  $8

2  movl   %esp, %ebp

3  pushl  %esp

4  pushl  $8

5  addl   $4, %esp

6  popl   %esp

這段彙編程式碼同樣首先在堆疊為空棧的情況下EBP和ESP暫存器都指向棧底。

第1行語句是將立即數8壓棧,即堆疊多了一個儲存單元並儲存立即數8,同時也改變了ESP暫存器。

第2行語句是把ESP暫存器的值放到EBP暫存器裡,堆疊空間沒有變化,但EBP暫存器發生了變化。

第3行語句是把ESP暫存器的內容壓棧到堆疊棧頂的儲存單元裡。需要注意的是,pushl指令本身會改變ESP暫存器。“pushl %esp”語句相當於如下兩條指令:

subl $4, %esp

movl %esp, (%esp)

顯然,在儲存ESP暫存器的值到堆疊中之前改變了ESP暫存器,儲存到棧頂的資料應該是當前ESP暫存器的值減4。ESP暫存器的值發生了變化,同時棧空間多了一個儲存單元儲存變化後的ESP暫存器的值。

第4行語句是將立即數8壓棧,即堆疊多了一個儲存單元儲存立即數8,同時也改變了ESP暫存器。

第5行語句是把ESP暫存器的值加4,這相當於堆疊空間收縮了一個儲存單元。 

最後一條語句相當於如下兩條指令:

movl (%esp), %esp

addl $4, %esp

也就是把當前棧頂的資料放到ESP暫存器中,然後又將ESP暫存器加4。這一段程式碼比較複雜,因為ESP暫存器既作為運算元,又被pushl/popl指令在執行過程中使用和修改。

讀者需要仔細分析和思考這段彙編程式碼以理解整個執行過程,本書後續內容會結合C程式碼的函式呼叫和函式返回,來進一步理解這段彙編程式碼中涉及的建立一個函式呼叫堆疊和拆除一個函式呼叫堆疊。

庖丁解牛Linux核心分析

孟寧  婁嘉鵬  劉宇棟 著

本書從理解計算機硬體的核心工作機制(儲存程式計算機和函式呼叫堆疊)和使用者態程式如何通過系統呼叫陷入核心(中斷異常)入手,通過上下兩個方向雙向夾擊的策略,並利用實際可執行程式的反彙編程式碼從實踐的角度理解作業系統核心,然後開始分析Linux核心原始碼,從系統呼叫陷入核心,程序排程與程序切換,最後返回到使用者態程序。

長按二維碼,可以關注我們喲

每天與你分享IT好文。

在“非同步圖書”後臺回覆“關注”,即可免費獲得2000門線上視訊課程

非同步圖書福利送不停

邀請10名好友關注10天直接獲取非同步圖書一本(點選文字獲取活動詳情哦)

點選閱讀原文,購買非同步圖書

閱讀原文