ICS計(jì)算機(jī)基礎(chǔ)教學(xué)課件第七章異??刂屏鱛第1頁
ICS計(jì)算機(jī)基礎(chǔ)教學(xué)課件第七章異常控制流_第2頁
ICS計(jì)算機(jī)基礎(chǔ)教學(xué)課件第七章異??刂屏鱛第3頁
ICS計(jì)算機(jī)基礎(chǔ)教學(xué)課件第七章異常控制流_第4頁
ICS計(jì)算機(jī)基礎(chǔ)教學(xué)課件第七章異??刂屏鱛第5頁
已閱讀5頁,還剩66頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第七章異常控制流

CPU控制流的概念

進(jìn)程上下文切換

異常和中斷的基本概念

異常和中斷的響應(yīng)和處理異??刂屏髦饕虒W(xué)目標(biāo)使學(xué)生了解程序執(zhí)行過程中正常的控制流和異常控制流的區(qū)別了解在較低層次上如何實(shí)現(xiàn)異??刂屏鞒醪嚼斫庥布绾魏筒僮飨到y(tǒng)協(xié)調(diào)工作,從而為將來理解和掌握操作系統(tǒng)核心內(nèi)容打下良好基礎(chǔ)。主要教學(xué)內(nèi)容CPU控制流、異常控制流進(jìn)程和進(jìn)程上下文切換異常和中斷的基本概念異常和中斷的響應(yīng)和處理異??刂屏鞣忠韵聝蓚€部分介紹第一講:進(jìn)程與進(jìn)程的上下文切換CPU的控制流、異常控制流程序和進(jìn)程、引入進(jìn)程的好處邏輯控制流和物理控制流進(jìn)程與進(jìn)程的上下文切換程序的加載和運(yùn)行第二講:異常和中斷異常和中斷的基本概念異常和中斷的響應(yīng)、處理IA-32/Linux下的異常/中斷機(jī)制回顧:程序的機(jī)器級表示與執(zhí)行intsum(inta[],unsignedlen){inti,sum=0;for(i=0;i<=len–1;i++) sum+=a[i];returnsum;}sum:….L3:…movl-4(%ebp),%eaxmovl12(%ebp),%edxsubl$1,%edxcmpl%edx,%eaxjbe .L3…程序的正常執(zhí)行順序有哪兩種?(1)按順序取下一條指令執(zhí)行(2)通過CALL/RET/Jcc/JMP等指令跳轉(zhuǎn)到轉(zhuǎn)移目標(biāo)地址處執(zhí)行CPU所執(zhí)行的指令的地址序列稱為CPU的控制流,通過上述兩種方式得到的控制流為正??刂屏?。程序始終按正??刂屏鲌?zhí)行嗎?異??刂屏鰿PU會因?yàn)橛龅絻?nèi)部異?;蛲獠恐袛嗟仍蚨驍喑绦虻恼?刂屏?,轉(zhuǎn)去執(zhí)行操作系統(tǒng)提供的針對這些特殊事件的處理程序。由于某些特殊情況引起用戶程序的正常執(zhí)行被打斷所形成的意外控制流稱為異常控制流(ExceptionalControlofFlow,ECF)。異??刂屏鞯男纬稍颍簝?nèi)部異常(缺頁、越權(quán)、越級、整除0、溢出等)外部中斷(Ctrl-C、打印缺紙、DMA結(jié)束等)進(jìn)程的上下文切換(發(fā)生在操作系統(tǒng)層)一個進(jìn)程直接發(fā)送信號給另一個進(jìn)程(發(fā)生在應(yīng)用軟件層)發(fā)生在硬件層本章主要介紹發(fā)生在OS層和硬件層的異常控制流“程序”和“進(jìn)程”進(jìn)程是OS對CPU執(zhí)行的程序的運(yùn)行過程的一種抽象。進(jìn)程有自己的生命周期,它由于任務(wù)的啟動而創(chuàng)建,隨著任務(wù)的完成(或終止)而消亡,它所占用的資源也隨著進(jìn)程的終止而釋放。一個可執(zhí)行目標(biāo)文件(即程序)可被加載執(zhí)行多次,也即,一個程序可能對應(yīng)多個不同的進(jìn)程。例如,用word程序編輯一個文檔時(shí),相應(yīng)的用戶進(jìn)程就是winword.exe,如果多次啟動同一個word程序,就得到多個winword.exe進(jìn)程,處理不同的數(shù)據(jù)。程序(program)指按某種方式組合形成的代碼和數(shù)據(jù)集合,代碼即是機(jī)器指令序列,因而程序是一種靜態(tài)概念。進(jìn)程(process)指程序的一次運(yùn)行過程。更確切說,進(jìn)程是具有獨(dú)立功能的一個程序關(guān)于某個數(shù)據(jù)集合的一次運(yùn)行活動,因而進(jìn)程具有動態(tài)含義。同一個程序處理不同的數(shù)據(jù)就是不同的進(jìn)程進(jìn)程的概念操作系統(tǒng)(管理任務(wù))以外的都屬于“用戶”的任務(wù)。計(jì)算機(jī)處理的所有“用戶”的任務(wù)由進(jìn)程完成。為強(qiáng)調(diào)進(jìn)程完成的是用戶的任務(wù),通常將進(jìn)程稱為用戶進(jìn)程。計(jì)算機(jī)系統(tǒng)中的任務(wù)通常就是指進(jìn)程。例如,Linux內(nèi)核中通常把進(jìn)程稱為任務(wù),每個進(jìn)程主要通過一個稱為進(jìn)程描述符(processdescriptor)的結(jié)構(gòu)來描述,其結(jié)構(gòu)類型定義為task_struct,包含了一個進(jìn)程的所有信息。所有進(jìn)程通過一個雙向循環(huán)鏈表實(shí)現(xiàn)的任務(wù)列表(tasklist)來描述,任務(wù)列表中每個元素是一個進(jìn)程描述符。IA-32中的任務(wù)狀態(tài)段(TSS)、任務(wù)門(taskgate)等概念中所稱的任務(wù),實(shí)際上也是指進(jìn)程。

回顧:Linux將虛存空間組織成“區(qū)域”的集合pgd:全局頁目錄地址vm_prot:訪問權(quán)限vm_flags:共享/本進(jìn)程私有vm_nextvm_nexttask_structmm_structpgdmmmmapvm_area_structvm_endvm_protvm_startvm_endvm_protvm_startvm_endvm_protvm_nextvm_startProcess

virtual

memoryTextDataShared

libraries0vm_flagsvm_flagsvm_flagstask_struct是某個進(jìn)程(即任務(wù))所有相關(guān)信息的描述結(jié)構(gòu)(稱進(jìn)程描述符),其中mm是其虛擬空間的描述結(jié)構(gòu)引入“進(jìn)程”的好處“進(jìn)程”的引入為應(yīng)用程序提供了以下兩方面的抽象:一個獨(dú)立的邏輯控制流每個進(jìn)程擁有一個獨(dú)立的邏輯控制流,使得程序員以為自己的程序在執(zhí)行過程中獨(dú)占使用處理器一個私有的虛擬地址空間每個進(jìn)程擁有一個私有的虛擬地址空間,使得程序員以為自己的程序在執(zhí)行過程中獨(dú)占使用存儲器進(jìn)程”的引入簡化了程序員的編程以及語言處理系統(tǒng)的處理,即簡化了編程、編譯、鏈接、共享和加載等整個過程。A25邏輯控制流t0t1t2t3t4t5t6WordWordIEt7t8對于確定的數(shù)據(jù)集,某進(jìn)程指令執(zhí)行地址序列是確定的。稱為進(jìn)程的邏輯控制流。

對于單處理器系統(tǒng),進(jìn)程會輪流使用處理器,即處理器的物理控制流由多個邏輯控制流組成。

