2023年全國碩士研究生考試考研英語一試題真題(含答案詳解+作文范文)_第1頁
已閱讀1頁,還剩34頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、<p><b>  目 錄</b></p><p><b>  1 緒論1</b></p><p>  1. 1課題背景及目的1</p><p>  1.1.1為什么要設(shè)計虛擬機(jī)1</p><p>  1.1.2虛擬機(jī)反對派觀點(diǎn)1</p><p>  1.

2、2國內(nèi)外研究狀況2</p><p>  1.3課題研究方法2</p><p>  1.4論文構(gòu)成及研究內(nèi)容2</p><p>  2 SVM 虛擬機(jī)設(shè)計3</p><p>  2.1運(yùn)形時系統(tǒng)與虛擬機(jī)3</p><p>  2.2 SVM 虛擬機(jī)3</p><p>  2.3 SV

3、M虛擬機(jī)處理器設(shè)計5</p><p>  2.3.1 機(jī)器處理器設(shè)計5</p><p>  2.3.2 SVM虛擬機(jī)處理器設(shè)計6</p><p>  2.4 SVM內(nèi)存分配8</p><p>  2.5 SVM內(nèi)存尋址8</p><p>  2.6 SVM 多字節(jié)存儲方式8</p><p

4、>  2.7 SVM輸入輸出9</p><p>  2.8 SVM 中斷10</p><p>  2.9 SVM 匯編器16</p><p>  2.10 SVM 反匯編器18</p><p>  2.11 SVM 調(diào)試器18</p><p>  2.11.1概述18</p><p

5、>  2.11.2調(diào)試技術(shù)19</p><p>  2.11.3 SVM 調(diào)試器的實(shí)現(xiàn)19</p><p>  2.12 建造運(yùn)行時系統(tǒng)20</p><p>  2.13 SVM 虛擬機(jī)的擴(kuò)展20</p><p>  3 SVM 虛擬機(jī)運(yùn)行時環(huán)境22</p><p>  3.1SVM執(zhí)行方式22<

6、;/p><p>  3.2 SVM調(diào)試方式23</p><p>  4 程序設(shè)計處理26</p><p>  4.1程序設(shè)計中的宏處理26</p><p>  4.2程序設(shè)計中的異常處理26</p><p><b>  總 結(jié)26</b></p><p>&l

7、t;b>  致 謝26</b></p><p><b>  參考文獻(xiàn)26</b></p><p><b>  1 緒論</b></p><p>  1. 1課題背景及目的</p><p>  1.1.1為什么要設(shè)計虛擬機(jī)</p><p>  就軟

8、件工業(yè)的發(fā)展趨勢而言,一方面是需要運(yùn)行在多種計算機(jī)平臺之上的實(shí)用系統(tǒng)越來越多,另一方面是以網(wǎng)絡(luò)為中心的計算情況越來越多,虛擬機(jī)也重新成為軟件工業(yè)的一個潮流。</p><p>  基于單一操作系統(tǒng)的軟件開發(fā)工具已經(jīng)不能滿足軟件工程師的需要。</p><p>  面對雜亂的信息系統(tǒng)和日新月異的技術(shù)發(fā)明,軟件工程師們開始重新審視開發(fā)虛擬機(jī)的優(yōu)點(diǎn)。</p><p>  編寫

9、虛擬機(jī)是軟件開發(fā)項目的一種,它體現(xiàn)了一種使投資價值最大化的思路。為了從資源方面的投資得到最大的回報,企業(yè)都希望自己花錢開發(fā)出來的軟件的使用期限能夠盡可能地長。把軟件包從一種平臺移植到另一種平臺的工作需要花費(fèi)不小的成本,而且并不是所有的軟件包都能夠移植到所有的平臺上去,軟件包所能支持的平臺種數(shù)是有限度的。大量事實(shí)表明,軟件移植工作往往會變成一場噩夢。</p><p>  使用虛擬機(jī)就可以在一定程度上避免這類事情的發(fā)

10、生。當(dāng)遇到一種新硬件平臺或者新操作系統(tǒng)的時候,唯一需要移植的應(yīng)用級軟件就是虛擬機(jī)本身[1]。</p><p>  1.1.2虛擬機(jī)反對派觀點(diǎn)</p><p>  有不少人反對使用虛擬機(jī),他們的觀點(diǎn)有許多種,其中最主要的就是虛擬機(jī)會降低程序的執(zhí)行性能。他們認(rèn)為,編譯型語言——如C語言——是以計算機(jī)自身的機(jī)器碼的形式執(zhí)行的,因此會執(zhí)行得更快些。但這種說法并不一定正確。</p>&

11、lt;p>  純粹的C++代碼并不一定比由虛擬機(jī)執(zhí)行的字節(jié)碼(byte code)更快。程序的執(zhí)行時間主要消耗在運(yùn)行時庫以及內(nèi)核模式中斷處理例程方面,只有當(dāng)處理的代碼是完全孤立且沒有調(diào)用任何用戶庫或系統(tǒng)調(diào)用時(因?yàn)槌绦蛞却到y(tǒng)的響應(yīng))才能百分之百肯定其機(jī)器碼會執(zhí)行得更快。</p><p>  對于企業(yè)應(yīng)用級系統(tǒng),虛擬級在可移植方面的優(yōu)勢足以彌補(bǔ)這些其實(shí)并慢不了多少的性能損失[1]。</p>

12、<p>  1.2國內(nèi)外研究狀況</p><p>  一個商業(yè)級的虛擬機(jī)實(shí)現(xiàn)是極其復(fù)雜的,一個開源虛擬機(jī)bochs 做得很好,其2.0.2版在Win32平臺下的有13萬行源代碼(C/C++)。能在其上運(yùn)行minux(linux 前身),F(xiàn)reeDSB, Windows95,Windows NT 4.0等操作系統(tǒng)。</p><p>  另一種虛擬機(jī)有自己的指令集,它是針對一種語言來

13、設(shè)計和實(shí)現(xiàn)的。比如JVM(JAVA virtual machine JAVA 虛擬機(jī))。.NET平臺。而由JVM所支持的JAVA語言,目前正得到廣泛的應(yīng)用。</p><p><b>  1.3課題研究方法</b></p><p>  一臺虛擬機(jī)與一臺真實(shí)存在的計算機(jī)的不同之處在于前者只是一個技術(shù)規(guī)范。這類技術(shù)規(guī)范由一系列規(guī)則構(gòu)成,而軟件工程師可以采用任何他自己認(rèn)為適當(dāng)

14、的手段來實(shí)現(xiàn)這些規(guī)則。這就使虛擬機(jī)能夠做到與具體的計算機(jī)平臺無關(guān)。對一臺虛擬機(jī)來說,只要它能夠遵從其技術(shù)規(guī)范里的各項規(guī)則,就可以存在于任何一種計算機(jī)平臺上,就可以用任何一種計算機(jī)語言來編寫[1]。</p><p>  我的畢業(yè)設(shè)計所做的虛擬機(jī)采用標(biāo)準(zhǔn)C/C++語言編寫,在結(jié)構(gòu)上模仿了8086計算機(jī)體系結(jié)構(gòu)。</p><p>  1.4論文構(gòu)成及研究內(nèi)容</p><p&g

15、t;  本論文作為對虛擬機(jī)開發(fā)的一個嘗試,實(shí)現(xiàn)的部分偏重于CPU也即指令執(zhí)行部件。而對于虛擬機(jī)這個運(yùn)行時系統(tǒng)的另一個很重要的部分——中斷處理,由于涉及面太廣,故只是象征性的實(shí)現(xiàn)了INT 10H 0EH中斷(向屏幕輸出),INT 20H中斷(退出程序)。</p><p>  我做的虛擬機(jī)取名為SVM(simple virual machine)——簡單的虛擬機(jī)。</p><p>  論文中將

