匯編語(yǔ)言之程序的基本結(jié)構(gòu).doc
《匯編語(yǔ)言之程序的基本結(jié)構(gòu).doc》由會(huì)員分享,可在線閱讀,更多相關(guān)《匯編語(yǔ)言之程序的基本結(jié)構(gòu).doc(31頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
第6章 程序的基本結(jié)構(gòu) 在前面幾章,我們分別介紹了用匯編語(yǔ)言進(jìn)行程序設(shè)計(jì)所需要的幾個(gè)最基本的知識(shí):內(nèi)存單元的尋址方式,變量定義和各種匯編指令格式。在掌握了這些基本內(nèi)容之后,就需要學(xué)習(xí)如何把它們組成一個(gè)完整的匯編語(yǔ)言程序。 6.1 源程序的基本組成 匯編語(yǔ)言源程序的組成部分有:模塊、段、子程序和宏等。一個(gè)模塊對(duì)應(yīng)一個(gè)目標(biāo)文件,當(dāng)開(kāi)發(fā)較大型的應(yīng)用程序時(shí),該程序可能由若干個(gè)目標(biāo)文件或庫(kù)結(jié)合而成的。有關(guān)模塊和子程序的知識(shí)和宏在第7章介紹,有關(guān)宏的知識(shí)將在第9章中敘述。 6.1.1 段的定義 微機(jī)系統(tǒng)的內(nèi)存是分段管理的,為了與之相對(duì)應(yīng),匯編語(yǔ)言源程序也分若干個(gè)段來(lái)構(gòu)成。8086CPU有四個(gè)段寄存器,在該系統(tǒng)環(huán)境下運(yùn)行的程序在某個(gè)時(shí)刻最多可訪問(wèn)四個(gè)段,而80386及其以后的CPU都含有六個(gè)段寄存器,于是,在這些系統(tǒng)環(huán)境下開(kāi)發(fā)的運(yùn)行程序在某個(gè)時(shí)刻最多可訪問(wèn)六個(gè)段。 不論程序在某個(gè)時(shí)刻最多能訪問(wèn)多少個(gè)段,在編程序時(shí),程序員都可以定義比該段數(shù)更多的段。在通常情況下,一個(gè)段的長(zhǎng)度不能超過(guò)64K,在80386及其以后系統(tǒng)的保護(hù)方式下,段基地址是32位,段的最大長(zhǎng)度可達(dá)4G。 段的長(zhǎng)度是指該段所占的字節(jié)數(shù): 、如果段是數(shù)據(jù)段,則其長(zhǎng)度是其所有變量所占字節(jié)數(shù)的總和; 、如果段是代碼段,則其長(zhǎng)度是其所有指令所占字節(jié)數(shù)的總和。 在定義段時(shí),每個(gè)段都有一個(gè)段名。在取段名時(shí),要取一個(gè)具有一定含義的段名。 段定義的一般格式如下: 段名 SEGMENT [對(duì)齊類(lèi)型] [組合類(lèi)型] [類(lèi)別] … ;段內(nèi)的具體內(nèi)容 … 段名 ENDS 其中:“段名”必須是一個(gè)合法的標(biāo)識(shí)符,前后二個(gè)段名要相同??蛇x項(xiàng)“對(duì)齊類(lèi)型”、“組合類(lèi)型”和“類(lèi)別”的說(shuō)明作用請(qǐng)見(jiàn)6.3節(jié)中的敘述。 一個(gè)數(shù)據(jù)段的定義例子: DATA1 SEGMENT word1 DW 1, 9078H, ? byte1 DB 21, World DD 12345678H DATA1 ENDS 一個(gè)代碼段的例子: CODE1 SEGMENT MOV AX, DATA1 ;把數(shù)據(jù)段DATA1的段值送AX MOV DS, AX ;把AX的值送給DS,即:DS存儲(chǔ)數(shù)據(jù)段的段值 … MOV AX, 4C00H INT 21H ;調(diào)用DOS功能,結(jié)束程序的運(yùn)行 CODE1 ENDS 6.1.2 段寄存器的說(shuō)明語(yǔ)句 在匯編語(yǔ)言源程序中可以定義多個(gè)段,每個(gè)段都要與一個(gè)段寄存器建立一種對(duì)應(yīng)關(guān)系。建立這種對(duì)應(yīng)關(guān)系的說(shuō)明語(yǔ)句格式如下: ASSUME 段寄存器名:段名[, 段寄存器名:段名, ……] 其中:段寄存器是CS、DS、ES、SS、FS和GS,段名是在段定義語(yǔ)句說(shuō)明時(shí)的段名。 在一條ASSUME語(yǔ)句中可建立多組段寄存器與段之間的關(guān)系,每種對(duì)應(yīng)關(guān)系要用逗號(hào)分隔。例如, ASSUME CS:CODE1, DS:DATA1 上面的語(yǔ)句說(shuō)明了:CS對(duì)應(yīng)于代碼段CODE1,DS對(duì)應(yīng)于數(shù)據(jù)段DATA1。 在ASSUME語(yǔ)句中,還可以用關(guān)鍵字NOTHING來(lái)說(shuō)明某個(gè)段寄存器不與任何段相對(duì)應(yīng)。下面語(yǔ)句說(shuō)明了段寄存器ES不與某段相對(duì)應(yīng)。 ASSUME ES:NOTHING 在通常情況下,代碼段的第一條語(yǔ)句就是用ASSUME語(yǔ)句來(lái)說(shuō)明段寄存器與段之間的對(duì)應(yīng)關(guān)系。在代碼段的其它位置,還可以用另一個(gè)ASSUME語(yǔ)句來(lái)改變前面ASSUME語(yǔ)句所說(shuō)明的對(duì)應(yīng)關(guān)系,這樣,代碼段中的指令就用最近的ASSUME語(yǔ)句所建立的對(duì)應(yīng)關(guān)系來(lái)確定指令中的有關(guān)信息。 例6.1 匯編語(yǔ)言段及其段說(shuō)明語(yǔ)句的作用。 DATA1 SEGMENT ;定義數(shù)據(jù)段DATA1 word1 DW 5678h byte1 DB "ABCDEFG" DATA1 ENDS DATA2 SEGMENT ;定義數(shù)據(jù)段DATA2 word2 DW 1234h word3 DW 9876h DATA2 ENDS DATA3 SEGMENT ;定義數(shù)據(jù)段DATA3 byte2 DB ? DATA3 ENDS CODE1 SEGMENT ;編寫(xiě)代碼段CODE1 ASSUME CS:CODE1, DS:DATA1, ES:DATA2 ;(1) MOV AX, DATA1 ;(2) MOV DS, AX ;(3) MOV AX, DATA2 ;(4) MOV ES, AX ;(5) … MOV AX, word1 ;訪問(wèn)段DATA1中的字變量word1 MOV word2, AX ;訪問(wèn)段DATA2中的字變量word2 … ASSUME DS:DATA3, ES:NOTHING ;(6) MOV AX, DATA3 MOV DS, AX MOV BL, byte2 ;訪問(wèn)段DATA3中的字節(jié)變量byte2 … MOV AX, 4C00H ;(7) INT 21H ;(8) CODE1 ENDS 語(yǔ)句(1)和(6)分別說(shuō)明了段和段寄存器之間的對(duì)應(yīng)關(guān)系,其中語(yǔ)句(6)重新說(shuō)明語(yǔ)句(1)所指定的對(duì)應(yīng)關(guān)系。 二組語(yǔ)句(2)和(3)、(4)和(5)實(shí)現(xiàn)對(duì)段寄存器DS和ES賦初值。ASSUME說(shuō)明語(yǔ)句只起說(shuō)明作用,它不會(huì)對(duì)段寄存器賦值,所以,必須對(duì)有關(guān)段寄存器賦值。在以后的其它源程序中也都是用此方法來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)段寄存器賦值的。 語(yǔ)句(7)和(8)是調(diào)用中斷21H的4CH號(hào)功能來(lái)結(jié)束本程序的執(zhí)行,程序的返回代碼由寄存器AL來(lái)確定。結(jié)束本程序執(zhí)行的指令是所有主模塊必須書(shū)寫(xiě)的語(yǔ)句。 注意:代碼段寄存器不能由程序員在源程序中對(duì)其賦值,其值是由操作系統(tǒng)在裝入它進(jìn)入系統(tǒng)運(yùn)行時(shí)自動(dòng)賦值的。 6.1.3 堆棧段的說(shuō)明 堆棧段是一個(gè)特殊的段,在程序中可以定義它,也可以不定義。除了要生成COM型執(zhí)行文件的源程序外,一個(gè)完整的源程序一般最好定義堆棧段。如果在程序中不定義堆棧段,那么,操作系統(tǒng)在裝入該執(zhí)行程序時(shí)將自動(dòng)為其指定一個(gè)64K字節(jié)的堆棧段。 在程序沒(méi)有定義堆棧段的情況下,在由連接程序生成執(zhí)行文件時(shí),將會(huì)產(chǎn)生一條如下的警告信息,但程序員可以不理會(huì)它,所生成的執(zhí)行文件是可以正常運(yùn)行的。 warning xxxx: no stack segment (其中:xxxx是錯(cuò)誤號(hào)) 在源程序中,可用以下方法來(lái)定義堆棧段。 方法1: STACK1 SEGMENT DB 256 DUP(?) ;256是堆棧的長(zhǎng)度,可根據(jù)需要進(jìn)行改變 TOP LABEL WORD STACK1 ENDS 以上堆棧段的定義如圖6.1所示。由于堆棧是按地址從大到小的存儲(chǔ)單元順序來(lái)存放內(nèi)容的,所以,在堆棧存儲(chǔ)單元說(shuō)明語(yǔ)句之后,再說(shuō)明一個(gè)棧頂別名,這樣,對(duì)棧頂寄存器SP的賦值就很方便。 在源程序的代碼段中,還要添加如下程序段,才能把段STACK1當(dāng)作堆棧段來(lái)使用。 圖6.1 堆棧段定義示意圖 … ASSUME SS:STACK1 ;可在代碼段的段指定語(yǔ)句中一起說(shuō)明 CLI ;禁止響應(yīng)可屏蔽中斷 MOV AX, STACK1 MOV SS, AX MOV SP, offset TOP ;給堆棧段的棧頂寄存器SP賦初值 STI ;恢復(fù)響應(yīng)可屏蔽中斷 … 方法2: STACK1 SEGMENT STACK ;定義一個(gè)堆棧段,其段名為STACK1 DB 256 DUP(?) STACK1 ENDS 上述段定義說(shuō)明了該段是堆棧段,系統(tǒng)會(huì)自動(dòng)把段寄存器SS和棧頂寄存器SP與該堆棧段之間建立相應(yīng)的關(guān)系,并設(shè)置其初值,而不用在代碼段對(duì)它們進(jìn)行賦值。 除了以上二種方法外,還有一種更簡(jiǎn)潔的方法來(lái)定義堆棧段,有關(guān)內(nèi)容請(qǐng)見(jiàn)第6.4.2節(jié)中的敘述。 6.1.4 源程序的結(jié)構(gòu) 下面的程序是一個(gè)完整的源程序,其功能是在屏幕上顯示字符串“Hello, World.”。讀者可參考此結(jié)構(gòu)編寫(xiě)自己的簡(jiǎn)單程序。 例6.2 在屏幕上顯示字符串“HELLO,WORLD.” 解:可運(yùn)行下面的控件,用鼠標(biāo)左鍵單擊程序中的某一行,可閱讀其含義;單擊“內(nèi)存”可切換內(nèi)存內(nèi)容的顯示方式。 偽指令END表示源程序到此為止,匯編程序?qū)υ撜Z(yǔ)句之后的任何內(nèi)容都不作處理,所以,通常情況下,偽指令END是源程序的最后一條語(yǔ)句。 偽指令END后面可附帶一個(gè)在程序中已定義的標(biāo)號(hào),由該標(biāo)號(hào)指明程序的啟動(dòng)位置。 如果源程序是一個(gè)獨(dú)立的程序或主模塊,那么,偽指令END后面一定要附帶一個(gè)標(biāo)號(hào);如果源程序僅是一個(gè)普通模塊,那么,其END后面就一定不能附帶標(biāo)號(hào)。 6.2 程序的基本結(jié)構(gòu) 在學(xué)習(xí)高級(jí)語(yǔ)言程序設(shè)計(jì)時(shí),我們知道了程序的三大主要結(jié)構(gòu):順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。在匯編語(yǔ)言的源程序也同樣有此三大結(jié)構(gòu),所不同的是它們的表現(xiàn)形式不同。用高級(jí)語(yǔ)言編寫(xiě)程序時(shí),由于不使用“轉(zhuǎn)移語(yǔ)句”而使這三種結(jié)構(gòu)清晰明了。 但在匯編語(yǔ)言的源程序中,很難不使用“轉(zhuǎn)移語(yǔ)句”(除非是一些只有簡(jiǎn)單功能的程序),有時(shí)甚至?xí)懈鞣N各樣的“轉(zhuǎn)移語(yǔ)句”。由于存在這些轉(zhuǎn)移語(yǔ)句,就使得:匯編語(yǔ)言源程序的基本結(jié)構(gòu)顯得不太明確。如果源程序的編寫(xiě)者思維混亂,編寫(xiě)出來(lái)的源程序在結(jié)構(gòu)上就會(huì)顯得雜亂無(wú)章,反之,如果編寫(xiě)者條理清晰,安排的操作井然有序,那么,編寫(xiě)出來(lái)的程序在結(jié)構(gòu)上就會(huì)一目了然。 總之,不論是高級(jí)語(yǔ)言的源程序,還是匯編語(yǔ)言的源程序,其程序的三大基本結(jié)構(gòu)也還是萬(wàn)變不離其宗的。 6.2.1 順序結(jié)構(gòu) 順序結(jié)構(gòu)是最簡(jiǎn)單的程序結(jié)構(gòu),程序的執(zhí)行順序就是指令的編寫(xiě)順序,所以,安排指令的先后次序就顯得至關(guān)重要。另外,在編程序時(shí),還要妥善保存已得到的處理結(jié)果,為后面的進(jìn)一步處理直接提供前面的處理結(jié)果,從而避免不必要的重復(fù)操作。 例6.3 編寫(xiě)程序段,完成下面公式的計(jì)算(其中:變量X和Y是32位有符號(hào)數(shù),變量A,B和Z是16位有符號(hào)數(shù))。 A←(X-Y+24)/Z的商,B←(X-Y+24)/Z的余數(shù) 解: DATA1 SEGMENT X DD ? Y DD ? Z DW ? A DW ? B DW ? … DATA1 ENDS CODE1 SEGMENT … MOV AX, X MOV DX, X+2 ;用(DX:AX)來(lái)保存32位變量X的數(shù)值 SUB AX,Y SBB DX, Y+2 ;(DX:AX)-(Y+2:Y) ADD AX, 24D ADC DX, 0 ;(DX:AX)+24 IDIV Z MOV A, AX MOV B, DX … CODE1 ENDS 在編程序時(shí),常常需要交換二變量之值。假設(shè)需要交換值的變量名為:var1和var2,臨時(shí)增加的變量名為temp。常用的算法如下: temp = var1 var1 = var2 var2 = temp 例6.4 假設(shè)有二個(gè)字變量word1和word2,編寫(xiě)程序段實(shí)現(xiàn)交換其值的功能。 解: 方法1:用匯編語(yǔ)言指令簡(jiǎn)單“直譯”上面的 交換數(shù)據(jù)方法 DATA1 SEGMENT … word1 DW ? word2 DW ? temp DW ? … DATA1 ENDS CODE1 SEGMENT … MOV AX, word1 MOV temp, AX ;上二語(yǔ)句實(shí)現(xiàn)語(yǔ)句“temp=word1” MOV AX, word2 MOV word1, AX ;上二語(yǔ)句實(shí)現(xiàn)語(yǔ)句“word1=word2” MOV AX, temp MOV word2, AX ;上二語(yǔ)句實(shí)現(xiàn)語(yǔ)句“word2=temp” … CODE1 ENDS 這種方法雖然也能完成功能,但顯然其不能充分利用匯編語(yǔ)言的特點(diǎn),程序效率很低。 方法2:用匯編語(yǔ)言指令的特點(diǎn)來(lái)直接編譯 DATA1 SEGMENT … word1 DW ? word2 DW ? … DATA1 ENDS CODE1 SEGMENT … MOV AX, word1 XCHG AX, word2 MOV word1, AX ;能XCHG word1, word2來(lái)代替這三條指令嗎? … CODE1 ENDS 該方法充分利用了匯編語(yǔ)言的特點(diǎn),不僅省去了中間變量temp的定義,而且程序的效率也提高了。 6.2.2 分支結(jié)構(gòu) 分支結(jié)構(gòu)是一種非常重要的程序結(jié)構(gòu),也是實(shí)現(xiàn)程序功能選擇所必要的程序結(jié)構(gòu)。由于匯編語(yǔ)言需要書(shū)寫(xiě)轉(zhuǎn)移指令來(lái)實(shí)現(xiàn)分支結(jié)構(gòu),而轉(zhuǎn)移指令肯定會(huì)破壞程序的結(jié)構(gòu),所以,編寫(xiě)清晰的分支結(jié)構(gòu)是掌握該結(jié)構(gòu)的重點(diǎn),也是用匯編語(yǔ)言編程的基本功。 在程序中,當(dāng)需要進(jìn)行邏輯分支時(shí),可用每次分二支的方法來(lái)達(dá)到程序最終分多支的要求,也可是用地址表的方法來(lái)達(dá)到分多支的目的。 一、顯示轉(zhuǎn)移指令實(shí)現(xiàn)的分支結(jié)構(gòu) 在高級(jí)語(yǔ)句中,分支結(jié)構(gòu)一般用IF語(yǔ)句來(lái)實(shí)現(xiàn),在匯編語(yǔ)言中,課用無(wú)條件轉(zhuǎn)移指令或條件轉(zhuǎn)移指令實(shí)現(xiàn)的分支結(jié)構(gòu)。如圖6.2給出了二種常用的分支結(jié)構(gòu)。 在編寫(xiě)分支程序時(shí),要盡可能避免編寫(xiě)“頭重腳輕”的結(jié)構(gòu),即:當(dāng)前分支條件成立時(shí),將執(zhí)行一系列指令,而條件不成立時(shí),所執(zhí)行的指令很少。這樣就使后一個(gè)分支離分支點(diǎn)較遠(yuǎn),有時(shí)甚至?xí)z忘編寫(xiě)后一分支程序。這種分支方式不僅不利于程序的閱讀,而且也不便將來(lái)的維護(hù)。 所以,在編寫(xiě)分支結(jié)構(gòu)時(shí),一般先處理簡(jiǎn)單的分支,再處理較復(fù)雜的分支。對(duì)多分支的情況,也可遵循“由易到難”的原則。因?yàn)楹?jiǎn)單的分支只需要較少的指令就能處理完,一旦處理完這種情況后,在后面的編程過(guò)程中就可集中考慮如何處理復(fù)雜的分支。 (a) if … endif結(jié)構(gòu) (b) if…else…endif結(jié)構(gòu) 圖6.2 分支結(jié)構(gòu)的二種結(jié)構(gòu) 例6.5 已知字節(jié)變量CHAR1,編寫(xiě)一程序段,把它由小寫(xiě)字母變成大寫(xiě)字母。 解: DATA1 SEGMENT … CHAR1 DB ? … DATA1 ENDS CODE1 SEGMENT … MOV AL, CHAR1 CMP AL, ‘a(chǎn)’ JB next CMP AL, ‘z’ JA next SUB CHAR1, 20H ;指令A(yù)ND CHAR1, 0DFH也可以 next: … … CODE1 ENDS 例6.6 編寫(xiě)一程序段,計(jì)算下列函數(shù)值。其中:變量X和Y是有符號(hào)字變量。 解: DATA1 SEGMENT … X DW ? Y DW ? … DATA1 ENDS CODE1 SEGMENT … MOV AX, X CMP AX, 0 JGE case23 ADD AX, 10 ;第一種情況的計(jì)算結(jié)果 JMP result case23: CMP AX, 10D JG case3 MOV BX, 30D IMUL BX ;第二種情況的計(jì)算結(jié)果 JMP result case3: SUB AX, 9 ;第三種情況的計(jì)算結(jié)果 result: MOV Y, AX ;把計(jì)算結(jié)果保存到變量Y中 … CODE1 ENDS 例6.7 把下列C語(yǔ)言的語(yǔ)句改寫(xiě)成等價(jià)的匯編語(yǔ)言程序段(不考慮運(yùn)算過(guò)程中的溢出)。 If (a+b > 0 && c%2 == 0) a = 62; else a = 21; 其中:變量a,b和c都是有符號(hào)的整型(int)變量。 解: DATA1 SEGMENT … A DW ? B DW ? C DW ? … DATA1 ENDS CODE1 SEGMENT … MOV AX, A ADD AX, B JLE _ELSE ;ADD指令會(huì)改變算術(shù)標(biāo)志位 TEST C, 1 ;C%2==0,也就是:看C的最低位是否為0 JNZ _ELSE MOV A, 62D JMP NEXT _ELSE: MOV A, 21D NEXT: … CODE1 ENDS 例6.8 用地址轉(zhuǎn)移表實(shí)現(xiàn)下列C語(yǔ)言的switch語(yǔ)句,其中:變量A和B是有符號(hào)的整型(int)變量。 switch (a%8) {case 0: b = 32; break; case 1: case 2: b = a + 43; break; case 3: b = 2*a; break; case 4: b--; break; case 5: case 6: case 7: printf(“Function 5_6_7”); break; } 解: DATA1 SEGMENT … A DW ? B DW ? Table DW case0. case12, case12, case3 DW case4, case567, case567, case567 MSG DB Function 5_6_7$ … DATA1 ENDS CODE1 SEGMENT … MOV AX, A MOV BX, AX AND BX, 7 ;得到BX的低三位,實(shí)現(xiàn)a%8的計(jì)算 SHL BX, 1 ;由于地址表是字類(lèi)型,其下標(biāo)要乘2 JMP Table[BX] ;利用地址表實(shí)現(xiàn)多路轉(zhuǎn)移 case0: MOV B, 32D JMP next case12: ADD AX, 43D MOV B, AX JMP next case3: SHL AX, 1 MOV B, AX JMP next case4: DEC B JMP next case567: LEA DX, MSG MOV AH, 9 INT 21H JMP next next: … CODE1 ENDS 用地址表實(shí)現(xiàn)多路轉(zhuǎn)移的關(guān)鍵在于:轉(zhuǎn)移入口的地址表和轉(zhuǎn)移情況可整數(shù)化。如果這二個(gè)要求有一個(gè)不滿足,或很難構(gòu)造,則無(wú)法使用該方法。 為了改善匯編語(yǔ)言源程序的結(jié)構(gòu),減少顯式轉(zhuǎn)移語(yǔ)句所帶來(lái)混亂,在宏匯編MASM 6.11系統(tǒng)中,增加了表達(dá)分支結(jié)構(gòu)的偽指令。該偽指令的書(shū)寫(xiě)格式與高級(jí)語(yǔ)言的書(shū)寫(xiě)方式相類(lèi)似,匯編程序在匯編時(shí)會(huì)自動(dòng)增加轉(zhuǎn)移指令和相應(yīng)的標(biāo)號(hào)。理解并掌握該知識(shí),對(duì)將來(lái)學(xué)習(xí)《編譯原理》課程也有一定的幫助。 分支偽指令的具體格式如下: 格式1: .IF condition ;以英文“句號(hào)”開(kāi)頭 指令序列 ;條件"condition"成立時(shí)所執(zhí)行的指令序列 .ENDIF 格式2: .IF condition 指令序列1 .ELSE 指令序列2 ;條件"condition"不成立時(shí)所執(zhí)行的指令序列 .ENDIF 格式3: .IF condition1 指令序列1 .ELSEIF condition2 指令序列2 ;條件"condition2"成立時(shí)所執(zhí)行的指令序列 .ENDIF 其中:條件表達(dá)式“condition”的書(shū)寫(xiě)方式與C語(yǔ)言中條件表達(dá)式的書(shū)寫(xiě)方式相似,也可用括號(hào)來(lái)組成復(fù)雜的條件表達(dá)式。 條件表達(dá)式中可用的操作符有:==(等于)、!=(不等)、>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、&(位操作與)、!(邏輯非)、&&(邏輯與)、||(邏輯或)等。 若在條件表達(dá)式中檢測(cè)標(biāo)志位的信息,則可以使用的符號(hào)名有:CARRY?(相當(dāng)于CF==1)、OVERFLOW?(OF==1)、PARITY?(PF==1)、SIGN?(SF==1)、ZERO?(ZF==1)等。例如: .IF CARRY? && AX != BX ;檢測(cè)CF==1且AX!=BX是否成立 ;匯編語(yǔ)言指令序列 .ENDIF 在指令序列中,還可再含有其它的.IF偽指令,即:允許嵌套。偽指令.ELSEIF引導(dǎo)出另一個(gè)二叉分支,但它不能作偽指令塊的第一個(gè)偽指令。 匯編程序在對(duì)“條件表達(dá)式”進(jìn)行代碼轉(zhuǎn)換時(shí)將進(jìn)行代碼優(yōu)化處理,以便盡可能生成最好的指令代碼。如: .IF ax == 0 匯編程序會(huì)把它轉(zhuǎn)換為指令“OR ax, ax”,而不是“CMP ax, 0”,因?yàn)榍罢弑群笳吒?,而不是?jiǎn)單直接地轉(zhuǎn)換為后者。 如果用偽指令來(lái)書(shū)寫(xiě)分支結(jié)構(gòu),那么,例6.5的代碼段部分就可寫(xiě)成如下程序段: … MOV AL, CHAR1 .IF AL>=a && AL<=z ;語(yǔ)句象C語(yǔ)言語(yǔ)句嗎? SUB CHAR1, 20H .ENDIF … 也可把例6.6的代碼段部分就可寫(xiě)成如下程序段: … MOV AX, X .IFAX < 0 ADD AX, 10 ;計(jì)算第一種情況的結(jié)果 .ELSEIF AX <= 10 MOV BX, 30D IMUL BX ;計(jì)算第二種情況的結(jié)果 .ELSE SUB AX, 9 ;計(jì)算第三種情況的結(jié)果 .ENDIF MOV Y, AX … ;把計(jì)算結(jié)果保存到變量Y中 例6.9 根據(jù)當(dāng)前計(jì)算機(jī)的時(shí)間和日期,顯示上午(AM)或下午(PM),以及所在的季節(jié)。 解:顯示解答 6.2.3 循環(huán)結(jié)構(gòu) 循環(huán)結(jié)構(gòu)是一個(gè)重要的程序結(jié)構(gòu),它具有重復(fù)執(zhí)行某段程序的功能。通常,循環(huán)結(jié)構(gòu)包括以下四個(gè)組成部分: 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)出來(lái),有時(shí)也并非清析地表達(dá)出來(lái)。常用的循環(huán)結(jié)構(gòu)如圖6.3所示。 (a)、Do—While結(jié)構(gòu) (b)、While結(jié)構(gòu) 圖6.3 常用的循環(huán)結(jié)構(gòu)示意圖 一、用循環(huán)指令構(gòu)成循環(huán)結(jié)構(gòu) 在編寫(xiě)循環(huán)結(jié)構(gòu)的程序片段時(shí),我們可以多種方法來(lái)循環(huán)結(jié)構(gòu)。如:循環(huán)次數(shù)是已知的,可用LOOP指令來(lái)構(gòu)造循環(huán);當(dāng)循環(huán)次數(shù)是未知或不定的,則可用條件轉(zhuǎn)移或無(wú)條件轉(zhuǎn)移來(lái)構(gòu)成循環(huán)結(jié)構(gòu)。 例6.10 分類(lèi)統(tǒng)計(jì)字?jǐn)?shù)組data中正數(shù)、負(fù)數(shù)和零的個(gè)數(shù),并分別存入內(nèi)存字變量Positive、Negative和Zero中,數(shù)組元素個(gè)數(shù)保存在其第一個(gè)字中。 解:顯示解答 例6.11 計(jì)算數(shù)組score的平均整數(shù),并存入內(nèi)存字變量Average中,數(shù)組以-1為結(jié)束標(biāo)志。 解: DATA1 SEGMENT data DW 90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1 Average DW 0 DATA1 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1 START: MOV AX, DATA1 MOV DS, AX XOR AX, AX XOR DX, DX ;用(DX,AX)來(lái)保存數(shù)組元素之和 XOR CX, CX ;用CX來(lái)保存數(shù)組元素個(gè)數(shù) LEA SI, data ;用指針SI來(lái)訪問(wèn)整個(gè)數(shù)組 again: MOV BX, word ptr [SI] CMP BX, 0 JL over ADD AX, BX ADC DX, 0 ;把當(dāng)前數(shù)組元素之值加到(DX,AX)中 INC CX ;數(shù)組元素個(gè)數(shù)加1 ADD SI, 2 JMP again over: JCXZ exit ;防止零作除數(shù),即數(shù)組是空數(shù)組 DIV CX MOV Average, AX exit: MOV AX, 4C00H INT 21H CODE1 ENDS END START 二、用偽指令實(shí)現(xiàn)的循環(huán)結(jié)構(gòu) 在宏匯編MASM 6.11系統(tǒng)中,還增加了表達(dá)循環(huán)結(jié)構(gòu)的偽指令,以便更清晰地表達(dá)WHILE循環(huán)、REPEAT-UNTIL循環(huán)。另外,還增加兩個(gè)輔助循環(huán)的偽指令。這些偽指令的書(shū)寫(xiě)格式和含義與高級(jí)語(yǔ)言中相應(yīng)語(yǔ)句的書(shū)寫(xiě)格式和含義相一致,所以,這些偽指令是很容易掌握的,也是非常有用的。 循環(huán)偽指令的格式和含義如下: 1、WHILE型循環(huán)偽指令 .WHILE condition 循環(huán)體的指令序列 ;條件"condition”成立時(shí)所執(zhí)行的指令序列 .ENDW 其中:.ENDW與前面的.WHILE相匹配,它標(biāo)志著其循環(huán)體到此結(jié)束。 如果條件表達(dá)式“condition”在循環(huán)開(kāi)始時(shí),就為“假”(false),那么,該循環(huán)體一次也不會(huì)被執(zhí)行。 2、REPEAT型循環(huán)偽指令 .REPEAT 循環(huán)體的指令序列 .UNTIL condition .REPEAT 循環(huán)體的指令序列 .UNTILCXZ [condition] REPEAT型循環(huán)在執(zhí)行完循環(huán)體后,才判定邏輯表達(dá)式condition的值。若該表達(dá)式的值為真,則終止該循環(huán),并將執(zhí)行偽指令.UNTIL[CXZ]后面的指令,否則,將向上跳轉(zhuǎn)到偽指令.REPEAT之后的指令,為繼續(xù)執(zhí)行其循環(huán)體作準(zhǔn)備。 如果.UNTILCXZ后面沒(méi)有寫(xiě)邏輯表達(dá)式,那么,由.REPEAT-.UNTILCXZ所構(gòu)成的循環(huán)與用LOOP指令所過(guò)程的循環(huán)是一致的,它們都是以“CX=0”為循環(huán)終止條件。 如果.UNTILCXZ后面書(shū)寫(xiě)了邏輯表達(dá)式,那么,該邏輯表達(dá)式的形式只能是:“EXP1==EXP2”或“EXP1!=EXP2”。所以,這時(shí)由“.REPEAT-.UNTILCXZ condition”所構(gòu)成的循環(huán)就與用LOOPNE/LOOPE指令所過(guò)程的循環(huán)是一致的,它們都是以“condition || CX=0”為循環(huán)終止條件。 和高級(jí)語(yǔ)言的REPEAT型的循環(huán)一樣,.REPEAT-.UNTIL[CXZ]的循環(huán)體也會(huì)至少被執(zhí)行一次。 .WHILE-.ENDW和.REPEAT-.UNTIL[CXZ]的循環(huán)體內(nèi)還可再含有循環(huán)偽指令,這樣就構(gòu)成了循環(huán)結(jié)構(gòu)的嵌套。 匯編程序在生產(chǎn)指令代碼時(shí)會(huì)進(jìn)行代碼優(yōu)化,以便盡可能得到最優(yōu)化的指令序列。 3、輔助循環(huán)偽指令 (1)、終止循環(huán)偽指令 .BREAK .BREAK .IF condition 該偽指令用來(lái)終止包含它的最內(nèi)層循環(huán)。前者是無(wú)條件終止循環(huán),后者是僅當(dāng)邏輯表達(dá)式condition為真時(shí),才終止循環(huán)。 .WHILE 1 .REPEAT … .BREAK .IF condition … … .BREAK .IF condition … ENDW .UNTIL 0 對(duì)于以上二個(gè)循環(huán),如果沒(méi)有指令來(lái)終止循環(huán)的話,它們都將進(jìn)入死循環(huán)狀態(tài),但如果在該層循環(huán)體內(nèi),存在偽指令“.BREAK .IF condition”的話,那么,當(dāng)邏輯表達(dá)式condition為真時(shí),該循環(huán)就會(huì)被終止了。 (2)、循環(huán)繼續(xù)偽指令 .CONTINUE .CONTINUE .IF condition 該偽指令用于直接跳轉(zhuǎn)到包含它的最內(nèi)層循環(huán)的計(jì)算循環(huán)條件表達(dá)式的代碼處。前者是無(wú)條件轉(zhuǎn)移到計(jì)算循環(huán)條件表達(dá)式的代碼處,后者是僅當(dāng)條件表達(dá)式condition為真時(shí),才進(jìn)行這樣的跳轉(zhuǎn)。 輔助循環(huán)偽指令.BREAK和.CONTINUE只能在偽指令.WHILE-.ENDW和.REPEAT-.UNTIL的循環(huán)體內(nèi)使用。 例6.12 顯示9個(gè)數(shù)字字母1~9,26個(gè)大寫(xiě)字母,和顯示任意輸入的數(shù)字字符,并用按“回車(chē)”鍵來(lái)結(jié)束本程序的運(yùn)行。 解: DATA1 SEGMENT MSG1 DB 13, 10, "Iteration: " NUM1 DB 1, "$" MSG2 DB 13, 10, "Alphabet: $" NUM2 DB A, " $" MSG3 DB 13, 10, "Type digits, then press ENTER: $" DATA1 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1 START: MOV AX, DATA1 MOV DS, AX MOV CX, 9 MOV AH, 09H MOV DX, OFFSET MSG1 .REPEAT INT 21H INC NUM1 ;顯示Iteration: 1,2,~,9 .UNTILCXZ MOV DX, OFFSET MSG2 INT 21H ;顯示字符串"Alphabet:" MOV AH, 09H MOV DX, OFFSET NUM2 .REPEAT INT 21H INC NUM2 ;顯示當(dāng)前字母 ;當(dāng)前字母向后移 .UNTIL NUM2 > Z ;顯示整個(gè)大寫(xiě)字母表 MOV AH, 09H MOV DX, OFFSET MSG3 INT 21H .WHILE 1 ;循環(huán)條件為永真的循環(huán) MOV AH, 07H INT 21H ;不帶回顯地從鍵盤(pán)讀一個(gè)字符 .BREAK .IF AL == 13 ;如果輸入“回車(chē)”鍵,則終止循環(huán) .CONTINUE .IF (AL<0) || (AL>9) ;如果字符不是數(shù)字字符,則繼續(xù)循環(huán) MOV DL, AL MOV AH, 02H INT 21H ;顯示所輸入的數(shù)字字母 .ENDW MOV AX, 4C00H INT 21H CODE1 ENDS END START 6.3 段的基本屬性 在通常情況下,一個(gè)復(fù)雜的應(yīng)用程序會(huì)由若干個(gè)模塊組成,一個(gè)模塊又會(huì)含有多個(gè)段。而不同模塊的段之間、同一模塊的段之間往往存在某種聯(lián)系,這種聯(lián)系就要體現(xiàn)在段屬性的說(shuō)明上。 段定義的一般格式如下: 段名 SEGMENT [對(duì)齊類(lèi)型] [組合類(lèi)型] [類(lèi)別] … 段名 ENDS 段屬性“對(duì)齊類(lèi)型”、“組合類(lèi)型”和“類(lèi)別”要按此順序說(shuō)明,但這些可選項(xiàng)可根據(jù)需要選擇書(shū)寫(xiě)。如果源程序中不指定某個(gè)屬性,那么,匯編程序?qū)⑹褂迷搶傩缘娜笔≈怠? 程序中的段名可以是唯一的,也可以與其它段同名。在同一模塊中,如果有二個(gè)段同名,則后者被認(rèn)為是前段的后續(xù),這樣,它們就屬同一段。 當(dāng)同一模塊出現(xiàn)二個(gè)同名段時(shí),則后者的可選項(xiàng)屬性要么與前者相同,要么不寫(xiě)其屬性而選用前者的段屬性。 例6.13 同段名的作用 DATA1 SEGMENT ;第一個(gè)數(shù)據(jù)段 MSG DB "Hello, " DATA1 ENDS CODE1 SEGMENT ;第一個(gè)代碼段 ASSUME CS:CODE1, DS:DATA1 START: MOV AX, DATA1 MOV DS, AX MOV DX, offset MSG MOV AH, 9 INT 21H CODE1 ENDS DATA1 SEGMENT ;第二個(gè)數(shù)據(jù)段 DB "World.$" DATA1 ENDS CODE1 SEGMENT ;第二個(gè)代碼段 MOV AX, 4C00H INT 21H CODE1 ENDS END START END 在上面的例子中,第二個(gè)數(shù)據(jù)段是第一個(gè)數(shù)據(jù)段的后續(xù),匯編程序把它們是合二為一,上述的代碼段也如此。 下面,詳細(xì)說(shuō)明段屬性的含義及其作用。 6.3.1 對(duì)齊類(lèi)型(ALIGN) 對(duì)齊類(lèi)型表示當(dāng)前段對(duì)起始地址的要求,連接程序(LINK.EXE)按表6.1的地址格式來(lái)定位段的起始地址。在進(jìn)行段定位時(shí),會(huì)根據(jù)其定位類(lèi)型進(jìn)行定位的,所以,各段之間就有可能出現(xiàn)一些空閑字節(jié),即可能浪費(fèi)幾個(gè)字節(jié)單元。 段對(duì)齊類(lèi)型PARA是一個(gè)適用于所有段類(lèi)型的對(duì)齊類(lèi)型,它也是缺省的對(duì)齊類(lèi)型。對(duì)齊類(lèi)型BYTE和WORD通常用于數(shù)據(jù)段的定位,對(duì)齊類(lèi)型DWORD通常用于80386及其以后CPU代碼段的定位。 表6.1 段對(duì)齊類(lèi)型與段起始地址之間的對(duì)應(yīng)關(guān)系 對(duì)齊類(lèi)型 起始地址(二進(jìn)制) 功能說(shuō)明 最多的空閑字節(jié)數(shù) BYTE xxxx xxxx xxxx xxxx xxxx 下一個(gè)字節(jié)地址 0 WORD xxxx xxxx xxxx xxxx xxx0 下一個(gè)字地址 1 DWORD xxxx xxxx xxxx xxxx xx00 下一個(gè)雙字地址 3 PARA xxxx xxxx xxxx xxxx 0000 下一個(gè)節(jié)地址 15 PAGE xxxx xxxx xxxx 0000 0000 下一個(gè)頁(yè)地址 127 6.3.2 組合類(lèi)型(COMBINE) 組合類(lèi)型是告訴連接程序如何把不同模塊中段名相同的段合并在一起。具體的組合類(lèi)型如下: NONE 表示當(dāng)前段在邏輯上獨(dú)立于其它模塊,并有其自己的基地址。NONE是缺省的組合類(lèi)型。 PUBLIC 表示當(dāng)前段與其它模塊中同段名的PUBLIC類(lèi)型段組合成一個(gè)段。組合的先后次序取決于LINK程序中目標(biāo)模塊排列的次序。在組合時(shí),后續(xù)段的起始地址要按其對(duì)齊類(lèi)型進(jìn)行定位,所以,同名段之間可能有間隔。 COMMON 表示當(dāng)前段與其它模塊中同名段重疊,也就是說(shuō),它們的起始地址相同。最終段的長(zhǎng)度是同名段的最大長(zhǎng)度。由于段覆蓋,所以,前一同名段中的初始化數(shù)據(jù)被后續(xù)段的初始數(shù)據(jù)覆蓋掉。 STACK 組合類(lèi)型STACK表示當(dāng)前段是堆棧棧,其組合情況與PUBLIC相同。 AT 數(shù)值表達(dá)式 該數(shù)值表達(dá)式是當(dāng)前段所指定的絕對(duì)起始地址的段地址。 6.3.3 類(lèi)別(CLASS) 類(lèi)別是一個(gè)由程序員指定的用單引號(hào)括起來(lái)的字符串。如果一個(gè)段沒(méi)有給出類(lèi)別,那么,這個(gè)段的類(lèi)別就為空。類(lèi)別是用于段的分類(lèi),連接程序利用該類(lèi)別來(lái)調(diào)整同名、同類(lèi)別的段,并使它們相鄰。典型的類(lèi)別是"Data"和"Code"。如果指定某段的類(lèi)別是"Code",那么,該段最好是代碼段,這樣,有的調(diào)試程序(如:CodeView)就可以順序工作。 例如: DATA1 SEGMENT WORD PUBLIC "Data" … DATA1 ENDS 上述段定義說(shuō)明了該段的起始地址是下一個(gè)字地址、組合類(lèi)型為PUBLIC、段類(lèi)別是"Data"。 6.3.4 段組(GROUP) 段組偽指令GROUP是用于把源程序模塊中若干個(gè)段結(jié)合成一個(gè)組,并對(duì)該段組定義一個(gè)段組名。段組偽指令的格式如下: 段組名 GROUP 段名[, 段名, ……] 其中:段名之間要用逗號(hào)間隔,段名也可以用表達(dá)式“SEG 變量”或“SEG 標(biāo)號(hào)”。 下面舉例說(shuō)明段組偽指令的使用方法和作用。 例6.12 段組的作用 方法1:用一個(gè)段寄存器對(duì)應(yīng)二個(gè)數(shù)據(jù)段 DATA1 SEGMENT ;第一個(gè)數(shù)據(jù)段 b1 DB 10h DATA1 ENDS DATA2 SEGMENT ;第二個(gè)數(shù)據(jù)段 b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1 ;(1) START: MOV AX, DATA1 MOV DS, AX ;(2)把數(shù)據(jù)段DATA1的段值賦給段寄存器DS … MOV BL, b1 ;(3)引用DS來(lái)訪問(wèn)DATA1中的變量b1 … ASSUME DS:DATA2 ;(4) MOV AX, DATA2 MOV DS, AX ;(5)把數(shù)據(jù)段DATA2的段值賦給段寄存器DS … MOV AL, b2 ;(6)引用DS來(lái)訪問(wèn)DATA2中的變量b2 … CODE1 ENDS END START 在上例中,語(yǔ)句(1)說(shuō)明DS與DATA1建立聯(lián)系,語(yǔ)句(2)對(duì)DS賦值,語(yǔ)句(3)用DS來(lái)訪問(wèn)DATA1段的變量名。語(yǔ)句(4)說(shuō)明DS與DATA2建立聯(lián)系,語(yǔ)句(5)對(duì)DS賦值,語(yǔ)句(6)用DS來(lái)訪問(wèn)DATA2段的變量名。 在該例子中,因?yàn)橹皇褂靡粋€(gè)段寄存器DS來(lái)對(duì)應(yīng)二個(gè)數(shù)據(jù)段,所以,需要切換DS的對(duì)應(yīng)關(guān)系(如:語(yǔ)句(4))。但我們也可以用段寄存器DS和ES來(lái)分別對(duì)應(yīng)段DATA1和DATA2,這樣,方法1就可變成方法2。 方法2:用二個(gè)段寄存器對(duì)應(yīng)二個(gè)數(shù)據(jù)段 DATA1 SEGMENT b1 DB 10h DATA1 ENDS DATA2 SEGMENT b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:DATA1, ES:DATA2 START: MOV AX, DATA1 MOV DS, AX ;把數(shù)據(jù)段DATA1的段值賦給段寄存器DS MOV AX, DATA2 MOV ES, AX ;把數(shù)據(jù)段DATA2的段值賦給段寄存器ES … MOV BL, b1 ;引用DS來(lái)訪問(wèn)DATA1中的變量b1 … MOV AL, b2 ;引用ES來(lái)訪問(wèn)DATA2中的變量b2 … CODE1 ENDS END START 我們還可以用段組來(lái)簡(jiǎn)化段寄存器的使用,把段DATA1和DATA2組成一個(gè)數(shù)據(jù)段。所以,把方法2再改寫(xiě)成方法3的形式。 方法3:用一個(gè)段組組成二個(gè)數(shù)據(jù)段 GSEG GROUP DATA1, DATA2 ;把段DATA1和DATA2定義成一個(gè)段組 DATA1 SEGMENT b1 DB 10h DATA1 ENDS DATA2 SEGMENT b2 DB 23h DATA2 ENDS CODE1 SEGMENT ASSUME CS:CODE1, DS:GSEG START: MOV AX, GSEG MOV DS, AX ;把段組GSEG的段值賦給段寄存器DS … MOV BL, b1 ;引用DS來(lái)訪問(wèn)DATA1中的變量b1 … MOV AL, b2 ;引用DS來(lái)訪問(wèn)DATA2中的變量b2 … CODE1 ENDS END START 定義段組后,段組內(nèi)各段所定義的標(biāo)號(hào)和變量,除了與定義它們的段起始點(diǎn)相關(guān)外,還與段組的起始點(diǎn)相關(guān)。規(guī)定如下: 、 如果在ASSUME偽指令中說(shuō)明段組與段寄存器相對(duì)應(yīng),那么,有關(guān)標(biāo)號(hào)或變量的偏移量就相對(duì)于段組起點(diǎn)計(jì)算; 、 如果在ASSUME偽指令中說(shuō)明段組內(nèi)的某各段與段寄存器相對(duì)應(yīng),那么,有關(guān)標(biāo)號(hào)或變量的偏移量就相對(duì)于該段的起點(diǎn)。 所以,在使用段組后,程序員要謹(jǐn)慎使用ASSUME偽指令,并保證段寄存器的值與段組或段相一致。 6.4 簡(jiǎn)化的段定義 前面,我們介紹了完整的段定義格式,用完整的段定義格式雖然可以控制段的各種屬性,但程序員很少會(huì)這樣做。現(xiàn)在的匯編程序提供了一種簡(jiǎn)化的段定義方式,它使定義段更簡(jiǎn)單、方便。 6.4.1 存儲(chǔ)模型說(shuō)明偽指令 在使用簡(jiǎn)化的段定義方式之前,必須使用存儲(chǔ)模式說(shuō)明偽指令來(lái)描述源程序所采用的存儲(chǔ)模式。該偽指令說(shuō)程序所使用的存儲(chǔ)模式,匯編程序?qū)⒂迷摯鎯?chǔ)模式生成相應(yīng)的ASSUME和GROUP語(yǔ)句,同時(shí)也為其它的簡(jiǎn)化段創(chuàng)建等價(jià)的預(yù)定義。 程序存儲(chǔ)模式說(shuō)明偽指令的格式如下: .MODEL 存儲(chǔ)模式[,語(yǔ)言類(lèi)型] [,操作系統(tǒng)類(lèi)型] [,堆棧類(lèi)型] 程序可選的存儲(chǔ)模式有:TINY、SMALL、COMPACT、MEDIUM、LARGE、HUGE和FLAT。 偽指令.MODEL必須寫(xiě)在源程序的首部,且只能出現(xiàn)一次,其前內(nèi)容只能是注釋。 如果用偽指令來(lái)指定程序所遵循的語(yǔ)言類(lèi)型,那么,將不允許子程序的嵌套定義。與子程序定義有關(guān)的內(nèi)容請(qǐng)見(jiàn)第7.5節(jié)。 一、存儲(chǔ)模式 如果要用匯編語(yǔ)言編寫(xiě)被高級(jí)語(yǔ)言調(diào)用的子程序,那么,該匯編程序的存儲(chǔ)模式必須與該高級(jí)語(yǔ)言編譯(或解釋)程序所使用的存儲(chǔ)模式相匹配。匯編語(yǔ)言程序所能使用的存儲(chǔ)模式、符號(hào)及其相關(guān)信息如表6.2所列。 在程序中,還可偽指令OPTION SEGMENT和SEGMENT來(lái)指定段的規(guī)模。 有關(guān)存儲(chǔ)模式的具體規(guī)定如下: 、TINY 在匯編程序MASM 6.11和TASM 4.0,該存儲(chǔ)類(lèi)型是為編寫(xiě)COM文件類(lèi)型而設(shè)置的。程序員還可用匯編命令行選項(xiàng)/AT和連接命令選項(xiàng)/TINY來(lái)達(dá)到此目的。 表6.2 存儲(chǔ)模式的符號(hào)及其相關(guān)含義 代碼的位距 數(shù)據(jù)的位距 段的寬度 數(shù)據(jù)段和代碼段能否合并 Code Distance Data Distance Segment Width Data & Code Combined? Tiny Small Compact Medium Large Huge Flat NEAR NEAR 16-bit Yes NEAR NEAR 16-bit No NEAR FAR 16-bit No FAR NEAR 16-bit No FAR FAR 16-bit No FAR FAR 16-bit No NEAR NEAR 32-bit Yes 、SMALL 所有的數(shù)據(jù)變量必須在一個(gè)數(shù)據(jù)段之內(nèi),所有的代碼也必須在一個(gè)代碼段之內(nèi)。在這種模型下,數(shù)據(jù)段寄存器的內(nèi)容保持不變,所有轉(zhuǎn)移也都是段內(nèi)轉(zhuǎn)移。 該存儲(chǔ)類(lèi)型是獨(dú)立匯編語(yǔ)言源程序常用的存儲(chǔ)模型。 、MEDIUM 所有的數(shù)據(jù)變量必須在一個(gè)數(shù)據(jù)段之內(nèi),但代碼段可以有多個(gè)。在這種模型下,數(shù)據(jù)段寄存器的內(nèi)容保持不變,轉(zhuǎn)移可以是段間轉(zhuǎn)移。 、COMPACT 數(shù)據(jù)段可以有多個(gè),但代碼段只能有一。 、LARGE 數(shù)據(jù)段和代碼段都可以有多個(gè),但一個(gè)數(shù)組的字節(jié)數(shù)不能超過(guò)64KB。 、HUGE 數(shù)據(jù)段和代碼段都可以有多個(gè),一個(gè)數(shù)組的字節(jié)數(shù)也可以超過(guò)64KB。 、FLAT FLAT存儲(chǔ)模式在創(chuàng)建執(zhí)行文件時(shí),將使該程序僅含一個(gè)包括程序數(shù)據(jù)和代碼的32位段,并且只能在80386及其以后的計(jì)算機(jī)系統(tǒng)中運(yùn)行。該程序的文件類(lèi)型為EXE。 在使用該存儲(chǔ)模式之前,必須先用偽指令.386、.486或其它偽指令來(lái)說(shuō)明更高性能的CPU類(lèi)型。也就是說(shuō):FLAT模式僅在386及其以后CPU模式下才能使用。 在該程序中,所有代碼和數(shù)據(jù)位距的缺省值都是NEAR,子程序的類(lèi)型也是NEAR,并且標(biāo)識(shí)符@CodeSize,@DataSize和@Model的值分別為:0、0和7。 在FLAT存儲(chǔ)模式下,程序?qū)⒉皇褂枚渭拇嫫鱂S和GS。匯編程序在處理說(shuō)明語(yǔ)句“.MODEL FLAT”時(shí),將自動(dòng)生成下列段寄存器說(shuō)明語(yǔ)句: ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:ERROR, GS:ERROR 當(dāng)然,程序員也可把該段寄存器說(shuō)明語(yǔ)句寫(xiě)在其指令序列之中。 二、語(yǔ)言類(lèi)型 其詳細(xì)說(shuō)明請(qǐng)見(jiàn)7.5.3節(jié)中所述。 三、操作系統(tǒng)類(lèi)型 OS_DOS是當(dāng)前唯一支持的選項(xiàng)值,也是該選項(xiàng)的缺省值。 四、堆棧類(lèi)型 堆棧類(lèi)型的值主要影響偽指令.STARTUP所生成的指令序列。該選項(xiàng)有二個(gè)可選值:NEARSTACK和FARSTACK。其中:NEARSTACK是該選項(xiàng)的缺省堆棧類(lèi)型。 、NEARSTACK——堆棧段和數(shù)據(jù)段是同一段; 、FARSTACK——堆棧段和數(shù)據(jù)段是不同的段,且堆棧不在段組DGROUP中。 例如: .MODEL SMALL, C, OS_DOS, FARSTACK 6.4.2 簡(jiǎn)化段定義偽指令 簡(jiǎn)化段定義偽指令在說(shuō)明一個(gè)新段即將開(kāi)始的同時(shí),也說(shuō)明了上一個(gè)段的結(jié)束。在本段定義結(jié)束時(shí),也不必用偽指令“ENDS”來(lái)標(biāo)識(shí)。 具體的偽指令說(shuō)明形式及其功能描述如下: 1、代碼段定義 .CODE 作用:說(shuō)明其下面的內(nèi)容是代碼段中內(nèi)容。 2、堆棧段定義 .STACK [堆棧字節(jié)數(shù)] 其中,“堆棧字節(jié)數(shù)”可以不寫(xiě),其缺省值為1024B。 3、數(shù)據(jù)段定義 .DATA / .DATA? / .CONST 作用:說(shuō)明其下面的內(nèi)容是數(shù)據(jù)段中的變量定義。 在一個(gè)源程序中,可以有多個(gè)偽指令.DATA定義的數(shù)據(jù)段,這就好象在源程序中定義多個(gè)同段名的數(shù)據(jù)段一樣。 偽指令.DATA?說(shuō)明下面是一個(gè)未初始化數(shù)據(jù)段的開(kāi)始,偽指令.CONST說(shuō)明下面是一個(gè)常數(shù)數(shù)據(jù)段的開(kāi)始。這二條偽指令很少使用,除非在與高級(jí)語(yǔ)言編寫(xiě)的程序相結(jié)合時(shí),為了遵守高級(jí)語(yǔ)言的某些約定,而需要特殊說(shuō)明時(shí)才使用。 匯編程序在處理簡(jiǎn)化的堆棧段和數(shù)據(jù)段定義時(shí),它會(huì)自動(dòng)地把偽指令.STACK、.DATA、.DATA?和.CONST所定義的段組合成一個(gè)段組。如果想定義一個(gè)獨(dú)立的、不與其它段組合在一起的數(shù)據(jù)段的話,那么,就可選用下面的數(shù)據(jù)段定義方式。 4、遠(yuǎn)程數(shù)據(jù)段定義 .FARDATA [段名] / .FARDATA? [段名] 其中:“段名”是可選項(xiàng),如果不指定的話,則該段名就取其缺省段名。 作用:說(shuō)明一個(gè)獨(dú)立的數(shù)據(jù)段。 偽指令.FARDATA?說(shuō)明下面是一個(gè)未初始化的、獨(dú)立數(shù)據(jù)段的開(kāi)始。通常情況下,很少使用該偽指令。 6.4.3 簡(jiǎn)化段段名的引用 當(dāng)使用簡(jiǎn)化的段定義時(shí),一般情況下,程序員可以不知道這些段的段名、段地址堆齊類(lèi)型和組合類(lèi)型等。但當(dāng)把簡(jiǎn)化定義的段和標(biāo)準(zhǔn)定義的段混合使用時(shí),就需要知道簡(jiǎn)化定義段的基本屬性。表6.3是在小模式下段的基本屬性對(duì)應(yīng)表。 表6.3 小模式下簡(jiǎn)化段定義的缺省屬性表 偽指令 缺省段名 對(duì)齊類(lèi)型 組合類(lèi)型 類(lèi)別 段組名 .CODE _TEXT WORD PUBLIC CODE .FARDATA FAR_DATA PARA NONE FAR_DATA .FARDATA? FAR_BSS PARA NONE FAR_BSS .STACK STACK PARA STACK STACK DGROUP .DATA DATA WORD PUBLIC DATA DGROUP .DATA? BSS WORD PUBLIC BSS DGROUP .CONST CONST WORD PUBLIC CONST DGROUP 在其它存儲(chǔ)模型下,由偽指令".CODE"說(shuō)明的代碼段段名在"_TEXT"之前還要加上其模塊名(源程序名)。假設(shè),某模塊名為ABC,則其缺省的代碼段段名就為ABC_TEXT。因此,在這種情況下,程序的模塊名或源程序名不要以數(shù)字開(kāi)頭。 例6.15 簡(jiǎn)化段定義的方法 .MODEL SMALL .STACK 128 .DATA MSG DB "Simplified Segment Directives.$" .CODE MOV AX, @DATA ;取數(shù)據(jù)段的段值 MOV DS, AX ;把給段寄存器DS賦值 MOV DX, offset MSG MOV AH, 9H INT 21h MOV AX, 4C00H INT 21h END 另外,在匯編程序MASM中,還提供了二組簡(jiǎn)化的代碼偽指令:.STARTUP和.EXIT。 、.STARTUP——在代碼段的開(kāi)始,用于自動(dòng)初始化寄存器DS、SS和SP; 、.EXIT——用于結(jié)束程序的運(yùn)行,它等價(jià)于下列二條語(yǔ)句: MOV AH, 4CH INT 21h 當(dāng)使用匯編程序TASM時(shí),以上二條偽指令分別改為:STARTUPCODE和- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
9.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開(kāi)word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 匯編語(yǔ)言 程序 基本 結(jié)構(gòu)
鏈接地址:http://www.820124.com/p-6608854.html