p1的邏輯控制流為A11~A13、A11~A14、A15~A16。在A12處被打斷一次!邏輯控制流不會因被其他進(jìn)程打斷而改變,還能回到原被打斷的“斷點(diǎn)”處繼續(xù)執(zhí)行。進(jìn)程p2的邏輯控制流為A21~A22、A23~A25。在A24處被打斷一次!P3未被打斷不同進(jìn)程的邏輯控制流在時(shí)間上交錯或重疊的情況稱為并發(fā)(concurrency)P1和P2、P2和P3是并發(fā)執(zhí)行;P1和P3不是并發(fā)執(zhí)行!復(fù)習(xí):一個典型程序的轉(zhuǎn)換處理過程#include<stdio.h>intmain(){printf("hello,world\n");}經(jīng)典的“hello.c”源程序#include<sp><stdio.3510511099108117100101326011511610010511146h>\n\nint<sp>main()\n{1046210101051101163210997105110404110123\n<sp><sp><sp><sp>printf("hel10323232321121141051101161024034104101108lo,<sp>world\n");\n}10811144321191111141081009211034415910125hello.c的ASCII文本表示復(fù)習(xí):Hello程序的數(shù)據(jù)流動過程“hello”Hello可執(zhí)行文件Red:shell命令行處理Blue:可執(zhí)行文件加載Cyan:hello程序執(zhí)行過程“hello”“hello,world/n”“hello,world/n”問題:hello程序何時(shí)被裝?誰來裝入?被誰啟動?每次是否被裝到相同的地方?hello程序是否知道還有其他程序同時(shí)運(yùn)行?這些問題是本章要回答的!Unix>./hellohello,worldUnix>

“進(jìn)程”

與“上下文切換”Unix>./hellohello,worldUnix>“Unix>”是shell命令行提示符,說明正在運(yùn)行shell進(jìn)程。在一個進(jìn)程的生命周期中,可能會有其他不同進(jìn)程在處理器上交替運(yùn)行!感覺到的運(yùn)行時(shí)間比真實(shí)執(zhí)行時(shí)間要長!OS通過處理器調(diào)度讓處理器輪流執(zhí)行多個進(jìn)程。實(shí)現(xiàn)不同進(jìn)程中指令交替執(zhí)行的機(jī)制稱為進(jìn)程的上下文切換(contextswitching)處理器調(diào)度等事件會引起用戶進(jìn)程正常執(zhí)行被打斷,因而形成異??刂屏鳌_M(jìn)程的上下文切換機(jī)制很好地解決了這類異??刂屏?,實(shí)現(xiàn)了從一個進(jìn)程安全切換到另一個進(jìn)程執(zhí)行的過程。

“進(jìn)程”

的“上下文”進(jìn)程的物理實(shí)體(代碼和數(shù)據(jù)等)和支持進(jìn)程運(yùn)行的環(huán)境合稱為進(jìn)程的上下文。由進(jìn)程的程序塊、數(shù)據(jù)塊、運(yùn)行時(shí)的堆和用戶棧(兩者通稱為用戶堆棧)等組成的用戶空間信息被稱為用戶級上下文;由進(jìn)程標(biāo)識信息、進(jìn)程現(xiàn)場信息、進(jìn)程控制信息和系統(tǒng)內(nèi)核棧等組成的內(nèi)核空間信息被稱為系統(tǒng)級上下文;處理器中各寄存器的內(nèi)容被稱為寄存器上下文(也稱硬件上下文),即進(jìn)程的現(xiàn)場信息。在進(jìn)行進(jìn)程上下文切換時(shí),操作系統(tǒng)把換下進(jìn)程的寄存器上下文保存到系統(tǒng)級上下文中的現(xiàn)場信息位置。用戶級上下文地址空間和系統(tǒng)級上下文地址空間一起構(gòu)成了一個進(jìn)程的整個存儲器映像

進(jìn)程的存儲器映像IA-32/Linux平臺下,每個(用戶)進(jìn)程具有獨(dú)立的私有地址空間(虛擬地址空間)每個進(jìn)程的地址空間劃分(即存儲映像)布局相同(如右圖)進(jìn)程的地址空間回顧:用戶模式和內(nèi)核模式為了使OS能夠起到管理程序執(zhí)行的目的,在一些時(shí)候處理器中必須運(yùn)行內(nèi)核代碼為了區(qū)分處理器運(yùn)行的是用戶代碼還是內(nèi)核代碼,必須有一個狀態(tài)位來標(biāo)識,這個狀態(tài)位稱為模式位通常處理器模式分為用戶模式(用戶態(tài))和內(nèi)核模式(核心態(tài))用戶模式(也稱目態(tài)、用戶態(tài))下,處理器運(yùn)行用戶進(jìn)程,此時(shí)不允許使用特權(quán)指令內(nèi)核模式(有時(shí)稱系統(tǒng)模式、管理模式、超級用戶模式、管態(tài)、內(nèi)核態(tài)、核心態(tài))下處理器運(yùn)行內(nèi)核代碼,允許使用特權(quán)指令,例如:停機(jī)指令、開/關(guān)中斷指令、Cache沖刷指令等。程序的加載和運(yùn)行UNIX/Linux系統(tǒng)中,可通過調(diào)用execve()函數(shù)來啟動加載器。execve()函數(shù)的功能是在當(dāng)前進(jìn)程上下文中加載并運(yùn)行一個新程序。execve()函數(shù)的用法如下:

intexecve(char*filename,char*argv[],*envp[]);

filename是加載并運(yùn)行的可執(zhí)行文件名(如./hello),可帶參數(shù)列表argv和環(huán)境變量列表envp。若錯誤(如找不到指定文件filename),則返回-1,并將控制權(quán)交給調(diào)用程序;若函數(shù)執(zhí)行成功,則不返回,最終將控制權(quán)傳遞到可執(zhí)行目標(biāo)中的主函數(shù)main。主函數(shù)main()的原型形式如下:

intmain(intargc,char**argv,char**envp);

或者:

intmain(intargc,char*argv[],char*envp[]);

argc指定參數(shù)個數(shù),參數(shù)列表中第一個總是命令名(可執(zhí)行文件名)

例如:命令行為“l(fā)d-otestmain.otest.o”時(shí),argc=5程序的加載和運(yùn)行Unix>ld

-otestmain.otest.o若在shell命令行提示符下輸入以下命令行l(wèi)d是可執(zhí)行文件名(即命令名),隨后是命令的若干參數(shù),argv是一個以null結(jié)尾的指針數(shù)組,argc=5在shell命令行提示符后鍵入命令并按“enter”鍵后,便構(gòu)造argv和envp,然后調(diào)用execve()函數(shù)來啟動加載器,最終轉(zhuǎn)main()函數(shù)執(zhí)行intexecve(char*filename,char*argv[],*envp[]);intmain(intargc,char*argv[],char*envp[]);程序的加載和運(yùn)行問題:hello程序的加載和運(yùn)行過程是怎樣的?Step1:在shell命令行提示符后輸入命令:Unix>./hello[enter]Step2:shell命令行解釋器構(gòu)造argv和envpargvargv[0]nullargv[]“./hello"Step3:調(diào)用fork()函數(shù),創(chuàng)建一個子進(jìn)程,與父進(jìn)程shell完全相同(只讀/共享),包括只讀段、可讀寫數(shù)據(jù)段、堆以及用戶棧等。Step4:調(diào)用execve()函數(shù),在當(dāng)前進(jìn)程(新創(chuàng)建的子進(jìn)程)的上下文中加載并運(yùn)行hello程序。將hello中的.text節(jié)、.data節(jié)、.bss節(jié)等內(nèi)容加載到當(dāng)前進(jìn)程的虛擬地址空間(僅修改當(dāng)前進(jìn)程上下文中關(guān)于存儲映像的一些數(shù)據(jù)結(jié)構(gòu),不從磁盤拷貝代碼、數(shù)據(jù)等內(nèi)容)Step5:調(diào)用hello程序的main()函數(shù),hello程序開始在一個進(jìn)程的上下文中運(yùn)行。intmain(intargc,char*argv[],char*envp[]);可執(zhí)行文件的加載通過調(diào)用execve系統(tǒng)調(diào)用函數(shù)來調(diào)用加載器加載器(loader)根據(jù)可執(zhí)行文件的程序(段)頭表中的信息,將可執(zhí)行文件的代碼和數(shù)據(jù)從磁盤“拷貝”到存儲器中(實(shí)際上不會真正拷貝,僅建立一種映像,這涉及到許多復(fù)雜的過程和一些重要概念,將在后續(xù)課上學(xué)習(xí))加載后,將PC(EIP)設(shè)定指向Entrypoint