16、主要說明整個SVM虛擬機(jī)的設(shè)計實(shí)現(xiàn)過程,由于涉及到編程語言C/C++,也參考了一些程序設(shè)計書上的內(nèi)容,在文中一并寫出來。</p><p><b>  (以后略……)</b></p><p>  2 SVM 虛擬機(jī)設(shè)計</p><p>  2.1運(yùn)形時系統(tǒng)與虛擬機(jī)</p><p>  運(yùn)形時系統(tǒng)(run-time sys

17、tem)是各種計算機(jī)程序在其中得以執(zhí)行的一個環(huán)境。運(yùn)行時系統(tǒng)提供了程序在執(zhí)行時所需要的一切東西。例如,運(yùn)行時系統(tǒng)要負(fù)責(zé)為應(yīng)用程序分配內(nèi)存,把該應(yīng)用程序加載到分配好的內(nèi)存里,然后開始執(zhí)行該程序中的指令。</p><p>  如果該程序通過調(diào)用系統(tǒng)調(diào)用要求位于底層的操作系統(tǒng)提供服務(wù),該運(yùn)行時系統(tǒng)還必須負(fù)責(zé)處理有關(guān)的服務(wù)請求。例如,如果應(yīng)用程序需要進(jìn)行文件I/O操作,運(yùn)行時系統(tǒng)就必須向它提供一種與磁盤控制器進(jìn)行通信并提

18、供讀寫訪問的機(jī)制。</p><p>  運(yùn)行時系統(tǒng)的種類有很多。對運(yùn)行時系統(tǒng)進(jìn)行分類的一個辦法是把它們按執(zhí)行程序指令的基本方式進(jìn)行劃分。對那些以處理其本身的機(jī)器碼為指令的程序而言,某計算機(jī)的處理器和操作系統(tǒng)就構(gòu)成了與之對應(yīng)的運(yùn)行時系統(tǒng),處理器提供了一種執(zhí)行指令的機(jī)制。CPU把編碼為數(shù)值形式的指令從內(nèi)存里取出并根據(jù)那些指令完成相應(yīng)的動作,操作系統(tǒng)則實(shí)現(xiàn)了(由處理器和操作系統(tǒng)構(gòu)成的)這個運(yùn)行時系統(tǒng)的策略部分。CPU負(fù)

19、責(zé)執(zhí)行指令, 操作系統(tǒng)負(fù)責(zé)決定事情何時,何地發(fā)生。</p><p>  對那些用機(jī)器指令編寫的程序來說,計算機(jī)本身就是一個運(yùn)行時系統(tǒng)。程序的指令由物理CPU在機(jī)器級上執(zhí)行,指令執(zhí)行的具體過程由操作系統(tǒng)管理。這類運(yùn)行時系涉及計算機(jī)硬件和軟件。</p><p>  那些指令不由物理處理器來直接執(zhí)行的程序需要一個完全由軟件構(gòu)成的運(yùn)行時系統(tǒng)。在這種情況下,程序的指令將由一臺虛擬機(jī)來執(zhí)行。虛擬機(jī)是類

20、似于計算機(jī)的一個軟件程序,它會像真正的處理器那樣取出并執(zhí)行程序指令,但兩者的區(qū)別在于虛擬機(jī)的指令執(zhí)行過程發(fā)生在軟件級而不是硬件級,即指令是由軟件而不是硬件執(zhí)行的[1]。</p><p>  2.2 SVM 虛擬機(jī)</p><p>  SVM虛擬機(jī)是通過模擬硬件平臺而實(shí)現(xiàn)的。 SVM采用8086指令集。這樣可以省去一些建造虛擬機(jī)的重要步驟——比如,指令集不用重建(事實(shí)上,我也沒有能力去定義一

21、個完備的指令集)。SVM虛擬機(jī)采用單任務(wù)方式,每次只運(yùn)行一個程序。</p><p>  虛擬機(jī)總體結(jié)構(gòu)如下:</p><p>  圖2.1 虛擬機(jī)總體結(jié)構(gòu)</p><p>  SVM 虛擬機(jī)源文件組成:</p><p>  c8086.h 聲明8086處理器類;</p><p>  c8086.cpp

22、 實(shí)現(xiàn)8086處理器類;</p><p>  ram.h 聲明內(nèi)存類;</p><p>  ram .cpp 實(shí)現(xiàn)內(nèi)存類;</p><p>  disasm.h 反匯編函數(shù)聲明;</p><p>  disasm .cpp 反匯編函數(shù)定義;</p><p>  debug.h

23、 調(diào)試器函數(shù)聲明;</p><p>  debug.cpp 調(diào)試器函數(shù)定義;</p><p>  fileLoader.h com文件加載函數(shù)聲明;</p><p>  fileLoader.cpp com文件加載函數(shù)定義;</p><p>  global.h 全局?jǐn)?shù)據(jù)類型定義;</p>&

24、lt;p>  test_CPU.cpp SVM測試程序主函數(shù)。</p><p><b>  編譯執(zhí)行環(huán)境:</b></p><p>  運(yùn)行,開發(fā)平臺:Windows 98 SE , Windows 2000 professional SP4</p><p>  編譯器:Visual C++ 6.0/7.0(VC是對標(biāo)準(zhǔn)C/C++支持

25、很好的一個編譯器)</p><p>  2.3 SVM虛擬機(jī)處理器設(shè)計</p><p>  2.3.1 機(jī)器處理器設(shè)計</p><p>  中央處理器可以實(shí)現(xiàn)為基于寄存器或者基于堆棧的機(jī)器。一個基于寄存器的處理器,如Intel 公司的Pentium芯片,有8個用來完成基本運(yùn)算的32位寄存器。一個基于堆棧的處理器,如Harris半導(dǎo)體公司的RTX32P芯片,有兩個用來

26、完成基本運(yùn)算的片上堆棧。</p><p>  基于堆棧的處理器在嵌入式系統(tǒng)中比較流行,這是因?yàn)檫@類處理器支持比較短小的程序,在資源有限的場合也能工作得很好。同時函數(shù)調(diào)用在基于堆棧的機(jī)器上完成得也更有效率,因?yàn)楹瘮?shù)參數(shù)都已經(jīng)被放到堆棧里去了。而在一臺基于寄存器的機(jī)器上,函數(shù)參數(shù)必須逐個收集并壓入堆棧,這就需要做更多的工作。上下文切換在基于堆棧的機(jī)器上的開銷也比較小。如果是在一臺基于寄存器的機(jī)器上進(jìn)行上下文切換,就必

27、須把它所有的寄存器的狀態(tài)都保存起來。對擁有大量寄存器的RISC體系結(jié)構(gòu)來說,上下文切換是一個消耗內(nèi)存的操作。基于堆棧的機(jī)器就不存在這種問題。基于堆棧的計算機(jī)可以為每個進(jìn)程分別準(zhǔn)備一個堆棧,切換上下文時只需變一下堆棧就行了。</p><p>  既然有這么多的優(yōu)點(diǎn),基于堆棧的機(jī)器為什么沒有成為計算機(jī)體系結(jié)構(gòu)的主流呢?這是因?yàn)榛诩拇嫫鞯奶幚砥饔幸粋€極其重要的優(yōu)勢:速度快。寄存器就在CPU的內(nèi)部,如果是對保存在寄存器

28、里的數(shù)據(jù)進(jìn)行運(yùn)算,那它的運(yùn)算速度將是非??斓?。Intel 公司在它新推出的64位處理器Itanium里安排了好幾百個片上寄存器,目的就是為了讓程序操作盡可能多地在芯片上執(zhí)行。再看基于堆棧地處理器,它們的片上堆棧幾乎總是會延伸到內(nèi)存里去。這就造成了這樣一種后果:即使執(zhí)行的是一個面向堆棧的基本操作,處理器也不得不到內(nèi)存里去讀取數(shù)據(jù)。這就大大降低了基于堆棧的處理器的執(zhí)行速度。并且基于寄存器的處理器比較容易調(diào)試(debug),因?yàn)橹噶畹膱?zhí)行過程

