20135213——信息安全系统设计基础第十周学习总结
第八章異常控制流
一、學習目標
1. 了解異常及其種類
2. 理解進程和并發的概念
3. 掌握進程創建和控制的系統調用及函數使用:fork,exec,wait,waitpid,exit,getpid,getppid,sleep,pause,setenv,unsetenv,
4. ?理解數組指針、指針數組、函數指針、指針函數的區別
5. 理解信號機制:kill,alarm,signal,sigaction
6. 掌握管道和I/O重定向:pipe, dup, dup2
?
二、學習資源
1. 教材:第八章《異常控制流》
2. 課程資料:https://www.shiyanlou.com/courses/413?? 實驗九,課程邀請碼:W7FQKW4Y
3. 教材中代碼和習題中代碼運行、思考一下,讀代碼的學習方法見這。
?
三、學習任務
1. 閱讀教材,完成課后練習(書中有參考答案)
2. 考核:練習題把數據變換一下
3. 加分題:課后作業最多兩人一組,互相不能重復,1星題目每人最多加一分,2星題目每人最多加二分,3星題目每人最多加三分,4星題目每人最多加四分。
?
四、學習過程
8.1 異常
從處理器運行開始到結束,程序計數器假設一個序列的值a0a1......an-1,這個控制轉義序列叫做處理器的控制流,異常,就是控制流中的突變,用來響應處理器狀態中的某些變化。
狀態的變化稱為事件,在任何情況下,當處理器檢測到有事件發生時,會通過一張叫做異常表的跳轉表,進行一個間接過程調用到專門處理程序——異常處理程序。當異常處理程序完成之后,根據引起引起異常的事件類型,會發生以下三種情況之一:
- 處理程序將控制返回給當前指令,即事件發生之時正在執行的指令。
- 處理程序將控制返回給如果沒有異常將會執行的下一條指令。
- 處理程序終止被中斷的程序。
異常處理
系統中可能的每種異常都被分配了唯一一個非負整數的異常號,異常表中的條目k中包含異常k的處理程序地址。異常表的起始地址存放在一個叫做異常表基址寄存器的特殊寄存器中。
異常類和過程調用的不同之處:
- 返回地址是當前地址或者下一條指令
- 處理器也會把額外的處理器狀態壓回棧中,在處理程序返回時,重新開始被中斷的程序會需要這些狀態。
- 如果控制從一個用戶程序轉移到內核,那么所有項目都會被壓到內核棧中而不是用戶棧。
- 異常處理程序運行在內核模式下,意味著他們對所有的系統資源擁有完全的訪問權限。
異常的類別
?
1.中斷
中斷是異步發生的,是來自處理器外部的I/O設備的信號的結果。因此是異步的。硬件中斷的異常處理程序通常稱為中斷處理程序。
其余異常類型都是同步發生的,是執行當前指令的結果。這一類指令稱為故障指令。
2.陷阱
陷阱是有意的異常,最重要的用途是在用戶程序和內核之間提供一個向過程一樣的接口,叫做系統調用。
為了允許內核服務的受控訪問,使用“syscall n”指令,跳轉到一個異常處理程序的陷阱,處理程序對參數解碼并調用適當的內核程序。
3.故障
故障由錯誤情況引起,可能能夠被故障處理程序修正。故障發生時,處理器將控制轉移給故障處理程序,若能修正,則將控制返回到引起故障的指令,重新執行;若不能修正,處理程序返回abort例程,終止引起故障的應用程序。
4.終止
終止是不可恢復的致命錯誤造成的結果,通常是硬件錯誤。終止處理程序將控制直接返回給abort例程,直接終止該應用程序。
Linux/A32系統中的異常
Linux/A32故障和終止
- 除法錯誤(異常0):應用試圖除以0,或者除法指令的結果對于目標操作數過大。
- 一般故障保護(異常13):通常因為一個程序引用一個未定義的虛擬存儲區域,或者試圖寫一個只讀文本段。
- 缺頁(異常14):處理程序將磁盤上虛擬存儲器相應頁面映射到物理存儲器的一個頁面,然后重新開始執行這條指令。
- 機器檢查(異常18):在導致故障的指令執行中檢測到致命的硬件錯誤。
Linux/A32系統調用
每個系統調用都對應著唯一的整數號,對應于一個到內核中跳轉表的偏移量。
IA32系統調用是通過一條稱為 int n 的陷阱指令提供的。
C程序通過syscall函數可以直接調用任何系統調用。
所有Linux系統調用都是通過通用寄存器而不是棧傳遞的,%eax包含系統調用號,%ebx、%ecx、%edx、esi%、%edi和%ebp包含最多6個參數。棧指針%esp不能使用,因為當進入內核模式時,內核會覆蓋它。
?
8.2 進程
進程的經典定義:一個執行中的程序的實例。
系統中的每個程序都是運行在某個進程的上下文中的。
上下文:由程序正確運行所需的狀態組成的。
進程提供給應用程序的關鍵抽象:
一個獨立的邏輯控制流:獨占的使用處理器
一個私有的地址空間:獨占的使用存儲器系統
1.邏輯控制流
(1)含義:
一系列的程序計數器PC的值,分別唯一的對應于包含子啊程序的可執行目標文件中的指令,或者是包含在運行時動態鏈接到程序的共享對象中的指令,這個PC值的序列就叫做邏輯控制流。
(2)運行:
進程輪流使用處理器,每個進程執行流的一部分,然后被搶占(暫時掛起)。每個進程執行它的流的一部分,然后被搶占,然后輪到其他進程。但是進程可以向每個程序提供一種假象,好像它在獨占的使用處理器。
(3)示例:
異常處理程序、進程、信號處理程序、線程、Java進程
2.并發流
(1)含義
一個邏輯流的執行在時間上與另一個流重疊。【與是否在同一處理器無關】
這兩個流并發的運行。
(2)幾個概念
并發:多個流并發的執行
多任務:一個進程和其他進程輪流運行(也叫時間分片)
時間片:一個進程執行它的控制流的一部分的每一時間段
(3)并行
兩個流并發的運行在不同的處理機核或者計算機上。
并行流并行的運行,并行的執行。
3.私有地址空間
進程為程序提供的假象,好像它獨占的使用系統地址空間。一般而言,和這個空間中某個地址相關聯的那個存儲器字節是不能被其他進程讀寫的。
4.用戶模式和內核模式
處理器通常是用某個控制寄存器中的一個模式位來提供這種功能的,該寄存器描述了進程當前享有的特權。
當設置了模式位時,進程就運行在內核模式中(超級用戶模式)。
沒有設置模式位時,進程就運行在用戶模式中。
進程從用戶模式變為內核模式的唯一方法是通過中斷、故障或者陷入系統調用這樣的異常實現的。
Linux提供/proc文件系統,允許用戶模式進程訪問內和數據結構的內容。
5.上下文切換
上下文:內核重新啟動一個被搶占的進程所需的狀態
操作系統內核使用上下文切換的較高層形式的異常控制流來實現多任務。
內核為每個進程維持一個上下文。
在進程執行的某些時刻,內核可以決定搶占當前進程,并重新開始一個先前被搶占的進程,成為調度。
由內核中成為調度器的代碼處理的。
使用上下文切換的機制來控制轉移到新的進程
保存當前進程的上下文
恢復某個先前被搶占的進程被保存的上下文
將控制傳遞給這個新恢復的進程
8.3 系統調用錯誤處理
- 當Unix系統級函數遇到錯誤時,它們典型地會返回-1,并設置全局證書變量errno來表示什么出錯了。
?
8.4進程控制
獲取進程ID
#include <sys/types.h>#include <unistd.h>pid_t getpid(void); 返回調用進程的PID pid_t getppid(void);返回父進程的PID(創建調用進程的進程)-
getpid和getppid函數返回一個類型為pid_t的整數值,在Linux系統上它在types.h中被定義為int
創建和終止進程
-
進程總是處于下面三種狀態之一
- 運行
- 停止:被掛起且不會被調度
-
終止:進程永遠停止
-
終止原因:
- 收到一個信號,該信號的默認行為是終止進程
- 從主程序返回
- 調用exit函數
-
-
父進程通過調用fork函數創建一個新的運行子進程:
#include <sys/types.h> #include <unistd.h>pid_t fork(void); - 子進程返回0,父進程返回子進程的PID,如果出錯,則為-1.
-
父進程和新創建的子進程之間最大的區別:
- 它們有不同的PID
-
fork函數只被調用一次,卻返回兩次。
- 一次是在父進程中
- 一次是在新創建的子進程中
- 在父進程中,fork返回子進程的PID
- 在子進程中,fork返回0.
- 子進程的PID總是非零的。
-
fork函數的并發執行
- 父進程和子進程是并發運行的獨立進程
-
fork函數的相同的但是獨立的地址空間
-
fork函數的共享文件
-
調用fork函數n次,產生2的n次方個進程
回收子進程
- 一個終止了但還未被回收的進程稱為僵死進程。
- 如果父進程沒有回收它的僵死子進程就終止了,那么內核就會安排init進程來回收它們。
-
一個進程可以通過調用waitpid函數來等待它的子進程終止或者停止。
- 成功返回子進程PID,如果WNOHANG,返回0,其他錯誤返回-1.
-
判定等待集合的成員
- 如果pid>0,那么等待集合就是一個單獨的子進程,它的進程ID等于pid。
- 如果pid=-1,那么等待集合就是由父進程所有的子進程組成的。
-
修改默認行為
-
可以通過將optioins設置為常量WNOHANG和WUNTRACED的各種組合。
-
WNOHANG:如果等待集合中的任何子進程都還沒有終止,那么就立即返回(返回值為0)。默認的行為是掛起調用進程,直到有子進程終止。
-
WUNTRACED:掛起調用進程的執行,直到等待集合中的一個進程變成已終止或者被停止。返回的PID為導致返回的已終止或被停止子進程的PID。默認的行為是只返回已終止的子進程。
-
WNOHANG|WUNTRACED:i級返回如果等待集合中沒有任何子進程被停止或已終止的子進程。檢查已終止和被停止的子進程時,該選項會有用。
-
-
-
檢查已回收子進程的退出狀態
-
wait.h頭文件定義了結束status參數的幾個宏:
- WIFEXITED:如果子進程通過調用exit或者一個返回正常終止,就返回真。
- WEXXITSTATUS:返回一個正常終止的子進程的退出狀態。只有在WIFEXITED返回為真時,才會定義這個狀態。
- WIFSIGNALED:如果子進程時因為一個未被捕獲的信號終止的,那么就返回真。
- WTERMSIG:返回導致子進程終止的信號的數量。只有在WIFSIGNALED返回為真時,才定義這個狀態。
- WIFSTOPPED:如果引起返回的子進程當前是被停止的,那么就返回真。
- WSTOPSIG:返回引起子進程停止的信號的數量。只有在WIFSTOPPED返回為真時,才定義這個狀態。
-
-
錯誤條件
- 如果調用進程沒有子進程,那么waitpid返回-1,并且設置errno為ECHILD。
- 如果waitpid函數被一個信號中斷,那么它返回-1,并設置errno為EINTR。
wait函數
- 其是waitpid函數的簡單版本
- 調用wait(&status)等價于調用waitpid(-1,&status,0)
讓進程休眠
- sleep函數將一個進程掛起一段指定的時間
- 如果請求的時間量已經到了,sleep返回0,否則返回還剩下的要休眠的秒數。
- pause函數讓調用函數休眠,直到該進程收到一個信號。
加載并運行程序
- execve函數加載并運行可執行目標文件filename,且帶參數列表argv和環境變量列表envp。
- 只有出現錯誤時,execve才會返回到調用程序。
- 調用一次并從不返回。
- getenv函數在環境數據中搜索字符串"name=value",如果找到了,它就返回一個指向value的指針,否則它就返回NULL。
- 如果環境數據包含一個形如“name=oldvalue”的字符串,那么unsetenv會刪除它,而setenv會用newvalue代替oldvalue,但是只有在overwrite非零時才會這樣。如果name不存在,那么setenv就把“name=newvalue”添加到數組中。
?讓進程休眠
1.sleep函數
sleep函數使一個進程掛起一段指定的時間。定義如下:
#include <unistd.h>unsigned int sleep(unsigned int secs);返回值是剩下還要休眠的秒數,如果到了返回0.
2.pause函數
#include <unistd.h>int pause(void);讓調用函數休眠,直到該進程收到一個信號。
?加載并運行程序——execve函數
#include <unistd.h>int execve(const char *filename, const char *argv[], const char *envp[]); 成功不返回,失敗返回-1.execve函數調用一次,從不返回。
- filename:可執行目標文件
- argv:參數列表
- envp:環境列表
新程序開始時:
getnev函數
#include <stdlib.h>char *getenv(const char *name); 若存在則為指向name的指針,無匹配是null在環境數組中搜尋字符串"name=value",如果找到了就返回一個指向value的指針,否則返回null。
setenv和unsetenv函數
#include <stdlib.h>int setenv(const char *name, const char *newvalue, int overwrite); 若成功返回0,錯誤返回-1 void unsetenv(const char *name); 無返回值如果環境數組包含"name=oldvalue"的字符串,unsetenv會刪除它,setenv會用newvalue代替oldvalue,只有在overwrite非零時成立。
如果name不存在,setenv會將"name=newvalue"寫進數組。
※fork函數和execve函數的區別
-
fork函數是創建新的子進程,是父進程的復制體,在新的子進程中運行相同的程序,父進程和子進程有相同的文件表,但是不同的PID
-
execve函數在當前進程的上下文中加載并運行一個新的程序,會覆蓋當前進程的地址空間,但是沒有創建一個新進程,有相同的PID,繼承文件描述符。
?
?
8.5信號
-
Unix信號:更高層的軟件形式的異常允許進程中斷其他進程。
信號術語
-
傳遞一個信號到目的進程的兩個步驟:
- 發送信號
- 接收信號
-
發送信號的原因:
- 內核檢測到一個系統事件
- 一個進程調用了kill函數,顯式的要求內核發送一個信號給目的進程。
-
一個進程可以發送信號給它自己。
-
接收信號:
- 1.忽略
- 2.終止
- 3.執行信號處理程序,捕獲信號
-
待處理信號:
- 只發出沒有被接收的信號
- 任何時刻,一種類型至多只會有一個待處理信號,多的會被直接丟棄
- 一個進程可以選擇性的阻塞接受某種信號,被阻塞仍可以被發送,但是不會被接收
- 一個待處理信號最多只能被接收一次。
- pending:待處理信號集合
-
blocked:被阻塞信號集合。
發送信號——基于進程組
-
進程組
- 每個進程都只屬于一個進程組。
- 進程組ID:正整數
- 一個子進程和他的父進程屬于同一進程組。
- 查看進程組id:getpgrp
- 修改進程組:setpgid
-
用/bin/kill程序發送信號
-
/bin/kill程序可以向另外的進程發送任意的信號,格式是:
- /bin/kill -n m
- n是信號,m是進程或進程組
- 當n>0時,發送信號n到進程m
-
當n<0時,使信號|n|發送到進程組m中的所有進程。
-
-
從鍵盤發送信號
- 在鍵盤輸入ctrl-c會導致一個SIGINT信號被發送到外殼。
- 外殼捕獲該信號,然后發送SIGINT信號到這個前臺進程組中的每個進程。
- 在默認情況下,結果是終止前臺作業。
- 輸入ctrl-z會發送一個SIGTSTP信號到外殼,外殼捕獲這個信號,并發送SIGTSTP信號給前臺進程組中的每個進程。
- 在默認情況下結果時停止前臺作業。
-
用kill函數發送信號
- 進程通過調用kill函數發送信號給其他進程(包括它們自己)
-
用alarm函數發送信號
- 進程可以通過調用alarm函數向它自己發送SIGALRM信號。
-
接收信號
-
信號類型的預定義的默認行為:
- 進程終止
- 進程終止并轉儲存儲器
- 進程停止直到被SIGCONT信號重啟
- 進程忽略該信號
-
signal函數通過下列三種方法來改變和信號signum相關聯的行為:
- 如果handler是SIG_IGN,那么忽略類型為signum的信號。
- 如果handler是SIG_DFL,那么類型為signum的信號行為恢復為默認行為。
- 否則,handler就是用戶定義的函數的地址,這個函數稱為信號處理程序,只要進程接收到一個類型為signum的信號,就會調用這個程序。
- 通過把狐貍程序的抵制傳遞到signal函數從而改變默認行為,稱為設置信號處理程序。
- 調用信號處理程序稱為捕獲信號
- 執行信號處理程序稱為處理信號
-
信號處理問題
* 待處理信號被阻塞 * 帶處理信號不會排隊等待 * 系統調用可以被中斷 * 不可以用信號來對其他進程中發生的事件計數可移植的信號處理
-
Signal包裝函數設置了一個信號處理程序,其信號處理語義如下:
- 只有這個處理程序當前正在處理的那種類型的信號被阻塞。
- 和所有信號實現一樣,信號不會排隊等待。
- 只要可能,被中斷的系統調用會自動重啟。
- 一旦設置了信號處理程序,它就會移至保持,直到Signal帶著handler參數為SIG_IGN或者SIG_DFL被調用。
顯式地阻塞和取消阻塞信號 p517
-
sigprocmask函數改變當前已阻塞信號的集合,具體行為依賴于how值:
- SIG_BLOCK:添加set中的信號到blocked中(blocked = blocked | set)
- SIG_UNBLOCK:從blocked中刪除set的信號(blocked = blocked &~ set)
- SIG_SETMASK:blocked = set
- 如果oldset非空,blocked位向量以前的值會保存在oldset中。
非本地跳轉
-
用戶級的異常控制流形式,通過setjmp和longjmp函數提供。
-
setjump函數在env緩沖區中保存當前調用環境,以供后面longjmp使用,并返回0.
-
調用環境:程序計數器,棧指針,通用目的寄存器
-
longjmp函數從env緩沖區中恢復調用環境,然后觸發一個從最近一次初始化env的setjmp調用的返回。然后setjmp返回,并帶有非零的返回值retval。
-
setjmp函數只被調用一次,但返回多次;
-
longjmp函數被調用一次,但從不返回。
操作進程的工具
- STRACE:打印一個正在運行的程序和他的子程序調用的每個系統調用的痕跡
- PS:列出當前系統中的進程,包括僵死進程
- TOP:打印出關于當前進程資源使用的信息
- PMAP:顯示進程的存儲器映射
轉載于:https://www.cnblogs.com/20135213lhj/p/4986881.html
總結
以上是生活随笔為你收集整理的20135213——信息安全系统设计基础第十周学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英文情侣id257个
- 下一篇: 橙光游戏《模特梦工厂》攻略