(即符號_start處),最終執(zhí)行main函數(shù),以啟動程序執(zhí)行。程序被啟動如$./P調(diào)用fork()以構(gòu)造的argv和envp為參數(shù)調(diào)用execve()execve()調(diào)用加載器進(jìn)行可執(zhí)行文件加載,并最終轉(zhuǎn)去執(zhí)行main__libc_init_first_initatexitmain_exit_start:ELF文件信息舉例$readelf-hmain

ELFHeader:Magic:7f454c46010101000000000000000000Class:ELF32Data:2'scomplement,littleendianVersion:1(current)OS/ABI:UNIX-SystemVABIVersion:0Type:EXEC(Executablefile)Machine:Intel80386Version:0x1Entrypointaddress:x8048580Startofprogramheaders:52(bytesintofile)Startofsectionheaders:3232(bytesintofile)Flags:0x0Sizeofthisheader:52(bytes)Sizeofprogramheaders:32(bytes)Numberofprogramheaders:8Sizeofsectionheaders:40(bytes)Numberofsectionheaders:29Sectionheaderstringtableindex:26

可執(zhí)行目標(biāo)文件的ELF頭程序加載和運(yùn)行fork、execve等OS內(nèi)核代碼當(dāng)IA-32/Linux系統(tǒng)開始執(zhí)行main()函數(shù)時(shí),在虛擬地址空間的用戶棧中的結(jié)構(gòu)如右圖所示

intmain(intargc,char*argv[],char*envp[]);shell命令行解釋器異??刂屏鞣忠韵聝蓚€部分介紹第一講:進(jìn)程與進(jìn)程的上下文切換CPU的控制流、異??刂屏鞒绦蚝瓦M(jìn)程、引入進(jìn)程的好處邏輯控制流和物理控制流進(jìn)程與進(jìn)程的上下文切換程序的加載和運(yùn)行第二講:異常和中斷

異常和中斷的基本概念異常和中斷的響應(yīng)、處理IA-32/Linux下的異常/中斷機(jī)制異常和中斷程序執(zhí)行過程中CPU會遇到一些特殊情況,使正在執(zhí)行的程序被“中斷”CPU中止原來正在執(zhí)行的程序,轉(zhuǎn)到處理異常情況或特殊事件的程序去執(zhí)行,結(jié)束后再返回到原被中止的程序處(斷點(diǎn))繼續(xù)執(zhí)行。程序執(zhí)行被“中斷”的事件(在硬件層面)有兩類內(nèi)部“異?!保涸贑PU內(nèi)部發(fā)生的意外事件或特殊事件按發(fā)生原因分為硬故障中斷和程序性中斷兩類硬故障中斷:如電源掉電、硬件線路故障等程序性中斷:執(zhí)行某條指令時(shí)發(fā)生的“例外(Exception)”,如溢出、缺頁、越界、越權(quán)、非法指令、除數(shù)為0、堆棧溢出、訪問超時(shí)、斷點(diǎn)設(shè)置、單步、系統(tǒng)調(diào)用等外部“中斷”:在CPU外部發(fā)生的特殊事件,通過“中斷請求”信號向CPU請求處理。如實(shí)時(shí)鐘、控制臺、打印機(jī)缺紙、外設(shè)準(zhǔn)備好、采樣計(jì)時(shí)到、DMA傳輸結(jié)束等。異常和中斷的處理發(fā)生異常(exception)和中斷(interrupt)事件后,系統(tǒng)將進(jìn)入OS內(nèi)核態(tài)對相應(yīng)事件進(jìn)行處理,即改變處理器狀態(tài)(用戶態(tài)→內(nèi)核態(tài))用戶進(jìn)程OS響應(yīng)異常/中斷具體的異?;蛑袛嗵幚?/p>

返回當(dāng)前指令返回下條指令終止(abort)事件當(dāng)前指令下條指令中斷或異常處理執(zhí)行的代碼不是一個進(jìn)程,而是“內(nèi)核控制路徑”,它代表異?;蛑袛喟l(fā)生時(shí)正在運(yùn)行的當(dāng)前進(jìn)程在內(nèi)核態(tài)執(zhí)行一個獨(dú)立的指令序列。內(nèi)核控制路徑比進(jìn)程更“輕”,其上下文信息比進(jìn)程上下文信息少得多。而上下文切換后CPU執(zhí)行的是另一個用戶進(jìn)程。

用戶進(jìn)程的正??刂屏髦胁迦肓艘欢蝺?nèi)核控制路徑異常的分類“異常”按處理方式分為故障、自陷和終止三類故障(fault):執(zhí)行指令引起的異常事件,如溢出、缺頁、堆棧溢出、訪問超時(shí)等。自陷(Trap):預(yù)先安排的事件(“埋地雷”),如單步跟蹤、斷點(diǎn)、系統(tǒng)調(diào)用(執(zhí)行訪管指令)等。是一種自愿中斷。終止(Abort):硬故障事件,此時(shí)機(jī)器將“終止”,調(diào)出中斷服務(wù)程序來重啟操作系統(tǒng)。不同體系結(jié)構(gòu)和教科書對“異?!焙汀爸袛唷倍x的內(nèi)涵不同,在看書時(shí)要注意!思考2:哪些故障補(bǔ)救后可繼續(xù)執(zhí)行,哪些只好終止當(dāng)前進(jìn)程?

缺頁、TLB缺失等:補(bǔ)救后可繼續(xù),回到發(fā)生故障的指令重新執(zhí)行。

溢出、除數(shù)為0、非法操作、內(nèi)存保護(hù)錯等:終止當(dāng)前進(jìn)程。

回到下條指令“斷點(diǎn)”為發(fā)生故障指令的地址“斷點(diǎn)”為自陷指令下條指令地址“斷點(diǎn)”是什么?隨便!思考1:自陷處理完成后回到哪條指令執(zhí)行?異常舉例—頁故障以下幾種情況都會發(fā)生“頁故障”缺頁:頁表項(xiàng)有效位為0地址越界:地址大于最大界限訪問越級或越權(quán)(保護(hù)違例):越級:用戶進(jìn)程訪問內(nèi)核數(shù)據(jù)(CPL=3/DPL=0)越權(quán):讀寫權(quán)限不相符(如對只讀段進(jìn)行了寫操作)可通過讀磁盤恢復(fù)故障不可恢復(fù),稱為“段故障(segmentationfault)”

“頁故障”事件何時(shí)發(fā)現(xiàn)?如何發(fā)現(xiàn)?執(zhí)行每條指令都要訪存(取指令、取操作數(shù)、存結(jié)果)在保護(hù)模式下,每次訪存都要進(jìn)行邏輯地址向物理地址轉(zhuǎn)換在地址轉(zhuǎn)換過程中會發(fā)現(xiàn)是否發(fā)生了“頁故障”!“頁故障”事件是軟件發(fā)現(xiàn)的還是硬件發(fā)現(xiàn)的?邏輯地址向物理地址的轉(zhuǎn)換由硬件(MMU)實(shí)現(xiàn),故“頁故障”事件由硬件發(fā)現(xiàn)。所有異常和中斷事件都由硬件檢測發(fā)現(xiàn)!異常舉例—頁故障假設(shè)在IA-32/linux系統(tǒng)中一個C語言源程序P如下:1 inta[1000];2 intx;3 main()4 {5 a[10]=1;6 a[1000]=3;7 a[10000]=4;8 }假設(shè)編譯、匯編和鏈接后,第5、6和7行源代碼對應(yīng)的指令序列如下:58048300:c7052890040801000000movl$0x1,0x804902868048309:c705a09f040803000000movl$0x3,0x8049fa078048313:c705402c050804000000movl$0x4,0x8052c40已知頁大小為4KB,若在運(yùn)行P對應(yīng)的進(jìn)程時(shí),系統(tǒng)中無其他進(jìn)程在運(yùn)行,則:(1)對于上述三條指令的執(zhí)行,在取指令時(shí)是否可能發(fā)生頁故障?(2)在數(shù)據(jù)訪問時(shí)分別會發(fā)生什么問題?(3)哪些問題是可恢復(fù)的?哪些問題是不可恢復(fù)的?正常的控制流為…、0x8048300、0x8048309、0x8048313、…可能的異??刂屏魇鞘裁矗慨惓Ee例—頁故障三條指令在讀指令時(shí)都不會發(fā)生缺頁,Why?它們都位于起始地址為0x08048000(是一個4KB頁面的起始位置)的同一個頁面,執(zhí)行這三條指令之前,該頁已經(jīng)調(diào)入內(nèi)存。因?yàn)闆]有其他進(jìn)程在系統(tǒng)中運(yùn)行,所以不會因?yàn)閳?zhí)行其他進(jìn)程而使得調(diào)入主存的頁面被調(diào)出到磁盤。因而都不會在取指令時(shí)發(fā)生頁故障。