29、更清晰(一部分操作數(shù)在寄存器中,在運(yùn)算完后還可以檢查參與運(yùn)算的數(shù)值是多少)[1]。</p><p>  表2.1 基于寄存器的處理器和基于寄存器的處理器的優(yōu)缺點(diǎn)</p><p>  2.3.2 SVM虛擬機(jī)處理器設(shè)計</p><p>  由于虛擬機(jī)完全由軟件構(gòu)成,沒有硬件設(shè)備,所以它不存在剛才提到的某些缺陷。</p><p>  與硬件處理器

30、的分類相似,虛擬機(jī)也有基于堆棧和基于寄存器之分。JVM就是基于堆棧的。這可以使JAVA字節(jié)碼文件很短。</p><p>  而我將SVM虛擬機(jī)的中央處理器實(shí)現(xiàn)為基于寄存器的機(jī)器。直接采用8086指令集。</p><p>  要知到,設(shè)計一個完備的指令集可不是一件簡單的事,至少我還沒有那種實(shí)力。SVM虛擬機(jī)的設(shè)計目標(biāo)是能夠運(yùn)行原8086平臺下的部分16位com程序(程序只能使用除去HLT,W

31、AIT,IN,OUT,LOCK,ESC的88條指令,并限制使用INT指令)。</p><p>  SVM虛擬機(jī)處理器的組成:</p><p><b>  寄存器</b></p><p>  SVM虛擬機(jī)有8個通用整數(shù)寄存器,4個段寄存器,一個指令指針,一個指令指針,一個標(biāo)志寄存器(它有16位,但只使用其中的9位)。這些寄存器及其用途如圖所示:&

32、lt;/p><p>  表2.2寄存器及其用圖</p><p>  其中,AX,BX,CX,DX 都能劃分為兩個8位寄存器。一個用來保存低字節(jié),一個用來保存高字節(jié)(如AX寄存器可以劃分為AH 和 AL)。</p><p><b>  運(yùn)算單元</b></p><p>  由C8086類(在C8086.C中)的成員函數(shù)實(shí)現(xiàn)。&

33、lt;/p><p>  2.4 SVM內(nèi)存分配</p><p>  SVM 虛擬機(jī)在啟動時會請求分配1M字節(jié)的內(nèi)存空間,內(nèi)存空間有可能會到虛擬內(nèi)存中去,因?yàn)闆]有對可用物理內(nèi)存進(jìn)行檢查。但由于只能加載com程序,實(shí)際上只使用了其中的64KB字節(jié)。</p><p>  2.5 SVM內(nèi)存尋址</p><p>  SVM 模擬8086處理器,選用20位

34、的實(shí)模式的地址空間,內(nèi)存中某個字節(jié)的地址時由兩位16位數(shù)值指定的,這兩個數(shù)值分別叫做“段地址”(segment address)和“偏移地址”(offset address)。一個給定字節(jié)的內(nèi)存地址是這樣計算出來的:把16位段地址乘以16(即0x10),然后把結(jié)果與偏移地址相加。</p><p>  2.6 SVM 多字節(jié)存儲方式</p><p>  多字節(jié)數(shù)據(jù)在內(nèi)存中有兩種存放方式:降序

35、格式(big-endian)和升序格式(little-endian)。如果一個多字節(jié)數(shù)據(jù)的最高位字節(jié)存放在內(nèi)存中的最低位地址,我們就說它采用的是降序記號。升序記號方式正好相反——多字節(jié)數(shù)據(jù)的最低位字節(jié)降存放在內(nèi)存中的最低地址。</p><p>  請看下面這個例子。假設(shè)有一個多字節(jié)值“0Xabcdef12”存放在內(nèi)存中的某個地方(我們不妨假設(shè)從地址24處開始存放)。這個數(shù)據(jù)的降序和升序表示法如圖所示:</p

36、><p><b>  降序存儲方式:</b></p><p>  24 25 26 27</p><p><b>  升序存儲方式:</b></p><p>  24 25 26 27 </p><p>  圖:多字節(jié)數(shù)據(jù)值在內(nèi)存中的

37、兩種存放方式:降序和升序</p><p>  以降序方式表示的數(shù)據(jù)也稱為“網(wǎng)絡(luò)順序”(network order)。這是因?yàn)門CP/IP等網(wǎng)絡(luò)協(xié)議要求通過網(wǎng)絡(luò)傳輸?shù)男畔⒍急仨毑捎媒敌蚋袷絒1]。</p><p>  SVM虛擬機(jī)的設(shè)計目標(biāo)是執(zhí)行DOS下的使用8086指令集的程序,故對多字節(jié)排列采用升序方式。</p><p>  2.7 SVM輸入輸出</p&g

38、t;<p>  對于8086平臺,它有兩個指令可以用來把寄存器長度的數(shù)據(jù)讀寫到外設(shè):IN 和OUT</p><p>  IN指令用來從某個I/O端口讀入數(shù)據(jù)。OUT用來把某個數(shù)據(jù)寫到某個I/O端口。I/O端口是被映射到某個外設(shè)或者外設(shè)的某個部件的一個數(shù)字。端口號的范圍是0到65535。</p><p>  由于對計算機(jī)里的I/O硬件進(jìn)行設(shè)置需要考慮太多的細(xì)節(jié),需要很長的時間去

39、收集齊全外設(shè)的信息(工作原理,功能號,端口號等),所以,在實(shí)現(xiàn)SVM虛擬機(jī)的I/O時,我只能用軟件來模擬實(shí)現(xiàn)I/O(還只能實(shí)現(xiàn)向屏幕輸出單個字符)。</p><p>  輸出 INT 0X10 功能號 0X0E,模擬實(shí)現(xiàn)。</p><p>  雖然在Win32下,用軟件實(shí)現(xiàn)SVM虛擬機(jī)的I/O時,使用底層的系統(tǒng)調(diào)用(system call)能夠獲得更好的性能,這些操作更接近硬件,并且一般不

40、提供緩沖功能(bufferring)或額外的格式化(formatting)。C語言標(biāo)準(zhǔn)的函數(shù)就是建立在系統(tǒng)調(diào)用層之上的(即封裝具體平臺下的底層系統(tǒng)調(diào)用),它更側(cè)重于功能而不是執(zhí)行速度。但倚賴與C語言標(biāo)準(zhǔn)API對我來說好入手一些,同時,也利于對SVM虛擬機(jī)本身的移植。</p><p>  2.8 SVM 中斷</p><p><b>  實(shí)模式下的中斷處理</b><

41、;/p><p>  通過置位/清零,F(xiàn)LAG的第10個比特位(如果下標(biāo)從0開始計算,就是第9位),我們就能激活/禁止實(shí)模式下的軟件中斷。人們把這個標(biāo)志位稱為IF(interrupt flag中斷標(biāo)志)。</p><p>  IF標(biāo)志可用兩條指令進(jìn)行置位或清除。STI指令用來對IF標(biāo)志進(jìn)行置位,從而使處理器能夠?qū)χ袛嘧龀鲰憫?yīng)。CLI指令用來清除IF標(biāo)志,從而使(大多數(shù))中斷都被屏蔽。</p

42、><p>  軟件中斷是用INT指令產(chǎn)生的。每執(zhí)行一條INT指令,就會產(chǎn)生一個軟件中斷。INT指令的操作數(shù)是一個單字節(jié)的整數(shù),人們把它稱為“中斷向量”(interrupt vector)。例如,用來處理第12個中斷向量的指令就是“INT 12”。</p><p>  中斷向量可以是0到255之間的任意整數(shù)。中斷向量其實(shí)只是“中斷向量表”(interrupt vector table ,IVT)

