Linux內核分析(心得篇)

Linux 內核分析——學習心得

經過這段時間的學習,我對linux的內核有了大致的瞭解。linux內核是個龐大的操作系統代碼,想要真正的弄清楚透徹決非一日之功,還必須循序漸進、持之以恆,可謂是任重而道遠。但是俗話說的好——“師傅領進門,修行看個人”,我們已經不再是一無所知的小白,我們見識到了一個操作系統內核的複雜,也對其中部分關鍵代碼進行理解、分析,雖然這部分相對整個內核來說不過九牛一毛,但這也教會了我們以後如何學習內核的方法。

當我們首次接觸計算機,發現它可以聽歌、看視頻、聊天、玩遊戲等等,一定會爲它的強大,甚至是無所不能所折服。我們肯定會想:爲什麼這麼神奇,怎麼辦到的?於是,有了第一個問題:

計算機是如何工作的?
其實很簡單,大家都知道‘死循環’這個概念吧,實際上計算機cpu開機啓動以後都會處於這樣一個狀態——等待用戶任務。當用戶有任務時(中斷過程),就會提交給cpu,cpu暫停當前的狀態,然後去執行這個任務,執行後又返回這個等待狀態,當有多個任務時,就每個任務執行一小段時間,因爲時間間隔太短,我們察覺不出來,所以給我們的感覺就是一直在運行。上面只是個簡單的描述,忽略了許多的細節,但總的來說是這樣一個過程。
計算機工作的三大法寶:
(1)存儲程序計算機工作模型,計算機系統最最基礎性的邏輯結構,用於保存cpu執行的指令;
(2)函數調用堆棧,高級語言得以運行的基礎,只有機器語言和彙編語言的時候堆棧機制對於計算機來說並不那麼重要,但有了高級語言及函數,堆棧成爲了計算機的基礎功能;
(3)中斷,多道程序操作系統的基點,沒有中斷機制程序只能從頭一直運行結束纔有可能開始運行其他程序。
下面我們說說,計算機開機啓動的過程。
當我們按下電源鍵的那一刻起,cpu首先會執行固件fireware(COMS/BIOS)裏面的內容,進行加電自檢POST,主要檢查硬件的好壞,對CPU、主板、內存、軟硬盤子系統、顯示子系統(包括顯示緩存)、串並行接口、鍵盤、CD-ROM光驅等檢測。如果都沒問題,cpu就會讀取硬盤第0號柱面第0號磁道的第一個扇區MBR(main boot record),把它加載到內存中,然後執行這段代碼,也叫引導程序(BootLoad),它會引導操作系統內核,實現內核的初始化。初始化包括加載驅動程序,驅動硬件;然後掛載文件系統;最後啓動init進程,開啓相關的服務。

操作系統是如何工作的?
當開機以後,在登錄界面輸入用戶名密碼登錄,就進入了操作系統的界面。實際上操作系統也是一個程序,只不過它的功能非常齊全,實現的任務比較多,因此代碼十分複雜龐大。但既然它也是一個程序,而且linux系統的源代碼都是由C和彙編組成的,那麼它也少不了編譯、鏈接、運行的過程。因此對於操作系統我們可以從一般到特殊,先了解普通程序是如何執行的。
1

源代碼首先經過彙編,然後編譯,再鏈接,形成可執行文件,最後加載到內存交給cpu執行。我們可以想象操作系統也是這樣一個流程,只不過它的文件更多,編譯鏈接時間要更長,總之,操作系統也是一個程序,它之所以神祕,是因爲我們還沒有對它真正的知根知底。

初探Linux內核源代碼
瞭解內核源碼的目錄結構,大致瞭解每個目錄的作用,以及初始化階段做了那些事情,執行的流程等等。

中斷和系統調用
中斷(廣義)是指改變處理器執行指令的順序,通常與cpu芯片內部或外部硬件電路產生的電信號相對應。Intel x86系列微機共支持256種向量中斷,爲使處理器較容易地識別每種中斷源,將它們從0到256編號,即賦以一箇中斷類型碼n,Intel把這個8位的無符號整數叫做一個向量,因此,也叫中斷向量。所有256種中斷可分爲兩大類:異常和中斷。異常又分爲故障(Fault)和陷阱(Trap),它們的共同特點是既不使用中斷控制器,又不能被屏蔽。中斷又分爲外部可屏蔽中斷(INTR)和外部非屏蔽中斷(NMI),所有I/O設備產生的中斷請求(IRQ)均引起屏蔽中斷,而緊急的事件(如硬件故障)引起的故障產生非屏蔽中斷。
非屏蔽中斷的向量和異常的向量是固定的,而屏蔽中斷的向量可以通過對中斷控制器的編程來改變。Linux對256個向量的分配如下:
• 從0~31的向量對應於異常和非屏蔽中斷。
• 從32~47的向量(即由I/O設備引起的中斷)分配給屏蔽中斷。
• 剩餘的從48~255的向量用來標識軟中斷。Linux只用了其中的一個(即128或0x80向量)用來實現系統調用。當用戶態下的進程執行一條int 0x80彙編指令時,CPU就切換到內核態,並開始執行system_call( )內核函數。