假設(shè)在IA-32/linux系統(tǒng)中一個C語言源程序P如下:1 inta[1000];2 intx;3 main()4 {5 a[10]=1;6 a[1000]=3;7 a[10000]=4;8 }假設(shè)編譯、匯編和鏈接后,第5、6和7行源代碼對應(yīng)的指令序列如下:58048300:c7052890040801000000movl$0x1,0x804902868048309:c705a09f040803000000movl$0x3,0x8049fa078048313:c705402c050804000000movl$0x4,0x8052c40已知頁大小為4KB,若在運(yùn)行P對應(yīng)的進(jìn)程時(shí),系統(tǒng)中無其他進(jìn)程在運(yùn)行,則:(1)對于上述三條指令的執(zhí)行,在取指令時(shí)是否可能發(fā)生頁故障?(2)在數(shù)據(jù)訪問時(shí)分別會發(fā)生什么問題?(3)哪些問題是可恢復(fù)的?哪些問題是不可恢復(fù)的?異常舉例—頁故障第5行指令取數(shù)據(jù)時(shí)是否發(fā)生頁故障,Why?對a[10](地址0x8049028)的訪問是對所在頁面(首址為0x08049000)的第一次訪問,故不在主存,缺頁處理結(jié)束后,再回到這條movl指令重新執(zhí)行,再訪問數(shù)據(jù)就沒有問題了。假設(shè)在IA-32/linux系統(tǒng)中一個C語言源程序P如下:1 inta[1000];2 intx;3 main()4 {5 a[10]=1;6 a[1000]=3;7 a[10000]=4;8 }假設(shè)編譯、匯編和鏈接后,第5、6和7行源代碼對應(yīng)的指令序列如下:58048300:c7052890040801000000movl$0x1,0x804902868048309:c705a09f040803000000movl$0x3,0x8049fa078048313:c705402c050804000000movl$0x4,0x8052c40已知頁大小為4KB,若在運(yùn)行P對應(yīng)的進(jìn)程時(shí),系統(tǒng)中無其他進(jìn)程在運(yùn)行,則:(1)對于上述三條指令的執(zhí)行,在取指令時(shí)是否可能發(fā)生頁故障?(2)在數(shù)據(jù)訪問時(shí)分別會發(fā)生什么問題?(3)哪些問題是可恢復(fù)的?哪些問題是不可恢復(fù)的?異常舉例—頁故障假設(shè)在IA-32/linux系統(tǒng)中一個C語言源程序P如下:1 inta[1000];2 intx;3 main()4 {5 a[10]=1;6 a[1000]=3;7 a[10000]=4;8 }假設(shè)編譯、匯編和鏈接后,第5、6和7行源代碼對應(yīng)的指令序列如下:58048300:c7052890040801000000movl$0x1,0x804902868048309:c705a09f040803000000movl$0x3,0x8049fa078048313:c705402c050804000000movl$0x4,0x8052c40已知頁大小為4KB,若在運(yùn)行P對應(yīng)的進(jìn)程時(shí),系統(tǒng)中無其他進(jìn)程在運(yùn)行,則:(1)對于上述三條指令的執(zhí)行,在取指令時(shí)是否可能發(fā)生頁故障?(2)在數(shù)據(jù)訪問時(shí)分別會發(fā)生什么問題?(3)哪些問題是可恢復(fù)的?哪些問題是不可恢復(fù)的?第6行指令取數(shù)據(jù)時(shí)是否發(fā)生頁故障,Why?對a[1000](地址0x8049fa0)的訪問是對所在頁面(首址為0x08049000)的第2次訪問,故在主存,不會發(fā)生缺頁。但a[1000]實(shí)際不存在,只不過編譯器未檢查數(shù)組邊界,0x8049fa0處可能是x的地址,故該指令執(zhí)行結(jié)果可能是x被賦值為3異常舉例—頁故障假設(shè)在IA-32/linux系統(tǒng)中一個C語言源程序P如下:1 inta[1000];2 intx;3 main()4 {5 a[10]=1;6 a[1000]=3;7 a[10000]=4;8 }假設(shè)編譯、匯編和鏈接后,第5、6和7行源代碼對應(yīng)的指令序列如下:58048300:c7052890040801000000movl$0x1,0x804902868048309:c705a09f040803000000movl$0x3,0x8049fa078048313:c705402c050804000000movl$0x4,0x8052c40已知頁大小為4KB,若在運(yùn)行P對應(yīng)的進(jìn)程時(shí),系統(tǒng)中無其他進(jìn)程在運(yùn)行,則:(1)對于上述三條指令的執(zhí)行,在取指令時(shí)是否可能發(fā)生頁故障?(2)在數(shù)據(jù)訪問時(shí)分別會發(fā)生什么問題?(3)哪些問題是可恢復(fù)的?哪些問題是不可恢復(fù)的?第7行指令取數(shù)據(jù)時(shí)是否發(fā)生頁故障,Why?地址0x8052c40偏離數(shù)組首址0x8049000已達(dá)4×10000

+4=40004個單元,即偏離了9個頁面,很可能超出可讀寫區(qū)范圍,故執(zhí)行該指令時(shí)可能會發(fā)生保護(hù)違例。頁故障處理程序發(fā)送一個“段錯誤”信號(SIGSEGV)給用戶進(jìn)程,用戶進(jìn)程接受到該信號后就調(diào)出一個信號處理程序執(zhí)行,該信號處理程序根據(jù)信號類型,在屏幕上顯示“段故障(segmentationfault)”信息,并終止用戶進(jìn)程。陷阱(Trap)異常陷阱也稱自陷或陷入,執(zhí)行陷阱指令(自陷指令)時(shí),CPU調(diào)出特定程序進(jìn)行相應(yīng)處理,處理結(jié)束后返回到陷阱指令下一條指令執(zhí)行。用戶進(jìn)程OS陷入OS內(nèi)核具體的陷阱處理(如系統(tǒng)調(diào)用)

返回下條指令事件陷阱指令下條指令陷阱的作用之一是在用戶和內(nèi)核之間提供一個像過程一樣的接口,這個接口稱為系統(tǒng)調(diào)用,用戶程序利用這個接口可方便地使用操作系統(tǒng)內(nèi)核提供的一些服務(wù)。操作系統(tǒng)給每個服務(wù)編一個號,稱為系統(tǒng)調(diào)用號。例如,Linux系統(tǒng)調(diào)用fork、read和execve的調(diào)用號分別是1、3和11。IA-32處理器中的int指令和sysenter指令、MIPS處理器中的

syscall指令等都屬于陷阱指令(相當(dāng)于“地雷”)。陷阱指令異常稱為編程異常(programmedexception),這些指令包括INTn、int3、into(溢出檢查)、bound(地址越界檢查)等