43、的下標(biāo),IVT中的元素都是雙字(4字節(jié))數(shù)值。既然中斷向量有256個可能的取值,IVT表的長度就是1024個字節(jié)。中斷向量表從處理器地址空間的最底端開始,因此它將占據(jù)內(nèi)存的第一個KB。IVT表中的每一個雙字?jǐn)?shù)據(jù)項包含著某個中斷服務(wù)程序的段地址和偏移地址。偏移地址保存在第一個字節(jié)里,段地址保存在隨后的第二個字里。中斷下向量表的構(gòu)造情況如圖所示:</p><p>  圖2.2 中斷下向量表的構(gòu)造圖</p>

44、<p>  處理器在執(zhí)行中斷指令時將按如下步驟進(jìn)行:</p><p>  把FLAG寄存器壓入堆棧</p><p>  把CS寄存器壓入堆棧</p><p>  把IP寄存器壓入堆棧(向量中斷處理結(jié)束后將要執(zhí)行的下一條指令)。</p><p>  清除IF和TF標(biāo)志位</p><p>  根據(jù)中斷向量找到

45、對應(yīng)的IVT數(shù)據(jù)項</p><p>  把IVT中的段地址和偏移地址分別加載到CS 和 IP 寄存器里去。</p><p>  從效果上講,這等于是讓程序控制條轉(zhuǎn)到中斷服務(wù)程序,中斷服務(wù)程序去做自己該做的事。為了讓處理器回到一種“清醒”的狀態(tài),放到中斷服務(wù)程序里的第一條指令應(yīng)該是STI指令,</p><p>  這將喚醒處理器并使它能夠再次接受中斷請求。中斷服務(wù)程序

46、必須用IRET指令返回,IRET指令將把以上步驟反過來執(zhí)行。使程序路徑能夠正確地回到緊跟再剛才這條中斷指令的下一條指令上去。具體來說,IRET指令將按以下步驟進(jìn)行:1)把堆棧頂部的16位數(shù)值彈出到IP寄存器里去。</p><p>  2)把堆棧頂部的16位數(shù)值彈出到CS寄存器里去。</p><p>  3)把堆棧頂部的16位數(shù)值彈出到FLAG寄存器里去。</p><p

47、>  SVM虛擬機(jī)將簡化以上硬件中斷處理的過程。它使用軟件模擬的方式實(shí)現(xiàn)BIOS中斷。</p><p>  SVM虛擬既需要依賴宿主操作系統(tǒng)提供諸如輸入輸出之類的基本服務(wù)。讓自己游離于硬件通信細(xì)節(jié)之外。SVM虛擬即讓宿主操作系統(tǒng)作為之給予精簡設(shè)備之間的中間人,不直接與硬件發(fā)生糾纏(實(shí)事上在Win32下,如果不是驅(qū)動程序,也不可能有ring0級權(quán)限去訪問硬件)。也就是說,宿主操作系統(tǒng)將代表虛擬機(jī)來請求各種底層

48、的操作細(xì)節(jié)。</p><p>  每一中操作系統(tǒng)都會提供一些人們稱之為“系統(tǒng)調(diào)用“(system call)的基本函數(shù),這些系統(tǒng)調(diào)用將負(fù)責(zé)管理機(jī)算計的可用資源調(diào)用。系統(tǒng)調(diào)用就像是一些原子元素,它們的各種組合構(gòu)成了操作系統(tǒng)這個宇宙中的一切事務(wù)。任何一個操作系統(tǒng)命令或任何一個用戶程序都可以分解為一系列系統(tǒng)調(diào)用。</p><p>  系統(tǒng)調(diào)用一般都處于非常底層的位置。它們的操作只能用特定機(jī)器的硬

49、件語言來描述。換句話說,系統(tǒng)調(diào)用大都是用匯編語言寫的。以匯編語言來編寫系統(tǒng)調(diào)用的原因并不是出于速度方面的考慮——執(zhí)行速度方面的邊界效應(yīng)與成千上萬行匯編代碼所形成的思維復(fù)雜性并不成比例。一會便于演變歇息同調(diào)用的真正原因是有些事情你只能用匯編語言來做。</p><p>  系統(tǒng)調(diào)用的輸入輸出參數(shù)還必須通過特定的機(jī)器寄存器來指定。</p><p>  為了降低復(fù)雜性,系統(tǒng)工程師會盡量把與硬件直接

50、相關(guān)的匯編代碼的操作系統(tǒng)的底層操作隔離開來。軟件開發(fā)人員再用C/C++對匯編代碼進(jìn)行打包以使之更容易使用。</p><p>  把機(jī)器操作歸結(jié)為一整套系統(tǒng)調(diào)用的做法是非常有遠(yuǎn)見的。但這絕不是對機(jī)器操作的抽象至少有兩個層次來隔離核心級匯編語言例程的系統(tǒng)調(diào)用以及來封裝系統(tǒng)調(diào)用的函數(shù)庫調(diào)用。如圖所示:</p><p><b>  圖2.3系統(tǒng)層次圖</b></p>

51、;<p>  C程序設(shè)計語言的標(biāo)準(zhǔn)函數(shù)庫是這種抽象歸納的經(jīng)典示例。比如putchar()函數(shù)。</p><p>  各種版本的標(biāo)準(zhǔn)函數(shù)庫實(shí)現(xiàn)大都以更通用的putc()函數(shù)定義putchar()函數(shù),putc()用來把一個字符寫到一個給定的輸出流去。就putchar()函數(shù)而言,它的輸出流被規(guī)定為標(biāo)準(zhǔn)輸出(stdout)。</p><p>  #define putchar(c

52、) putc(c, stdout)</p><p>  因此,要想了解putchar(),必須先把putc()搞清楚:</p><p>  int putc(int ch, FILE *stream)</p><p><b>  {</b></p><p><b>  int ret;</b>&l

53、t;/p><p>  ret = write(stream, &ch, 1);</p><p>  if (ret != 1) {return (EOF);}else{return (ch);}</p><p><b>  }</b></p><p>  putc()函數(shù)又用到了一個名為write()的系統(tǒng)調(diào)用,這種

54、嵌套結(jié)構(gòu)的特點(diǎn)是:越接近硬件,函數(shù)或例程的功能就越通用,越基本。</p><p><b>  /*</b></p><p>  stream = output stream to write to </p><p>  buffer = buffer of bytes to write to stream</p><p>

55、;  nbytes = number of bytes to write</p><p>  returns = number of bytes written to stream</p><p><b>  */</b></p><p>  int write(FILE *stream, void *buffer, int nbytes)&l

56、t;/p><p><b>  {</b></p><p>  struct call_struct;</p><p>  call_struct.type = FILE_SYSTEM;</p><p>  call_struct.subtype = BUFF_OUTPUT;</p><p>  cal

57、l_struct.param1 = (long)stream;</p><p>  call_struct.param2 =(long)buffer;</p><p>  call_struct.param3=nbytes;</p><p><b>  asm</b></p><p><b>  {</b

58、></p><p>  MOV ECX,USE_LIBRARY</p><p>  LEA EAX,call_struct</p><p>  INT SYSTEM_CALL</p><p><b>  }</b></p><p><b>  }</b></p&g

59、t;<p>  write()函數(shù)實(shí)際上是一個二傳手,它將把球在傳給一個名為system_call的系統(tǒng)調(diào)用通道,一般地,操作系統(tǒng)只有一個對系統(tǒng)調(diào)用請求進(jìn)行集中分配的機(jī)制,而這是很有必要的。這是因?yàn)?,系統(tǒng)調(diào)用通常都是用軟件中斷實(shí)現(xiàn)的,而產(chǎn)生軟件中斷的辦法只有一種(如在Intel平臺上使用的INT指令)。換句話說,系統(tǒng)調(diào)用其實(shí)就是一系列相同的基本指令編寫出不同的變化組合。</p><p>  從上圖中