系統調用是一種中斷,中斷號爲128(0x80)。通過int 0x80指令,就可以調用。system_call函數(實際上是彙編代碼)是linux中所有系統調用的入口點,每個系統調用至少有一個參數,即由eax傳遞的系統調用號,其他參數依次由ebx,ecx,edx,esi,edi,ebp傳入。
寄存器傳遞參數具有如下限制:
• 1)每個參數的長度不能超過寄存器的長度,即32位
• 2)在系統調用號(eax)之外,參數的個數不能超過6個(ebx,ecx,edx,esi,edi,ebp)

系統調用運行機制
系統調用的執行過程:
1、程序調用libc庫中封裝的系統調用函數。
2、調用中斷int 0x80 陷入內核。
3、在內核中執行system_call函數(實際上是一段彙編代碼),將系統調用號(eax)和可以所有相關寄存器保存到內核堆棧中(由SAVE_ALL完成),然後根據系統調用號在系統調用表中查找到對應的系統調用服務例程。
4、執行該服務例程。
5、執行完畢後,轉入ret_from_sys_call 例程,從系統調用返回

進程的描述與創建
進程是程序執行的一個實例,它是最小的系統資源分配基本單元,在Linux內核代碼中,常把進程稱爲任務(task)或線程(thread)。也就是說在linux中沒有線程的概念,有的只是輕量級進程(相當於線程)。
對於多任務處理的操作系統而言,通常系統上都會運行着多個進程(任務),爲了管理進程,系統必須對每個進程所做的事情進行詳細地描述。在linux系統中,進程描述符是由內核定義的一個task_struct類型數據結構,它在/include/linux/sched.h文件中定義,內容非常複雜,由四百多行的c代碼組成。它包含了進程的所有信息,包括:進程狀態、進程內核堆棧、進程標誌符、優先級、進程鏈表、內存管理、進程標識符、線程組標識符、父子進程、兄弟進程、該進程中對應cpu相關寄存器信息、文件系統、相關信號及處理等等。
在linux中,fork(),vfork(),clone都可以創建一個新進程,並且它們都是通過do_fork()函數(文件路徑:linux-3.18.6/kernel/fork.c)實現的。一個新的進程創建的時候,從用戶態來看,fork語句的下一條語句即爲子進程執行的開始;從內核態看,子進程的執行從ret_from_fork(文件路徑:/arch/x86/kernel/entry_32.S)處開始。

如何裝載和啓動一個可執行程序
linux系統中,可執行文件的格式爲elf(Executable and Linking Format)格式。它有三種類型:
(1)可重定位文件
也就是通常稱的目標文件,後綴爲.o。鏈接器將它作爲輸入,經鏈接處理後,生成一個可執行的對象文件 (Executable file) 或者一個可被共享的對象文件。
(2)共享文件
這些就是所謂的動態庫文件,也即 .so 文件。如果拿前面的靜態庫來生成可執行程序,那每個生成的可執行程序中都會有一份庫代碼的拷貝。如果在磁盤中存儲這些可執行程序,那就會佔用額外的磁盤空間;另外如果拿它們放到Linux系統上一起運行,也會浪費掉寶貴的物理內存。如果將靜態庫換成動態庫,那麼這些問題都不會出現。
(3)可執行文件

execve函數用於執行可執行文件,根據指定的文件名找到可執行文件,並用它來取代調用進程的內容,換句話說,就是在調用進程內部執行一個可執行文件。這裏的可執行文件既可以是二進制文件,也可以是任何Linux下可執行的腳本文件。

進程調度與切換
爲了控制進程的執行,內核必須有能力掛起正在CPU上執行的進程,並恢復以前掛起的某個進程的執行,這叫做進程切換、任務切換、上下文切換;掛起正在CPU上執行的進程,與中斷時保存現場是不同的,中斷前後是在同一個進程上下文中,只是由用戶態轉向內核態執行;
進程上下文包含了進程執行需要的所有信息:
(1) 用戶地址空間:包括程序代碼,數據,用戶堆棧等
(2) 控制信息:進程描述符,內核堆棧等
(3) 硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不同)

最一般的情況:正在運行的用戶態進程X切換到運行用戶態進程Y的過程
(1)正在運行的用戶態進程X
(2)發生中斷——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
(3) SAVE_ALL //保存現場
(4) 中斷處理過程中或中斷返回前調用了schedule(),其中的switch_to做了關鍵的進程上下文切換
(5)在標號1之後開始運行用戶態進程Y(這裏Y曾經通過以上步驟被切換出去過因此可以從標號1繼續執行)
(6) restore_all //恢復現場
(7) iret —— pop cs:eip/ss:esp/eflags from kernel stack
(8)繼續運行用戶態進程Y

以上就是這段時間學習linux內核的個人心得。That is all!Thank you!

=========== 王傑 原創作品轉載請註明出處==============
《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章