有條件“爆炸”Trap舉例:OpeningFile用戶程序中調(diào)用函數(shù)open(filename,options)open函數(shù)執(zhí)行陷阱指令(即系統(tǒng)調(diào)用指令“int”)0804d070<__libc_open>:...804d082: cd80int$0x80804d084: 5b pop%ebx...UserProcessOS陷入OS文件打開操作返回到pop指令執(zhí)行int$0x80pop%ebxOpen系統(tǒng)調(diào)用(systemcall):OSmustfindorcreatefile,getitreadyforreadingorwriting,Returnsintegerfiledescriptor通過執(zhí)行“int$0x80”指令,調(diào)出OS完成一個具體的“服務(wù)”(稱為系統(tǒng)調(diào)用)這種“地雷”一定“爆炸”陷阱(Trap)異常利用陷阱機(jī)制可實(shí)現(xiàn)程序調(diào)試功能,包括設(shè)置斷點(diǎn)和單步跟蹤IA-32中,當(dāng)CPU處于單步跟蹤狀態(tài)(TF=1且IF=1)時(shí),每條指令都被設(shè)置成了陷阱指令,執(zhí)行每條指令后,都會發(fā)生中斷類型號為1的“調(diào)試”異常,從而轉(zhuǎn)去執(zhí)行“單步跟蹤處理程序”。

注意:

當(dāng)陷阱指令是轉(zhuǎn)移指令時(shí),不能返回到轉(zhuǎn)移指令的下條指令執(zhí)行,而是返回到轉(zhuǎn)移目標(biāo)指令執(zhí)行。

(在一定的條件下,每條指令都變成“地雷”)IA-32中,用于程序調(diào)試的“斷點(diǎn)設(shè)置”陷阱指令為int3,對應(yīng)機(jī)器碼為CCH。若調(diào)試程序在被調(diào)試程序某處設(shè)置了斷點(diǎn),則調(diào)試程序就在該處加入一條int3指令。執(zhí)行到該指令時(shí),會暫停被調(diào)試程序的運(yùn)行,并發(fā)出“EXCEPTION_BREAKPOINT”異常,以調(diào)出調(diào)試程序執(zhí)行,執(zhí)行結(jié)束后回到被調(diào)試程序執(zhí)行。

(int3是一定爆炸的“地雷”)問題:你用過單步跟蹤、斷點(diǎn)設(shè)置等調(diào)試功能嗎?你知道這些功能是如何實(shí)現(xiàn)的嗎?SKIP通過“埋地雷”的方式實(shí)現(xiàn)IA-32的標(biāo)志寄存器6個條件標(biāo)志OF、SF、ZF、CF各是什么標(biāo)志(條件碼)?AF:輔助進(jìn)位標(biāo)志(BCD碼運(yùn)算時(shí)才有意義)PF:奇偶標(biāo)志3個控制標(biāo)志DF(DirectionFlag):方向標(biāo)志(自動變址方向是增還是減)IF(InterruptFlag):中斷允許標(biāo)志(僅對外部可屏蔽中斷有用)TF(TrapFlag):陷阱標(biāo)志(是否是單步跟蹤狀態(tài))……808680286/386終止(Abort)異常如果在執(zhí)行指令過程中發(fā)生了嚴(yán)重錯誤,例如,控制器出現(xiàn)問題,訪問DRAM或SRAM時(shí)發(fā)生校驗(yàn)錯等,則程序?qū)o法繼續(xù)執(zhí)行,只好終止發(fā)生問題的進(jìn)程,在有些嚴(yán)重的情況下,甚至要重啟系統(tǒng)。這種異常是隨機(jī)發(fā)生的,無法確定發(fā)生異常的是哪條指令。中斷的概念外設(shè)通過中斷請求信號線向CPU提出“中斷”請求,不由指令引起,故中斷也稱為異步異常。事件:Ctrl-C、DMA傳送結(jié)束、網(wǎng)絡(luò)數(shù)據(jù)到達(dá)、打印缺紙、……每執(zhí)行完一條指令,CPU就查看中斷請求引腳,若引腳的信號有效,則進(jìn)行中斷響應(yīng):將當(dāng)前PC(斷點(diǎn))和當(dāng)前機(jī)器狀態(tài)保存到棧中,并“關(guān)中斷”,然后,從數(shù)據(jù)總線讀取中斷類型號,根據(jù)中斷類型號跳轉(zhuǎn)到對應(yīng)的中斷服務(wù)程序執(zhí)行。中斷檢測及響應(yīng)過程由硬件完成。中斷服務(wù)程序執(zhí)行具體的中斷處理工作,中斷處理完成后,再回到被打斷程序的“斷點(diǎn)”處繼續(xù)執(zhí)行。溢出、整除0、缺頁等異常和外部中斷都是由硬件檢測并響應(yīng)的!用戶進(jìn)程中斷服務(wù)程序中斷響應(yīng)進(jìn)行中斷處理,例如,鍵盤中斷時(shí),將鍵盤緩沖區(qū)的字符取到存儲器中返回下條指令執(zhí)行8048500:pushl…8048402:movl…斷點(diǎn)是什么?保護(hù)斷點(diǎn)、關(guān)中斷、轉(zhuǎn)中斷處理中斷的分類Intel將中斷分成可屏蔽中斷(maskableinterrupt)和不可屏蔽中斷(nonmaskableinterrupt,NMI)??善帘沃袛啵和ㄟ^INTR向CPU請求,可通過設(shè)置屏蔽字來屏蔽請求,若中斷請求被屏蔽,則不會被送到CPU。不可屏蔽中斷:非常緊急的硬件故障,如:電源掉電,硬件線路故障等。通過NMI向CPU請求。一旦產(chǎn)生,就被立即送CPU,以便快速處理。這種情況下,中斷服務(wù)程序會盡快保存系統(tǒng)重要信息,然后在屏幕上顯示相應(yīng)的消息或直接重啟系統(tǒng)。CPU中斷控制器NMIINTR異常/中斷響應(yīng)過程檢測到異?;蛑袛鄷r(shí),CPU須進(jìn)行以下基本處理:①關(guān)中斷(“中斷允許位”清0):使CPU處于“禁止中斷”狀態(tài),以防止新中斷破壞斷點(diǎn)(PC)、程序狀態(tài)(PSW)和現(xiàn)場(通用寄存器)。②保護(hù)斷點(diǎn)和程序狀態(tài):將斷點(diǎn)和程序狀態(tài)保存到?;蛱厥饧拇嫫髦?/p>

PC→棧或EPC(專門存放斷點(diǎn)的寄存器)PSWR→?;駿PSWR(專門保存程序狀態(tài)的寄存器)PSW(ProgramStatusWord):程序狀態(tài)字PSWR(PSW寄存器):如IA-32中的的EFLAGS寄存器③識別異常事件

有軟件識別和硬件識別(向量中斷)兩種不同的方式。異常/中斷響應(yīng)過程有兩種不同的識別方式:軟件識別和硬件識別(向量中斷)。(1)軟件識別(MIPS采用)

設(shè)置一個異常狀態(tài)寄存器(MIPS中為Cause寄存器),用于記錄異常原因。操作系統(tǒng)使用一個統(tǒng)一的異常處理程序,該程序按優(yōu)先級順序查詢異常狀態(tài)寄存器,識別出異常事件。

(例如:MIPS中位于內(nèi)核地址0x80000180處有一個專門的異常處理程序,用于檢測異常的具體原因,然后轉(zhuǎn)到內(nèi)核中相應(yīng)的異常處理程序段中進(jìn)行具體的處理)

(2)硬件識別(向量中斷)(IA-32采用)用專門的硬件查詢電路按優(yōu)先級順序識別異常,得到“中斷類型號”,根據(jù)此號,到中斷向量表中讀取對應(yīng)的中斷服務(wù)程序的入口地址。

所有事件都被分配一個“中斷類型號”,每個中斷都有相應(yīng)的“中斷服務(wù)程序”,可根據(jù)中斷類型號找到中斷服務(wù)程序的入口地址。IA-32的向量中斷方式有256種不同類型的異常和中斷每個異常和中斷都有唯一編號,稱之為中斷類型號(也稱向量號)。如類型0為“除法錯”,類型2為“NMI中斷”,類型14為“缺頁”每個異常和中斷有與其對應(yīng)的異常處理程序或中斷服務(wù)程序,其入口地址放在一個專門的中斷向量表或中斷描述符表中。前32個類型(0~31)保留給CPU使用,剩余的由用戶自行定義(這里的用戶指機(jī)器硬件的用戶,即操作系統(tǒng))通過執(zhí)行INTn(指令第二字節(jié)給出中斷類型號n,n=32~255)使CPU自動轉(zhuǎn)到OS給出的中斷服務(wù)程序執(zhí)行實(shí)模式下,用中斷向量表描述保護(hù)模式下,用中斷描述符表描述IA-32的中斷類型用戶自定義類型號為32~255,部分用于可屏蔽中斷,部分用于軟中斷可屏蔽中斷通過CPU的INTR引腳向CPU發(fā)出中斷請求軟中斷指令