60、可以看出,系統(tǒng)調(diào)用通道是用戶級函數(shù)庫與各種系統(tǒng)調(diào)用之間的一條必經(jīng)之路。在具備內(nèi)存保護(hù)機(jī)制的操作機(jī)制的操作系統(tǒng)里,系統(tǒng)調(diào)用通道將是用戶執(zhí)行各種系統(tǒng)調(diào)用的唯一途徑,除此之外,沒有第二條路可走。這就使計算機(jī)的運(yùn)行狀態(tài)產(chǎn)生了“內(nèi)河模式”(kernel mode)和“用戶模式”(user mode)之分。當(dāng)CPU正在執(zhí)行的指令屬于某個系統(tǒng)調(diào)用時,我們就說它運(yùn)行在內(nèi)核模式;當(dāng)計算機(jī)正在執(zhí)行的指令屬于某個庫函數(shù)或者屬于用戶編寫出來的某個函數(shù)時,我們就

61、說它運(yùn)行在用戶模式。</p><p>  在某種程度上,我們可以把操作系統(tǒng)看作是由它的全體系統(tǒng)調(diào)用所構(gòu)成的一個集合,那些系統(tǒng)調(diào)用就好比是操作系統(tǒng)的簽名。但系統(tǒng)調(diào)用接口摒不能把操作系統(tǒng)完全的定義下來,而是由其系統(tǒng)調(diào)用接口以及那些系統(tǒng)調(diào)用的具體實(shí)現(xiàn)方法所定義的[1]。</p><p>  SVM虛擬機(jī)的中斷調(diào)用結(jié)構(gòu)如下圖:</p><p>  圖2.4 SVM虛擬機(jī)中斷

62、調(diào)用結(jié)構(gòu):</p><p>  2.9 SVM 匯編器</p><p><b>  匯編語言</b></p><p>  在4月份對C8086類的測試中(單元測試,即單獨(dú)測試一個個的指令執(zhí)行單元),我是以手工方式建立機(jī)器碼文件。但是,如果是面對大量的機(jī)器碼編程,需要考慮周全的瑣碎細(xì)節(jié),這只能使人感到力不從心。</p><p&

63、gt;  不用手工方式來建立機(jī)器碼可執(zhí)行文件的辦法是存在的。具體地說,用一種匯編語言來編寫可執(zhí)行文件是完全能夠做到的。匯編語言是一種底層程序設(shè)計語言。為了更好的理解這句話的含義,我們必須先搞清楚幾個概念。</p><p>  “程序設(shè)計語言”是一種能夠用來準(zhǔn)確地寫出程序的符號系統(tǒng)。程序設(shè)計語言通過他們的語法(syntax,該語言所能使用的符號以及這些符號的使用規(guī)則)和語義(semantics,語言符號所代表的含義

64、)得到定義[1] 。</p><p>  程序設(shè)計語言的符號化語句不會產(chǎn)生歧義,這是他們與數(shù)學(xué)語句的相似之處。但程序設(shè)計語言的符號化語句卻不必非得解析成“真”或“假”,這是它們與數(shù)學(xué)語句的不同之處[1]。</p><p>  語言的語法可以通過一套名為“上下文無關(guān)文法”(context-free grammar)的規(guī)則集合做出正規(guī)定義。程序設(shè)計去眼大都采用一種名為“巴科斯·諾爾范

65、式”(Backas-Naur form,BNF)的記號來表示它們的語法規(guī)則。語言的寓意很難用含義精確的邏輯符號來描述[1]。</p><p>  “匯編語言”是一種程序設(shè)計語言,它直接把符號化的助記符映射為機(jī)器指令,機(jī)器指令和助記符之間的映射結(jié)果幾乎是一對一的關(guān)系[1]。</p><p>  1110 1001 0000 1111 0000 0000 直接映射為:JMP 0012</

66、p><p>  匯編語言里還提供有“宏指令”(macro directivec)。洪指令用來經(jīng)以各種符號,這些符號可以代表內(nèi)存地址,數(shù)值常數(shù)或一組機(jī)器指令。匯編語言中的宏指令的用法與C程序設(shè)計語言的情況基本相同[1]。</p><p>  一般來說,用匯編語言寫成的源文件可以被一種人們稱為“匯編器”(assembler)的開發(fā)工具翻譯——或者匯編——為機(jī)器碼可執(zhí)行文件。匯編器能夠體程序員完成內(nèi)

67、存地址,偏移量和其他瑣碎的安排記錄工作[1]。</p><p>  程序設(shè)計語言是對處理器指令的抽象,我們可以根據(jù)這種抽象的高低層次來對它們進(jìn)行分類。低級語言——如匯編語言——的特征與機(jī)器指令有相當(dāng)直接的對應(yīng)關(guān)系。匯編語言中的一條語句通常直接對應(yīng)一條機(jī)器指令。而高級語言——如BASIC——與機(jī)器操作細(xì)節(jié)的距離則相當(dāng)遙遠(yuǎn),BASIC語言中的一條語句往往相當(dāng)于很多條機(jī)器指令。中級語言——如C語言——則用使具備執(zhí)行低級

68、操作和高級操作的能力[1]。</p><p>  匯編器的設(shè)計將要涉及一些將當(dāng)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。好在有NASM,MASM等匯編器存在。因?yàn)閰R編器比虛擬機(jī)要復(fù)雜很多。</p><p>  SVM 虛擬機(jī)采用的是8086指令集,這樣就可以用已有的支持8086的匯編器,如NASM , TASM, MASM等。我使用的是NASM,用來編譯com文件的格式是:</p><p>

69、  C:\program files>nasm test.asm –f bin –o test.com</p><p>  -f 用來生成com文件;</p><p>  -o 用來指定生成的文件明。</p><p>  2.10 SVM 反匯編器</p><p>  作為SVM虛擬機(jī)調(diào)試器的組件之一,為便于管理代碼,從調(diào)試器代碼中

70、獨(dú)立了出來。SVM反匯編器簡單地將機(jī)器碼翻譯為對應(yīng)的匯編源程序,其結(jié)構(gòu)和C8086類很相似,只是在處理機(jī)器碼時不執(zhí)行罷了。</p><p>  2.11 SVM 調(diào)試器</p><p><b>  2.11.1概述</b></p><p>  “調(diào)試器”(debugger)是一種軟件開發(fā)工具, 它能讓一個程序的執(zhí)行路徑暫停下來以便人們查看和修改

71、概進(jìn)程的機(jī)器狀態(tài)。調(diào)試器就像是一個特殊的實(shí)驗(yàn)室,你可以在里面運(yùn)行和分析程序,看它在執(zhí)行時到底在干些什么。例如,在某程序執(zhí)行路徑上的某個特定地點(diǎn),你可以把一切都凍結(jié)起來,然后查看一下寄存器或內(nèi)存區(qū)間的情況以檢查某個給定變量的值。有些不易發(fā)現(xiàn)的程序漏洞只有在這類環(huán)境下才有可能被捕獲和分析[1]。</p><p>  調(diào)試器又分為兩個基本類型</p><p><b>  機(jī)器級調(diào)試器&

72、lt;/b></p><p><b>  源碼級調(diào)試器</b></p><p>  劃分這兩類調(diào)試器的標(biāo)準(zhǔn)是它們所管理的”指令粒度”(granularity of instructions)。</p><p>  機(jī)器級調(diào)試器處理的指令是二進(jìn)制編碼形式的底層機(jī)器指令。它使你能夠觀察到計算機(jī)最底層,最基本的操作情況。機(jī)器級調(diào)試器是最后一道防

