攥寫人:於涵 學號:20132119html
( *原創做品轉載請註明出處*)linux
( 學習課程:《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-100程序員
博客連接(前幾回是新浪微博後統一換成博客園):算法
1.反彙編一個簡單的C程序:
http://blog.sina.com.cn/s/blog_e43db01b0102w6ho.html
2.操做系統是如何工做的:
http://blog.sina.com.cn/s/blog_e43db01b0102w6wk.html
3.跟蹤分析Linux內核的啓動過程:
http://blog.sina.com.cn/s/blog_e43db01b0102w7bo.html
4.使用庫函數API和C代碼中嵌入彙編代碼兩種方式使用同一個系統調用:
http://www.cnblogs.com/yuhan20132119/p/5299172.html
5.分析system_call中斷處理過程:
http://www.cnblogs.com/yuhan20132119/p/5322807.html
6.分析Linux內核建立一個新進程的過程:
http://www.cnblogs.com/yuhan20132119/p/5341695.html
7.Linux內核如何裝載和啓動一個可執行程序:
http://www.cnblogs.com/yuhan20132119/p/5371399.html
8.理解進程調度時機跟蹤分析進程調度與進程切換的過程:
http://www.cnblogs.com/yuhan20132119/p/5402435.html
第一章:shell
一、pushl %eax 把eax壓棧到堆棧棧底 即首先把esp減4 esp表示堆棧棧頂 ebp表示堆棧基址 二、popl %eax 把eax從堆棧棧頂取32位,放在寄存器eax中 即首先把棧頂esp的數值放在eax中,再把棧頂加4 三、call 0x12345 調用該地址 即將當前的eip(當前CPU執行命令的指針)壓棧,賦給eip一個新值(CPU下一條執行的指令) 四、ret 即將call時保存的eip還原到eip寄存器,return call以前的那條指令 eip(*)這個*指程序員不能直接修改eip
第二章:框架
cs : eip:老是指向下一條的指令地址 • 順序執行:老是指向地址連續的下一條指令 • 跳轉/分支:執行這樣的指令的時候,cs : eip的值會 根據程序須要被修改 • call:將當前cs : eip的值壓入棧頂,cs : eip指向被 調用函數的入口地址 • ret:從棧頂彈出原來保存在這裏的cs : eip的值,放 入cs : eip中
第三章:tcp
一、中斷上下文的切換:保存現場和恢復現場編輯器
二、進程上下文的切換函數
使用gdb跟蹤調試內核學習
輸入如下命令
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
-S表示:在CPU初始化以前,凍結CPU
-s表示在:1234端口上建立一個tcp接口
第四章:
CPU每條指令的讀取都是經過cs:eip(代碼段選擇寄存器:偏移量寄存器)這兩個寄存器,由硬件完成判斷。
內核態時,cs與eip的值能夠訪問任意地址
用戶態時,cs與eip只能夠訪問0x00000000—0xbfffffff的地址空間
系統調用的三層皮
一層皮:API
二層皮:中斷向量對應的中斷服務程序
三層皮:系統調用對應的不少不一樣種類的服務程序
第五章:
系統調用在內核代碼中的處理過程
系統調用在內核代碼中的工做機制和初始化
整個系統調用過程當中,時間很重要。
以system_call爲例,int 0x80指令與systemcall是經過中斷向量聯繫起來的,而API和對應的sys是經過系統調用號聯繫起來的
用戶態時,系統調用xyz()使用int 0x80,它對應調用system_call
第六章:
進程管理 內存管理 文件系統
0號進程是手工寫入它的進程描述符數據,1號進程的建立是複製了0號進程的PCB,根據1號進程的須要,修改PID,加載一個init可執行程序。
創建一個新進程在內核中的執行過程
fork、vfork和clone三個系統調用均可以建立一個新進程,並且都是經過調用do_fork來實現進程的建立。
Linux經過複製父進程來建立一個新進程,那麼這就給咱們理解這一個過程提供一個想象的框架:
複製一個PCB——task_struct
要給新進程分配一個新的內核堆棧
要修改複製過來的進程數據,好比pid、進程鏈表等等都要改改,見copy_process內部。
從用戶態的代碼看fork();函數返回了兩次,即在父子進程中各返回一次,父進程從系統調用中返回比較容易理解,子進程從系統調用中返回。那它在系統調用處理過程當中的哪裏開始執行的呢?這就涉及子進程的內核堆棧數據狀態和task_struct中thread記錄的sp和ip的一致性問題,這是在哪裏設定的?copy_thread in copy_process
第七章:
C代碼—>預處理—>彙編代碼—>目標代碼—>可執行文件
ELF中三種目標文件
一個可重定位(relocatable)文件保存着代碼和適當的數據,用來和其餘的object文件一塊兒來建立一個可執行文件或者是一個共享文件。(主要是.o文件)
一個可執行(executable)文件保存着一個用來執行的程序;該文件指出了exec(BA_OS)如何來建立程序進程映象。
一個共享object文件保存着代碼和合適的數據,用來被下面的兩個連接器連接。第一個是鏈接編輯器[請參看ld(SD_CMD)],能夠和其餘的可重定位和共享object文件來建立其餘的object。第二個是動態連接器,聯合一個可執行文件和其餘的共享object文件來建立一個進程映象。(主要是.so文件)
正常的系統調用:陷入到內核態,返回到用戶態,執行系統調用的下一條指令。
fork:進入到內核態,兩次返回:第一次返回到父進程的位置,繼續執行。第二次,在子進程中從ret_from_fork開始執行而後返回用戶態。
execve:當前的可執行程序執行到execve時,陷入到內核態,用execve加載的可執行文件將當前的可執行程序覆蓋掉,當execve系統調用返回時,返回的不是原來的系統調用,而是新的可執行程序的執行起點,即main函數的位置。
第八章:
進程分類
第一種分類
I/O-bound:等待I/O
CPU-bound:大量佔用CPU進行計算
第二種分類
交互式進程(shell)
實時進程
批處理進程
調度策略:是一組規則,它們決定何時以怎樣的方式選擇一個新進程運行
Linux的調度基於分時和優先級。
Linux的進程根據優先級排隊
根據特定的算法計算出進程的優先級,用一個值表示
這個值表示把進程如何適當的分配給CPU
Linux進程中的優先級是動態的
調度程序會根據進程的行爲週期性地調整進程的優先級
例如:
較長時間未被分配到cpu的進程,一般↑
已經在cpu上運行了較長時間的進程,一般↓
內核中的調度算法相關代碼使用了相似OOD中的策略模式
分析schedule函數
schedule()函數選擇一個新的進程來運行,並調用context_switch進行上下文的切換,這個宏調用switch_to來進行關鍵上下文切換
next = pick_next_task(rq, prev);//進程調度算法都封裝這個函數內部
context_switch(rq, prev, next);//進程上下文切換
switch_to利用了prev和next兩個參數:prev指向當前進程,next指向被調度的進程