INTn被設(shè)定為一種陷阱異常,例如,Linux通過int$0x80指令將128號設(shè)定為系統(tǒng)調(diào)用,而Windows通過int$0x2e指令將46號設(shè)定為系統(tǒng)調(diào)用。回顧:用“系統(tǒng)思維”分析問題代碼段一:inta=0x80000000;intb=a/-1;printf("%d\n",b);運(yùn)行結(jié)果為-2147483648代碼段二:inta=0x80000000;intb=-1;intc=a/b;printf("%d\n",c);運(yùn)行結(jié)果為“Floatingpointexception”,顯然CPU檢測到了溢出異常objdump反匯編代碼,得知除以-1被優(yōu)化成取負(fù)指令neg,故未發(fā)生除法溢出為什么兩者結(jié)果不同!理解該問題需要知道:編譯器如何優(yōu)化機(jī)器級數(shù)據(jù)的表示機(jī)器指令的含義和執(zhí)行計(jì)算機(jī)內(nèi)部的運(yùn)算電路除法錯異常的處理……a/b用除法指令I(lǐng)DIV實(shí)現(xiàn),但它不生成OF標(biāo)志,那么如何判斷溢出異常的呢?實(shí)際上是“除法錯”異常#DE(類型0)Linux中,對#DE類型發(fā)SIGFPE信號實(shí)地址模式下的中斷向量表實(shí)地址模式(RealMode)是Intel為80286及其之后的處理器提供的一種8086兼容模式。尋址空間1MB,指令地址=CS<<4+IP。中斷向量表位于0000H~03FFH。共256組,每組占四個字節(jié)CS:IP。CS:IP例1:除法錯的中斷類型號為0,故其向量地址為:0x4=0例2:NMI的中斷類型號為2,故其向量地址為:2x4=8000~003H004~007H008~00BH3FC~3FFH除法錯單步NMI

中斷向量表中每一項(xiàng)是對應(yīng)中斷服務(wù)程序或異常處理程序的入口地址,被稱為中斷向量(InterruptVector)。CS:IPCS:IPCS:IPCS:IP實(shí)地址模式下沒有分頁管理機(jī)制!實(shí)地址模式下的中斷向量表開機(jī)后系統(tǒng)首先在實(shí)地址模式下工作(只有1MB的尋址空間)開機(jī)過程中,需要先準(zhǔn)備在實(shí)模式下的中斷向量表和中斷服務(wù)程序。通常,由固化在主板上一塊ROM芯片中的BIOS程序完成BIOS程序檢測顯卡、鍵盤、內(nèi)存等,并在00000H~003FFH區(qū)建立中斷向量表,在中斷向量所指主存區(qū)建立相應(yīng)的中斷服務(wù)程序BIOS利用INT指令執(zhí)行特定的中斷服務(wù)程序把OS從磁盤加載到內(nèi)存中。例如,BIOS可通過執(zhí)行int0x19指令來調(diào)用中斷向量0x19對應(yīng)的中斷服務(wù)程序,將啟動盤上的0號磁頭對應(yīng)盤面的0磁道1扇區(qū)中的引導(dǎo)程序裝入內(nèi)存BIOS(BasicInput/OutputSystem)是基本輸入/輸出系統(tǒng)的簡稱,是針對具體主板設(shè)計(jì)的,與安裝的操作系統(tǒng)無關(guān)。BIOS包含各種基本設(shè)備驅(qū)動程序,通過執(zhí)行BIOS程序,基本設(shè)備驅(qū)動程序以中斷服務(wù)程序的形式被加載到內(nèi)存,以提供基本I/O系統(tǒng)調(diào)用。一旦進(jìn)入保護(hù)模式,就不再使用BIOS。保護(hù)模式下的中斷描述符表保護(hù)模式下,通過中斷描述符表獲異常處理或中斷服務(wù)程序入口地址中斷描述符表(InterruptDescriptorTable,IDT)是OS內(nèi)核中的一個表,共有256個表項(xiàng),每個表項(xiàng)占8個字節(jié),IDT共占用2KB

寄存器IDTR中存放IDT在內(nèi)存的首地址每一個表項(xiàng)是一個中斷門描述符、陷阱門描述符或任務(wù)門描述符P:Linux總把P置1。DPL:訪問本段要求的最低特權(quán)級。主要用于防止惡意應(yīng)用程序通過INTn指令模擬非法異常而進(jìn)入內(nèi)核態(tài)執(zhí)行破壞性操作TYPE:標(biāo)識門的類型。TYPE=1110B:中斷門;TYPE=1111B:陷阱門;TYPE=0101B:任務(wù)門段選擇符用來指示異常處理程序或中斷服務(wù)程序所在段的段描述符在GDT中的位置,其RPL=0;偏移地址則給出異常處理程序或中斷服務(wù)程序第一條指令所在偏移量。中斷門描述符格式:IA-32中異常和中斷的處理引導(dǎo)程序被讀到內(nèi)存后,開始執(zhí)行引導(dǎo)程序,以裝入操作系統(tǒng)內(nèi)核,并對GDT、IDT等進(jìn)行了初始化,系統(tǒng)啟動后,進(jìn)入保護(hù)模式IA-32中,每條指令執(zhí)行后,下條指令的邏輯地址(虛擬地址)由CS和EIP指示每條指令執(zhí)行過程中,CPU會根據(jù)執(zhí)行情況判定是否發(fā)生了某種內(nèi)部異常事件,并在每條指令執(zhí)行結(jié)束時(shí)判定是否發(fā)生了外部中斷請求

(由此可見,異常事件和中斷請求的檢測都是在某一條指令執(zhí)行過程中進(jìn)行的,顯然由硬件完成)在CPU根據(jù)CS和EIP取下條指令之前,會根據(jù)檢測的結(jié)果判斷是否進(jìn)入中斷響應(yīng)階段(異常和中斷的響應(yīng)也都是在某一條指令執(zhí)行過程中進(jìn)行的,顯然也由硬件完成)IA-32中異常和中斷響應(yīng)過程(1)確定中斷類型號i,從IDTR指向的IDT中取出第i個表項(xiàng)IDTi。(2)根據(jù)IDTi中段選擇符,從GDTR指向的GDT中取出相應(yīng)段描述符,得到對應(yīng)異?;蛑袛嗵幚沓绦蛩诙蔚腄PL、基地址等信息。Linux下中斷門和陷阱門對應(yīng)的即為內(nèi)核代碼段,所以DPL為0,基地址為0。(3)若CPL<DPL或編程異常IDTi的DPL<CPL,則發(fā)生13號異常。Linux下,前者不會發(fā)生。后者用于防止惡意程序模擬INTn陷入內(nèi)核進(jìn)行破壞性操作。(4)若CPL≠DPL,則從用戶態(tài)換至內(nèi)核態(tài),以使用內(nèi)核棧。切換棧的步驟:①讀TR寄存器,以訪問正在運(yùn)行的用戶進(jìn)程的TSS段;②將TSS段中保存的內(nèi)核棧的段選擇符和棧指針分別裝入寄存器SS和ESP,然后在內(nèi)核棧中保存原來用戶棧的SS和ESP。(5)若是故障,則將發(fā)生故障的指令的邏輯地址寫入CS和EIP,以使處理后回到故障指令執(zhí)行。其他情況下,CS和EIP不變,使處理后回到下條指令執(zhí)行。(6)在當(dāng)前棧中保存EFLAGS、CS和EIP寄存器的內(nèi)容(斷點(diǎn)和程序狀態(tài))。(7)若異常產(chǎn)生了一個硬件出錯碼,則將其保存在內(nèi)核棧中。(8)將IDTi中的段選擇符裝入CS,IDTi中的偏移地址裝入EIP,它們是異常處理程序或中斷服務(wù)程序第一條指令的邏輯地址(Linux中段基址=0)。