73、線,一般用來分析已經(jīng)成品化了的程序[1]。</p><p>  源代碼級的調(diào)試器處理的指令是高級程序設(shè)計語言的語句。源代碼級調(diào)試器使我們能夠在程序設(shè)計語言的框架里追蹤程序的執(zhí)行路徑。一般來說,源代碼級調(diào)試器要比機(jī)器級調(diào)試器更容易使用,因?yàn)楣こ處焸冇貌恢侔丫速M(fèi)在大量的機(jī)器細(xì)節(jié)</p><p>  上,源代碼級調(diào)試器都已經(jīng)替他們照顧到了[1]。</p><p> 

74、 2.11.2調(diào)試技術(shù)</p><p>  為了提供基本調(diào)試功能,各種調(diào)試器都使用了兩種基本技術(shù):</p><p><b>  斷點(diǎn)</b></p><p><b>  單步執(zhí)行</b></p><p><b> ?。?)斷點(diǎn)</b></p><p> 

75、 “斷點(diǎn)”(bread point )是一種特殊類型的機(jī)器指令, 在使用中,它們將插入到程序的正文段(text segment)里。斷點(diǎn)既可以在程序運(yùn)行時被插入——既把斷點(diǎn)放到某個進(jìn)程的內(nèi)存映像里去,也可以在編譯時插入——即把斷點(diǎn)放到可執(zhí)行文件里去。不論采用的是哪種方法,斷點(diǎn)的作用都是一樣的:讓處理器暫停某個任務(wù)的執(zhí)行并把程序控制轉(zhuǎn)交給調(diào)試器,以便用戶查看和修改該任務(wù)的機(jī)器狀態(tài)[1]。</p><p><b

76、> ?。?)單步執(zhí)行</b></p><p>  “單步執(zhí)行”(simle-step excution)是處理器的一種執(zhí)行模式,在這種模式里,處理器每執(zhí)行完一條語句,就會把程序控制轉(zhuǎn)交給調(diào)試器。在單步執(zhí)行模式下,調(diào)試器能夠一條指令一條指令地追蹤進(jìn)程的執(zhí)行路徑。</p><p>  一般情況下,用在在接近某個預(yù)定代碼區(qū)域的某個地方設(shè)置一個斷點(diǎn)。當(dāng)執(zhí)行路徑到達(dá)這個斷點(diǎn)并把程序

77、控制轉(zhuǎn)交給調(diào)試器之后,用戶再以單步執(zhí)行方式通過這個預(yù)定代碼區(qū)域,看該代碼區(qū)域里會發(fā)生什么事情[1]。</p><p>  2.11.3 SVM 調(diào)試器的實(shí)現(xiàn)</p><p>  SVM 調(diào)試器是一個機(jī)器級調(diào)試器。僅僅作為一個嘗試,SVM 調(diào)試器很簡陋,只提供了幾個服務(wù)。不支持?jǐn)帱c(diǎn),寄存器修改等功能。</p><p>  該調(diào)試器的功能見SVM虛擬機(jī)調(diào)試器的使用。&l

78、t;/p><p>  2.12 建造運(yùn)行時系統(tǒng)</p><p>  建造一個虛擬機(jī)運(yùn)行時系統(tǒng)的步驟大體上如下圖:</p><p>  圖2.5 建造虛擬機(jī)網(wǎng)絡(luò)圖</p><p>  2.13 SVM 虛擬機(jī)的擴(kuò)展</p><p>  到此,SVM 虛擬機(jī)的功能仍然是很不完善的,由于初始設(shè)計的原因,要對其進(jìn)行擴(kuò)展有可能要重新

79、設(shè)計整個程序的結(jié)構(gòu),尤其是處理器對調(diào)試器的支持部分。</p><p>  SVM 虛擬機(jī)可以擴(kuò)展的方面還有很多,還可以做虛擬設(shè)備,擴(kuò)展指令集,加載NE 文件,實(shí)現(xiàn)IN,OUT 等涉及硬件的指令,實(shí)現(xiàn)更多的BIOS中斷。其中BIOS中斷又有兩種實(shí)現(xiàn)方式——用軟件模擬實(shí)現(xiàn),或在建好虛設(shè)備的基礎(chǔ)上載入一段BIOS程序。</p><p>  關(guān)于調(diào)試器的擴(kuò)展,原本調(diào)試器的功能可以更強(qiáng)的,比如指定反

80、匯編的位置,設(shè)置斷點(diǎn)等。但對于命令行的處理太過繁瑣,需要對參數(shù)進(jìn)行嚴(yán)格的檢查。時間不夠,我也就沒有做了。而調(diào)試器中的相關(guān)接口函數(shù)確實(shí)是提供了指令定位的功能。</p><p>  還可以加入更多的防錯處理使得SVM虛擬機(jī)更健壯。</p><p>  當(dāng)然,擴(kuò)展是在16位數(shù)據(jù)的基礎(chǔ)上的,若是要建造32位的虛擬機(jī),SVM整個都要改,不只是表面上指令的操作數(shù)位數(shù)不同了,IA32相對于16體系結(jié)構(gòu)變

81、化很大,出現(xiàn)了3種指令執(zhí)行模式:實(shí)模式,保護(hù)模式,虛擬86模式。技術(shù)的發(fā)展是趨于完善,復(fù)雜的,SVM只是一個嘗試。對于SVM,要改成32位虛擬機(jī),那就不叫擴(kuò)展,而是重構(gòu)了。目前,BOCHS虛擬機(jī)(一個開源的虛擬機(jī))在模擬32位硬件平臺上就做得很好。</p><p> ?。?SVM 虛擬機(jī)運(yùn)行時環(huán)境</p><p>  3.1SVM執(zhí)行方式</p><p><

82、b>  SVM虛擬機(jī)生命期</b></p><p>  圖3.1 SVM 虛擬機(jī)生命期</p><p><b>  啟動虛擬機(jī)</b></p><p>  C:\Program files>svm test2.com</p><p><b>  運(yùn)行示例:</b></p

83、><p>  圖3.2 SVM運(yùn)行圖</p><p>  3.2 SVM調(diào)試方式</p><p><b>  進(jìn)入調(diào)試方式</b></p><p>  c:\program files>svm test2.com –d</p><p><b>  -q 退出調(diào)試器</b>&

84、lt;/p><p>  顯示存儲單元內(nèi)容——D命令(Dump Command)</p><p><b>  -d</b></p><p>  從即將執(zhí)行的地址開始, 顯示80H個字節(jié)單元內(nèi)容</p><p>  圖3.3 顯示內(nèi)存單元</p><p>  上述顯示內(nèi)容分為三部分:左邊是每一行存儲單元的

85、起始地址(段基值:偏移量);</p><p>  中間是16個字節(jié)單元,以兩位十六進(jìn)制數(shù)顯示其現(xiàn)行內(nèi)容;右邊是中間各字節(jié)單元用相應(yīng)的ASCII碼字符顯示,如該單元數(shù)據(jù)是不可顯示字符,使用“.“表示。</p><p>  (2)顯示寄存器內(nèi)容——R命令(Register Command)</p><p><b>  -r</b></p>

86、;<p>  圖3.4 顯示寄存器內(nèi)容</p><p>  鍵入R后, CPU各寄存器內(nèi)容全部顯示出來。第二行后半部顯示標(biāo)志寄存器各標(biāo)志位狀態(tài),且各標(biāo)志位的復(fù)位(“0”狀態(tài))和置位(“1”狀態(tài))是用兩個字符來表示的,如表所示;顯示的第三行表示現(xiàn)在CS:IP指向的下面將要執(zhí)行的指令。</p><p>  表3.1 標(biāo)志寄存器個標(biāo)志位的狀態(tài)字符</p><p&

