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