下個時(shí)鐘周期開始,從CS:EIP所指處開始執(zhí)行異?;蛑袛嗵幚沓绦颍A-32/Linux中的分段機(jī)制為使能移植到絕大多數(shù)流行處理器平臺,Linux簡化了分段機(jī)制RISC對分段支持非常有限,因此Linux僅使用IA-32的分頁機(jī)制,而對于分段,則通過在初始化時(shí)將所有段描述符的基址設(shè)為0來簡化若把運(yùn)行在用戶態(tài)的所有Linux進(jìn)程使用的代碼段和數(shù)據(jù)段分別稱為用戶代碼段和用戶數(shù)據(jù)段;把運(yùn)行在內(nèi)核態(tài)的所有Linux進(jìn)程使用的代碼段和數(shù)據(jù)段分別稱為內(nèi)核代碼段和內(nèi)核數(shù)據(jù)段,則Linux初始化時(shí),將上述4個段的段描述符中各字段設(shè)置成下表中的信息:初始化時(shí),上述4個段描述符被存放在GDT中IA-32中異常和中斷返回過程

中斷或異常處理程序最后一條指令是IRET。CPU在執(zhí)行IRET指令過程中完成以下工作:(1)從棧中彈出硬件出錯碼(保存過的話)、EIP、CS和EFLAGS(2)檢查當(dāng)前異?;蛑袛嗵幚沓绦虻腃PL是否等于CS中最低兩位,若是則說明異?;蛑袛囗憫?yīng)前、后都處于同一個特權(quán)級,IRET指令完成操作;否則,再繼續(xù)完成下一步工作。(3)從內(nèi)核棧中彈出SS和ESP,以恢復(fù)到異?;蛑袛囗憫?yīng)前的特權(quán)級進(jìn)程所使用的棧。(4)檢查DS、ES、FS和GS段寄存器的內(nèi)容,若其中有某個寄存器的段選擇符指向一個段描述符且其DPL小于CPL,則將該段寄存器清0。這是為了防止惡意應(yīng)用程序(CPL=3)利用內(nèi)核以前使用過的段寄存器(DPL=0)來訪問內(nèi)核地址空間。