87、gt;  顯示匯編語言指令(反匯編)——U命令(Unassemble Command)</p><p>  在調(diào)試狀態(tài)下運(yùn)行程序是執(zhí)行某內(nèi)存區(qū)域的目標(biāo)代碼,為了知道執(zhí)行的是什么指令,操作數(shù)的地址在哪里等,希望把目標(biāo)代碼“還原”為匯編語言指令(即源程序中指令),這個操作叫做反匯編。U命令從當(dāng)前地址開始,顯示32個字節(jié)目標(biāo)代碼的匯編語言指令。</p><p>  執(zhí)行U命令后,屏幕顯示示例如下

88、:</p><p>  圖3.5 反匯編輸出</p><p>  (4)單步運(yùn)行方式——T命令(Trap Command)</p><p>  每次執(zhí)行T命令,僅執(zhí)行一條指令。每執(zhí)行完一條指令后,就自動顯示CPU中各寄存器和標(biāo)志寄存器內(nèi)容。并顯示下一條即將執(zhí)行的指令。T命令執(zhí)行的顯示示例如下:</p><p>  圖3.6 跟蹤方式輸出<

89、;/p><p><b>  4 程序設(shè)計處理</b></p><p>  4.1程序設(shè)計中的宏處理</p><p>  C8086類由一個譯指令成員函數(shù)和執(zhí)行成員函數(shù)以及一些輔助成員函數(shù)組成。</p><p>  當(dāng)一個指令執(zhí)行時,譯碼成員函數(shù)對其第一個字節(jié)進(jìn)行翻譯,并選取相應(yīng)的執(zhí)行函數(shù)對指令進(jìn)行處理。為了盡可能的提高指令

90、的執(zhí)行速度,我將執(zhí)行成員函數(shù)及輔助成員函數(shù)全部聲明為內(nèi)聯(lián)函數(shù),以省去函數(shù)調(diào)用的開銷。當(dāng)然,最后的可執(zhí)行文件要比基于函數(shù)的大很多。</p><p>  注:在各種類型的C 編譯器里,函數(shù)調(diào)用總是會有一定的開銷。調(diào)用一個函數(shù)通常需要把一些數(shù)值壓入堆棧,把程序執(zhí)行點(diǎn)切換到內(nèi)存里的另一個地點(diǎn),最后在從堆棧里彈出一些數(shù)值。避免這類開銷的辦法之一是把函數(shù)定義為宏(macro)。例如有一個函數(shù),如果它會被頻繁地調(diào)用,為了節(jié)省函

91、數(shù)調(diào)用過程中系統(tǒng)開銷,我們可以把函數(shù)寫成宏:</p><p>  #define abs(x) ( (x) >= 0) ? (x) : -(x)</p><p>  這樣,(通過預(yù)處理程序展開宏)我們每一次調(diào)用abs(x),譬如:</p><p>  int a = abs(-5);</p><p>  我們就相當(dāng)于直接寫:</p

92、><p>  int a = ( (5) >= 0) ? (5) : -(5);</p><p>  效率明顯比編寫一個函數(shù)然后調(diào)用它要好。</p><p>  但宏也不是萬能的,它有很多不盡人意的方面,例如:</p><p>  int a = abs(5) + 1;/* 結(jié)果應(yīng)該等于6 */</p><p>

93、  然而,預(yù)處理程序把宏展開:</p><p>  int a = ( (5) >= 0) ? (5) : -(5) + 1;</p><p>  “+”運(yùn)算符的優(yōu)先級比“?”要高,所以上面的式子其實(shí)是:</p><p>  int a = ( (5) >= 0) ? (5) : (-(5) + 1);/* a = 5 !*/</p>

94、<p>  為了避免這樣的漏洞,我們要小心翼翼地提方,盡可能采用適當(dāng)?shù)拇胧?lt;/p><p>  #define abs(x) ( ( (x) >= 0) ? (x) : -(x))</p><p>  雖然這里“加括號”可以解決問題,但由于宏有不少“副作用”,某些場合就頗為棘手。</p><p>  因?yàn)楹陜H僅是一種記號替換,不像函數(shù),它沒有辦法知

95、道真正的參數(shù)時什么,從而無法對參數(shù)進(jìn)行檢查,也不能像函數(shù)那樣把某些運(yùn)算局限在內(nèi)部。</p><p>  因此由C++提出和實(shí)現(xiàn)了“內(nèi)聯(lián)涵數(shù)”,它本身的確是函數(shù),但必要時編譯器可以把它的代碼像宏那樣“嵌入”到調(diào)用它的地方,從而既節(jié)省系統(tǒng)開銷又沒有宏的缺點(diǎn)。</p><p>  今天,C99也擁有了這項語言特性[2]。</p><p>  4.2程序設(shè)計中的異常處理&l

96、t;/p><p>  我曾經(jīng)考慮過學(xué)習(xí)C++中的try catch throw 異常處理機(jī)制,然后用在SVM虛擬機(jī)的實(shí)現(xiàn)中。但最終未采用該機(jī)制,SVM虛擬機(jī)的執(zhí)行效率已經(jīng)很難讓人恭維了,加入該機(jī)制只會使虛擬機(jī)的運(yùn)行更慢。不過在此,仍簡要介紹一下該機(jī)制。</p><p>  在異常處理技術(shù)得到廣泛應(yīng)用之前,即使應(yīng)用程序理出現(xiàn)了奇怪的事情,你也只能依靠全局變量和函數(shù)的返回值來判斷到底發(fā)生了什么事情

97、。</p><p>  然而,你也不能期望一個孤零零的出錯值總是能向你提供足夠的信息,函數(shù)出錯并不可怕,可要是函數(shù)反回了一個“-1”這樣的整數(shù)值,那即使是再高明的程序員也很難找出函數(shù)失敗的真正原因,這種做法的最終結(jié)果將是丟失程序的狀態(tài)信息。</p><p><b>  給出一段代碼:</b></p><p>  FILE *fptr;</

98、p><p><b>  int ch;</b></p><p>  fptr = fopen(“myfile.txt”, “rb”);</p><p><b>  /*</b></p><p>  forget to check for fptr == NULL</p><p>

99、  sends everything to the big room if the file is missing.</p><p><b>  */</b></p><p>  ch = fgetc(fptr);</p><p>  while(ch != EOF)</p><p><b>  {</b

100、></p><p>  printf(“%c”, (char)ch);</p><p>  ch = fgetc(fptr);</p><p><b>  }</b></p><p>  fclose(fptr);</p><p>  在沒有異常處理功能的平臺上,上面這段代碼在myfile.

101、txt文件真的不存在時將會造成一場可怕的混亂,而具備異常處理功能的平臺則會把這場返回值混亂消除。</p><p>  異常是程序在試圖進(jìn)行某種非正常操作時生成的一個結(jié)構(gòu)。這并不意味著每個異常都代表著一個因某些基本的系統(tǒng)服務(wù)沒有執(zhí)行成功而導(dǎo)致的程序出錯。只要是偏離程序員設(shè)計意圖的情況都可以用異常來表示。</p><p>  當(dāng)異常出現(xiàn)時,程序員執(zhí)行路徑將從產(chǎn)生這個異常的代碼位置跳轉(zhuǎn)到預(yù)先安排

102、好的異常處理代碼位置去,這種跳轉(zhuǎn)大多是一些“長跳轉(zhuǎn)”(non-local jump,從一個函數(shù)跳轉(zhuǎn)到另一個函數(shù)里去)。人們經(jīng)常用“拋出”(throw)和“捕獲”(catch)這兩個詞來描述異常處理中的這個跳轉(zhuǎn)動作。</p><p>  生成異常的代碼拋出一個異常,而將要對之進(jìn)行處理的代碼則捕獲了它。整個過程如圖所示:</p><p>  圖 4.1 異常處理示意圖</p>&

