版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、第6章 程序的基本結(jié)構(gòu)在前面幾章,我們分別介紹了用匯編語言進行程序設(shè)計所需要的幾個最基本的知識:內(nèi)存單元的尋址方式,變量定義和各種匯編指令格式。在掌握了這些基本內(nèi)容之后,就需要學(xué)習(xí)如何把它們組成一個完整的匯編語言程序。6.1 源程序的基本組成匯編語言源程序的組成部分有:模塊、段、子程序和宏等。一個模塊對應(yīng)一個目標(biāo)文件,當(dāng)開發(fā)較大型的應(yīng)用程序時,該程序可能由若干個目標(biāo)文件或庫結(jié)合而成的。有關(guān)模塊和子程序的知識和宏在第7章介紹,有關(guān)宏的知識將在第9章中敘述。6.1.1 段的定義微機系統(tǒng)的內(nèi)存是分段管理的,為了與之相對應(yīng),匯編語言源程序也分若干個段來構(gòu)成。8086CPU有四個段寄存器,在該系統(tǒng)環(huán)境下
2、運行的程序在某個時刻最多可訪問四個段,而80386及其以后的CPU都含有六個段寄存器,于是,在這些系統(tǒng)環(huán)境下開發(fā)的運行程序在某個時刻最多可訪問六個段。不論程序在某個時刻最多能訪問多少個段,在編程序時,程序員都可以定義比該段數(shù)更多的段。在通常情況下,一個段的長度不能超過64K,在80386及其以后系統(tǒng)的保護方式下,段基地址是32位,段的最大長度可達4G。段的長度是指該段所占的字節(jié)數(shù):、如果段是數(shù)據(jù)段,則其長度是其所有變量所占字節(jié)數(shù)的總和;、如果段是代碼段,則其長度是其所有指令所占字節(jié)數(shù)的總和。在定義段時,每個段都有一個段名。在取段名時,要取一個具有一定含義的段名。段定義的一般格式如下:段名SEG
3、MENT對齊類型 組合類型 類別;段內(nèi)的具體內(nèi)容段名ENDS其中:“段名”必須是一個合法的標(biāo)識符,前后二個段名要相同??蛇x項“對齊類型”、“組合類型”和“類別”的說明作用請見6.3節(jié)中的敘述。一個數(shù)據(jù)段的定義例子:DATA1SEGMENTword1DW1, 9078H, ?byte1DB21, 'World'DD12345678HDATA1ENDS一個代碼段的例子:CODE1SEGMENTMOVAX, DATA1;把數(shù)據(jù)段DATA1的段值送AXMOVDS, AX;把AX的值送給DS,即:DS存儲數(shù)據(jù)段的段值MOVAX, 4C00HINT21H;調(diào)用DOS
4、功能,結(jié)束程序的運行CODE1ENDS6.1.2 段寄存器的說明語句在匯編語言源程序中可以定義多個段,每個段都要與一個段寄存器建立一種對應(yīng)關(guān)系。建立這種對應(yīng)關(guān)系的說明語句格式如下:ASSUME 段寄存器名:段名, 段寄存器名:段名, 其中:段寄存器是CS、DS、ES、SS、FS和GS,段名是在段定義語句說明時的段名。在一條ASSUME語句中可建立多組段寄存器與段之間的關(guān)系,每種對應(yīng)關(guān)系要用逗號分隔。例如,ASSUME CS:CODE1, DS:DATA1上面的語句說明了:CS對應(yīng)于代碼段CODE1,DS對應(yīng)于數(shù)據(jù)段DATA1。在ASSUME語句中,還可以用關(guān)鍵字NOTH
5、ING來說明某個段寄存器不與任何段相對應(yīng)。下面語句說明了段寄存器ES不與某段相對應(yīng)。ASSUME ES:NOTHING在通常情況下,代碼段的第一條語句就是用ASSUME語句來說明段寄存器與段之間的對應(yīng)關(guān)系。在代碼段的其它位置,還可以用另一個ASSUME語句來改變前面ASSUME語句所說明的對應(yīng)關(guān)系,這樣,代碼段中的指令就用最近的ASSUME語句所建立的對應(yīng)關(guān)系來確定指令中的有關(guān)信息。例6.1 匯編語言段及其段說明語句的作用。DATA1SEGMENT;定義數(shù)據(jù)段DATA1word1DW5678hbyte1DB"ABCDEFG"DATA1ENDSDATA2SEGME
6、NT;定義數(shù)據(jù)段DATA2word2DW1234hword3DW9876hDATA2ENDSDATA3SEGMENT;定義數(shù)據(jù)段DATA3byte2DB?DATA3ENDSCODE1SEGMENT;編寫代碼段CODE1ASSUMECS:CODE1, DS:DATA1, ES:DATA2;(1)MOVAX, DATA1;(2)MOVDS, AX;(3)MOVAX, DATA2;(4)MOVES, AX;(5)MOVAX, word1;訪問段DATA1中的字變量word1MOVword2, AX;訪問段DATA2中的字變量word2ASSUMEDS:DATA3, ES:NOTHING;(6)MOV
7、AX, DATA3MOVDS, AXMOVBL, byte2;訪問段DATA3中的字節(jié)變量byte2MOVAX, 4C00H;(7)INT21H;(8) CODE1 ENDS語句(1)和(6)分別說明了段和段寄存器之間的對應(yīng)關(guān)系,其中語句(6)重新說明語句(1)所指定的對應(yīng)關(guān)系。二組語句(2)和(3)、(4)和(5)實現(xiàn)對段寄存器DS和ES賦初值。ASSUME說明語句只起說明作用,它不會對段寄存器賦值,所以,必須對有關(guān)段寄存器賦值。在以后的其它源程序中也都是用此方法來實現(xiàn)對數(shù)據(jù)段寄存器賦值的。語句(7)和(8)是調(diào)用中斷21H的4CH號功能來結(jié)束本程序的執(zhí)行,程序的返回代碼由寄存器A
8、L來確定。結(jié)束本程序執(zhí)行的指令是所有主模塊必須書寫的語句。注意:代碼段寄存器不能由程序員在源程序中對其賦值,其值是由操作系統(tǒng)在裝入它進入系統(tǒng)運行時自動賦值的。6.1.3 堆棧段的說明堆棧段是一個特殊的段,在程序中可以定義它,也可以不定義。除了要生成COM型執(zhí)行文件的源程序外,一個完整的源程序一般最好定義堆棧段。如果在程序中不定義堆棧段,那么,操作系統(tǒng)在裝入該執(zhí)行程序時將自動為其指定一個64K字節(jié)的堆棧段。在程序沒有定義堆棧段的情況下,在由連接程序生成執(zhí)行文件時,將會產(chǎn)生一條如下的警告信息,但程序員可以不理會它,所生成的執(zhí)行文件是可以正常運行的。warning xxxx: no stack se
9、gment (其中:xxxx是錯誤號)在源程序中,可用以下方法來定義堆棧段。方法1:STACK1SEGMENTDB256 DUP(?) 256是堆棧的長度,可根據(jù)需要進行改變TOPLABEL WORDSTACK1ENDS以上堆棧段的定義如圖6.1所示。由于堆棧是按地址從大到小的存儲單元順序來存放內(nèi)容的,所以,在堆棧存儲單元說明語句之后,再說明一個棧頂別名,這樣,對棧頂寄存器SP的賦值就很方便。在源程序的代碼段中,還要添加如下程序段,才能把段STACK1當(dāng)作堆棧段來使用。圖6.1 堆棧段定義示意圖ASSUMESS:STACK1;可在代碼段的段指定語句中一起說明C
10、LI;禁止響應(yīng)可屏蔽中斷MOVAX, STACK1MOVSS, AXMOVSP, offset TOP;給堆棧段的棧頂寄存器SP賦初值STI;恢復(fù)響應(yīng)可屏蔽中斷方法2:STACK1SEGMENTSTACK;定義一個堆棧段,其段名為STACK1DB256 DUP(?)STACK1ENDS上述段定義說明了該段是堆棧段,系統(tǒng)會自動把段寄存器SS和棧頂寄存器SP與該堆棧段之間建立相應(yīng)的關(guān)系,并設(shè)置其初值,而不用在代碼段對它們進行賦值。除了以上二種方法外,還有一種更簡潔的方法來定義堆棧段,有關(guān)內(nèi)容請見第6.4.2節(jié)中的敘述。6.1.4 源程序的結(jié)構(gòu)下面的程序是一個完整的源程序,其功能是在屏幕上顯示字符串
11、“Hello, World.”。讀者可參考此結(jié)構(gòu)編寫自己的簡單程序。例6.2 在屏幕上顯示字符串“HELLO,WORLD.”解:可運行下面的控件,用鼠標(biāo)左鍵單擊程序中的某一行,可閱讀其含義;單擊“內(nèi)存”可切換內(nèi)存內(nèi)容的顯示方式。偽指令END表示源程序到此為止,匯編程序?qū)υ撜Z句之后的任何內(nèi)容都不作處理,所以,通常情況下,偽指令END是源程序的最后一條語句。偽指令END后面可附帶一個在程序中已定義的標(biāo)號,由該標(biāo)號指明程序的啟動位置。如果源程序是一個獨立的程序或主模塊,那么,偽指令END后面一定要附帶一個標(biāo)號;如果源程序僅是一個普通模塊,那么,其END后面就一定不能附帶標(biāo)號。6.2 程序的基本結(jié)構(gòu)在
12、學(xué)習(xí)高級語言程序設(shè)計時,我們知道了程序的三大主要結(jié)構(gòu):順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。在匯編語言的源程序也同樣有此三大結(jié)構(gòu),所不同的是它們的表現(xiàn)形式不同。用高級語言編寫程序時,由于不使用“轉(zhuǎn)移語句”而使這三種結(jié)構(gòu)清晰明了。但在匯編語言的源程序中,很難不使用“轉(zhuǎn)移語句”(除非是一些只有簡單功能的程序),有時甚至?xí)懈鞣N各樣的“轉(zhuǎn)移語句”。由于存在這些轉(zhuǎn)移語句,就使得:匯編語言源程序的基本結(jié)構(gòu)顯得不太明確。如果源程序的編寫者思維混亂,編寫出來的源程序在結(jié)構(gòu)上就會顯得雜亂無章,反之,如果編寫者條理清晰,安排的操作井然有序,那么,編寫出來的程序在結(jié)構(gòu)上就會一目了然??傊?,不論是高級語言的源程序,還是匯編
13、語言的源程序,其程序的三大基本結(jié)構(gòu)也還是萬變不離其宗的。6.2.1 順序結(jié)構(gòu)順序結(jié)構(gòu)是最簡單的程序結(jié)構(gòu),程序的執(zhí)行順序就是指令的編寫順序,所以,安排指令的先后次序就顯得至關(guān)重要。另外,在編程序時,還要妥善保存已得到的處理結(jié)果,為后面的進一步處理直接提供前面的處理結(jié)果,從而避免不必要的重復(fù)操作。例6.3 編寫程序段,完成下面公式的計算(其中:變量X和Y是32位有符號數(shù),變量A,B和Z是16位有符號數(shù))。A(X-Y+24)/Z的商,B(X-Y+24)/Z的余數(shù)解:DATA1SEGMENTXDD?YDD?ZDW?ADW?BDW?DATA1ENDSCODE1SEGMENTMOVAX, XMOVDX,
14、X+2;用(DX:AX)來保存32位變量X的數(shù)值SUBAX,YSBBDX, Y+2;(DX:AX)-(Y+2:Y)ADDAX, 24DADCDX, 0;(DX:AX)+24IDIVZMOVA, AXMOVB, DXCODE1ENDS在編程序時,常常需要交換二變量之值。假設(shè)需要交換值的變量名為:var1和var2,臨時增加的變量名為temp。常用的算法如下:temp = var1var1 = var2var2 = temp例6.4 假設(shè)有二個字變量word1和word2,編寫程序段實現(xiàn)交換其值的功能。解:方法1:用匯編語言指令簡單“直譯”上面的 交換數(shù)據(jù)方法DATA1SEGMENTword1DW
15、?word2DW?tempDW?DATA1ENDSCODE1SEGMENTMOVAX, word1MOVtemp, AX;上二語句實現(xiàn)語句“temp=word1”MOVAX, word2MOVword1, AX;上二語句實現(xiàn)語句“word1=word2”MOVAX, tempMOVword2, AX;上二語句實現(xiàn)語句“word2=temp”CODE1ENDS這種方法雖然也能完成功能,但顯然其不能充分利用匯編語言的特點,程序效率很低。方法2:用匯編語言指令的特點來直接編譯DATA1SEGMENTword1DW?word2DW?DATA1ENDSCODE1SEGMENTMOVAX, word1XC
16、HGAX, word2MOVword1, AX;能XCHG word1, word2來代替這三條指令嗎?CODE1ENDS該方法充分利用了匯編語言的特點,不僅省去了中間變量temp的定義,而且程序的效率也提高了。6.2.2 分支結(jié)構(gòu)分支結(jié)構(gòu)是一種非常重要的程序結(jié)構(gòu),也是實現(xiàn)程序功能選擇所必要的程序結(jié)構(gòu)。由于匯編語言需要書寫轉(zhuǎn)移指令來實現(xiàn)分支結(jié)構(gòu),而轉(zhuǎn)移指令肯定會破壞程序的結(jié)構(gòu),所以,編寫清晰的分支結(jié)構(gòu)是掌握該結(jié)構(gòu)的重點,也是用匯編語言編程的基本功。在程序中,當(dāng)需要進行邏輯分支時,可用每次分二支的方法來達到程序最終分多支的要求,也可是用地址表的方法來達到分多支的目的。一、顯示轉(zhuǎn)移指令實現(xiàn)的分支結(jié)
17、構(gòu)在高級語句中,分支結(jié)構(gòu)一般用IF語句來實現(xiàn),在匯編語言中,課用無條件轉(zhuǎn)移指令或條件轉(zhuǎn)移指令實現(xiàn)的分支結(jié)構(gòu)。如圖6.2給出了二種常用的分支結(jié)構(gòu)。在編寫分支程序時,要盡可能避免編寫“頭重腳輕”的結(jié)構(gòu),即:當(dāng)前分支條件成立時,將執(zhí)行一系列指令,而條件不成立時,所執(zhí)行的指令很少。這樣就使后一個分支離分支點較遠,有時甚至?xí)z忘編寫后一分支程序。這種分支方式不僅不利于程序的閱讀,而且也不便將來的維護。所以,在編寫分支結(jié)構(gòu)時,一般先處理簡單的分支,再處理較復(fù)雜的分支。對多分支的情況,也可遵循“由易到難”的原則。因為簡單的分支只需要較少的指令就能處理完,一旦處理完這種情況后,在后面的編程過程中就可集中考慮如
18、何處理復(fù)雜的分支。 (a) if endif結(jié)構(gòu)(b) ifelseendif結(jié)構(gòu)圖6.2 分支結(jié)構(gòu)的二種結(jié)構(gòu)例6.5 已知字節(jié)變量CHAR1,編寫一程序段,把它由小寫字母變成大寫字母。解:DATA1SEGMENTCHAR1DB?DATA1ENDSCODE1SEGMENTMOVAL, CHAR1CMPAL, aJBnextCMPAL, zJAnextSUBCHAR1, 20H;指令A(yù)ND CHAR1, 0DFH也可以next:CODE1ENDS例6.6 編寫一程序段,計算下列函數(shù)值。其中:變量X和Y是有符號字變量。解:DATA1SEGMENTXDW?YDW?DATA1ENDSCODE1SEGM
19、ENTMOVAX, XCMPAX, 0JGEcase23ADDAX, 10;第一種情況的計算結(jié)果JMPresultcase23:CMPAX, 10DJGcase3MOVBX, 30DIMULBX;第二種情況的計算結(jié)果JMPresultcase3:SUBAX, 9;第三種情況的計算結(jié)果result:MOVY, AX;把計算結(jié)果保存到變量Y中CODE1ENDS例6.7 把下列C語言的語句改寫成等價的匯編語言程序段(不考慮運算過程中的溢出)。If (a+b > 0 && c%2 = 0) a = 62;else a = 21;其中:變量a,b和c都是有符號的整型(int)變量。
20、解:DATA1SEGMENTADW?BDW?CDW?DATA1ENDSCODE1SEGMENTMOVAX, AADDAX, BJLE_ELSE;ADD指令會改變算術(shù)標(biāo)志位 TESTC, 1;C%2=0,也就是:看C的最低位是否為0JNZ_ELSEMOVA, 62DJMPNEXT_ELSE: MOVA, 21DNEXT:CODE1ENDS例6.8 用地址轉(zhuǎn)移表實現(xiàn)下列C語言的switch語句,其中:變量A和B是有符號的整型(int)變量。switch(a%8)case 0:b = 32;break;case 1:case 2:b = a + 43;break;case 3:b = 2*
21、a;break;case 4:b-;break;case 5:case 6:case 7:printf(“Function 5_6_7”);break;解:DATA1SEGMENTADW?BDW?TableDWcase0. case12, case12, case3DWcase4, case567, case567, case567MSGDB'Function 5_6_7$'DATA1ENDSCODE1SEGMENTMOVAX, AMOVBX, AXANDBX, 7;得到BX的低三位,實現(xiàn)a%8的計算SHL BX, 1;由于地址表是字類型,其下標(biāo)要乘2JMPTable
22、BX;利用地址表實現(xiàn)多路轉(zhuǎn)移case0:MOVB, 32DJMPnextcase12:ADDAX, 43DMOVB, AXJMPnextcase3:SHLAX, 1MOVB, AXJMPnextcase4:DECBJMPnextcase567:LEA DX, MSGMOVAH, 9INT21HJMPnextnext:CODE1ENDS用地址表實現(xiàn)多路轉(zhuǎn)移的關(guān)鍵在于:轉(zhuǎn)移入口的地址表和轉(zhuǎn)移情況可整數(shù)化。如果這二個要求有一個不滿足,或很難構(gòu)造,則無法使用該方法。為了改善匯編語言源程序的結(jié)構(gòu),減少顯式轉(zhuǎn)移語句所帶來混亂,在宏匯編MASM 6.11系統(tǒng)中,增加了表達分支結(jié)構(gòu)的偽指令。該偽指令
23、的書寫格式與高級語言的書寫方式相類似,匯編程序在匯編時會自動增加轉(zhuǎn)移指令和相應(yīng)的標(biāo)號。理解并掌握該知識,對將來學(xué)習(xí)編譯原理課程也有一定的幫助。分支偽指令的具體格式如下:格式1:.IF condition;以英文“句號”開頭 指令序列 ;條件"condition"成立時所執(zhí)行的指令序列.ENDIF格式2:.IF condition 指令序列1.ELSE 指令序列2;條件"condition"不成立時所執(zhí)行的指令序列.ENDIF格式3:.IF condition1 指令序列1.ELSEIF condition2 指令序列2;條件"condition
24、2"成立時所執(zhí)行的指令序列.ENDIF其中:條件表達式“condition”的書寫方式與C語言中條件表達式的書寫方式相似,也可用括號來組成復(fù)雜的條件表達式。條件表達式中可用的操作符有:=(等于)、!=(不等)、>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、&(位操作與)、!(邏輯非)、&&(邏輯與)、|(邏輯或)等。若在條件表達式中檢測標(biāo)志位的信息,則可以使用的符號名有:CARRY?(相當(dāng)于CF=1)、OVERFLOW?(OF=1)、PARITY?(PF=1)、SIGN?(SF=1)、ZERO?(ZF=1)等。例如:.IF
25、CARRY? && AX != BX;檢測CF=1且AX!=BX是否成立;匯編語言指令序列.ENDIF在指令序列中,還可再含有其它的.IF偽指令,即:允許嵌套。偽指令.ELSEIF引導(dǎo)出另一個二叉分支,但它不能作偽指令塊的第一個偽指令。匯編程序在對“條件表達式”進行代碼轉(zhuǎn)換時將進行代碼優(yōu)化處理,以便盡可能生成最好的指令代碼。如:.IFax = 0匯編程序會把它轉(zhuǎn)換為指令“ORax, ax”,而不是“CMPax, 0”,因為前者比后者更好,而不是簡單直接地轉(zhuǎn)換為后者。如果用偽指令來書寫分支結(jié)構(gòu),那么,例6.5的代碼段部分就可寫成如下程序段:MOVAL, CHAR1.IFAL>
26、;='a' && AL<='z'語句象C語言語句嗎?SUBCHAR1, 20H.ENDIF也可把例6.6的代碼段部分就可寫成如下程序段:MOV AX, X.IF AX < 0ADDAX, 10;計算第一種情況的結(jié)果.ELSEIFAX <= 10MOVBX, 30DIMULBX;計算第二種情況的結(jié)果.ELSESUBAX, 9;計算第三種情況的結(jié)果.ENDIFMOVY, AX;把計算結(jié)果保存到變量Y中例6.9 根據(jù)當(dāng)前計算機的時間和日期,顯示上午(AM)或下午(PM),以及所在的季節(jié)。解:顯示解答6
27、.2.3 循環(huán)結(jié)構(gòu)循環(huán)結(jié)構(gòu)是一個重要的程序結(jié)構(gòu),它具有重復(fù)執(zhí)行某段程序的功能。通常,循環(huán)結(jié)構(gòu)包括以下四個組成部分:1、循環(huán)初始化部分初始化循環(huán)控制變量、循環(huán)體所用到變量;2、循環(huán)體部分循環(huán)結(jié)構(gòu)的主體;3、循環(huán)調(diào)整部分循環(huán)控制變量的修改、或循環(huán)終止條件的檢查;4、循環(huán)控制部分程序執(zhí)行的控制轉(zhuǎn)移。以上四部分可以在程序中用各種不同的形式體現(xiàn)出來,有時也并非清析地表達出來。常用的循環(huán)結(jié)構(gòu)如圖6.3所示。(a)、DoWhile結(jié)構(gòu)(b)、While結(jié)構(gòu)圖6.3 常用的循環(huán)結(jié)構(gòu)示意圖一、用循環(huán)指令構(gòu)成循環(huán)結(jié)構(gòu)在編寫循環(huán)結(jié)構(gòu)的程序片段時,我們可以多種方法來循環(huán)結(jié)構(gòu)。如:循環(huán)次數(shù)是已知的,可用LOOP指令來構(gòu)
28、造循環(huán);當(dāng)循環(huán)次數(shù)是未知或不定的,則可用條件轉(zhuǎn)移或無條件轉(zhuǎn)移來構(gòu)成循環(huán)結(jié)構(gòu)。例6.10 分類統(tǒng)計字?jǐn)?shù)組data中正數(shù)、負(fù)數(shù)和零的個數(shù),并分別存入內(nèi)存字變量Positive、Negative和Zero中,數(shù)組元素個數(shù)保存在其第一個字中。解:顯示解答例6.11 計算數(shù)組score的平均整數(shù),并存入內(nèi)存字變量Average中,數(shù)組以-1為結(jié)束標(biāo)志。解:DATA1SEGMENTdataDW90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1AverageDW0DATA1ENDSCODE1SEGMENTASSUMECS:CODE1, DS:DATA1START:MOVAX,
29、 DATA1MOVDS, AXXORAX, AXXORDX, DX;用(DX,AX)來保存數(shù)組元素之和XORCX, CX;用CX來保存數(shù)組元素個數(shù)LEASI, data;用指針SI來訪問整個數(shù)組again:MOVBX, word ptr SICMPBX, 0JLoverADDAX, BXADCDX, 0;把當(dāng)前數(shù)組元素之值加到(DX,AX)中INCCX;數(shù)組元素個數(shù)加1ADDSI, 2JMPagainover:JCXZexit;防止零作除數(shù),即數(shù)組是空數(shù)組DIVCXMOVAverage, AXexit:MOVAX, 4C00HINT21HCODE1ENDSENDSTART二、用偽指令實現(xiàn)的循環(huán)
30、結(jié)構(gòu)在宏匯編MASM 6.11系統(tǒng)中,還增加了表達循環(huán)結(jié)構(gòu)的偽指令,以便更清晰地表達WHILE循環(huán)、REPEAT-UNTIL循環(huán)。另外,還增加兩個輔助循環(huán)的偽指令。這些偽指令的書寫格式和含義與高級語言中相應(yīng)語句的書寫格式和含義相一致,所以,這些偽指令是很容易掌握的,也是非常有用的。循環(huán)偽指令的格式和含義如下:1、WHILE型循環(huán)偽指令.WHILE condition循環(huán)體的指令序列;條件"condition”成立時所執(zhí)行的指令序列.ENDW其中:.ENDW與前面的.WHILE相匹配,它標(biāo)志著其循環(huán)體到此結(jié)束。如果條件表達式“condition”在循環(huán)開始時,就為“假”(false),
31、那么,該循環(huán)體一次也不會被執(zhí)行。2、REPEAT型循環(huán)偽指令.REPEAT 循環(huán)體的指令序列.UNTIL condition .REPEAT 循環(huán)體的指令序列.UNTILCXZ conditionREPEAT型循環(huán)在執(zhí)行完循環(huán)體后,才判定邏輯表達式condition的值。若該表達式的值為真,則終止該循環(huán),并將執(zhí)行偽指令.UNTILCXZ后面的指令,否則,將向上跳轉(zhuǎn)到偽指令.REPEAT之后的指令,為繼續(xù)執(zhí)行其循環(huán)體作準(zhǔn)備。如果.UNTILCXZ后面沒有寫邏輯表達式,那么,由.REPEAT.UNTILCXZ所構(gòu)成的循環(huán)與用LOOP指令所過程的循環(huán)是一致的,它們都是以“CX=0”為循環(huán)終
32、止條件。如果.UNTILCXZ后面書寫了邏輯表達式,那么,該邏輯表達式的形式只能是:“EXP1=EXP2”或“EXP1!=EXP2”。所以,這時由“.REPEAT.UNTILCXZ condition”所構(gòu)成的循環(huán)就與用LOOPNE/LOOPE指令所過程的循環(huán)是一致的,它們都是以“condition | CX=0”為循環(huán)終止條件。和高級語言的REPEAT型的循環(huán)一樣,.REPEAT.UNTILCXZ的循環(huán)體也會至少被執(zhí)行一次。.WHILE.ENDW和.REPEAT.UNTILCXZ的循環(huán)體內(nèi)還可再含有循環(huán)偽指令,這樣就構(gòu)成了循環(huán)結(jié)構(gòu)的嵌套。匯編程序在生產(chǎn)指令代碼時會進行代碼優(yōu)化,以便盡可能得到
33、最優(yōu)化的指令序列。3、輔助循環(huán)偽指令(1)、終止循環(huán)偽指令.BREAK.BREAK .IF condition該偽指令用來終止包含它的最內(nèi)層循環(huán)。前者是無條件終止循環(huán),后者是僅當(dāng)邏輯表達式condition為真時,才終止循環(huán)。.WHILE 1.REPEAT.BREAK .IF condition.BREAK .IF conditionENDW.UNTIL0對于以上二個循環(huán),如果沒有指令來終止循環(huán)的話,它們都將進入死循環(huán)狀態(tài),但如果在該層循環(huán)體內(nèi),存在偽指令“.BREAK .IF condition”的話,那么,當(dāng)邏輯表達式condition為真時,該循環(huán)就會被終止了。(
34、2)、循環(huán)繼續(xù)偽指令.CONTINUE.CONTINUE.IF condition該偽指令用于直接跳轉(zhuǎn)到包含它的最內(nèi)層循環(huán)的計算循環(huán)條件表達式的代碼處。前者是無條件轉(zhuǎn)移到計算循環(huán)條件表達式的代碼處,后者是僅當(dāng)條件表達式condition為真時,才進行這樣的跳轉(zhuǎn)。輔助循環(huán)偽指令.BREAK和.CONTINUE只能在偽指令.WHILE.ENDW和.REPEAT.UNTIL的循環(huán)體內(nèi)使用。 例6.12 顯示9個數(shù)字字母'1''9',26個大寫字母,和顯示任意輸入的數(shù)字字符,并用按“回車”鍵來結(jié)束本程序的運行。解:DATA1SEGMENTMSG1DB13, 10,
35、60; "Iteration: "NUM1DB'1', "$"MSG2DB13, 10, "Alphabet: $"NUM2DB'A', " $"MSG3DB13, 10, "Type digits, then press ENTER: $"DATA1ENDSCODE1SEGMENTASSUMECS:CODE1, DS:DATA1START:MOVAX, DATA1MOVDS, AXMOVCX, 9MOVAH, 09HMOVDX, OFFSET MSG
36、1.REPEATINT21HINCNUM1;顯示Iteration: 1,2,9.UNTILCXZMOVDX, OFFSET MSG2INT21H;顯示字符串"Alphabet:"MOVAH, 09HMOVDX, OFFSET NUM2.REPEATINT21HINCNUM2;顯示當(dāng)前字母;當(dāng)前字母向后移.UNTILNUM2 > 'Z'顯示整個大寫字母表MOVAH, 09HMOVDX, OFFSET MSG3INT21H.WHILE 1;循環(huán)條件為永真的循環(huán)MOVAH, 07HINT21H;不帶回顯地從鍵盤讀一個字符.BREAK .IF A
37、L = 13;如果輸入“回車”鍵,則終止循環(huán).CONTINUE .IF (AL<'0') | (AL>'9');如果字符不是數(shù)字字符,則繼續(xù)循環(huán)MOVDL, ALMOVAH, 02HINT21H;顯示所輸入的數(shù)字字母.ENDWMOVAX, 4C00HINT21HCODE1ENDSENDSTART6.3 段的基本屬性在通常情況下,一個復(fù)雜的應(yīng)用程序會由若干個模塊組成,一個模塊又會含有多個段。而不同模塊的段之間、同一模塊的段之間往往存在某種聯(lián)系,這種聯(lián)系就要體現(xiàn)在段屬性的說明上。段定義的一般格式如下:段名SEGMENT對齊類型組合類型類別段名ENDS段屬
38、性“對齊類型”、“組合類型”和“類別”要按此順序說明,但這些可選項可根據(jù)需要選擇書寫。如果源程序中不指定某個屬性,那么,匯編程序?qū)⑹褂迷搶傩缘娜笔≈怠3绦蛑械亩蚊梢允俏ㄒ坏?,也可以與其它段同名。在同一模塊中,如果有二個段同名,則后者被認(rèn)為是前段的后續(xù),這樣,它們就屬同一段。當(dāng)同一模塊出現(xiàn)二個同名段時,則后者的可選項屬性要么與前者相同,要么不寫其屬性而選用前者的段屬性。例6.13 同段名的作用DATA1SEGMENT;第一個數(shù)據(jù)段MSGDB "Hello, "DATA1ENDSCODE1SEGMENT;第一個代碼段ASSUMECS:CODE1, DS:DATA1START:
39、MOVAX, DATA1MOVDS, AXMOVDX, offset MSGMOVAH, 9INT21HCODE1ENDSDATA1SEGMENT;第二個數(shù)據(jù)段DB "World.$"DATA1ENDSCODE1SEGMENT;第二個代碼段MOVAX, 4C00HINT21HCODE1ENDSENDSTARTEND在上面的例子中,第二個數(shù)據(jù)段是第一個數(shù)據(jù)段的后續(xù),匯編程序把它們是合二為一,上述的代碼段也如此。下面,詳細說明段屬性的含義及其作用。6.3.1 對齊類型(ALIGN)對齊類型表示當(dāng)前段對起始地址的要求,連接程序(LINK.EXE)按表6.1的地址格式來定位段的起始
40、地址。在進行段定位時,會根據(jù)其定位類型進行定位的,所以,各段之間就有可能出現(xiàn)一些空閑字節(jié),即可能浪費幾個字節(jié)單元。段對齊類型PARA是一個適用于所有段類型的對齊類型,它也是缺省的對齊類型。對齊類型BYTE和WORD通常用于數(shù)據(jù)段的定位,對齊類型DWORD通常用于80386及其以后CPU代碼段的定位。表6.1 段對齊類型與段起始地址之間的對應(yīng)關(guān)系對齊類型起始地址(二進制)功能說明最多的空閑字節(jié)數(shù)BYTExxxx xxxx xxxx xxxx xxxx下一個字節(jié)地址0WORDxxxx xxxx xxxx xxxx xxx0下一個字地址1DWORDxxxx xxxx xxxx xxxx xx00下一
41、個雙字地址3PARAxxxx xxxx xxxx xxxx 0000下一個節(jié)地址15PAGExxxx xxxx xxxx 0000 0000下一個頁地址1276.3.2 組合類型(COMBINE)組合類型是告訴連接程序如何把不同模塊中段名相同的段合并在一起。具體的組合類型如下:NONE表示當(dāng)前段在邏輯上獨立于其它模塊,并有其自己的基地址。NONE是缺省的組合類型。PUBLIC表示當(dāng)前段與其它模塊中同段名的PUBLIC類型段組合成一個段。組合的先后次序取決于LINK程序中目標(biāo)模塊排列的次序。在組合時,后續(xù)段的起始地址要按其對齊類型進行定位,所以,同名段之間可能有間隔。COMMON表示當(dāng)前段與其它
42、模塊中同名段重疊,也就是說,它們的起始地址相同。最終段的長度是同名段的最大長度。由于段覆蓋,所以,前一同名段中的初始化數(shù)據(jù)被后續(xù)段的初始數(shù)據(jù)覆蓋掉。STACK組合類型STACK表示當(dāng)前段是堆棧棧,其組合情況與PUBLIC相同。AT 數(shù)值表達式該數(shù)值表達式是當(dāng)前段所指定的絕對起始地址的段地址。6.3.3 類別(CLASS)類別是一個由程序員指定的用單引號括起來的字符串。如果一個段沒有給出類別,那么,這個段的類別就為空。類別是用于段的分類,連接程序利用該類別來調(diào)整同名、同類別的段,并使它們相鄰。典型的類別是"Data"和"Code"。如果指定某段的類別是&q
43、uot;Code",那么,該段最好是代碼段,這樣,有的調(diào)試程序(如:CodeView)就可以順序工作。例如:DATA1SEGMENT WORD PUBLIC "Data"DATA1ENDS上述段定義說明了該段的起始地址是下一個字地址、組合類型為PUBLIC、段類別是"Data"。6.3.4 段組(GROUP)段組偽指令GROUP是用于把源程序模塊中若干個段結(jié)合成一個組,并對該段組定義一個段組名。段組偽指令的格式如下:段組名 GROUP 段名, 段名, 其中:段名之間要用逗號間隔,段名也
44、可以用表達式“SEG 變量”或“SEG 標(biāo)號”。下面舉例說明段組偽指令的使用方法和作用。例6.12 段組的作用方法1:用一個段寄存器對應(yīng)二個數(shù)據(jù)段DATA1SEGMENT;第一個數(shù)據(jù)段b1DB10hDATA1ENDSDATA2SEGMENT;第二個數(shù)據(jù)段b2DB23hDATA2ENDSCODE1SEGMENTASSUMECS:CODE1, DS:DATA1;(1)START:MOVAX, DATA1MOVDS, AX (2)把數(shù)據(jù)段DATA1的段值賦給段寄存器DSMOVBL, b1;(3)引用DS來訪問DATA1中的變量b1ASSUMEDS:DATA2;(4)MOVAX, DATA2
45、MOVDS, AX;(5)把數(shù)據(jù)段DATA2的段值賦給段寄存器DSMOVAL, b2;(6)引用DS來訪問DATA2中的變量b2CODE1ENDSENDSTART在上例中,語句(1)說明DS與DATA1建立聯(lián)系,語句(2)對DS賦值,語句(3)用DS來訪問DATA1段的變量名。語句(4)說明DS與DATA2建立聯(lián)系,語句(5)對DS賦值,語句(6)用DS來訪問DATA2段的變量名。在該例子中,因為只使用一個段寄存器DS來對應(yīng)二個數(shù)據(jù)段,所以,需要切換DS的對應(yīng)關(guān)系(如:語句(4)。但我們也可以用段寄存器DS和ES來分別對應(yīng)段DATA1和DATA2,這樣,方法1就可變成方法2。方法2:用二個段寄
46、存器對應(yīng)二個數(shù)據(jù)段DATA1SEGMENTb1DB10hDATA1ENDSDATA2SEGMENTb2DB23hDATA2ENDSCODE1SEGMENTASSUMECS:CODE1, DS:DATA1, ES:DATA2START:MOVAX, DATA1MOVDS, AX 把數(shù)據(jù)段DATA1的段值賦給段寄存器DSMOVAX, DATA2MOVES, AX;把數(shù)據(jù)段DATA2的段值賦給段寄存器ESMOVBL, b1;引用DS來訪問DATA1中的變量b1MOVAL, b2;引用ES來訪問DATA2中的變量b2CODE1ENDSENDSTART我們還可以用段組來簡化段寄存器的使用,把段
47、DATA1和DATA2組成一個數(shù)據(jù)段。所以,把方法2再改寫成方法3的形式。方法3:用一個段組組成二個數(shù)據(jù)段GSEGGROUPDATA1, DATA2;把段DATA1和DATA2定義成一個段組DATA1SEGMENTb1DB10hDATA1ENDSDATA2SEGMENTb2DB23hDATA2ENDSCODE1SEGMENTASSUMECS:CODE1, DS:GSEGSTART:MOVAX, GSEGMOVDS, AX 把段組GSEG的段值賦給段寄存器DSMOVBL, b1;引用DS來訪問DATA1中的變量b1MOVAL, b2;引用DS來訪問DATA2中的變量b2CODE1END
48、SENDSTART定義段組后,段組內(nèi)各段所定義的標(biāo)號和變量,除了與定義它們的段起始點相關(guān)外,還與段組的起始點相關(guān)。規(guī)定如下:、如果在ASSUME偽指令中說明段組與段寄存器相對應(yīng),那么,有關(guān)標(biāo)號或變量的偏移量就相對于段組起點計算;、如果在ASSUME偽指令中說明段組內(nèi)的某各段與段寄存器相對應(yīng),那么,有關(guān)標(biāo)號或變量的偏移量就相對于該段的起點。所以,在使用段組后,程序員要謹(jǐn)慎使用ASSUME偽指令,并保證段寄存器的值與段組或段相一致。6.4 簡化的段定義前面,我們介紹了完整的段定義格式,用完整的段定義格式雖然可以控制段的各種屬性,但程序員很少會這樣做。現(xiàn)在的匯編程序提供了一種簡化的段定義方式,它使定
49、義段更簡單、方便。6.4.1 存儲模型說明偽指令在使用簡化的段定義方式之前,必須使用存儲模式說明偽指令來描述源程序所采用的存儲模式。該偽指令說程序所使用的存儲模式,匯編程序?qū)⒂迷摯鎯δJ缴上鄳?yīng)的ASSUME和GROUP語句,同時也為其它的簡化段創(chuàng)建等價的預(yù)定義。程序存儲模式說明偽指令的格式如下: .MODEL 存儲模式,語言類型 ,操作系統(tǒng)類型 ,堆棧類型程序可選的存儲模式有:TINY、SMALL、COMPACT、MEDIUM、LARGE、HUGE和FLAT。偽指令.MODEL必須寫在源程序的首部,且只能出現(xiàn)一次,其前內(nèi)容只能是注釋。如果用偽指令來指定程序所遵循的語言類型,那么,
50、將不允許子程序的嵌套定義。與子程序定義有關(guān)的內(nèi)容請見第7.5節(jié)。一、存儲模式如果要用匯編語言編寫被高級語言調(diào)用的子程序,那么,該匯編程序的存儲模式必須與該高級語言編譯(或解釋)程序所使用的存儲模式相匹配。匯編語言程序所能使用的存儲模式、符號及其相關(guān)信息如表6.2所列。在程序中,還可偽指令OPTION SEGMENT和SEGMENT來指定段的規(guī)模。有關(guān)存儲模式的具體規(guī)定如下:、TINY在匯編程序MASM 6.11和TASM 4.0,該存儲類型是為編寫COM文件類型而設(shè)置的。程序員還可用匯編命令行選項/AT和連接命令選項/TINY來達到此目的。表6.2 存儲模式的符號及其相關(guān)含義代碼的位距數(shù)據(jù)的位
51、距段的寬度數(shù)據(jù)段和代碼段能否合并Code DistanceData DistanceSegment WidthData & Code Combined?TinySmallCompact MediumLargeHugeFlatNEARNEAR16-bitYesNEARNEAR16-bitNoNEARFAR16-bitNoFARNEAR16-bitNoFARFAR16-bitNoFARFAR16-bitNoNEARNEAR32-bitYes、SMALL所有的數(shù)據(jù)變量必須在一個數(shù)據(jù)段之內(nèi),所有的代碼也必須在一個代碼段之內(nèi)。在這種模型下,數(shù)據(jù)段寄存器的內(nèi)容保持不變,所有轉(zhuǎn)移也都是段內(nèi)轉(zhuǎn)移。該存
52、儲類型是獨立匯編語言源程序常用的存儲模型。、MEDIUM所有的數(shù)據(jù)變量必須在一個數(shù)據(jù)段之內(nèi),但代碼段可以有多個。在這種模型下,數(shù)據(jù)段寄存器的內(nèi)容保持不變,轉(zhuǎn)移可以是段間轉(zhuǎn)移。、COMPACT數(shù)據(jù)段可以有多個,但代碼段只能有一。、LARGE數(shù)據(jù)段和代碼段都可以有多個,但一個數(shù)組的字節(jié)數(shù)不能超過64KB。、HUGE數(shù)據(jù)段和代碼段都可以有多個,一個數(shù)組的字節(jié)數(shù)也可以超過64KB。、FLATFLAT存儲模式在創(chuàng)建執(zhí)行文件時,將使該程序僅含一個包括程序數(shù)據(jù)和代碼的32位段,并且只能在80386及其以后的計算機系統(tǒng)中運行。該程序的文件類型為EXE。在使用該存儲模式之前,必須先用偽指令.386、.486或其
53、它偽指令來說明更高性能的CPU類型。也就是說:FLAT模式僅在386及其以后CPU模式下才能使用。在該程序中,所有代碼和數(shù)據(jù)位距的缺省值都是NEAR,子程序的類型也是NEAR,并且標(biāo)識符CodeSize,DataSize和Model的值分別為:0、0和7。在FLAT存儲模式下,程序?qū)⒉皇褂枚渭拇嫫鱂S和GS。匯編程序在處理說明語句“.MODEL FLAT”時,將自動生成下列段寄存器說明語句:ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:ERROR, GS:ERROR當(dāng)然,程序員也可把該段寄存器說明語句寫在其指令序列之中。二、語言類型其詳細說明請見7.5.3節(jié)中所述。三、操作系統(tǒng)類型OS_DOS是當(dāng)前唯一支持的選項值,也是該選項的
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度茶葉科研與技術(shù)推廣服務(wù)合同4篇
- 2025年度茶葉品牌授權(quán)經(jīng)營合同模板4篇
- 2025年度產(chǎn)業(yè)園區(qū)配套服務(wù)場承包經(jīng)營合同樣本4篇
- 專業(yè)廣告策劃與推廣服務(wù)協(xié)議樣本版A版
- 2025年度智能家居系統(tǒng)產(chǎn)品試用體驗合同4篇
- 專業(yè)拓展訓(xùn)練服務(wù)協(xié)議范例版
- 專業(yè)保安人員派遣合同合同2024年版版
- 專業(yè)儲油罐租賃服務(wù)協(xié)議示例版
- 2024年04月恒豐銀行合肥分行2024年社會招考筆試歷年參考題庫附帶答案詳解
- 2025年度體育場館場地租賃安全與賽事運營管理合同4篇
- 小學(xué)利潤問題應(yīng)用題100道附答案(完整版)
- 對表達方式進行選擇與運用
- 投資固定分紅協(xié)議
- 蘇教版三年級數(shù)學(xué)下冊全單元測試題(加答案)
- 副廠長競聘演講稿
- 2024年河北省廊坊市廣陽區(qū)中考一模道德與法治試題
- 電影項目策劃書
- 產(chǎn)業(yè)園區(qū)金融綜合服務(wù)創(chuàng)新藍皮書(2024.1)
- 高一數(shù)學(xué)單元練習(xí)卷
- 國際標(biāo)準(zhǔn)IQ測試題及答案樣本
- 美容院管理制度章程
評論
0/150
提交評論