執(zhí)行完IRET指令后,CPU回到原來發(fā)生異?;蛑袛嗟倪M(jìn)程繼續(xù)執(zhí)行Linux中的異常和中斷處理Linux利用陷阱門來處理異常,利用中斷門來處理中斷。異常和中斷對應(yīng)處理程序都屬于內(nèi)核代碼段,所以,所有中斷門和陷阱門的段選擇符(0x60)都指向GDT中的“內(nèi)核代碼段”描述符。通過中斷門進(jìn)入到一個中斷服務(wù)程序時(shí),CPU會清除EFLAGS寄存器中的IF標(biāo)志,即關(guān)中斷;通過陷阱門進(jìn)入一個異常處理程序時(shí),CPU不會修改IF標(biāo)志。也就是說,外部中斷不支持嵌套處理,而內(nèi)部異常則支持嵌套處理。任務(wù)門描述符中不包含偏移地址,只包含TSS段選擇符,這個段選擇符指向GDT中的一個TSS段描述符,CPU根據(jù)TSS段中的相關(guān)信息裝載EIP和ESP等寄存器,從而執(zhí)行相應(yīng)的異常處理程序。Linux中,將類型號為8的雙重故障(#DF)用任務(wù)門實(shí)現(xiàn),而且是唯一通過任務(wù)門實(shí)現(xiàn)的異常。雙重故障TSS段描述符在GDT中位于索引值為0x1f的表項(xiàng)處,即13位索引為0000000011111,且其TI=0(指向GDT),RPL=00(內(nèi)核級代碼),即任務(wù)門描述符中的段選擇符為00F8H。Why?試想一下處理缺頁時(shí)又有非法指令或棧溢出等!Linux中的中斷門、陷阱門和任務(wù)門所有中斷門和陷阱門描述符中的段選擇符都是0x60任務(wù)門描述符中的段選擇符都是0xf8IA-32的標(biāo)志寄存器6個條件標(biāo)志OF、SF、ZF、CF各是什么標(biāo)志(條件碼)?AF:輔助進(jìn)位標(biāo)志(BCD碼運(yùn)算時(shí)才有意義)PF:奇偶標(biāo)志3個控制標(biāo)志DF(DirectionFlag):方向標(biāo)志(自動變址方向是增還是減)IF(InterruptFlag):中斷允許標(biāo)志(僅對外部可屏蔽中斷有用)TF(TrapFlag):陷阱標(biāo)志(是否是單步跟蹤狀態(tài))……808680286/386Linux中中斷描述符表的初始化

CPU負(fù)責(zé)對異常和中斷的檢測與響應(yīng),而操作系統(tǒng)則負(fù)責(zé)初始化IDT以及編制好異常處理程序或中斷服務(wù)程序。Linux運(yùn)用提供的三種門描述符格式,構(gòu)造了以下5種類型的門描述符。(1)中斷門:DPL=0,TYPE=1110B。激活所有中斷(2)系統(tǒng)門:DPL=3,TYPE=1111B。激活4、5和128三個陷阱異常,分別對應(yīng)指令into、bound和int$0x80三條指令。因DPL為3,CPL≤DPL,故在用戶態(tài)下可使用這三條指令(3)系統(tǒng)中斷門:DPL=3,TYPE=1110B。激活3號中斷(即調(diào)試斷點(diǎn)),對應(yīng)指令int3。因DPL為3,CPL≤DPL,故用戶態(tài)下可使用int3指令。(4)陷阱門:DPL=0,TYPE=1111B。激活所有內(nèi)部異常,并阻止用戶程序使用INTn(n≠128或3)指令模擬非法異常來陷入內(nèi)核態(tài)運(yùn)行。(5)任務(wù)門:DPL=0,TYPE=0101B。激活8號中斷(雙重故障)。

Linux內(nèi)核在啟用異常和中斷機(jī)制之前,先設(shè)置好IDT的每個表項(xiàng),并把IDT首址存入IDTR。系統(tǒng)初始化時(shí),Linux完成對GDT、GDTR、IDT和IDTR等的設(shè)置,以后一旦發(fā)生異?;蛑袛?,CPU就可通過異常和中斷響應(yīng)機(jī)制調(diào)出異常或中斷處理程序執(zhí)行。

Linux中對異常的處理異常處理程序發(fā)送相應(yīng)的信號給發(fā)生異常的當(dāng)前進(jìn)程,或者進(jìn)行故障恢復(fù),然后返回到斷點(diǎn)處執(zhí)行。

例如,若執(zhí)行了非法操作,CPU就產(chǎn)生6號異常(#UD),在對應(yīng)的異常處理程序中,向當(dāng)前進(jìn)程發(fā)送一個SIGILL信號,以通知當(dāng)前進(jìn)程中止運(yùn)行。采用向發(fā)生異常的進(jìn)程發(fā)送信號的機(jī)制實(shí)現(xiàn)異常處理,可盡快完成在內(nèi)核態(tài)的異常處理過程,因?yàn)楫惓L幚磉^程越長,嵌套執(zhí)行異常的可能性越大,而異常嵌套執(zhí)行會付出較大的代價(jià)。并不是所有異常處理都只是發(fā)送一個信號到發(fā)生異常的進(jìn)程。

例如,對于14號頁故障異常(#PF),需要判斷是否訪問越級、越權(quán)或越界等,若發(fā)生了這些無法恢復(fù)的故障,則頁故障處理程序發(fā)送SIGSEGV信號給發(fā)生頁故障異常的進(jìn)程;若只是缺頁,則頁故障處理程序負(fù)責(zé)把所缺失頁面從磁盤裝入主存,然后返回到發(fā)生缺頁故障的指令繼續(xù)執(zhí)行。

Linux中對異常的處理所有異常處理程序的結(jié)構(gòu)是一致的,都可劃分成以下三個部分:(1)準(zhǔn)備階段:在內(nèi)核棧保存通用寄存器內(nèi)容(稱為現(xiàn)場信息),這部分大多用匯編語言程序?qū)崿F(xiàn)。(2)處理階段:采用C函數(shù)進(jìn)行具體處理。函數(shù)名由do_前綴和處理程序名組成,如do_overflow為溢出處理函數(shù)。

大部分函數(shù)的處理方式:保存硬件出錯碼(如果有的話)和異常類型號,然后,向當(dāng)前進(jìn)程發(fā)送一個信號。當(dāng)前進(jìn)程接受到信號后,若有對應(yīng)信號處理程序,則轉(zhuǎn)信號處理程序執(zhí)行;若沒有,則調(diào)用內(nèi)核abort例程執(zhí)行,以終止當(dāng)前進(jìn)程。(3)恢復(fù)階段:恢復(fù)保存在內(nèi)核棧中的各個寄存器的內(nèi)容,切換到用戶態(tài)并返回到當(dāng)前進(jìn)程的斷點(diǎn)處繼續(xù)執(zhí)行。

Linux中對異常的處理Linux中異常對應(yīng)的信號名和處理程序名

為何除法錯顯示卻是“浮點(diǎn)異常”的原因!回顧:用“系統(tǒng)思維”分析問題代碼段一:inta=0x80000000;intb=a/-1;printf("%d\n",b);運(yùn)行結(jié)果為-2147483648代碼段二:inta=0x80000000;intb=-1;intc=a/b;printf("%d\n",c);運(yùn)行結(jié)果為“Floatingpointexception”,顯然CPU檢測到了溢出異常objdump反匯編代碼,得知除以-1被優(yōu)化成取負(fù)指令neg,故未發(fā)生除法溢出為什么兩者結(jié)果不同!理解該問題需要知道:編譯器如何優(yōu)化機(jī)器級數(shù)據(jù)的表示機(jī)器指令的含義和執(zhí)行計(jì)算機(jī)內(nèi)部的運(yùn)算電路除法錯異常的處理……a/b用除法指令I(lǐng)DIV實(shí)現(xiàn),但它不生成OF標(biāo)志,那么如何判斷溢出異常的呢?實(shí)際上是“除法錯”異常#DE(類型0)Linux中,對#DE類型發(fā)SIGFPE信號Linux中對中斷的處理對于大部分異常,Linux只是給引起異常的當(dāng)前進(jìn)程發(fā)送一個信號就結(jié)束異常處理,具體的異常處理轉(zhuǎn)到信號處理程序進(jìn)行。對于中斷,因?yàn)橹袛嗍录陌l(fā)生與正在執(zhí)行的當(dāng)前進(jìn)程很可能沒有關(guān)系,所以將一個信號發(fā)給當(dāng)前進(jìn)程沒有意義。Linux中有三種類型中斷。①I/O中斷:I/O外設(shè)的中斷請求;②時(shí)鐘中斷:某時(shí)鐘產(chǎn)生的中斷請求,告知固定時(shí)間間隔到;③處理器中斷:多處理器系統(tǒng)中其他處理器發(fā)出的中斷請求。后兩種超出了本教材范圍I/O中斷:每個能發(fā)中斷請求的外設(shè)控制器都有一條IRQ線,所有IRQ線連接到一個可編程中斷控制器PIC(ProgrammableInterruptController)中對應(yīng)的IRQ引腳上,PIC中每個IRQ引腳都有一個編號,如IRQ0、IRQ1、…、IRQi、…,將與IRQi關(guān)聯(lián)的中斷類型號設(shè)定為32+i。哪些來自CPU?哪些送CPU?哪些來自設(shè)備?可編程中斷控制器PICINTRIA-32的中斷類型用戶自定義類型號為32~255,部分用于可屏蔽中斷,部分用于軟中斷可屏蔽中斷通過CPU的INTR引腳向CPU發(fā)出中斷請求

中斷類型號為32+i

(i為中斷請求號IRQi)軟中斷指令

INTn被設(shè)定為一種陷阱異常,例如,Linux通過int$0x80指令將128號設(shè)定為系統(tǒng)調(diào)用,而Windows通過int$0x2e指令將46號設(shè)定為系統(tǒng)調(diào)用。Linux中對中斷的處理PIC需對所有外設(shè)來的IRQ請求按優(yōu)先級排隊(duì),若至少有一個IRQ線有請求且未被屏蔽,則PIC向CPU的INTR引腳發(fā)中斷請求。CPU每執(zhí)行完一條指令都會查詢INTR,若發(fā)現(xiàn)有中斷請求,則進(jìn)入中斷響應(yīng)過程,調(diào)出中斷服務(wù)程序執(zhí)行。所有中斷服務(wù)程序的結(jié)構(gòu)類似,都劃分為以下三個階段。①準(zhǔn)備階段:在內(nèi)核棧中保存各通用寄存器的內(nèi)容(稱為現(xiàn)場信息)以及所請求IRQi的值等,并給PIC回送應(yīng)答信息,允許其發(fā)送新的中斷請求信號。②處理階段:執(zhí)行IRQi對應(yīng)的中斷服務(wù)例程ISR(InterruptServerRoutine)。中斷類型號為32+i③恢復(fù)階段:恢復(fù)保存在內(nèi)核棧中的各個寄存器的內(nèi)容,切換到用戶態(tài)并返回到當(dāng)前進(jìn)程的邏輯控制流的斷點(diǎn)處繼續(xù)執(zhí)行。IA-32/Linux的系統(tǒng)調(diào)用系統(tǒng)調(diào)用(陷阱)是特殊異常事件,是OS為用戶程序提供服務(wù)的手段。Linux提供了幾百種系統(tǒng)調(diào)用,主要分為以下幾類:進(jìn)程控制、文件操作、文件系統(tǒng)操作、系統(tǒng)控制、內(nèi)存管理、網(wǎng)絡(luò)管理、用戶管理、進(jìn)程通信等系統(tǒng)調(diào)用號是系統(tǒng)調(diào)用跳轉(zhuǎn)表索引值,跳轉(zhuǎn)表給出系統(tǒng)調(diào)用服務(wù)例程首址Trap舉例:OpeningFile用戶程序中調(diào)用函數(shù)open(filename,options)open函數(shù)執(zhí)行陷阱指令(即系統(tǒng)調(diào)用指令“int”)0804d070<__libc_open>:...804d082: cd80int$0x80804d084: 5b pop%ebx...UserProcessOS陷入OS文件打開操作返回到pop指令執(zhí)行int$0x80pop%ebxOpen系統(tǒng)調(diào)用(systemcall):OSmustfindorcreatefile,getitreadyforreadingorwriting,Returnsintegerfiledescriptor通過執(zhí)行“int$0x80”指令,調(diào)出OS完成一個具體的“服務(wù)”(稱為系統(tǒng)調(diào)用)這種“地雷”一定“爆炸”IA-32/Linux的系統(tǒng)調(diào)用通常,系統(tǒng)調(diào)用被封裝成用戶程序能直接調(diào)用的函數(shù),如exit()、read()和open(),這些是標(biāo)準(zhǔn)C庫中系統(tǒng)調(diào)用對應(yīng)的封裝函數(shù)。Linux中系統(tǒng)調(diào)用所用參數(shù)通過寄存器傳遞,傳遞參數(shù)的寄存器順序依次為:EAX(調(diào)用號)、EBX、ECX、EDX、ESI、EDI和EBP,除調(diào)用號以外,最多6個參數(shù)。封裝函數(shù)對應(yīng)的機(jī)器級代碼有一個統(tǒng)一的結(jié)構(gòu):總是若干條傳送指令后跟一條陷阱指令。傳送指令用來傳遞系統(tǒng)調(diào)用的參數(shù),陷阱指令(如int$0x80)用來陷入內(nèi)核進(jìn)行處理。例如,若用戶程序調(diào)用系統(tǒng)調(diào)用write(1,“hello,world!\n”,14),將字符串“hello,world!\n”中14個字符顯示在標(biāo)準(zhǔn)輸出設(shè)備文件stdout上,則其封裝函數(shù)對應(yīng)機(jī)器級代碼(用匯編指令表示)如下:

movl$4,%eax//調(diào)用號為4,送EAX movl$1,%ebx//標(biāo)準(zhǔn)輸出設(shè)備stdout的文件

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論