103、lt;p>  由于執(zhí)行效率的原因,SVM虛擬機(jī)不易采用C++的try/throw/catch 異常處理機(jī)制[1]。</p><p><b>  總 結(jié)</b></p><p>  SVM虛擬機(jī)的模塊化設(shè)計并不好,沒有能夠?qū)⒅噶罴亩x獨(dú)立出來。變量,函數(shù)的命名不是很規(guī)范。整個的編碼工作的關(guān)鍵部分是在4月份完成的,五月初加入了調(diào)試器代碼。</p>

104、<p>  整個源文件的擴(kuò)展過程是:</p><p>  先建好8086模擬器,分布在C8086.H C8086.CPP中,一些全局?jǐn)?shù)據(jù)類型定義在GLOBAL.H中,同時主函數(shù)在test_CPU.cpp中。</p><p>  C8086 基本通過測試后(實(shí)際上只測試了ADD,OR,JMP,LODSB,AND等指令,測試太耗時間了!然后接著是巨痛苦的DEBUG階段?。┌裄

105、am的功能從C8086類中分離出來,建了Ram類,在文件Ram.h ,Ram.cpp中。</p><p>  為了便于調(diào)試程序又編寫了簡單的調(diào)試器debug.h,debug.cpp。</p><p>  5月初,在老師的建議下,給調(diào)試器件入了反匯編的功能。實(shí)現(xiàn)在disasm.h,disasm.cpp中。</p><p>  由于沒有異常處理,SVM虛擬機(jī)并不健壯,例

106、如數(shù)組越界的問題還未能很好的解決。所以為了防止代碼長度超出1 MB而溢出,目前只能加載只有64KB的.com程序。(這也不能保證不出錯)。</p><p>  SVM虛擬機(jī)的擴(kuò)展部分主要集中在BIOS,DOS等調(diào)用部分,建立虛擬設(shè)備。中斷部分的可擴(kuò)展部分實(shí)在是太多了。但我目前對此無能為力,涉及面太寬。所以稱為SVM是蠻合適的。</p><p>  另外,擴(kuò)展fileLoader部

107、分,以使虛擬機(jī)可以執(zhí)行16位DOS NE 文件。</p><p>  事實(shí)上,SVM虛擬機(jī)的設(shè)計,主要目的是了解計算機(jī)的硬件體系結(jié)構(gòu)。學(xué)會在熟悉了一個硬件平臺的基礎(chǔ)上(主要包括 指令集,CPU與硬件的通信接口,中斷等),用軟件來搭建虛擬的平臺。SVM虛擬機(jī)的難點(diǎn)在于了解CPU的工作機(jī)制,其是所涉及的算法和數(shù)據(jù)機(jī)構(gòu)很簡單。如果是做編譯器,或者是操作系統(tǒng)的畢業(yè)設(shè)計,我很可能要推遲畢業(yè)了,編譯器涉及大量復(fù)雜的數(shù)據(jù)結(jié)構(gòu),

108、什么二叉檢索樹,哈希表,向量等等。而操作系統(tǒng)則更難,它要對底層的硬件資源進(jìn)行管理,由其是內(nèi)存,再有就是文件處理,當(dāng)然,如果是針對一臺虛擬機(jī)來設(shè)計操作系統(tǒng)可能要容易一些。好在只是做虛擬機(jī)——很簡單的虛擬機(jī)——設(shè)計實(shí)現(xiàn)。</p><p>  商業(yè)上級虛擬機(jī)肯定是很復(fù)雜的,要在上面模擬一個完整的硬件平臺應(yīng)該是有很多困難的,隨著虛擬機(jī)受到系統(tǒng)工程師的關(guān)注,現(xiàn)在虛擬機(jī)的設(shè)計也成為了一門新興的研究領(lǐng)域,它在防病毒檢測,開發(fā)跨

109、平臺軟件,開發(fā)操作系統(tǒng)等項目上得到了廣泛應(yīng)用。</p><p>  正如《虛擬機(jī)設(shè)計與實(shí)現(xiàn)》上所說的:</p><p>  “如今,計算機(jī)硬件的體系結(jié)構(gòu)越來越復(fù)雜,要想根上摩爾定律,工程師就不得不面對更大的挑戰(zhàn)。例如,對負(fù)責(zé)開發(fā)編譯器的的系統(tǒng)程序員們來說,與80年代的處理器相比,如今的EPIC(Explicitly Parallel Instruction Computing 并行指令計算

110、)處理器架構(gòu)絕對是一個嚴(yán)峻得多的挑戰(zhàn)。為了支持諸如指令級并行處理(instruction-level parallelism)之類的功能,提高執(zhí)行效率的大部分責(zé)任都已經(jīng)從處理器芯片轉(zhuǎn)移到了系統(tǒng)工程師(他們可真了不起)肩上,要想提高執(zhí)行效率,就必須預(yù)測計算機(jī)指令的執(zhí)行情況并盡可能地讓它們并行執(zhí)行。這類預(yù)測必須滿足兩項要求:一要盡量避免因預(yù)測錯誤而降低執(zhí)行效率,二是生成能夠通過預(yù)測而提高效率的代碼。因此,實(shí)現(xiàn)這類預(yù)測功能的工作量是相當(dāng)大的。

111、不夸張地說,這足以把任何一位工程師逼得跳樓。</p><p>  更糟糕的是,計算機(jī)的處理器芯片的這些芯片的指令集總是處于變化和發(fā)展當(dāng)中。當(dāng)一個穩(wěn)定,高效的編譯器被推向市場并被接納為一種標(biāo)準(zhǔn)化工局的時候,計算機(jī)硬件肯定又有了新的進(jìn)展,這就迫使設(shè)計該編譯器的工程師們不得不埋頭于改進(jìn)該編譯器的后端(back end)。為了跟上硬件開發(fā)人員的步伐,像我這樣的系統(tǒng)開發(fā)人員就不得不一刻不停地跑下去,根本沒有喘息的機(jī)會——這

112、是一種永遠(yuǎn)的痛?!?lt;/p><p>  “在不斷改進(jìn)開發(fā)工具后端的辦法之外并不是沒有其他的道路。具體地說,你可以選擇一臺虛擬機(jī)(virtual machine)為目標(biāo)。……”。</p><p>  這也是虛擬機(jī)開發(fā)的源動力。</p><p><b>  致 謝</b></p><p>  我的畢業(yè)設(shè)計課題原來是DL

113、X模擬器設(shè)計,后來,我想以8086處理器的指令集為基準(zhǔn)建一個小型虛擬機(jī)會更有意思一些。在和導(dǎo)師商量之后,導(dǎo)師同意我換一個類似的課題。我的整個畢業(yè)設(shè)計從3月中旬正式開始。</p><p>  在我的整個畢業(yè)設(shè)計過程中,感謝***老師的積極建議,比如鑒于時間的關(guān)系,SVM虛擬機(jī)首先實(shí)現(xiàn)對無格式com文件的加載執(zhí)行;完善SVM虛擬機(jī)的DEBUG部分,加入反匯編的功能。整個DEBUG程序模仿DOS下的調(diào)試器;程序可以省去

114、不必要的GUI編程,這使得我能把精力集中在虛擬機(jī)的內(nèi)部實(shí)現(xiàn)上。</p><p><b>  參考文獻(xiàn)</b></p><p>  [1] 【美】B.Blunden,楊濤,楊曉云,王建橋,高文雅,張玉亭 譯.虛擬機(jī)的設(shè)計與實(shí)現(xiàn)-C/C++ 機(jī)械工業(yè)出版社,2003,1.</p><p>  [2] 姚新顏.C/C++深層探索.人民郵電出版社, 2

溫馨提示

  • 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. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論