1、《Linux內核分析》總結linux
(一)計算機是如何工做的git
1.存儲程序計算機工做模型程序員
2. X86CPU的寄存器:通用寄存器、段寄存器、標誌寄存器等。算法
3.計算機的彙編指令安全
(1)movl指令:服務器
注意:AT&T彙編格式與Intel彙編格式略有不一樣,Linux內核使用的是AT&T彙編格式。網絡
(2)其餘指令數據結構
堆棧是向下增加的,有一個基址ebp指向堆棧棧底併發
注意:*是指這些指令是僞指令,程序員不能直接修改這些,即eip寄存器不能被直接修改,只能經過特殊指令間接修改。框架
4.將C代碼編譯成彙編代碼
(1)函數調用堆棧是由邏輯上多個堆棧疊加起來的
(2)函數的返回值默認使用eax寄存器存儲返回給上一級函數
(3)使用命令編譯成彙編代碼:gcc –S –o main.s main.c -m32
(二)操做系統是如何工做的
1. 堆棧——堆棧式C語言程序運行時必須的一個記錄調用路徑和參數的空間。包括:函數調用框架;傳遞參數;保存返回地址(如eax);提供局部變量空間
2. 堆棧寄存器:esp 堆棧指針和ebp 基址指針(在C語言中表示當前函數調用基址)
3. 堆棧操做:push棧頂指針減小4個字節(32位)和pop 棧頂指針增長4個字節
4. 參數傳遞與局部變量
(1)創建框架(至關於 call 指令)
push %ebp
movl %esp,%ebp
(2)拆除框架(至關於 ret 指令)
movl %ebp,%esp
pop %ebp
函數返回時必定會拆除框架,創建和拆除是一一對應的。
(3)傳遞參數
在創建子函數的框架以前,局部變量的值保存在調用者堆棧框架中,因此在子函數框架創建以前能夠採用變址尋址的方式將變量值入棧。
!函數的返回值經過eax寄存器傳遞
(三)構造一個簡單的Linux系統MenuOS
1. 計算機三個法寶:存儲程序計算機、函數調用堆棧、中斷
2. 操做系統兩把寶劍:中斷上下文的切換(保存現場和恢復現場)以及進程上下文的切換
3. 總結:rest_init爲0號進程,一直存在。0號進程建立了1號進程kernel_init,還建立了其餘的服務線程。即道生一(start_kernel....cpu_idle),一輩子二(kernel_init和kthreadd),二生三(即前面0、1和2三個進程),三生萬物(1號進程是全部用戶態進程的祖先,2號進程是全部內核線程的祖先)。
Linux在無進程概念的狀況下將一直從初始化部分的代碼執行到start_kernel,而後再到其最後一個函數調用rest_init。
從rest_init開始,Linux開始產生進程,由於init_task是靜態製造出來的,pid=0,它試圖將從最先的彙編代碼一直到start_kernel的執行都歸入到init_task進程上下文中。在rest_init函數中,內核將經過下面的代碼產生第一個真正的進程(pid=1)。而後init_task變爲一個idle task,init_idle函數的第一個參數current就是&init_task,在init_idle中將會把init_task加入到cpu的運行隊列中,這樣當運行隊列中沒有別的就緒進程時,init_task(也就是idle task)將會被調用,它的核心是一個while(1)循環,在循環中它將會調用schedule函數以便在運行隊列中有新進程加入時切換到該新進程上。
(四)扒開系統調用的三層皮
1.用戶態和內核態
Intel x86 CPU有四種不一樣的執行級別0—3,Linux只是用了期中的0級和3級分別表示內核態和用戶態。
2.理解中斷處理的完整過程:中斷信號(int指令)完成:保存cs:eip的值、當前堆棧段棧頂和當前標誌,同時加載了當前中斷信號或是系統調用的相關聯的中斷服務入口到cs:eip裏面,把當前對戰段和esp也加載到CPU裏面。
SAVE ALL完成後若沒有發生調度,則接着執行RESTORE_ALL;若發生進程調度,則當前的狀態會暫時的保存在系統裏面,當下一次發生進程調度切換到當前進程時再接着執行完畢。
3. 系統調用的三個層次
系統調用的三個層次依次是:xyz函數(API)、system_ call(中斷向量)和 sys_ xyz(中斷服務程序)。
4. 總結:
在Linux系統中是經過激活0x80中斷來觸發系統調用的,須要調用的系統調用號實現賦值給eax存儲器,若是有傳入參數可賦值給ebx寄存器,若是多於1個則按順序賦值給ebx、ecx、edx、esi、edi、ebp,若是超過6個則經過指針變量指向另外一片堆棧區,若是無參數傳入則賦值爲0。
雖然Intel X86 CPU有4種執行級別0~3,可是在Linux系統中僅使用了0和3級,分別表示內核態和用戶態。一些涉及底層、硬件、核心的操做必須在內核態下才容許執行,爲操做系統程序和驅動程序專享,普通程序僅能執行在用戶態下。若是普通程序須要涉及內核態的操做,就須要經過系統調用來實現。這樣作的好處是屏蔽平臺相關操做下降了軟件開發難度,加強了系統安全性,使程序具備更好的移植性(Linux系統及其餘Unix系統遵循統一標準,系統調用基本同樣)。
(五)進程額管理和進程的建立
操做系統內核三大功能:進程管理(核心)、內存管理和文件系統。
1.Linux經過複製父進程來建立一個新進程,經過調用do_fork來實現。
2.Linux爲每一個新建立的進程動態地分配一個task_struct結構。
3.爲了把內核中的全部進程組織起來,Linux提供了幾種組織方式,其中哈希表和雙向循環鏈表方式是針對系統中的全部進程(包括內核線程),而運行隊列和等待隊列是把處於同一狀態的進程組織起來。
4.fork()函數被調用一次,但返回兩次。
(六)可執行程序的裝載
1.可執行程序過程:先預處理.cpp,在編譯成彙編代碼.s到目標代碼.o,再連接成可執行文件,加載到內存中執行。
2.可執行文件加載到內存中開始執行的第一行代碼,0X8048X00爲實際的入口。
3. 動態連接分爲可執行程序裝載時動態連接和運行時動態連接。
4. do_ execve調用do_ execve_ common,do_ execve_ common主要依靠exec_ binprm,其中重要的函數:search_binary_handler(bprm)。
(七)進程的切換和系統的通常執行過程
1. 進程調度算法——每一個進程對CPU、I/O等資源需求不同。
2. 進程調度(schedule()函數實現)的時機:
注意:用戶態進程只能被動調度,內核線程是隻有內核態沒有用戶態的特殊進程。
3. 操做系統(任何計算機系統都包含一個基本的程序集合)有兩個目的:
4. 本週主要理解Linux中進程調度與進程切換過程。進程調度是按必定的策略動態地把處理機分配給處於就緒隊列中的某一個進程,以使之執行。而進程切換是從正在運行的進程中收回處理器,而後再使待運行進程來佔用處理器。實質上就是把進程存放在處理器的寄存器中的中間數據找個地方存起來,從而把處理器的寄存器騰出來讓其餘進程使用。
2、《Linux內核設計與實現》總結
(一)第一章 Linux內核簡介
Linux系統的基礎是內核、C庫、工具集和系統的基本工具。
1.操做系統:整個系統中負責完成最基本功能和系統管理的部分。
2.內核(操做系統的內在覈心,通常處於系統態):
由響應中斷的中斷服務程序;管理多個進程,分享處理器時間調度程序;管理進程地址空間的內存管理程序;網絡、進程間通訊等系統服務程序組成。
3.內核空間:系統態和被保護起來的內存空間
4.系統調用:應用程序與內核通訊。應用程序經過系統調用界面陷入內核是應用程序完成工做的基本行爲方式。
6.Unix內核一般須要硬件系統提供頁機制(MMU)以管理內存,這樣能夠增強對內存空間的保護,並能夠保證每一個進程都運行於不一樣的虛地址空間上。
7.單內核與微內核比較:
(1)單內核——以單個靜態二進制文件形式存放於磁盤中,全部內核服務在一個大內核地址空間上運行。
特色:內核能夠直接調用函數,簡單並性能高。但一個功能的崩潰會致使整個內核沒法使用。
(2)微內核——內核按功能被劃分紅各個獨立的過程。每一個過程叫作一個服務器。全部服務器獨立並運行在本身的地址空間上。
特色:經過消息傳遞處理爲內核通訊,採用進程間通訊(IPC)機制。安全。一個服務器失效不會影響其餘服務器。內核各個服務之間的調用涉及進程間的通訊,比較複雜且效率低。
8.Linux內核總結:
爲單內核,但具有微內核的一些特徵:模塊化設計、搶佔式內核、支持內核線程、動態裝載內核模塊。同時避微內核設計上的性能缺陷:讓全部事情運行在內核態,直接調用函數,無需消息傳遞。支持動態加載內核模塊;支持對稱多處理(SMP);內核能夠搶佔(preemptive),容許內核運行的任務有優先執行的能力;不區分線程和進程;提供具備設備類的面向對象的設備模型、熱插拔事件,以及用戶空間的設備文件系統(sysfs)。
(二) 第二章 從內核出發
1.使用Git(管理內核源碼的分佈式控制系統)獲取最新提交到Linus版本樹的一個副本:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
2.安裝內核源代碼
兩種形式:GNU zip(gzip)(運行:$ tar xvzf linux-x.y.z.tar.gz)和bzip2(運行:$ tar xvjf linux-x.y.z.tar.bz2)。
3. 配置內核(關於make與config)
配置編譯過程:
• make config:遍歷全部配置項,並讓用戶選擇
• make deconfig:基於默認的配置
• make oldconfig:先將/boot目錄下的配置文件寫進.config文件中,採用的是註釋的形式寫進新增長的功能。
• zcat /proc/config.gz > .config:配置選項CONFIG_IKCONFIG_PROC把完整的壓縮過的內核配置文件存放在/
proc/config.gz中,再次編譯時能夠方便地克隆當前的配置。
• make:默認的Makefile自動化編譯。
4.減小編譯的垃圾信息;衍生多個編譯做業
5.安裝新內核——把全部已編譯的模塊安裝到正確的主目錄/lib/modules下:% make modules_install。編譯時在內核代碼樹的根目錄下建立一個System.map文件(符號對照表),用來將內核符號與它們的起始地址對應起來。
6.同步和併發
• Linux是搶佔多任務操做系統
• 內核支持對稱多處理器系統(SMP)
• 中斷是異步到來的
• Linux內核能夠搶佔
經常使用的解決競爭的辦法是自旋鎖和信號量
(三) 第三章——進程管理
1.進程就是處於執行期的程序(目標碼存放在某種存儲介質上),不只侷限於一段可執行程序代碼,還包含其餘資源,如打開的文件、掛起的信號、內核內部數據等。提供兩種虛擬機制:虛擬處理器和虛擬內存。
2.線程(執行線程)是在進程中活動的對象,擁有獨立的程序計數器、進程棧和一組進程寄存器。注意:內核調度的是線程而不是進程!
3.系統調用經過複製一個現有進程來建立一個全新的進程。調用fork()的進程爲父進程,新產生的進程稱爲子進程。fork()系統調用從內和返回兩次:一次回到父進程,一次回到新產生的子進程。
4. 共有五種進程狀態:
5.進程建立:寫時拷貝——fork()——vfork()
6.進程終結:刪除進程描述符——孤兒進程形成的進退維谷
(四)第四章——進程調度
1.多任務系統分爲兩類:非搶佔式多任務和搶佔式
2.策略:調度策略一般在兩個矛盾的目標中間尋找平衡:進程響應迅速(響應時間短)和最大系統利用率(高吞吐量)。
3. 進程優先級
在某些系統中,優先級高的進程使用的時間片也比較長。調度程序老是選擇時間片未用盡並且優先級最高的進程運行。用戶和系統均可以經過設置進程的優先級來影響系統的調度。
Linux採用了兩種不一樣的優先級範圍——nice值和實時優先級值。
(1) nice值,範圍是-20到19,數值越大優先級越低,默認值爲0。Linux中,nice值則表明時間片的比例。能夠經過ps-el命令查看系統中的進程列表,結果中標記NI的一列就是進程對應的nice值。
(2) 實時優先級值,默認0到99,數值越大優先級越高。任何實時進程的優先級都高於普通的進程。
4.公平調度——CFS中,任何進程所得到的處理器時間是由它本身和其餘全部可運行進程nice值的相對差值決定。任何nice值對應的絕對時間是處理器的使用比。
5.調度的實現——CFS相關代碼四個組成部分:時間記帳、進程選擇、調度器入口和睡眠和喚醒。
6.用戶搶佔(會檢查need_ resched標誌)發生時機:
7.內核搶佔發生時機:
8.實時調度策略
linux 提供兩種實時調度策略SCHED_FIFO和SCHED_RR。
這兩種算法實現的都是靜態優先級。Linux實時調度算法是軟實時工做方式——內核調度進程,儘可能使進程在它的限定時間到來前運行,但內核不能保證可以總能知足。
實時優先級範圍是0到MAX_RT_PRIO減1。默認狀況下,MAX_RT_PRIO爲100,nice值從-20到19直接對應的是100到139的實時優先級範圍。
(五)第五章——系統調用
重點——Linux系統調用的規則和實現方法。
1.如何定義一個系統調用:asmlinkage long sys_getpid(void)
2.Linux系統調用執行快,兩個緣由:
3.通知內核的機制是靠軟中斷實現的
4.x86-32系統中,參數傳遞時ebx,ecx,edx,esi,edi按順序存放前五個參數。給用戶空間的返回值也經過寄存器傳遞。在x86系統上,它存放在eax寄存器中。
5.系統調用上下文
• 內核在執行系統調用的時候處於進程上下文。
• 在進程上下文中,內核能夠休眠而且能夠被搶佔。
• 當系統調用返回的時候,控制權仍在system_call()中,它最終會負責切換到用戶空間,並讓用戶進程繼續執行下去。
(六)第七章 連接
1.靜態連接:連接器將重定位目標文件(relocatable object files)組合成一個可執行目標文件。cpp(c previous processor,C預處理器);ccl(C編譯器);as(彙編器)。
爲了建立靜態連接,連接器完成兩個主要任務:
2.目標文件有三種形式:
3.重定位由兩步組成:
4.注意:靜態連接與動態連接的區別——靜態連接是把程序所須要的庫代碼和數據拷貝和嵌入到引用它們的可執行文件中;而動態連接是全部引用該庫的可執行文件文件共享這個.so(dll)文件中的代碼和數據。
5.動態連接器經過執行下面的重定位完成連接任務:
學習感想與體會:
從這學期還沒開學開始學習雲課堂《Linux內核分析》,跟着孟老師一步一步瞭解Linux內核,到如今半個學期已通過去,又對課本《Linux內核設計與實現》的一些章節,搭配着視頻進行學習鞏固。時間感受過得很快。但同時也學到了很多知識。
首先,經過這門課的學習,加深了我對操做系統理論的理解,知道了Linux系統是如何工做的,如何經過代碼閱讀、調試去跟蹤驗證Linux系統的運行機制。其次,Linux做爲一個極其成功的操做系統,其內核紛繁複雜、博大精深,我我的學習起來也是至關困難。雖然完成了網課、看了課本,孟老師也講得不錯,但我仍是感受本身剛剛開始學習,並且須要在深刻挖掘的東西還有不少不少。
經過半個學期的學習,我認爲重要的不是學習到了多少內核代碼(其實也很重要);但更重要重要的是學習方法,即從何處着手學習Linux內核,例如:如何調試內核、如何看懂內核中的彙編代碼,如何分析系統調用等。總之,學習尚未結束,還有半個學期,繼續加油~