![第3章匯編語(yǔ)言程序設(shè)計(jì)_第1頁(yè)](http://file4.renrendoc.com/view/b5584a482c100582751055865c32fefe/b5584a482c100582751055865c32fefe1.gif)
![第3章匯編語(yǔ)言程序設(shè)計(jì)_第2頁(yè)](http://file4.renrendoc.com/view/b5584a482c100582751055865c32fefe/b5584a482c100582751055865c32fefe2.gif)
![第3章匯編語(yǔ)言程序設(shè)計(jì)_第3頁(yè)](http://file4.renrendoc.com/view/b5584a482c100582751055865c32fefe/b5584a482c100582751055865c32fefe3.gif)
![第3章匯編語(yǔ)言程序設(shè)計(jì)_第4頁(yè)](http://file4.renrendoc.com/view/b5584a482c100582751055865c32fefe/b5584a482c100582751055865c32fefe4.gif)
![第3章匯編語(yǔ)言程序設(shè)計(jì)_第5頁(yè)](http://file4.renrendoc.com/view/b5584a482c100582751055865c32fefe/b5584a482c100582751055865c32fefe5.gif)
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第3章匯編語(yǔ)言程序設(shè)計(jì)3.1匯編語(yǔ)言程序格式3.2偽指令3.3匯編語(yǔ)言源程序結(jié)構(gòu)3.4匯編語(yǔ)言程序設(shè)計(jì)3.4程序設(shè)計(jì)舉例3.1匯編語(yǔ)言程序格式3.1.1程序結(jié)構(gòu)【例3-1】給出一個(gè)完整的匯編語(yǔ)言源程序,該程序的功能是完成兩個(gè)字節(jié)數(shù)據(jù)相加。DATA SEGMENT ;段定義開(kāi)始(DATA段)BUF1 DB 34H ;第1個(gè)加數(shù)BUF2 DB 2AH ;第2個(gè)加數(shù)SUM DB ? ;準(zhǔn)備用來(lái)存放和數(shù)的單元DATA ENDS ;段定義結(jié)束(DATA段)CODE SEGMENT ;段定義開(kāi)始(CODE段)ASSUME CS:CODE,DS:DATA ;規(guī)定DATA、CODE分別為數(shù)據(jù)段和代碼段START: MOV AX,DATAMOV DS, AX ;給數(shù)據(jù)段寄存器DS賦值MOV AL, BUF1 ;取第1個(gè)加數(shù)ADD AL, BUF2 ;和第2個(gè)加數(shù)相加MOV SUM,AL ;存放結(jié)果MOV AH,4CH INT 21H ;返回DOS狀態(tài)CODE ENDS ;段定義結(jié)束(CODE段)END START ;整個(gè)源程序結(jié)束從上面這個(gè)例子可以看出,匯編語(yǔ)言源程序由若干條語(yǔ)句組成,語(yǔ)句分為如下兩類(lèi)。1)指令語(yǔ)句指令語(yǔ)句是由8086/8088CPU提供的指令形成的語(yǔ)句,能完成一定的操作功能,能夠翻譯成機(jī)器代碼的語(yǔ)句。2)偽指令語(yǔ)句偽指令語(yǔ)句也叫指示性語(yǔ)句,它只是為匯編程序在翻譯匯編語(yǔ)言源程序時(shí)提供有關(guān)信息,并不翻譯成機(jī)器代碼。例如,程序中的語(yǔ)句:BUF1 DB 34HBUF2 DB 2AHSUM DB ?就是偽指令語(yǔ)句,其功能是在內(nèi)存中開(kāi)辟3個(gè)名字分別為BUF1、BUF2、SUM的字節(jié)單元,前兩個(gè)單元的初值分別為34H和2AH,SUM僅指定一個(gè)字節(jié)單元,不定義確定的初值。實(shí)際上,匯編語(yǔ)言源程序中還可出現(xiàn)宏指令語(yǔ)句。宏指令語(yǔ)句就是由若干條指令語(yǔ)句形成的語(yǔ)句體。一條宏指令語(yǔ)句的功能相當(dāng)于若干條指令語(yǔ)句的功能。3.1.2語(yǔ)句格式指令語(yǔ)句和偽指令語(yǔ)句的格式是類(lèi)似的,其格式如下:[名字]操作碼操作數(shù)[;注釋]其中,帶方括號(hào)的項(xiàng)可以省略,注釋內(nèi)容以分號(hào)(;)引導(dǎo)。
1.名字1)名字的標(biāo)識(shí)符名字也就是由用戶(hù)按一定規(guī)則定義的標(biāo)識(shí)符,可由下列符號(hào)組成:(1)英文字母(A~Z,a~z);(2)數(shù)字(0~9);(3)特殊符號(hào)(?、@、_等)。2)名字的定義規(guī)則名字的定義要滿(mǎn)足如下規(guī)則:(1)數(shù)字不能作為名字的第一個(gè)符號(hào);(2)單獨(dú)的問(wèn)號(hào)(?)不能作為名字;(3)一個(gè)名字的最大有效長(zhǎng)度為31位,超過(guò)31位的部分計(jì)算機(jī)不再識(shí)別;(4)匯編語(yǔ)言中有特定含義的保留字(如操作碼、寄存器名等),不能作為名字使用。為了便于記憶,名字的定義應(yīng)該做到見(jiàn)名知義,如用BUFFER表示緩沖區(qū)、SUM表示累加和等。3)名字的兩種主要形式名字有標(biāo)號(hào)和變量?jī)煞N主要形式。(1)標(biāo)號(hào)在代碼段中定義,后面跟著冒號(hào)“:”,它也可以用LABEL或EQU偽操作來(lái)定義。此外,它還可以作為子程序名定義,由于子程序由偽指令定義,故子程序名不需冒號(hào)說(shuō)明。標(biāo)號(hào)經(jīng)常在轉(zhuǎn)移指令或CALL指令的操作數(shù)字段出現(xiàn),用以表示轉(zhuǎn)向地址。標(biāo)號(hào)有三種屬性:段、偏移及類(lèi)型。段屬性:用于定義標(biāo)號(hào)的段起始地址。此值必須在一個(gè)段寄存器中,而標(biāo)號(hào)的段則總是在CS寄存器中。偏移屬性:標(biāo)號(hào)的偏移地址是從段起始地址到定義標(biāo)號(hào)的位置之間的字節(jié)數(shù)。對(duì)于16位段是16位無(wú)符號(hào)數(shù);對(duì)于32位段則是32位無(wú)符號(hào)數(shù)。類(lèi)型屬性:用來(lái)指出該標(biāo)號(hào)是在本段內(nèi)引用還是在其他段中引用的。如在段內(nèi)引用,則稱(chēng)為NEAR,對(duì)于16位段,指針長(zhǎng)度為2字節(jié);對(duì)于32位段,指針長(zhǎng)度為4字節(jié)。如在段外引用,則稱(chēng)為FAR,對(duì)于16位段,指針長(zhǎng)度為4字節(jié)(段地址2字節(jié),偏移地址2字節(jié));對(duì)于32位段,指針長(zhǎng)度為6字節(jié)(段地址2字節(jié),偏移地址4字節(jié))。(2)變量在數(shù)據(jù)段、附加數(shù)據(jù)段或堆棧段中定義,后面不跟冒號(hào)。它也可以用LABEL或EQU偽操作來(lái)定義。變量經(jīng)常在操作數(shù)字段出現(xiàn),它也有段、偏移及類(lèi)型三種屬性。段屬性:用于定義變量的段起始地址。此值必須在一個(gè)段寄存器中。偏移屬性:變量的偏移地址是從段的起始地址到定義變量的位置之間的字節(jié)數(shù)。對(duì)于16位段,是16位無(wú)符號(hào)數(shù);對(duì)于32位段,則是32位無(wú)符號(hào)數(shù)。在當(dāng)前段內(nèi)給出變量的偏移值等于當(dāng)前地址計(jì)數(shù)器的值,當(dāng)前地址計(jì)數(shù)器的值可以用$來(lái)表示。類(lèi)型屬性:變量的類(lèi)型屬性定義該變量所保留的字節(jié)數(shù)。如BYTE(DB,1個(gè)字節(jié)長(zhǎng))、WORD(DW,2個(gè)字節(jié)長(zhǎng))、DWORD(DD,4個(gè)字節(jié)長(zhǎng))、FWORD(DF,6個(gè)字節(jié)長(zhǎng))、QWORD(DQ,8個(gè)字節(jié)長(zhǎng))、TBYTE(DT,10個(gè)字節(jié)長(zhǎng))。在同一個(gè)程序中,同樣的標(biāo)號(hào)或變量的定義只允許出現(xiàn)一次,否則匯編程序會(huì)指示出錯(cuò)。2.操作碼操作碼用來(lái)指明操作的性質(zhì)或功能,指令中的助記符都是操作碼。操作碼與操作數(shù)之間用空格分開(kāi),如MOV、ADD等都是操作碼。
3.操作數(shù)指令中的操作數(shù)是用來(lái)指定參與操作的數(shù)據(jù)。對(duì)于一般指令,可以有一個(gè)或兩個(gè)操作數(shù),也可以沒(méi)有操作數(shù);對(duì)于偽指令和宏指令,可以有多個(gè)操作數(shù)。當(dāng)操作數(shù)多于一個(gè)時(shí),操作數(shù)之間用逗號(hào)分開(kāi)。操作數(shù)可以是常數(shù)和表達(dá)式。1)常數(shù)(1)數(shù)值常數(shù)。匯編語(yǔ)言中的數(shù)值常數(shù)可以是二進(jìn)制、八進(jìn)制、十進(jìn)制或十六進(jìn)制數(shù),書(shū)寫(xiě)時(shí)用加后綴(二進(jìn)制用B、八進(jìn)制用O或Q、十進(jìn)制用D、十六進(jìn)制用H)的方式標(biāo)明即可。對(duì)于十進(jìn)制數(shù)可以省掉后綴,對(duì)于十六進(jìn)制數(shù),當(dāng)以A~F開(kāi)頭時(shí),前面加數(shù)字0,以避免和名字混淆,如十六進(jìn)制數(shù)A6H應(yīng)該寫(xiě)成0A6H,否則容易和名字A6H相混。(2)字符串常數(shù)。包含在單引號(hào)中的若干個(gè)字符形成字符串常數(shù),字符串在計(jì)算機(jī)中存儲(chǔ)的是相應(yīng)字符的ASCII碼。如‘A’的值是41H,‘AB’的值是4142H等。(3)符號(hào)常數(shù)。常數(shù)用符號(hào)名來(lái)代替就是符號(hào)常數(shù)。如用COUNTEQU3或COUNT=3定義后,COUNT就是一個(gè)符號(hào)常數(shù),與數(shù)值常數(shù)3等價(jià)。2)表達(dá)式由運(yùn)算對(duì)象和運(yùn)算符組成的合法式子就是表達(dá)式,分為數(shù)值表達(dá)式和地址表達(dá)式兩種。數(shù)值表達(dá)式的運(yùn)算結(jié)果是一個(gè)數(shù),地址表達(dá)式的運(yùn)算結(jié)果是一個(gè)存儲(chǔ)單元的地址。(1)算術(shù)運(yùn)算符有+(加)、-(減)、*(乘)、/(除)、MOD(取余)。算術(shù)運(yùn)算符可以用于數(shù)值表達(dá)式和地址表達(dá)式中,用于地址表達(dá)式中要注意地址表達(dá)式的物理意義。同一段中的兩個(gè)地址相減(其值為兩個(gè)地址之間字節(jié)單元的個(gè)數(shù))、一個(gè)地址加上一個(gè)整數(shù)(其值為另一個(gè)單元的地址)、一個(gè)地址減去一個(gè)整數(shù)(其值為另一個(gè)單元的地址)是有意義的;兩個(gè)地址相加、兩個(gè)地址相乘或兩個(gè)地址相除是沒(méi)有意義的。下面的兩條指令是正確的。MOV AL,4*8+5 ;數(shù)值表達(dá)式MOV SI,OFFSET BUF+12 ;地址表達(dá)式(2)邏輯運(yùn)算符有AND(與)、OR(或)、XOR(異或)、NOT(非)。邏輯運(yùn)算符只能用于數(shù)值表達(dá)式中,不能用于地址表達(dá)式中。邏輯運(yùn)算符和邏輯運(yùn)算指令是有區(qū)別的。邏輯運(yùn)算符的功能在匯編階段完成,邏輯運(yùn)算指令的功能在程序執(zhí)行階段完成。在匯編階段,指令A(yù)NDAL,78HAND0FH等價(jià)于指令A(yù)NDAL,08H。(3)關(guān)系運(yùn)算符有EQ(相等)、LT(小于)、LE(小于等于)、GT(大于)、GE(大于等于)、NE(不等于)。關(guān)系運(yùn)算符要有兩個(gè)運(yùn)算對(duì)象,兩個(gè)運(yùn)算對(duì)象要么都是數(shù)值,要么都是同一個(gè)段內(nèi)的地址。運(yùn)算結(jié)果為真時(shí),表示為0FFFFH;運(yùn)算結(jié)果為假時(shí),表示為0000H。指令MOVBX,32EQ45等價(jià)于MOVBX,0;指令MOVBX,56GT30等價(jià)于MOVBX,0FFFFH。
3.注釋項(xiàng)注釋是語(yǔ)句的說(shuō)明部分,用來(lái)說(shuō)明一條指令或一段程序的功能,由分號(hào)(;)開(kāi)始。適當(dāng)?shù)丶有┳⑨寖?nèi)容,可以增加程序的可讀性,便于閱讀、理解和修改程序。匯編源程序時(shí),注釋部分不產(chǎn)生機(jī)器代碼。一條語(yǔ)句可以寫(xiě)成多行,續(xù)行符使用&。3.2偽指令匯編語(yǔ)言程序的語(yǔ)句除指令以外還可以由偽操作和宏指令組成。偽操作又稱(chēng)為偽指令,它們不像機(jī)器指令那樣是在程序運(yùn)行期間由計(jì)算機(jī)來(lái)執(zhí)行的,而是在匯編程序?qū)υ闯绦騾R編期間由匯編程序處理的,它們可以完成如處理器選擇、定義程序模式、定義數(shù)據(jù)、分配存儲(chǔ)區(qū)、指示程序結(jié)束等功能。偽指令形式上與一般指令相似,但偽指令只是為匯編程序提供有關(guān)信息,不產(chǎn)生相應(yīng)的機(jī)器代碼。3.2.1定義符號(hào)的偽指令1.等值偽指令EQU格式:<符號(hào)名>EQU<表達(dá)式>功能:給符號(hào)名定義一個(gè)值,賦予一個(gè)符號(hào)名、表達(dá)式或助記符。此后,程序中凡需要用到該表達(dá)式之處,就可以用表達(dá)式名來(lái)代替了。可見(jiàn),EQU的引入提高了程序的可讀性,也使其更加易于修改。上式中的表達(dá)式可以是任何有效的操作數(shù)格式,可以是任何可以求出常數(shù)值的表達(dá)式,也可以是任何有效的助記符。舉例如下:CONSTANT EQU 256;將數(shù)256賦以符號(hào)名CONSTANTDATA EQU HEIGHT+12;HEIGHT為一標(biāo)號(hào),地址表達(dá)式賦以符號(hào)名DATAALPHA EQU 7BETA EQU ALPHA-2;這是一組賦值偽操作,把7-2=5賦以符號(hào)名BETAADDR EQU VAR+BETA ;將VAR+5賦以符號(hào)名ADDRB EQU [BP+8] ;變址引用賦以符號(hào)名BP8 EQU DS:[BP+8] ;加段前綴的變址引用賦以符號(hào)名P8在EQU語(yǔ)句的表達(dá)式中,如果有變量或標(biāo)號(hào)的表達(dá)式,則在該語(yǔ)句前應(yīng)該先給出它們的定義。例如,語(yǔ)句 AB EQUDATA_ONE+2必須放在DATA_ONE的定義之后,否則匯編程序?qū)⒅甘境鲥e(cuò)。
2.等號(hào)偽指令“=”另外,還有一個(gè)與EQU相類(lèi)似的“=”偽操作也可以作為賦值操作使用。它們之間的區(qū)別是:EQU偽操作中的表達(dá)式名是不允許重復(fù)定義的,而“=”偽操作則允許重復(fù)定義。例如,EMP=6或EMPEQU6都可以使數(shù)6賦給符號(hào)名EMP,然而不允許兩者同時(shí)使用。但是,語(yǔ)句EMP=7EMP=EMP+1在程序中是允許使用的,因?yàn)椤?”偽操作允許重復(fù)定義。這種情況下,在第一個(gè)語(yǔ)句后的指令中,EMP的值為7;而在第二個(gè)語(yǔ)句后的指令中,EMP的值為8?!?/p>
3.解除定義偽指令PURGE格式:PURGE<符號(hào)1,符號(hào)2,…,符號(hào)N>功能:解除指定符號(hào)的定義。解除符號(hào)定義后,可用EQU重新進(jìn)行定義。如: Y1 EQU 7 ;定義Y1的值為7 PURGE Y1 ;解除Y1的定義 Y1 EQU 36 ;重新定義Y1的值為363.2.2定義數(shù)據(jù)的偽指令這一類(lèi)偽指令的格式是:[變量]助記符操作數(shù),…,操作數(shù)[;注釋?zhuān)莨δ埽簽椴僮鲾?shù)分配存儲(chǔ)單元,并用變量與存儲(chǔ)單元建立聯(lián)系。其中,變量是可有可無(wú)的,它用符號(hào)地址表示,其作用與指令語(yǔ)句前的標(biāo)號(hào)相同,但它的后面不跟冒號(hào)。如果語(yǔ)句中有變量名,則匯編程序使其記為第一個(gè)字節(jié)的偏移地址。注釋字段用來(lái)說(shuō)明該偽指令的功能,它也是可有可無(wú)的。助記符即偽指令用來(lái)說(shuō)明所定義的數(shù)據(jù)類(lèi)型。常用的偽指令有以下幾種:(1)DB用來(lái)定義字節(jié),其后的每個(gè)操作數(shù)都占有一個(gè)字節(jié)(8位)的存儲(chǔ)單元。(2)DW用來(lái)定義字,其后的每個(gè)操作數(shù)占有一個(gè)字(16位,其低位字節(jié)在第一個(gè)字節(jié)地址中,高位字節(jié)在第二個(gè)字節(jié)地址中)。(3)DD用來(lái)定義雙字(4個(gè)字節(jié)),其后的每個(gè)操作數(shù)占有兩個(gè)字(32位)。(4)DF用來(lái)定義3字(6個(gè)字節(jié)),其后的每個(gè)操作數(shù)占有48位,可用來(lái)存放遠(yuǎn)地址。這一偽指令只能用于386及其后繼機(jī)型中。(5)DQ用來(lái)定義4字(8個(gè)字節(jié)),其后的每個(gè)操作數(shù)占有4個(gè)字(64位),可用來(lái)存放雙精度浮點(diǎn)數(shù)。(6)DT用來(lái)定義5字(10個(gè)字節(jié)),其后的每個(gè)操作數(shù)占有5個(gè)字,形成壓縮的BCD碼形式。這些偽指令可以把其后跟著的數(shù)據(jù)存入指定的存儲(chǔ)單元,形成初始化數(shù)據(jù),或者只分配存儲(chǔ)空間而并不存入確定的數(shù)值,形成未初始化數(shù)據(jù)空間。DW和DD偽指令還可存儲(chǔ)地址,DF偽指令則可存儲(chǔ)由16位段地址及32位偏移地址組成的遠(yuǎn)地址指針。下面舉例說(shuō)明?!纠?-2】操作數(shù)可以是常數(shù),或者是表達(dá)式(根據(jù)該表達(dá)式可以求得一個(gè)常數(shù)),如:DATA_BYTE DB 10,4,10HDATA_WORD DW 100,100H,-5DATA_DW DD 3C,0FFFDH圖3.1例3-2的匯編結(jié)果【例3-3】操作數(shù)也可以是字符串,如: MESSAGE DB 'HELLO'存儲(chǔ)情況如圖3.2(a)所示,而DB'AB'和DW'AB'的存儲(chǔ)情況則分別如圖3.2(b)和(c)所示?!纠?-4】操作數(shù)“?”可以保留存儲(chǔ)空間,但不存入數(shù)據(jù)。如: ABC DB 0,?,?,0DEF DW ?,52,?經(jīng)匯編后的存儲(chǔ)情況如圖3.3所示。圖3.2例3-3的匯編結(jié)果(a)字符串的存儲(chǔ);(b)DB‘AB’;(c)DW‘AB’操作數(shù)還可以使用復(fù)制操作符(DUPLICATIONOPERATOR)來(lái)復(fù)制某個(gè)(或某些)操作數(shù)。其格式為REPEAT_COUNT DUP (OPERAND,…,OPERAND)其中,REPEAT_COUNT可以是一個(gè)表達(dá)式,它的值應(yīng)該是一個(gè)正整數(shù),用來(lái)指定括號(hào)中的操作數(shù)的重復(fù)次數(shù)?!纠?-5】使用DUP實(shí)現(xiàn)重復(fù)定義。ARRAY1 DB 2 DUP(0,1,2,?)ARRAY2 DB 100 DUP(?)經(jīng)匯編后的存儲(chǔ)情況如圖3.4所示。由圖可見(jiàn),例3-5中的第一個(gè)語(yǔ)句和語(yǔ)句ARRAY1DB0,1,2,?,0,1,2,?是等價(jià)的。圖3.3例3-4的匯編結(jié)果 圖3.4例3-5的匯編結(jié)果說(shuō)明:①這里操作數(shù)中的變量或標(biāo)號(hào)可以使用表達(dá)式,如:VARIABLE±CONSTANT EXPRESSIONLABEL±CONSTANT EXPRESSION在這種情況下,匯編后,存儲(chǔ)器中應(yīng)該存入表達(dá)式的值。②DB、DW、DD、DF、DQ和DT等偽指令在MASM6.0中可用BYTE、WORD、DWORD、FWORD、QWORD和TBYTE來(lái)取代,其含義是等同的。③變量的類(lèi)型屬性(TYPEATTRIBUTE)問(wèn)題:在數(shù)據(jù)定義偽指令前面的變量的值,是該偽指令中的第一個(gè)數(shù)據(jù)項(xiàng)在當(dāng)前段內(nèi)的第一個(gè)字節(jié)的偏移地址。此外,它還有一個(gè)類(lèi)型屬性,用來(lái)表示該語(yǔ)句中的每一個(gè)數(shù)據(jù)項(xiàng)的長(zhǎng)度(以字節(jié)為單位表示)。因此,DB偽指令的類(lèi)型屬性為1,DW為2,DD為4,DF為6,DQ為8,DT為10。變量表達(dá)式的屬性和變量的屬性是相同的,匯編程序可以用這種隱含的類(lèi)型屬性來(lái)確定某些指令是字指令還是字節(jié)指令。3.2.3定義程序開(kāi)始和結(jié)束的偽指令在程序的開(kāi)始部分可以用NAME或TITLE為模塊命名。NAME的格式是:NAME MODULE_NAME匯編程序?qū)⒁越o出的MODULE_NAME作為模塊的名字。如果程序中沒(méi)有使用NAME偽操作,則可使用TITLE偽操作,其格式為T(mén)ITLE TEXTTITLE偽操作可指定列表文件的每一頁(yè)上打印的標(biāo)題。同時(shí),如果程序中沒(méi)有使用NAME偽操作,則匯編程序?qū)⒂肨EXT中的前六個(gè)字符作為模塊名。TEXT中最多可有60個(gè)字符。如果程序中既無(wú)NAME又無(wú)TITLE偽操作,則將用源文件名作為模塊名。所以,NAME及TITLE偽操作并不是必要的,但一般經(jīng)常使用TITLE,以便在列表文件中能打印出標(biāo)題來(lái)。表示源程序結(jié)束的偽操作的格式為END [LABEL]其中,標(biāo)號(hào)(LABEL)指示程序開(kāi)始執(zhí)行的起始地址。如果多個(gè)程序模塊相連接,則只有主程序要使用標(biāo)號(hào),其他子程序模塊只用END而不必指定標(biāo)號(hào)。匯編程序?qū)⒃谟龅紼ND時(shí)結(jié)束匯編,而程序則將從主模塊的第一個(gè)標(biāo)號(hào)處開(kāi)始執(zhí)行。3.2.4指令集選擇偽指令由于80x86的所有處理器都支持8086/8088指令系統(tǒng),而且每一種高檔的機(jī)型又都增加了一些新的指令,因此,在編寫(xiě)程序時(shí)要對(duì)所用處理器有一個(gè)確切的選擇。也就是說(shuō),要告訴匯編程序應(yīng)該選擇哪一種指令系統(tǒng)。指令集選擇偽指令的功能就是確定作用指令系統(tǒng)。此類(lèi)偽指令主要有以下幾種:(1).8086:選擇8086指令系統(tǒng)。(2).286:選擇80286指令系統(tǒng)。(3).286P:選擇保護(hù)方式下的80286指令系統(tǒng)。(4).386:選擇80386指令系統(tǒng)。(5).386P:選擇保護(hù)方式下的80386指令系統(tǒng)。(6).486:選擇80486指令系統(tǒng)。(7).486P:選擇保護(hù)方式下的80486指令系統(tǒng)。(8).586:選擇Pentium指令系統(tǒng)。(9).586P:選擇保護(hù)方式下的Pentium指令系統(tǒng)。有關(guān)“選擇保護(hù)方式下的XXXX指令系統(tǒng)”的含義是指包括特權(quán)指令在內(nèi)的指令系統(tǒng)。此外,上述偽指令均支持相應(yīng)的協(xié)處理器指令。這類(lèi)偽指令一般放在整個(gè)程序的最前面,如不給出,則匯編程序默認(rèn)值為.8086指令系統(tǒng)。它們可放在程序中,如程序中使用了一條80486所增加的指令,則可以在該指令的上一行加上.486。3.2.5地址計(jì)數(shù)器與對(duì)準(zhǔn)偽操作1.地址計(jì)數(shù)器——$在匯編程序?qū)υ闯绦騾R編的過(guò)程中,使用地址計(jì)數(shù)器(LOCATIONCOUNTER)來(lái)保存當(dāng)前正在匯編的指令的偏移地址。當(dāng)開(kāi)始匯編或在每一段開(kāi)始時(shí),把地址計(jì)數(shù)器初始化為零,以后在匯編過(guò)程中,每處理一條指令,地址計(jì)數(shù)器就增加一個(gè)值,此值為該指令所需要的字節(jié)數(shù)。地址計(jì)數(shù)器的值可用$來(lái)表示,匯編語(yǔ)言允許用戶(hù)直接用$來(lái)引用地址計(jì)數(shù)器的值,因此指令JNE$+6的轉(zhuǎn)向地址是JNE指令的首地址加上6。當(dāng)$用在指令中時(shí),它表示本條指令的第一個(gè)字節(jié)的地址。在這里,$+6必須是另一條指令的首地址,否則,匯編程序?qū)⒅甘境鲥e(cuò)信息。當(dāng)$用在偽操作的參數(shù)字段時(shí),則和它用在指令中的情況不同,它所表示的是地址計(jì)數(shù)器的當(dāng)前值?!纠?-6】$用法示例。ARRAYDW 1,2,$+4,3,4,$+4如匯編時(shí)ARRAY分配的偏移地址為0074,則匯編后的存儲(chǔ)區(qū)將如圖3.4所示。注意:ARRAY數(shù)組中的兩個(gè)$+4得到的結(jié)果是不同的,這是由于$的值是在不斷變化的緣故。當(dāng)在指令中用到$時(shí),它只代表該指令的首地址,而與$本身所在的字節(jié)無(wú)關(guān)。圖3.4例3-6的匯編結(jié)果
2.ORG偽操作ORG偽操作用來(lái)設(shè)置當(dāng)前地址計(jì)數(shù)器的值,其格式為ORGCONSTANTEXPRESSION 如常數(shù)表達(dá)式的值為N,則ORG偽操作可以使下一個(gè)字節(jié)的地址成為常數(shù)表達(dá)式的值N。例如:VECTORSSEGMENT ORG 10VECT1 DW 47A5H ORG 20VECT2 DW 0C596HVECTORSENDS則VECT1的偏移地址值為0AH,而VECT2的偏移地址值為14H。常數(shù)表達(dá)式也可以表示從當(dāng)前已定義過(guò)的符號(hào)開(kāi)始的位移量,或表示從當(dāng)前地址計(jì)數(shù)器值$開(kāi)始的位移量,如: ORG $+8可以表示跳過(guò)8個(gè)字節(jié)的存儲(chǔ)區(qū),亦即建立了一個(gè)8字節(jié)的未初始化的數(shù)據(jù)緩沖區(qū)。如程序中需要訪問(wèn)該緩沖區(qū),則可用LABEL偽操作來(lái)定義該緩沖區(qū)的如下變量名BUFFER LABEL BYTE ORG $+8當(dāng)然,其完成的功能和 BUFFER DB 8 DUP(?)是一樣的。
3.EVEN偽操作EVEN偽操作使下一個(gè)變量或指令開(kāi)始于偶數(shù)字節(jié)地址。一個(gè)字的地址最好從偶地址開(kāi)始,所以對(duì)于字類(lèi)型數(shù)組,為保證其從偶地址開(kāi)始,可以在其前用EVEN偽操作來(lái)達(dá)到這一目的。例如:DATA_SEG SEGMENT EVEN ;保證地址從偶地址開(kāi)始WORD_ARRAYDW 100 DUP(?)DATA_SEG ENDS……
3.ALIGN偽操作ALIGN偽操作為保證雙字類(lèi)型數(shù)組邊界從4的倍數(shù)開(kāi)始創(chuàng)造了條件,其格式為ALIGN BOUNDARY其中,BOUNDARY必須是2的冪,例如:.DATAALIGN 4ARRAY DB 100 DUP(?)就可保證ARRAY的值為4的倍數(shù)。當(dāng)然,ALIGN2和EVEN是等價(jià)的?!?.3匯編語(yǔ)言源程序結(jié)構(gòu)1.完整段定義的程序結(jié)構(gòu)存儲(chǔ)器的物理地址是由段地址和偏移地址組合而成的,匯編程序在把源程序轉(zhuǎn)換為目標(biāo)程序時(shí),必須確定標(biāo)號(hào)和變量(代碼段和數(shù)據(jù)段的符號(hào)地址)的偏移地址,并且需要把有關(guān)信息通過(guò)目標(biāo)模塊傳送給連接程序,以便連接程序把不同的段和模塊連接在一起,形成一個(gè)可執(zhí)行程序。為此,需要用段定義偽操作,其格式如下:SEGMENT_NAME SEGMENTSEGMENT_NAME ENDS其中,刪節(jié)號(hào)部分對(duì)于數(shù)據(jù)段、附加段和堆棧段來(lái)說(shuō),一般是存儲(chǔ)單元的定義、分配等偽操作;對(duì)于代碼段則是指令及偽操作?!送?,還必須明確段和段寄存器的關(guān)系,這可用ASSUME偽操作來(lái)實(shí)現(xiàn),其格式為ASSUME<段寄存器名>:段名[,<段寄存器名>:段名,...]ASSUME<段寄存器名>:NOTHING其中,段寄存器名必須是CS、DS、ES和SS(對(duì)于386及其后繼機(jī)型還有FS和GS)中的一個(gè),而段名則必須是由SEGMENT定義的段中的段名。ASSUMENOTHING則可取消前面由ASSUME所指定的段寄存器。例如,下面是一個(gè)較為完整的匯編源程序段定義。DATE_SEG1SEGMENT ;定義數(shù)據(jù)段DATE_SEG1ENDSDATA_SEG2SEGMENT ;定義數(shù)據(jù)附加段
DATA_SEG2ENDSCODE_SEG SEGMENT ;定義代碼段 ASSUMECS:CODE_SEG,DS:DATA_SEG1,ES:DATA_SEG2START: ;開(kāi)始執(zhí)行的入口地址……;設(shè)置DS寄存器為當(dāng)前數(shù)據(jù)段 MOV AX,DATA_SEG1;將數(shù)據(jù)段地址賦予DS MOV DS,AX ;設(shè)置ES寄存器為當(dāng)前附加段 MOV AX,DATA_SEG2;將附加數(shù)據(jù)段地址賦予ES MOV ES,AX CODE_SEG ENDS ;代碼段定義結(jié)束 END START ;源程序結(jié)束…由于ASSUME偽操作只是指定某個(gè)段分配給哪一個(gè)段寄存器,它并不能把段地址裝入段寄存器中,要把段地址裝入段寄存器中,就必須在代碼段中有對(duì)段地址裝入相應(yīng)的段寄存器中的指令。如在上面的程序中,分別用兩條MOV指令完成這一操作。如果程序中有堆棧段,也需要把段地址裝入SS中。但是,代碼段CS不需要這樣做,這一操作是在程序初始化時(shí)完成的。為了對(duì)段定義作進(jìn)一步地控制,SEGMENT偽操作添加有類(lèi)型及屬性的說(shuō)明,其格式如下:<段名>SEGMENT[定位類(lèi)型][組合類(lèi)型][使用類(lèi)型][類(lèi)別]
<段名>ENDS在一般情況下,這些說(shuō)明可以不用。但是,如果需要用連接程序把本程序與其他程序模塊相連接時(shí),就需要使用這些說(shuō)明。…
2.定位類(lèi)型(ALIGN_TYPE)定位類(lèi)型用于說(shuō)明段的起始地址應(yīng)有怎樣的邊界值,其取值可以是:PARA:指定段的起始地址必須從小段邊界開(kāi)始,即段起始地址最低位必須為0。這樣,偏移地址可以從0開(kāi)始。BYTE:該段可以從任何地址開(kāi)始,這樣,起始偏移地址可能不是0。WORD:該段必須從字的邊界開(kāi)始,即段起始地址必須為偶數(shù)。DWORD:該段必須從雙字邊界開(kāi)始,即段起始地址的最低位必須為4的倍數(shù)。PAGE:該段必須從負(fù)的邊界開(kāi)始,即段起始地址的最低兩個(gè)十六進(jìn)制數(shù)位必須為0(該地址能被256整除)。定位類(lèi)型的默認(rèn)項(xiàng)是PARA,即若未指定定位類(lèi)型時(shí),則匯編程序默認(rèn)為PARA。
3.組合類(lèi)型(COMBINE_TYPE)組合類(lèi)型用于說(shuō)明程序連接時(shí)段的合并方法,其取值可以是:PRIVATE :該段為私有段,在連接時(shí)將不與其他模塊中的同名段合并。PUBLIC:該段連接時(shí)可以把不同模塊中的同名段相連接而合并為一個(gè)段,其連接次序由連接命令指定。每一分段都從小段的邊界開(kāi)始,因此,各模塊的原有段之間可能存在小于16個(gè)字節(jié)的間隙。COMMON:該段在連接時(shí)可以把不同模塊中的同名段重疊而形成一個(gè)段,由于各同名段有相同的起始地址,所以會(huì)產(chǎn)生覆蓋。COMMON的連接長(zhǎng)度是各分段中的最大長(zhǎng)度。重疊部分的內(nèi)容取決于排列在最后一段的內(nèi)容。ATEXPRESSTION:使段地址為表達(dá)式所計(jì)算出來(lái)的16位值,但它不能用來(lái)指定代碼段。MEMORY:與PUBLIC同義。STACK:把不同模塊中的同名段組合而形成一個(gè)堆棧段,該段的長(zhǎng)度為原有各堆棧段長(zhǎng)度的總和,原有各段之間并無(wú)PUBLIC所連接段中的間隙,而且棧頂可自動(dòng)指向連接后形成的大堆棧段的棧頂。組合類(lèi)型的默認(rèn)項(xiàng)是PRIVATE。
3.使用類(lèi)型(USE_TYPE)使用類(lèi)型只適用于386及其后繼機(jī)型,它用來(lái)說(shuō)明是使用16位尋址方式還是使用32位尋址方式。其取值可以是:USE16:使用16位尋址方式。USE32:使用32位尋址方式。當(dāng)使用16位尋址方式時(shí),段長(zhǎng)不超過(guò)64KB,地址的形式是16位段地址和16位偏移地址組合;當(dāng)使用32位尋址方式時(shí),段長(zhǎng)可達(dá)4GB,地址的形式是16位段地址和32位偏移地址組合??梢钥闯觯趯?shí)模式下,應(yīng)該使用USE16。使用類(lèi)型的默認(rèn)項(xiàng)是USE16。
5.類(lèi)別名(‘CLASS’)在引號(hào)中給出連接時(shí)組成段組的類(lèi)型名。類(lèi)別說(shuō)明并不能把相同類(lèi)別的段合并起來(lái),但在連接后形成的裝入模塊中,可以把它們的位置靠在一起。3.4匯編語(yǔ)言程序設(shè)計(jì)3.4.1流程圖的組成借助于流程圖可以清晰地把程序思路表達(dá)出來(lái),有助于編寫(xiě)正確的程序。流程圖對(duì)程序設(shè)計(jì)人員,特別是初學(xué)者來(lái)說(shuō)是一種非常有用的工具。流程圖是用一些圖框表示各種操作,用圖形表示算法,直觀形象,易于理解。美國(guó)國(guó)家標(biāo)準(zhǔn)化協(xié)會(huì)ANSI(AmericanNationalStandardInstitute)規(guī)定了一些常用的流程圖,已為世界各國(guó)程序工作者普遍采用。圖3.7流程圖的組成成分1)執(zhí)行框(矩形框)執(zhí)行框的作用是表示一段程序或一個(gè)模塊的功能,對(duì)于結(jié)構(gòu)化程序,一個(gè)執(zhí)行框只有一個(gè)入口和一個(gè)出口。2)判別框(菱形框)判別框的作用是對(duì)一個(gè)給定的條件進(jìn)行判斷,根據(jù)給定的條件是否成立來(lái)決定如何執(zhí)行其后的操作。它有一個(gè)入口,兩個(gè)出口,表示比較、判斷條件。3)開(kāi)始框和終止框開(kāi)始框和終止框表示程序的起始和終止。4)指向線指向線表示程序執(zhí)行的順序。5)連接點(diǎn)連接點(diǎn)是用于將畫(huà)在不同地方的流程線連接起來(lái)。如圖3.8中,有兩個(gè)以①為標(biāo)志的連接點(diǎn),它表示這兩個(gè)點(diǎn)是互相連接在一起的。實(shí)際上它們是同一個(gè)點(diǎn),只是當(dāng)在紙張上畫(huà)不下才分開(kāi)來(lái)畫(huà)。使用連接點(diǎn)可以避免流程線的交叉或過(guò)長(zhǎng),使流程圖清晰。圖3.8流程圖的繪制示意可以看出,流程圖是表示算法的較好工具。一個(gè)流程圖包括以下幾部分:(1)表示相應(yīng)操作的框;(2)帶箭頭的流程線;(3)框內(nèi)外必要的文字說(shuō)明。繪制流程線不要忘記畫(huà)箭頭,因?yàn)樗欠从沉鞒痰膱?zhí)行先后次序的,如不畫(huà)出箭頭就難以判定各框的執(zhí)行次序了。用流程圖表示算法直觀形象,比較清楚地顯示出各個(gè)框之間的邏輯關(guān)系。常用的還有N-S結(jié)構(gòu)化流程圖。程序編制人員都應(yīng)當(dāng)掌握傳統(tǒng)流程圖,會(huì)看會(huì)畫(huà)。3.4.2BIOS中斷調(diào)用1.BIOS中斷調(diào)用概述BIOS(BasicInput/OutputSystem)是IBM-PC機(jī)的監(jiān)控程序,它固化在微型機(jī)主板的ROM中,它的內(nèi)容主要有系統(tǒng)測(cè)試程序(POST)、初始化引導(dǎo)程序(BOOT)、I/O設(shè)備的基本驅(qū)動(dòng)程序和許多常用程序模塊,它們一般以中斷服務(wù)程序的形式存在。例如,負(fù)責(zé)顯示輸出的顯示I/O程序?yàn)?0H號(hào)中斷服務(wù)程序;負(fù)責(zé)打印輸出的打印I/O程序?yàn)?7H號(hào)中斷服務(wù)程序等。圖3.9是用戶(hù)程序和操作系統(tǒng)關(guān)系示意圖,由圖可見(jiàn),BIOS程序直接建立在硬件基礎(chǔ)上,磁盤(pán)操作系統(tǒng)(DOS)和其他操作系統(tǒng)建立在BIOS基礎(chǔ)上,各種高級(jí)語(yǔ)言則建立在操作系統(tǒng)基礎(chǔ)上。用戶(hù)程序可以使用高級(jí)語(yǔ)言,也可以調(diào)用DOS或其他操作系統(tǒng),還可以調(diào)用BIOS,甚至直接指揮硬件設(shè)備。圖3.9用戶(hù)程序和操作系統(tǒng)關(guān)系示意圖通常,應(yīng)用程序調(diào)用DOS提供的系統(tǒng)功能,完成輸入/輸出或其他操作,這樣做用戶(hù)可以少考慮硬件,實(shí)現(xiàn)起來(lái)容易。應(yīng)用程序直接對(duì)硬件編程的優(yōu)點(diǎn)是程序的效率高,缺點(diǎn)是需要程序員對(duì)硬件性能有較深的了解,編程復(fù)雜,所以一般不直接對(duì)硬件編程。BIOS中斷程序處于DOS功能調(diào)用和硬件環(huán)境之間,和DOS功能調(diào)用相比,其優(yōu)點(diǎn)是效率高,缺點(diǎn)是編程相對(duì)復(fù)雜;和直接對(duì)硬件編程相比,優(yōu)點(diǎn)是實(shí)現(xiàn)相對(duì)容易,缺點(diǎn)是效率相對(duì)低。在下列情況下可考慮使用BIOS中斷。(1)有些功能DOS沒(méi)有提供,但BIOS提供了;(2)有些場(chǎng)合無(wú)法使用DOS功能調(diào)用;(3)其他原因。
2.BIOS中斷調(diào)用方法BIOS的調(diào)用就是人們借用每一臺(tái)計(jì)算機(jī)中BIOS固有的I/O操作程序來(lái)方便地解決自己的問(wèn)題,由于它已經(jīng)在計(jì)算機(jī)中了,因此人們不必再把它寫(xiě)入自己的程序,只要指明它的操作位置就可以了。1)BIOS調(diào)用的基本操作由于BIOS中的每一種功能調(diào)用往往包含不同的幾個(gè)操作細(xì)節(jié),所以調(diào)用時(shí)需要說(shuō)明三部分,基本步驟為:(1)設(shè)置分功能號(hào):按實(shí)現(xiàn)的操作功能的要求,給指定寄存器(通常為AH)送入分功能號(hào)。(2)置入口參數(shù):按操作要求,給寄存器填寫(xiě)相應(yīng)參數(shù)的內(nèi)容(某些調(diào)用無(wú)參數(shù))。(3)使用中斷語(yǔ)句INTn:執(zhí)行調(diào)用的功能,其中n為中斷號(hào)。(4)分析出口參數(shù)。具體步驟為例如 MOV AH,0 ;分功能號(hào)為0 MOV AL,10H ;置入口參數(shù) INT 1AH ;1AH為中斷號(hào),功能為讀時(shí)間計(jì)數(shù)器的值注意:某些BIOS調(diào)用可能沒(méi)有出口參數(shù),這時(shí)省略第(4)步操作。2)BIOS打印功能BIOSI7H號(hào)中斷指令提供了由AH寄存器指定的三種不同的操作。(1)BIOS中斷17H號(hào)的功能0是打印一個(gè)字符。要打印輸出的字符放在AL中,打印機(jī)號(hào)放在DX中,BIOS最多允許連接三臺(tái)打印機(jī),機(jī)號(hào)分別為0,1和2。如果只有一臺(tái)打印機(jī),那么就是0號(hào)打印機(jī),打印機(jī)的狀態(tài)信息被回送到AH寄存器。MOV AH,0 ;請(qǐng)求打印MOV AL,CHAR ;寫(xiě)入打印字符MOV DX,0 ;設(shè)置0#打印口INT 17H ;調(diào)用BIOS(2)17H號(hào)的功能1是初始化打印機(jī)并回送打印機(jī)狀態(tài)到AH寄存器。如果把打印機(jī)開(kāi)關(guān)關(guān)上然后又打開(kāi),打印機(jī)各部分就復(fù)位到初始值。此功能和打開(kāi)打印機(jī)時(shí)的作用一樣。在每個(gè)程序的初始化部分可以用17H號(hào)的功能1來(lái)初始化打印機(jī)。MOV AH,01 ;初始化打印機(jī)MOV DX,0 ;設(shè)置0#打印口INT 17H ;調(diào)用BIOS這個(gè)操作要發(fā)送一個(gè)換頁(yè)符,因此,這個(gè)操作能把打印機(jī)頭設(shè)置在一頁(yè)的頂部。對(duì)于大多數(shù)打印機(jī),只要一接通電源,就會(huì)自動(dòng)地初始化打印機(jī)。(3)BIOS17H號(hào)的功能2是把狀態(tài)字節(jié)讀入AH寄存器中。打印機(jī)的狀態(tài)字節(jié)如圖3.10所示。打印機(jī)忙表示打印機(jī)正在接收數(shù)據(jù)、正在打印或處于脫機(jī)狀態(tài)。應(yīng)答位表示打印機(jī)已發(fā)出一個(gè)表明它已經(jīng)接收到數(shù)據(jù)的信號(hào)。選擇位表示打印機(jī)是聯(lián)機(jī)的。超時(shí)位表示打印機(jī)發(fā)出忙信號(hào)很長(zhǎng)一段時(shí)間了,系統(tǒng)將不再給它傳送數(shù)據(jù)。表示打印出錯(cuò)的是第5位(紙出界)或第3位(I/O錯(cuò))為1。如果打印機(jī)沒(méi)有接上電源,沒(méi)有裝上紙或沒(méi)有聯(lián)機(jī),而打印程序已開(kāi)始運(yùn)行,這時(shí)顯示器的指示光標(biāo)會(huì)不停地閃爍,當(dāng)接通打印機(jī)的電源后,某些輸出數(shù)據(jù)就會(huì)丟失。圖3.10打印機(jī)的狀態(tài)字節(jié)如果在打印程序中先安排指令測(cè)試打印機(jī)的狀態(tài),則BIOS操作就會(huì)送回狀態(tài)碼,DOS打印操作是自動(dòng)進(jìn)行測(cè)試的,但對(duì)各種情況都顯示一個(gè)“紙出界”的信息。當(dāng)打印機(jī)接通電源后,即開(kāi)始正常打印,而且不丟失任何數(shù)據(jù)。3)BIOS串行通信口功能IBM-PC及其兼容機(jī)提供了一種有較強(qiáng)的硬件依賴(lài)性,但卻比較靈活的串行口I/O的方法,即通過(guò)INT14H調(diào)用ROMBIOS串行通信口中斷服務(wù)程序。該中斷服務(wù)程序包括將串行口初始化為指定的字節(jié)結(jié)構(gòu)和傳輸速率,檢查控制器的狀態(tài),讀/寫(xiě)字符等功能。具體功能設(shè)置如表3-1所示。表3-1串行通信口BIOS功能(INT14H)AH功能調(diào)用參數(shù)返回參數(shù)0初始化串行通信口AL=初始化參數(shù)DX=通信口號(hào):COM1=0COM2=1,etcAH=通信口狀態(tài)(AL)=調(diào)制解調(diào)器狀態(tài)
1向串行通信口寫(xiě)字符AL=所寫(xiě)字符DX=通信口號(hào):COM1=0COM2=1,etc寫(xiě)字符成功:(AH)=0,(AL)=字符寫(xiě)字符失?。?AH)7=1,(AH)0~6=通信口狀態(tài)2從串行通信口讀字符DX=通信口號(hào):COM1=0COM2=1,etc
讀成功:(AH)7,=0(AL)=字符讀失?。?AH)7=1,(AH)0~6=通信口狀態(tài)3取通信口狀態(tài)DX=通信口號(hào):COM1=0COM2=1(AH)=通信狀態(tài)AL=調(diào)制解調(diào)器狀態(tài)圖3.11串行通信口初始化參數(shù)【例3-8】要求0號(hào)通信口的傳輸率為2400波特,字長(zhǎng)為8位,終止位為1位,無(wú)奇偶校驗(yàn)。MOVAH,0 ;串行通信口初始化MOVAL,0A3H ;0A3H=10100011BMOVDX,0 ;指向COM1INT14H ;調(diào)用BIOS返回參數(shù)中通信口狀態(tài)字節(jié)各位置1的含義如圖3.12所示。圖3.12串行通信口狀態(tài)字節(jié)在接收和發(fā)送過(guò)程,錯(cuò)誤狀態(tài)位(1,2,3,4位)一旦被置為1,則讀入的接收數(shù)據(jù)已不是有效數(shù)據(jù),所以在串行通信應(yīng)用程序中,應(yīng)檢測(cè)數(shù)據(jù)傳輸是否出錯(cuò)。奇偶錯(cuò):通信線上(尤其是用電話線傳輸時(shí))的噪音引起某些數(shù)據(jù)位的改變,產(chǎn)生奇偶錯(cuò)。通常檢測(cè)出奇偶錯(cuò)時(shí),要求正在接收的數(shù)據(jù)至少應(yīng)重新發(fā)送一段。超越錯(cuò):在上一個(gè)字符還未被處理機(jī)取走,又有字符要傳送到數(shù)據(jù)寄存器里時(shí),就會(huì)引起超越錯(cuò)。如果處理機(jī)處理字符的速度小于單行通信口的波特率,則會(huì)產(chǎn)生這種錯(cuò)誤。幀格式錯(cuò):當(dāng)接收/發(fā)送器未接收到一個(gè)字符數(shù)據(jù)的停止位,則會(huì)引起幀格式錯(cuò)。這種錯(cuò)誤可能是由于通信線上的噪音引起停止位的丟失,或者是由于接收方和發(fā)送方初始化不匹配而造成的。間斷:間斷有時(shí)候并不能算是一個(gè)錯(cuò)誤,而是為某些特殊的通信環(huán)境設(shè)置的“空格”狀態(tài)。當(dāng)間斷位為1時(shí),說(shuō)明接收的“空格”狀態(tài)超過(guò)了一個(gè)完整的數(shù)據(jù)字傳輸時(shí)間。PS/2以及所有的PC機(jī),AH=04功能允許程序員將波特率設(shè)置為19200,數(shù)據(jù)位的長(zhǎng)度可以設(shè)置為5、6、7或8位,而不是像AH=0功能那樣只能設(shè)置成7或8位。3.4.3DOS功能調(diào)用1.DOS功能調(diào)用概述8086/8088指令系統(tǒng)中,有一種軟中斷指令I(lǐng)NTn。每執(zhí)行一條軟中斷指令,就調(diào)用一個(gè)相應(yīng)的中斷服務(wù)程序。當(dāng)n=5~1FH時(shí),調(diào)用BIOS中的服務(wù)程序,一般稱(chēng)作系統(tǒng)中斷調(diào)用;當(dāng)n=20~3FH時(shí),調(diào)用DOS中的服務(wù)程序,稱(chēng)作功能調(diào)用。其中,INT21H是一個(gè)具有調(diào)用多種功能的服務(wù)程序的軟中斷指令,故稱(chēng)其為DOS系統(tǒng)功能調(diào)用。
2.DOS功能調(diào)用方法1)DOS軟中斷(INT20H~I(xiàn)NT27H)指令DOS軟中斷功能、入口及出口參數(shù)見(jiàn)表3-2。表中的入口參數(shù)是指在執(zhí)行軟中斷指令前有關(guān)寄存器必須設(shè)置的值,出口參數(shù)記錄的是執(zhí)行軟中斷以后的結(jié)果及特征,供用戶(hù)分析使用。DOS中斷的使用方法是:首先按照DOS中斷的規(guī)定,輸入入口參數(shù),然后執(zhí)行INT指令,最后分析出口參數(shù),如下所示:設(shè)置入口參數(shù)執(zhí)行INTn分析出口參數(shù)表3-2中INT22H、INT23H和INT24H用戶(hù)不能直接調(diào)用。例如,INT23H是只有當(dāng)同時(shí)按下CTRL和BREAK鍵時(shí)才形成DOS的23H號(hào)調(diào)用,其功能是:終止正在運(yùn)行的程序,返回操作系統(tǒng)。INT25H為絕對(duì)讀盤(pán),INT26H為絕對(duì)寫(xiě)盤(pán),這兩條軟中斷的調(diào)用需要用戶(hù)熟知磁盤(pán)結(jié)構(gòu),準(zhǔn)確指出讀/寫(xiě)的扇區(qū)號(hào)、扇區(qū)數(shù)、磁盤(pán)驅(qū)動(dòng)器號(hào),還需要知道與磁盤(pán)交換信息的內(nèi)存緩沖區(qū)的首地址。因此,這種讀/寫(xiě)磁盤(pán)的方式較落后,除特殊用途外,基本上已不采用。常用的磁盤(pán)讀/寫(xiě)的方法請(qǐng)參閱《DOS系統(tǒng)功能調(diào)用》一書(shū)的介紹。INT20H是兩字節(jié)指令,它的作用是終止正在運(yùn)行的程序,返回操作系統(tǒng)。這種終止程序的方法只適用于.COM文件,而不適用于.EXE文件。INT27H指令的作用是終止正在運(yùn)行的程序,返回操作系統(tǒng),被終止的程序駐留在內(nèi)存中作為DOS的一部分,它不會(huì)被其他程序覆蓋。在其他用戶(hù)程序中,可以利用軟中斷來(lái)調(diào)用這個(gè)駐留的程序。表3-2DOS軟中斷軟中斷功能入口參數(shù)出口參數(shù)INT20H程序正常退出
INT21H系統(tǒng)功能調(diào)用AH=功能號(hào)功能調(diào)用相應(yīng)的入口參數(shù)功能調(diào)用相應(yīng)的出口參數(shù)INT22H結(jié)束退出
INT23HCTRL+BREAK退出
INT24H出錯(cuò)退出
INT25H讀盤(pán)CX=讀出扇區(qū)數(shù)DX=起始邏輯扇區(qū)DS:BX=緩沖區(qū)地址AL=盤(pán)號(hào)CF=1出錯(cuò)INT26H寫(xiě)盤(pán)CX=寫(xiě)扇區(qū)數(shù)DX=起始邏輯扇區(qū)DS:BX=緩沖區(qū)地址AL=盤(pán)號(hào)CF=1出錯(cuò)INT27H駐留退出
INT28H~I(xiàn)NT2FHDOS專(zhuān)用
2)DOS系統(tǒng)功能調(diào)用(INT21H)系統(tǒng)功能調(diào)用INT21H是一個(gè)有近90個(gè)子功能的中斷服務(wù)程序,這些子功能的編號(hào)稱(chēng)為功能號(hào)。INT21H的功能大致可以分為四個(gè)方面:設(shè)備管理、目錄管理、文件管理和其他。設(shè)備管理主要包括鍵盤(pán)輸入、顯示器輸出、打印機(jī)輸出、串行設(shè)備輸入/輸出、初始化磁盤(pán)、選擇當(dāng)前磁盤(pán)、取剩余磁盤(pán)空間等。目錄管理主要包括查找目錄項(xiàng)、查找文件、置/取文件屬性、文件改名等。文件管理主要包括打開(kāi)、關(guān)閉、讀/寫(xiě)、刪除文件等,這是DOS提供給用戶(hù)的最重要的系統(tǒng)功能調(diào)用。文件管理有兩種方法:一種是傳統(tǒng)管理方法(功能號(hào)小于24H),與8位機(jī)的CP/M操作系統(tǒng)兼容;另一種是擴(kuò)充的文件管理方法(功能號(hào)大于3CH),這是MS-DOS獨(dú)有的。其他功能有終止程序、置/取中斷矢量、分配內(nèi)存、置/取日期及時(shí)間等。系統(tǒng)功能調(diào)用(INT21H)的使用方法如下:設(shè)置功能號(hào)n(AH)設(shè)置入口參數(shù)執(zhí)行INT21H分析出口參數(shù)(1)鍵盤(pán)輸入。IBM-PC及PC/XT鍵盤(pán)上的按鍵分為三種類(lèi)型:第一類(lèi)是字符鍵,如字母、數(shù)字、字符等。按下此類(lèi)鍵,即可輸入此鍵相應(yīng)的編碼。第二類(lèi)是功能鍵,如BackSpace、Home、End、Del、PageUp、PageDown、F1~F10等。按下此類(lèi)鍵,可以產(chǎn)生一個(gè)動(dòng)作。例如,按下BackSpace可以使光標(biāo)向左移動(dòng)一個(gè)位置。第三類(lèi)是組合鍵及雙態(tài)鍵,如Shift、Alt、Ctrl、Ins、NumLock、CapsLock、ScrollLock等。使用這些鍵能改變其他鍵所產(chǎn)生的字符碼。①掃描碼與字符碼。鍵的掃描碼——鍵盤(pán)的每一個(gè)鍵都有一對(duì)掃描碼,掃描碼用一個(gè)字節(jié)表示。低7位是掃描碼的數(shù)字編碼01~83,即01H~53H,最高位BIT7表示鍵的狀態(tài)。當(dāng)某鍵按下時(shí),掃描碼的BIT7=0,稱(chēng)為通碼,當(dāng)此鍵放開(kāi)時(shí),掃描碼的BIT7=1,稱(chēng)為斷碼。通碼和斷碼的值相差80H。鍵的字符碼——鍵的字符碼是鍵的ASCII碼或擴(kuò)充碼,見(jiàn)第1章的ASCII碼表。②有關(guān)鍵盤(pán)的系統(tǒng)功能調(diào)用。DOS系統(tǒng)功能調(diào)用中的功能1、7、8、A、B、C等都與鍵盤(pán)有關(guān),包括單字符輸入、字符串輸入和鍵盤(pán)狀態(tài)檢驗(yàn)等。檢查鍵盤(pán)狀態(tài)——DOS系統(tǒng)功能調(diào)用的0BH號(hào)功能可以檢查是否有字符鍵入。如果有鍵按下,使AL=FFH,否則AL=00H。這個(gè)調(diào)用十分有用,例如,有時(shí)要求程序保持運(yùn)行狀態(tài),而不是無(wú)限期等待鍵盤(pán)輸入,但又要靠用戶(hù)接任意一鍵使程序結(jié)束或退出循環(huán)時(shí),就必須使用0BH號(hào)調(diào)用。如,LOOP: MOV AH,0BH INT 21H ;檢查鍵盤(pán)狀態(tài) INC AL JNZ LOOP ;無(wú)鍵入字符,則循環(huán) RET ;有鍵入字符,則停止循環(huán)返回單字符輸入——功能1、7、8都可以直接接收鍵入的字符。程序中常常利用這些功能,回答程序中的提示信息,或選擇菜單中的可選項(xiàng)以執(zhí)行不同的程序段。用戶(hù)還可以利用功能7、8不回顯的特性,鍵入需要保密的信息。【例3-9】從鍵盤(pán)接收單個(gè)字符并判斷轉(zhuǎn)移。MAIN: KEY: MOV AH,1 ;等待鍵入字符,當(dāng)按下鍵后 INT 21H ;AL=鍵入的字符 CMP AL,'Y' JE YES ;鍵入字符"Y",轉(zhuǎn)至YES語(yǔ)句處 CMP AL,'N' JE NOT ;鍵入字符“N”,轉(zhuǎn)至NOT語(yǔ)句處 JMP KEY ;鍵入其他字符,轉(zhuǎn)至KEY語(yǔ)句處,繼續(xù)等待鍵入字符YES:
NOT: ………鍵入字符串——用戶(hù)程序經(jīng)常需要從鍵盤(pán)上接收一串字符。0AH號(hào)功能可以接收鍵入的字符串將其存入內(nèi)存中用戶(hù)定義的緩沖區(qū)。緩沖區(qū)結(jié)構(gòu)如圖3.13所示。緩沖區(qū)第一字節(jié)為用戶(hù)定義的最大鍵入字符數(shù),若用戶(hù)鍵入的字符數(shù)(包括回車(chē)符)大于此數(shù),則機(jī)器鈴響且光標(biāo)不再右移,直到鍵入回車(chē)符為止。緩沖區(qū)第二字節(jié)為實(shí)際鍵入的字符數(shù)(不包括回車(chē)符),由DOS自動(dòng)填入。從第三字節(jié)開(kāi)始存放鍵入的字符,顯然,緩沖區(qū)的大小等于最大字符數(shù)加2。如例3-10所示。圖3.13用戶(hù)定義的緩沖區(qū)(2)顯示器(CRT)輸出。功能2、6、9是關(guān)于CRT的系統(tǒng)功能調(diào)用。其中,顯示單個(gè)字符的功能2、6與BIOS調(diào)用類(lèi)似,此處不作介紹。顯示字符串的功能9是DOS調(diào)用獨(dú)有的,可以在用戶(hù)程序運(yùn)行過(guò)程之中,在CRT上向用戶(hù)提示下一步操作的內(nèi)容。使用功能調(diào)用9需要注意兩點(diǎn):第一,被顯示的字符串必須以“$”為結(jié)束符;第二,當(dāng)顯示由功能0AH鍵入的字符串時(shí),DS:DX應(yīng)指向用戶(hù)定義的緩沖區(qū)的第三字節(jié),即鍵入的第一個(gè)字符的存儲(chǔ)單元。例如,編寫(xiě)下面一段程序,并鍵入字符串‘HELLO’,則緩沖區(qū)的內(nèi)容如圖3.13所示?!纠?-10】從鍵盤(pán)接收字符串并輸出到顯示器。DATA SEGMENTBUFSIZE DB25ACTCHAR DB?CHARTEXT DB50DUP(20H) DB'$'DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART: MOVAX,DS MOVDS,AX MOVDX,OFFSETBUFSIZE MOVAH,0AH INT21H ;鍵入字符串,放入緩沖區(qū) MOVDX,OFFSETCHARTEXT MOVAH,09H INT21H ;顯示鍵入的字符串 HLTCODE ENDS END START(3)打印機(jī)輸出。關(guān)于打印機(jī)操作的系統(tǒng)功能調(diào)用只有一種,即打印一個(gè)字符的功能5。利用此功能還可以改變打印機(jī)的打印方式。下面一段程序?qū)PSON-80打印機(jī)設(shè)置為“加重打印”方式?!纠?-11】打印機(jī)設(shè)置為“加重打印”方式。DATA SEGMENTSTR DB 1BH,45H ;“加重打印”的控制碼
CODE SEGMENT…… MOV CX,2 MOV AH,5 LEA BX,STRPRINT: MOV DL,[BX] INT 21H INC BX LOOP PRINT…這段程序既可以放在用戶(hù)程序中,也可以作為一個(gè)獨(dú)立的文件,經(jīng)匯編、連接后單獨(dú)運(yùn)行。若要取消加重打印方式,或設(shè)置其他方式,只需與之類(lèi)似的程序段即可。相應(yīng)的控制碼請(qǐng)查閱打印機(jī)手冊(cè)。3.4.4宏匯編在程序設(shè)計(jì)中,為了簡(jiǎn)化程序的設(shè)計(jì),將多次重復(fù)使用的程序段用宏指令代替。宏指令是指程序員事先定義的特定的“指令”,這種“指令”是一組重復(fù)出現(xiàn)的程序指令塊的縮寫(xiě)和替代。宏指令定義以后,凡在宏指令出現(xiàn)的地方,宏匯編程序總是自動(dòng)地把它們替換成對(duì)應(yīng)的程序指令塊。宏指令有時(shí)也稱(chēng)為宏,包含有宏定義和宏調(diào)用。宏指令的特點(diǎn):簡(jiǎn)化源程序的編寫(xiě),匯編語(yǔ)言編程的參數(shù)傳遞特別靈活,功能更強(qiáng)。
1.宏指令定義宏是源程序中的一段具有獨(dú)立功能的程序代碼。它只要在源程序中定義一次,就可以多次調(diào)用,調(diào)用時(shí)只要使用一個(gè)宏指令語(yǔ)句就可以了。宏指令定義由開(kāi)始偽指令MACRO、宏指令體、宏指令定義結(jié)束偽指令ENDM組成。格式如下:宏指令名 MACRO[形式參數(shù)1,形式參數(shù)2,…,形式參數(shù)N] ;宏指令體(宏體)ENDM…其中,宏指令名是宏定義為宏體程序指令塊規(guī)定的名稱(chēng),可以是任一合法的名字,也可以是系統(tǒng)保留字(如指令助記符、偽指令操作符等),當(dāng)宏指令名是系統(tǒng)保留字時(shí),則該系統(tǒng)保留字就被賦予新的含義,從而失去原有的意義。MACRO語(yǔ)句到ENDM語(yǔ)句之間的所有匯編語(yǔ)句構(gòu)成宏指令體,簡(jiǎn)稱(chēng)宏體,宏體中使用的形式參數(shù)必須在MACRO語(yǔ)句中列出。形式參數(shù)是出現(xiàn)在宏體內(nèi)某些位置上可以變化的符號(hào),也可以是任一合法的名字,甚至是寄存器名。如果形式參數(shù)中使用某些寄存器名,那么在宏匯編展開(kāi)時(shí),將不認(rèn)為這些寄存器名是寄存器本身,而是形式參數(shù),并被實(shí)際參數(shù)所代替。形式參數(shù)可以缺省,也可以有一個(gè)或多個(gè)。當(dāng)形式參數(shù)多于一個(gè)時(shí),形式參數(shù)之間用逗號(hào)隔開(kāi),形式參數(shù)個(gè)數(shù)每行應(yīng)小于等于132個(gè)字符。宏指令定義一般放在源程序的開(kāi)頭,以避免產(chǎn)生不應(yīng)發(fā)生的錯(cuò)誤。宏指令必須先定義后調(diào)用(引用)。宏指令可以重新定義,也可以嵌套定義。嵌套定義是指在宏指令體內(nèi)還可以再定義宏指令或調(diào)用另一宏指令。
2.宏調(diào)用宏指令一旦定義后,就可以用宏指令名字(宏名)來(lái)調(diào)用(或引用)。宏調(diào)用的格式為宏指令名實(shí)際參數(shù)1,實(shí)際參數(shù)2,…,實(shí)際參數(shù)N其中,實(shí)際參數(shù)的類(lèi)型和順序要與形式參數(shù)的類(lèi)型和順序保持一致,宏調(diào)用時(shí)將一一對(duì)應(yīng)地替換宏指令體中的形式參數(shù)。當(dāng)有兩個(gè)以上參數(shù)時(shí),中間用逗號(hào)、空格或制表符隔開(kāi)。宏指令調(diào)用時(shí),實(shí)際參數(shù)的數(shù)目并不一定要和形式參數(shù)的數(shù)目一致,當(dāng)實(shí)參個(gè)數(shù)多于形參的個(gè)數(shù)時(shí),忽略多余的實(shí)參;當(dāng)實(shí)參個(gè)數(shù)少于形參個(gè)數(shù)時(shí),多余的形參用空串代替?!纠?-12】定義一條INOUT宏指令,既可以引用它輸入一串字符,也可引用它顯示一串提示字符。宏定義:INPUT MACRO ;定義一條從鍵盤(pán)輸入一個(gè)字符的宏指令I(lǐng)NPUT MOV AH,1 ;采用宏指令語(yǔ)句INPUT編程,類(lèi)似于高級(jí)語(yǔ)言語(yǔ)句 INT 21H ENDMLF MACRO ;定義一條換行宏指令LF MOV DL,10 MOV AH,2 INT 21H ENDMCR MACRO ;定義一條回車(chē)宏指令CR MOV DL,13 MOV AH,2 INT 21H ENDMINOUT MACRO X,Y ;定義一條輸入/輸出宏指令I(lǐng)NOUTMOV AH,XLEA DX,YINT 21HENDM宏調(diào)用:DATAS SEGMENTINPUT DB 'PLEASEINPUTANYCHARACTERS:’,'$'KEYBUF DB 10,11DUP(?),13,10,'$'DATAS ENDSCODES SEGMENT ASSUMECS:CODES,DS:DATASSTART: PUSH DS XOR AX,AX PUSH AX MOV AX,DATAS MOV DS,AX INOUT 9,INPUT ;顯示一串提示符的宏指令調(diào)用 LF ;換行,調(diào)用宏定義 CR ;回車(chē),調(diào)用宏定義 INOUT 10,KEYBUF ;輸入一串字符的宏指令調(diào)用 LF CR INOUT 9,KEYBUF+2 ;顯示輸入的一串字符的宏指令調(diào)用 RETCODES ENDS END START注意:本例有顯示輸出,上機(jī)更直觀。
3.宏展開(kāi)宏匯編程序若遇到宏指令定義時(shí)并不對(duì)它進(jìn)行匯編,只有在程序中引用的時(shí)候,匯編程序才把對(duì)應(yīng)的宏指令體調(diào)出進(jìn)行匯編處理(語(yǔ)法檢查和代碼塊的插入),這個(gè)過(guò)程稱(chēng)宏展開(kāi)(或宏擴(kuò)展)。宏指令調(diào)用后,在宏指令調(diào)用處產(chǎn)生用實(shí)參替換形參的宏體指令語(yǔ)句。在MASM匯編生成列表文件(.LST)的每行中間用符號(hào)“+”作為標(biāo)志,表明本行語(yǔ)句為宏指令展開(kāi)生成的語(yǔ)句。本章為說(shuō)明是宏展開(kāi)生成的語(yǔ)句,在語(yǔ)句的左邊仍用符號(hào)“+”標(biāo)志。例如,上述INOUT宏指令調(diào)用后,宏展開(kāi)后的語(yǔ)句如下: +MOV AH,9+LEA DX,INPUT+INT 21H+MOV DL,10+MOV AH,2+INT 21H+MOV DL,13+MOV AH,2+INT 21H+MOV AH,10+LEA DX,KEYBUF+INT 21H+MOV AH,9+LEA DX,KEYBUF+2+INT 21H這里實(shí)際參數(shù)是以整體去替換形參的整體(即對(duì)應(yīng)符號(hào)的整體代替)。如果只希望某一符號(hào)以數(shù)值(實(shí)參)代替形參,則可使用特殊宏計(jì)算符號(hào)“&”和“%”。3.4.5子程序結(jié)構(gòu)形式與操作1.子程序定義可把具有獨(dú)立功能的程序段定義為子程序,供其他程序調(diào)用,類(lèi)似于C語(yǔ)言的函數(shù)。子程序定義偽操作用在子程序的前后,使整個(gè)子程序形成清晰的、具有特定功能的代碼塊。子程序定義的語(yǔ)法格式為:<子程序名>PROC AttributeRET <子程序名>ENDP其中,子程序名為標(biāo)識(shí)符,它又是子程序入口的符號(hào)地址,它的寫(xiě)法與標(biāo)號(hào)的寫(xiě)法相同;屬性(Attribute)是指類(lèi)型屬性,它可以是NEAR或FAR。如前所述,CALL和RET指令都有NEAR和FAR的屬性,段內(nèi)調(diào)用使用NEAR屬性,但可以不顯示地寫(xiě)出;段間調(diào)用使用FAR屬性。為了使用戶(hù)的工作更加方便,80x86的匯編程序用PROC偽操作的類(lèi)型屬性來(lái)確定CALL和RET指令的屬性。也就是說(shuō),如果所定義的子程序是FAR屬性的,那么對(duì)它的調(diào)用和返回一定都是FAR屬性;如果所定義的子程序是NEAR屬性的,那么對(duì)它的調(diào)用和返回也一定是NEAR屬性。這樣,用戶(hù)只需在定義子程序時(shí)考慮它的屬性,而CALL和RET的屬性可以由匯編程序來(lái)確定。用戶(hù)對(duì)子程序?qū)傩源_定原則很簡(jiǎn)單,即:(1)如調(diào)用程序和子程序在同一個(gè)代碼段中,則使用NEAR屬性;(2)如調(diào)用程序和子程序不在同一個(gè)代碼段中,則使用FAR屬性?!纠?-13】調(diào)用程序和子程序在同一代碼段中。MAIN PROC FAR;主程序CALL SUBR1 RETMAIN ENDPSUBR1 PROC NEAR;子程序(NEAR可省略) RETSUBR1 ENDP………由于調(diào)用程序MAIN和子程序SUBR1是在同一代碼段中的,所以SUBR1定義為NEAR屬性。這樣,MAIN中對(duì)SUBR1的調(diào)用和SUBR1中的RET就都是NEAR屬性。但是一般說(shuō)來(lái),主程序MAIN應(yīng)定義為FAR屬性,這是由于把程序的主子程序看作DOS調(diào)用的一個(gè)子程序,因而DOS對(duì)MAIN的調(diào)用以及MAIN中的RET就是FRA屬性。當(dāng)然,CALL和RET的屬性是匯編程序確定的,用戶(hù)只需正確選擇PROC的屬性就可以了。也就是說(shuō),子程序定義也可以嵌套,一個(gè)子程序定義中可以包括多個(gè)子程序定義。例3-13的情況也可以寫(xiě)成如下的程序:MAIN PROC FAR CALL SUBR1 RETSUBR1 PROC NEAR RETSUBR1 ENDPMAIN ENDP………【例3-14】調(diào)用程序和子程序不在同一個(gè)代碼段內(nèi)。SEGX SEGMENTSUBT PROC FARRETSUBT ENDP CALL SUBTSEGX ENDSSEGY SEGMENT
CALL SUBT
SEGY ENDS……………SUBT是一個(gè)子程序,它在兩處被調(diào)用,一處是與SEGX同在段內(nèi),另一處是在SEGY段內(nèi)。為此,SUBT必須具有FAR屬性以適應(yīng)SEGY段調(diào)用的需要。SUBT既然有FAR屬性,則不論在SEGX段還是SEGY段中,對(duì)SUBT的調(diào)用就都具有FAR屬性了,這樣不會(huì)發(fā)生什么錯(cuò)誤。反之,如果這里的SUBT使用了NEAR屬性,則在SEGY段內(nèi)對(duì)它的調(diào)用就要出錯(cuò)了。
2.子程序的調(diào)用和返回子程序的正確執(zhí)行是由子程序的正確調(diào)用和正確返回保證的,80x86的CALL和RET指令完成的就是調(diào)用和返回的功能。為保證其正確性,除PROC的屬性要正確選擇外,還應(yīng)該注意子程序運(yùn)行期間的堆棧狀態(tài)。由于執(zhí)行CALL時(shí)已使返回地址入棧,所以執(zhí)行RET時(shí)應(yīng)該使返回地址出棧,如果子程序中不能正確使用堆棧而造成執(zhí)行RET前SP并未指向進(jìn)入子程序時(shí)的返回地址,則必然會(huì)導(dǎo)致運(yùn)行出錯(cuò)。因此,子程序中對(duì)堆棧的使用應(yīng)該特別小心,以免發(fā)生錯(cuò)誤。
3.現(xiàn)場(chǎng)保護(hù)與現(xiàn)場(chǎng)恢復(fù)由于主程序和子程序通常是分別編制的,所以它們所使用的寄存器往往會(huì)發(fā)生沖突。如果主程序在調(diào)用子程序之前的某個(gè)寄存器內(nèi)容在從子程序返回后還有用,而子程序又恰好使用了同一個(gè)寄存器,這就破壞了該寄存器的原有內(nèi)容,因而會(huì)造成程序運(yùn)行錯(cuò)誤,這是不允許的。為避免這種錯(cuò)誤的發(fā)生,在進(jìn)入子程序后,就應(yīng)該把子程序所需要使用的寄存器內(nèi)容保存在堆棧中,此過(guò)程稱(chēng)作現(xiàn)場(chǎng)保護(hù);而在退出子程序前把寄存器內(nèi)容恢復(fù)原狀,此過(guò)程稱(chēng)作現(xiàn)場(chǎng)恢復(fù)?,F(xiàn)場(chǎng)保護(hù)與現(xiàn)場(chǎng)恢復(fù)分別使用壓棧和彈出指令實(shí)現(xiàn)。例如SUBT PROC PUSH AX ;現(xiàn)場(chǎng)保護(hù) PUSH BX PUSH CX PUSH DX<子程序體> POP DX;現(xiàn)場(chǎng)恢復(fù) POP CX POP BX POP AX RETSUBT ENDP…在子程序設(shè)計(jì)時(shí),應(yīng)仔細(xì)考慮哪些寄存器是必須保護(hù)的,哪些寄存器是不必要保護(hù)的。一般說(shuō)來(lái),子程序中用到的寄存器是應(yīng)該保護(hù)的。但是,如果使用寄存器在主程序和子程序之間傳送參數(shù)的話,則這種寄存器就不一定需要保護(hù),特別是用來(lái)向主程序回送結(jié)果的寄存器,就更不應(yīng)該因保存和恢復(fù)寄存器而破壞了應(yīng)該向主程序傳送的信息。從80286CPU開(kāi)始使用的PUSHA/POPA指令以及從80386CPU開(kāi)始的高檔微機(jī)使用的PUSHAD/POPAD指令為子程序中保存和恢復(fù)寄存器內(nèi)容提供了有力的支持。
3.子程序嵌套主程序調(diào)用子程序,子程序還可以調(diào)用其他子程序,這就是子程序的嵌套調(diào)用,子程序可以多重嵌套調(diào)用?!纠?-15】設(shè)從BUF開(kāi)始存放若干無(wú)符號(hào)字節(jié)數(shù)據(jù),找出其中的最小值并以十六進(jìn)制形式輸出。分析:本題用子程序SEARCH來(lái)求最小數(shù)字節(jié)數(shù)并輸出,再調(diào)用一個(gè)子程序輸出1位十六進(jìn)制數(shù),由于數(shù)據(jù)多,因此可以利用子程序的嵌套。DATA SEGMENT BUF DB13,25,23,100,423,78,90,134;定義數(shù)據(jù) CNT EQU$-BUF ;數(shù)據(jù)個(gè)數(shù)DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AX MOV CX,CNT-1 ;比較次數(shù) MOV SI,OFFSETBUF ;首地址 CALL SEARCH MOV AH,4CH ;返回DOS INT 21H SEARCH PROCNEAR MOV BL,[SI] ;假定第一個(gè)數(shù)為最小數(shù)SEAR1: INC SI ;指向下—個(gè)數(shù) CMP BL,[SI] ;比較 JBE SEAR2 ;BL中的數(shù)小,轉(zhuǎn)SEAR2 MOV BL,[SI] ;BL中的數(shù)大,把它替換掉SEAR2: DEC CX JNZ SEAR1 ;循環(huán)比較 MOV DL,BL ;最小值送DL MOV CL,4 SHR DL,CL ;分離出高4位 CALL DISP ;調(diào)用子程序顯示輸出 MOV DL,BL ;最小值送DL AND DL,0FH ;分離出低4位 CALL DISP ;調(diào)用子程序顯示輸出 RETSEARCH ENDPDISP PROC NEAR CMP DL,9 ;DL和9比較 JBE DISP1 ;小于等于9加30H,否則加37H ADD DL,7DISP1: ADD DL,30H MOV AH,2 ;輸出 INT 21H RETDISP ENDPCODE ENDS END START注意:本例有顯示輸出子程序部分,上機(jī)更直觀。3.4.6順序程序設(shè)計(jì)順序程序結(jié)構(gòu)是指完全按順序逐條執(zhí)行的指令序列,這在程序段中是大量存在的,但作為完整的程序則很少見(jiàn),一般作為程序的一部分。順序結(jié)構(gòu)程序是最簡(jiǎn)單的程序,在順序結(jié)構(gòu)程序中,指令按照先后順序一條一條執(zhí)行?!纠?-16】將兩個(gè)字節(jié)數(shù)據(jù)相加,并存放到一個(gè)結(jié)果單元中。DATA SEGMENTAD1 DB 4CH ;定義第1個(gè)加數(shù)AD2 DB 25H ;定義第2個(gè)加數(shù)SUM DB ? ;定義結(jié)果單元DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AXMOV AL,AD1 ;取出第1個(gè)加數(shù)ADD AL,AD2 ;和第2個(gè)加數(shù)相加MOV SUM,AL ;存放結(jié)果MOV BL,AL ;顯示十六進(jìn)制結(jié)果MOV CL,4SHR AL,CLAND AL,0FHADD AL,30HMOV DL,ALMOV AH,2INT 21HMOV AL,BLAND AL,0FHADD AL,30HMOV DL,ALMOV AH,2INT 21HMOV AH,4CH ;返回DOSINT 21H CODE ENDS END START注意:①本程序的結(jié)束,采用了DOS中斷調(diào)用的4CH號(hào)功能,來(lái)退出程序段運(yùn)行,返回DOS現(xiàn)場(chǎng)。這是一種常用的執(zhí)行程序返回DOS現(xiàn)場(chǎng)的方法。②本例可顯示輸出。3.4.7分支程序設(shè)計(jì)1.分支程序結(jié)構(gòu)形式分支程序結(jié)構(gòu)可以有兩種形式,如圖3.14所示。它們分別相當(dāng)于高級(jí)語(yǔ)言中的IF_THEN_ELSE語(yǔ)句和CASE語(yǔ)句,適用于要求根據(jù)不同條件作不同處理的情況。IF_THEN_ELSE語(yǔ)句可以引出兩個(gè)分支,CASE語(yǔ)句則可以引出多個(gè)分支。不論哪一種形式,它們的共同特點(diǎn)是:運(yùn)行方向是向前的,在某一種特定條件下,只能執(zhí)行多個(gè)分支中的一個(gè)分支。圖3.14分支程序的結(jié)構(gòu)形式(a)IF_THEN_ELSE結(jié)構(gòu);(b)CASE結(jié)構(gòu)
2.分支程序設(shè)計(jì)方法程序的分支一般用條件轉(zhuǎn)移指令來(lái)產(chǎn)生,利用轉(zhuǎn)移指令不影響條件碼的特性,連續(xù)地使用條件轉(zhuǎn)移指令可使程序產(chǎn)生多個(gè)不同的分支?!纠?-17】TABLE是一字節(jié)數(shù)組的首地址,長(zhǎng)度為100。統(tǒng)計(jì)此數(shù)組中正數(shù)、0及負(fù)數(shù)的個(gè)數(shù),并分別放在COUNT1、COUNT2和COUNT3變量中。其流程圖如圖3.15所示。圖3.15例3-17流程圖DATA SEGMENTTABLE DB 100 DUP(?)COUNT1DB 0COUNT2DB 0COUNT3DB 0DATAENDSCODE SEGMENT ASSUME CS:CODE,DS:DATAALLO PROC FARSTART:PUSH DS XOR AX,AX PUSH AX MOV AX,DATA MOV DS,AXMOV CX,100MOV BX,0AGAIN:CMP TABLE[BX],0 JGE SS12 INC COUNT3 JMP SHORT NEXTSS12:JG SS1 INC COUNT1 JMP SHORT NEXTSS1: INC COUNT2NEXT:INC BX LOOP AGAIN RETALLO ENDPCODE ENDS END START本程序段在開(kāi)始時(shí)出現(xiàn)了兩次壓棧操作,既PUSHDS和PUSHAX((AX)=0)。DOS環(huán)境是由COMMAND.COM管理的,而.COM文件的特點(diǎn)之一是四段合一,即(CS)=(DS)=(SS)=(ES),壓棧DS就相當(dāng)于壓棧CS的內(nèi)容。由于本程序段是一個(gè)FAR屬性的子程序,在程序結(jié)束執(zhí)行RET時(shí)將引起兩次出棧操作,會(huì)使(CS)內(nèi)容等于未執(zhí)行本程序前的值,(IP)=0。在(CS):(IP)位置有一段程序,功能就是退出程序段運(yùn)行,返回DOS現(xiàn)場(chǎng)。這是第二種執(zhí)行程序返回DOS現(xiàn)場(chǎng)的方法。3.4.8循環(huán)程序設(shè)計(jì)1.循環(huán)程序結(jié)構(gòu)循環(huán)程序結(jié)構(gòu)可以總結(jié)為兩種結(jié)構(gòu)形式
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 語(yǔ)文素養(yǎng)大賽策劃書(shū)3篇
- 2025年榆林能源科技職業(yè)學(xué)院高職單招語(yǔ)文2018-2024歷年參考題庫(kù)頻考點(diǎn)含答案解析
- 專(zhuān)題02 漫畫(huà)素材類(lèi)選擇題(50題)
- 2024年電商應(yīng)用與品牌市場(chǎng)洞察報(bào)告
- 課題申報(bào)參考:數(shù)據(jù)驅(qū)動(dòng)的帆板高效推進(jìn)搖帆策略研究
- 駕馭考試戰(zhàn)場(chǎng)的戰(zhàn)術(shù)思維
- 幼兒植樹(shù)節(jié)出游活動(dòng)策劃方案五篇
- 酒店委托經(jīng)營(yíng)合同范本
- 范文二手房買(mǎi)賣(mài)合同
- 商服用房買(mǎi)賣(mài)合同
- 文檔協(xié)同編輯-深度研究
- 七年級(jí)數(shù)學(xué)新北師大版(2024)下冊(cè)第一章《整式的乘除》單元檢測(cè)習(xí)題(含簡(jiǎn)單答案)
- 2024-2025學(xué)年云南省昆明市盤(pán)龍區(qū)高一(上)期末數(shù)學(xué)試卷(含答案)
- 五年級(jí)上冊(cè)寒假作業(yè)答案(人教版)
- 2024年財(cái)政部會(huì)計(jì)法律法規(guī)答題活動(dòng)題目及答案一
- 2025年中考語(yǔ)文復(fù)習(xí)熱搜題速遞之說(shuō)明文閱讀(2024年7月)
- 和達(dá)投資集團(tuán)(杭州)有限公司招聘筆試沖刺題2025
- 綜治工作培訓(xùn)課件
- 2024年云網(wǎng)安全應(yīng)知應(yīng)會(huì)考試題庫(kù)
- 2024年全國(guó)職業(yè)院校技能大賽高職組(智能節(jié)水系統(tǒng)設(shè)計(jì)與安裝賽項(xiàng))考試題庫(kù)-下(多選、判斷題)
- 2024年廣東省事業(yè)單位考試真題及答案5
評(píng)論
0/150
提交評(píng)論