匯編語言課件_第1頁
匯編語言課件_第2頁
匯編語言課件_第3頁
匯編語言課件_第4頁
匯編語言課件_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第1章第2章第3章第4章第5章第6章第7章第8章第9章第10章

第二早

匯編語言程序設(shè)計

指令系統(tǒng)中的指令,在計算機內(nèi)存中,都是以二進制編碼的形式存儲的,這種編碼

稱為機器碼,或者稱為機器指令.在程序運行時,指令由內(nèi)存讀入CPU,然后譯碼,

執(zhí)行.只有內(nèi)存中的機器碼,計算機才能執(zhí)行.然而,.機器碼很難記憶,使用時極

易出錯,因此,直接利用機器碼編制程序是極其困難又枯燥乏味的工作.編程的程

序,晦澀難懂,即使編程者本人,,編程后不出數(shù)日,對自己的程序,也可能不解其

慧,需仔細琢磨才能恍然大悟.這時,若有詳細的程序注釋,那將會給你帶來極大

方便,免除再度疲勞之苦.

實際的需要激發(fā)人們?nèi)?chuàng)造一種符號一助記符,用他們?nèi)ゴ鏅C器碼來表示指令,

既有簡單明了的詞意,一目了然,又便于理解和記憶,于是,匯編語言應(yīng)運而生.

現(xiàn)在,我們可以用指令助記符和表示地址或數(shù)據(jù)等的各種符號,按照規(guī)定的格式,

來編制程序,這樣的程序,稱為匯編語言程序.這些表示指令,地址,數(shù)據(jù)等的符號

以及有關(guān)規(guī)定,是計算機進行:“思想”的工具,亦即計算機匯編語言.

匯編語言與具體的計算機類型有密切的關(guān)系,不同的中央處理單元,其指令系統(tǒng)

也各不相同,相應(yīng)的匯編語言也互不相同.與硬件關(guān)系密切的程序,或者實時性要

求很高的程序,往往采用匯編程序.

在編輯程序的支持下,匯編語言程序從鍵盤輸入,編輯形成匯編語言源程序.源程

序是用匯編語言的語句編寫的,在計算機內(nèi)部,源程序的各條語句是以ascii碼

表示的,存在磁盤上,又稱為源文件。它區(qū)別與機器指令之處是不能被計算機執(zhí)行,

但它可以用來顯示和打印,作為檢查和保存的檔案.

匯編語言源程序經(jīng)過匯編程序的語法檢查和翻譯,形成二進制代碼表示的目的碼

文件.如果源程序中有語法錯誤,匯編程序會指出錯誤的類型和出錯所在的語句,

以便用戶重新進行編輯修改,再形成新的源程序.源文件和有其生成的目的碼文

件可以是一個或者是兒個.

目的碼文件并不能直接上機運行,必須經(jīng)過連接程序把它和庫文件連接在一起,

形成可執(zhí)行文件.這個可執(zhí)行文件有操作系統(tǒng)裝入計算機內(nèi)存,才能運行.

本章介紹匯編語言的語法規(guī)則,它是匯編語言的“法律”,編程時必須遵循,同時

也介紹匯編語言程序設(shè)計方法,以共參考.

3.1宏匯編基本語法

ibmpc微機中,有兩個匯編程序,一個是小匯編程序asm,另一個是宏匯編程序

masm,宏匯編程序功能比較強,并且支持宏匯編和有關(guān)的函數(shù)及偽指令,自然它需

要的存儲容量,比小匯編程序所需要的要稍微大一些.

3.1.1匯編語言程序舉例

我們通過一個例子介紹匯編語言的格式.這個例子的功能是把block中的正數(shù),

負數(shù)分別送到兩個緩沖區(qū)中去.程序如下:

datasegment;定義數(shù)據(jù)段

blockdb43h,Oabh;定義block變量及其數(shù)據(jù)初值

pdatadb20dup(?);定義存放正數(shù)的緩沖區(qū)

npatadb20dup(?);定義存放負數(shù)的緩沖區(qū)

dataends;數(shù)據(jù)段定義結(jié)束

codesegment;定義碼段

assumecs:code,ds:data;確定cs,ds和對應(yīng)段的關(guān)系

explprofar;定義過程

start:pushds;保存原ds

movax,0

pushas;ax;保存在堆棧

movax,data

movds,ax;數(shù)據(jù)段段址送ds,es

moves,ax

leasi,block;分別置偏移地址

leadi,pdata

leabx,ndata

cld

movex,pdata-block;數(shù)據(jù)個數(shù)送ex

goon:lodsb;數(shù)據(jù)送al

testal,80h

jnzminus;判是負數(shù),則轉(zhuǎn)minus

stosb;判是正數(shù),送去存入緩沖器

jmpagain

minus:xchgbx,di;交換,使di中為負數(shù)緩沖器便址

stosb;存負數(shù)

xchgbx,di;恢復(fù)原便址寄存器

again:loopgoon;循環(huán)次數(shù)未完,則轉(zhuǎn)goon

ret;返回dos

explendp;過程定義結(jié)束

codeends;碼段定義結(jié)束

endstart;匯編結(jié)束,斷定入口地址

從這個例子,不難發(fā)現(xiàn)匯編語言程序通常由數(shù)據(jù)段,碼段組成.數(shù)據(jù)段存放數(shù)據(jù),

碼段存放程序指令,實現(xiàn)相應(yīng)的功能.程序結(jié)束處,必須是規(guī)定程序執(zhí)行的起始地

址,也稱為入口地址.本程序開始執(zhí)行的地址是start.

程序語句行由四個部分組成,即標(biāo)號(或名字),操作碼,操作數(shù)和注釋.語句左邊

第?列起為標(biāo)號區(qū),句末分號后的為注釋區(qū),中間的部分為操作數(shù)區(qū).按照這種格

式書寫并輸入計算機,既是程序的要求,也使人閱讀時清清楚楚,賞心悅目.

3.1.2匯編語言程序結(jié)構(gòu)

匯編語言源程序通常由一個或兒個程序模塊組成,每個模塊包括數(shù)據(jù)段,堆棧段

和若干個代碼段.有時程序中可以不設(shè)堆棧段,而利用系統(tǒng)中已設(shè)定的堆棧段.代

碼段中有若干個過程,過程又稱子程序。過程中的語句分為兩類,兩類是指示性

語句,另一類是指示性語句.指示性語句是計算機能執(zhí)行的指令,而指示性語句,

計算機并不能執(zhí)行。匯編時,依據(jù)指示性語句的規(guī)定,匯編程序?qū)υ闯绦蜻M行相

應(yīng)的處理操作,進行諸如定義數(shù)據(jù)、分配存儲區(qū)、指示程序開始和結(jié)束等服務(wù)性

工作,以減輕編程員的負擔(dān)。指示性語句又成偽指令。

這里,用等式表示程序和過程的結(jié)果內(nèi)容:

程序={塊[數(shù)據(jù)段,堆棧段,代碼段(過程1,過程2,……)],快……}

過程={指示性語句,指令性語句}

指示性語句的格式如下:

[名字][偽指令][操作數(shù)][;注釋]

例如:

SUMPROCFAR;定義一個過程

SUMENDP;過程定義結(jié)束

指令性語句的格式為:

[標(biāo)號:][前綴][指令助記符][操作數(shù)][;注釋]

例如:

LP1:MOVBX,OFFSETDAREA;DAREA的地址送BX

語句中名字和符號,又稱為符標(biāo)識符,是程序員自己確定的,它不允許與指令助

記符或偽指令同名,也不允許有數(shù)字打頭,字符個數(shù)不得超過31個。

3.1.3數(shù)據(jù)項與表達式

操作數(shù)是指令和偽指令中很重要的一部分內(nèi)容,它可以用寄存器、存儲器單元或

數(shù)據(jù)項來表示。其中,數(shù)據(jù)項是最靈活多變的,它有三種形式:常量、標(biāo)號、變

量。常量、變量和標(biāo)號以及他們的表達式都可以作為操作數(shù)使用。下面分別介紹。

1常量

常量包括數(shù)字常量和字符常量兩種。

(1)數(shù)字常量

二進制常量——以字母為結(jié)尾的數(shù)為二進制數(shù)。例如,10111010。

十進制常量——以字母結(jié)尾或沒有字母結(jié)尾的數(shù)為十進制數(shù)。例如8914,2376

十六進制常量——以字母結(jié)尾的數(shù)為十六進制數(shù)。例如1在匯編程序中,凡是以

字母開始的十六進制數(shù),必須在前面加上數(shù)字0,以避免和表示符相混淆。

(2)字符串常量

以單引號內(nèi)一個或多個ASCH字符構(gòu)成字符串常量。匯編程序把他們翻譯成對應(yīng)

的ASCH碼值,一個字符對應(yīng)一個字節(jié)。例如,字符串常量,AB,和'C,在匯

編時分別被翻譯成4142H和43Ho

2.標(biāo)號

標(biāo)號是存放某條指令的存儲單元的符號地址,通常他用作條件轉(zhuǎn)移,無條件轉(zhuǎn)移

指令或調(diào)用指令的目標(biāo)操作數(shù)。

標(biāo)號是由標(biāo)識符即標(biāo)號后面跟一個冒號來定義的。例如:

START:MOVAX,DATA

LP1:MOVCX,COUNT

這兩條語句分別定義了兩個標(biāo)號START和LP1,他們可以供轉(zhuǎn)移指令,循環(huán)指令

或調(diào)用指令當(dāng)作目標(biāo)操作數(shù)來使用。

標(biāo)號作為存儲單元的符號地址,他具有3種屬性:段值,偏移量和類型。標(biāo)號的

段值,偏移量屬性分別指它的段地址和偏移地址,而標(biāo)號的類型分NEAR和FAR

兩種。

NEAR類型的標(biāo)號是指標(biāo)號所在的語句和調(diào)用指令或轉(zhuǎn)移指令在同一個碼段中,

執(zhí)行調(diào)用指令或轉(zhuǎn)移指令時,只需要把標(biāo)號的偏移地址送給IP,就可以實現(xiàn)調(diào)

用或轉(zhuǎn)移,并不需要改變碼段段址。

而FAR和NEAR類型不同,F(xiàn)AR類型標(biāo)號所在語句與其調(diào)用指令或轉(zhuǎn)移指令不

在用一碼段中,執(zhí)行調(diào)用指令或轉(zhuǎn)移指令時,不僅需要改變偏址IP的值,而且

需要改變段值CS的值。這是段間的調(diào)用或轉(zhuǎn)移。

3.變量

變量是內(nèi)存中的數(shù)據(jù)區(qū),由若干個存儲單元構(gòu)成,內(nèi)存中的內(nèi)容是可以修改的,

因此,變量的值也是可以哦改變的。變量在程序中,作為存儲器操作數(shù)來使用。

變量具有3中屬性:

(1)段值(SEGMENT)——變量定義所在段的段地址。為了確保匯編程序能找

到該變量,應(yīng)在偽指令(ASSUME)中加以說明,把其段值放在一個短寄存器中,

如CS,DS,ES或SS。

(2)偏移量(OFFSET)一—變量的地址和變量所在段的起始地址之間的偏移量。

(3)類型(TYPE)——變量的類型定義了該變量存儲區(qū)內(nèi)每個數(shù)據(jù)所占內(nèi)存單

元的字節(jié)數(shù),如字節(jié),字,雙字類型變量分別站用內(nèi)存1,2,4個字節(jié)單元。

變量定義的格式如下:

[變量名],[數(shù)據(jù)定義偽操作],[表達式]

變量名有字母打頭,最多允許31個字符,定義以后,凡是用到這個變量名時,

必須注意其三個屬性。數(shù)據(jù)定義偽操作將該變量名定義成某種類型的變量(數(shù)據(jù)

定義偽操作在以后敘述)。而表達式則確定了變量的初值和這個變量數(shù)據(jù)區(qū)的大

小,它允許采用數(shù)值表達式或地址表達式。

變量使用時,要注意以下幾點:

(1)變量類型與指令要求的操作數(shù)類型相符。例如,MOVAL,VARI指令中,

要求VARI應(yīng)該是字節(jié)類型的,才與AL的類型匹配。而指令MOVBX,VAR2則要

求VAR2應(yīng)該定義成字類型的變量。

(2)變量的編址。變量定義以后,變量名僅僅對應(yīng)這個數(shù)據(jù)區(qū)的首地址。若這

個數(shù)據(jù)區(qū)中有若干個數(shù)據(jù)項,在對其后面的數(shù)據(jù)項進行操作時,其地址需要改變。

例如,欲求變量XY數(shù)據(jù)區(qū)中20個字的和,在加下一個數(shù)據(jù)項時,地址應(yīng)該進行

修改,以指向那個數(shù)據(jù)項。具體程序段如下:

XYDW20DUP(?)

MOVAX,XY+38;送最后一個字給AX

MOVBX,38

LP1:SUBBX,2;偏址修改

ADDAX,XY[BX];求和

CUPBX,0;判是否是第一個數(shù)字

JNELP1;不是,則幾需求和

(3)變量的斷址。指令中的操作數(shù)的斷址往往不直接表示出來,而是隱含的,

或者稱為默認的或缺省的。變量使用時,其段屬性應(yīng)與所在指令的缺省段寄存器

相符。如若不符,應(yīng)該把段地址直接表示出來,這種表示方法,稱為跨段前綴。

跨段前綴可以用段寄存器或段名來表示。例如:

MOVAX,ES:[BX]

MOVAX,DATA:[DI]

4表達式

匯編程序允許使用表達式。然而,表達式并不是指令,它本身不能執(zhí)行。程序被

匯編時,匯編程序?qū)Τ绦蛑械谋磉_式進行相應(yīng)的運算,其運算結(jié)果是一個值。因

此,在程序被執(zhí)行時,表達式本身已經(jīng)是一個有確定值的操作數(shù)。

變達式中的運算有三類運算符一一算術(shù)運算符、邏輯運算符和關(guān)系運算符來表

/J、.O

(1)算術(shù)運算符

有+,*,/,MOD五種算術(shù)運算符,前面4種是最常見到的加、減、乘、除、

四則運算符,而MOD是表示求兩個數(shù)相除以后的余數(shù)。例如,23M0D7其結(jié)果是

2,即23除以7,其余數(shù)是2。

算術(shù)運算符用于數(shù)字表達式,其結(jié)果仍是數(shù)字。

算術(shù)運算符也可以用于地址表達式,但其應(yīng)用范圍受到一定的限制,那就是地址

表達式的運算必須有明確的物理意義,其運算結(jié)果才有效,否則該地址表達式是

錯誤的。

通常,地址表達式中使用加或者減運算。地址加或者減一個數(shù)字量,表示對原地

址偏移該數(shù)字的若干個單元的地址。例如,VAR+2表示變量VAR的地址加上2

得到的和作為新的存儲單元的地址。同一段中兩個存儲單元地址之差,表示他們

之間的地址偏移量,或者有時表示這兩個存儲單元之間有多少個字節(jié)。而不同段

址的兩個偏移地址的加或者減是沒有物理意義的,兩個地址相乘或相除同樣也是

沒有物理意義的。例如,若要把字數(shù)祖阿惹第九個字傳到AX寄存器,用指令可

以這樣表示:

MOVAX,VAR+(9T)*2

其中,VAR是該數(shù)組的首地址,(9T)*2是第9個字的地址與首地址的偏移量。

(2)邏輯運算符

有AND,OR,NOT和XOR四種邏輯運算符,邏輯運算是按位操作的,邏輯運算符

只能用于數(shù)字表達式,不能用于存儲器地址表達式。例如:

MOVAL,OADHANDOCCH

匯編時,計算上式中右邊邏輯表達式,得到結(jié)果為8cH,這樣就轉(zhuǎn)化為指令

MOVAL,8CH

表達式VAROR80H是無效的,因為邏輯運算符不能用于地址表達式。

那么,指令OUTPORTANDFEH,AL是否有效呢?答案是肯定的,有效。因為PORT

是1個字節(jié)的數(shù)字,而不是一個變量,盡管它名義上是作為外設(shè)口的地址,實

際上匯編程序認為它是一個數(shù)字,PORT是?個數(shù)字表達式,因此允許使用邏輯

運算符。該指令在匯編時,若PORT是偶數(shù),則表達式結(jié)果與原端口號相同,若

PORT是奇數(shù)時,該指令的輸出端口為一偶數(shù),比PORT端口號小1。

這里需要提醒的是這些邏輯運算符是用于數(shù)字表達式的運算符,并不是邏輯運算

指令的操作碼。前者是匯編程序在進行匯編時處理的,而后者是在程序運行時執(zhí)

行的。

(3)關(guān)系運算符

有EQ,NE,LT,GT,LE,GE六種關(guān)系運算符。這些關(guān)系運算符分別表示兩個操

作數(shù)是否相等,不等,小于,大于,小于等于和大于等于。關(guān)系運算的兩個操作

數(shù)必須都是數(shù)字或者都是同一段內(nèi)的存儲器地址。關(guān)系運算的結(jié)果是一個邏輯

值,結(jié)果為真,邏輯值是OFFFFH;結(jié)果為假,值為0。例如:

MOVAX,VARIGTVAR2

如果VARI地址大于VAR2,則匯編結(jié)果應(yīng)該是:

MOVAX,OFFFFH

否則,匯編結(jié)果就成為:

MOVAX,0000H

數(shù)字表達式比較容易理解,而地址表達式比較復(fù)雜。

地址表達式由變量,標(biāo)號,常量,基址,變址寄存器以及相關(guān)的運算符組成,它

表示了存儲器的地址。地址表達式有三種屬性,即段值,偏移量,類型。地址表

達式的段值,偏移量即是其段地址和偏移地址。而類型則有字節(jié),字和雙字類型,

以及近(NEAR)和遠(FAR)類型兩種,前者和數(shù)據(jù)的存儲單元相對應(yīng),后者與

程序轉(zhuǎn)移或調(diào)用的目標(biāo)地址相對應(yīng)。

和地址表達式有關(guān)的運算符,除了前面所提及的,還有下面兩種操作符。

(1)類型操作符一一PTR程序中對變量或標(biāo)號定義后,變量或標(biāo)號的屬性便確

定了。也就是有它的段址,偏址和類型。但在實際使用時,可能會出現(xiàn)與原先定

義的類型不匹配的情況,需要臨時加以調(diào)整。PTR操作符給地址表達式臨時賦予

一個新的類型,而地址表達式的斷值,偏移量屬性不便。其操作的格式如下:

類型地址表達式

其中的類型可以是或

例如,給已定義為字:

varidw?

那么,只能在字操作令中使用vari這個變量,如movax,varl時合法的。但是,

要把varl當(dāng)作字操作數(shù)來使用,便是非法的,指令

movvari,al

會出現(xiàn)類型不配的錯誤,而指令

movbyteptrvarl,al

則合法的。操作符ptr產(chǎn)生了一個新的地址操作數(shù),該操作數(shù)的段地址和偏移地

址與varl相同,而類型為字節(jié)型,不是原先定義的字類型。

若標(biāo)號next原來定義是near類型,現(xiàn)在另一個段中的程序要轉(zhuǎn)移到此next處,

那么采用指令

jmpfarptrnext

來實現(xiàn)段間的轉(zhuǎn)移。

(2)樹枝返回操作符——segoffset有時,并不希望對變量的內(nèi)容進行處理,

而需要這個變量的地址以便量進行操作;有時,并不希望轉(zhuǎn)移到某個標(biāo)號定義

的目標(biāo)地址去,而是需要對這個標(biāo)號的地址進行處理。在這兩種情況下,需要利

用seg和offset這兩個數(shù)值返回操作符,他的操作格式如下:

seg變量或標(biāo)號

offseg變量或標(biāo)號

seg操作符返回變量或者標(biāo)號的段址。而offseg操作符返回變量或者標(biāo)號的偏

移量。

例如:

movaxmsegvarname

movbx,offsegvarname

分別得到varname段址和對短起始地址的偏移量,傳送給ax和bx寄存器。

32指示性語句

指示性語句.偽操作語句。偽操作不是計算機指令系統(tǒng)的一部分,而是匯編程序

提供源程序的服務(wù)工具,用以完成會變得輔助性工作,諸如變量定義,符號賦值,

程序守為標(biāo)志等。Ibm宏匯編提供以下兒類操作語句:變量定義語句:符號賦值

語句;斷定義語句;過程定義語句;??於x語句。

下面對這兒類為操作的常用部分加以敘述。書中沒有涉及的偽操作,讀者需要是

可以查閱手冊。

3.2.1變量定語句

變量定義語句為變量分配若干個初值。這一類操作的格式為:

[變量名]助記符操桌數(shù)。?!僮罃?shù)[;注釋]

其中變量子段名用符號地址表示,分配的春儲單元的第一個字節(jié)的偏移地址是這

個變量名的值。這個變量名字段也可以沒有,表示只分配若干個存儲單元。

注釋子段用來對該偽朝作做一些說明,如它的功能等。

超作數(shù)子段可以有若個個操捉數(shù),偽操作把這些數(shù)據(jù)存入指定的存儲單元。這里

操作數(shù)可以是指定的數(shù)值表達式、ASC字符穿、地址表達式。助記符字段是定義

變量的偽操作,常用的有DB,DW,DD等兒種。

DB偽操作用來定義字節(jié)形變量,其中的每個操作數(shù)都占有一個字節(jié)存儲單元,

每個操作數(shù)的值不操過255。

DW偽操作用來定義字形變量,其中的每個操作數(shù)都占有兩個字節(jié),字的低位字

節(jié)在第一個字節(jié)地址單元中,字的低位字節(jié)在第二個字節(jié)地址單元中,簡單的說,

就是低位在前、高位在后、或低位低地址、高位高地址。

DD偽操作用來定義雙字型變量,其中的每個操作數(shù)都占有兩個字,雙字的最低

位字節(jié)在第一個字節(jié)地址單元中,次低位字節(jié)在第二個字節(jié)地址單元中,次高位

字節(jié)在第三個字節(jié)地址單元中,高位字節(jié)在第四個字節(jié)地址單元中。

例操作數(shù)是常數(shù)或者表達式。

BYTE_VARDB12,4,12H

WORD_VARDW100H,-2,10*6

DW_VARDDOFEFDH

匯編程序在匯編時,根據(jù)表達式可以求得一個常數(shù),把數(shù)據(jù)結(jié)果存入存儲器,如圖

3-1.

例操作數(shù)可以是字符串,如:

STRINGDB'OK!'

CHARDB'AB'

WARDDW'AB'

匯編后,存儲器的存儲情況如圖3-2所示.

例操作數(shù)字段用符號?來表示,即保留存儲空間,不存入起始數(shù)值.操作數(shù)字段

也可以用復(fù)制操作符DUP復(fù)制某些數(shù)據(jù),如:

ARRAY1DB4DUP(?)

ARRAY2DB10DUP(0,1)

DUP前面的數(shù)據(jù)指定括號中的操作數(shù)的重復(fù)次數(shù),它可以是一個表達式.匯編后,

存儲器的存儲情況如圖3-3.

3.2.2符號賦值語句

程序中,有時多次出現(xiàn)同一個表達式,為了方便起見,用賦值偽操作給表達式賦予

一個符號名,以后,凡用到該表達式的地方都可以用這個符號名來表示,這樣,意

義清楚,修改容易.格式如下:

符號名EQU表達式

其中表達式可以是任何有效的操作數(shù),可以是任何結(jié)果為常數(shù)的表達式,也可以

是助組記符.例如:

COUNTEQU256

BEQU[BP+8]

P8EQUDS:[BP+8]

LPNEQULP1+12H;給^^賦地址表達式

SSBEQUSTOSB

EQU語句的表達式中,如果有變量或符號出現(xiàn),則在該語句前后必須給出它們的

定義,表達式才有效,否則匯編程序?qū)⑻崾境鲥e.例中的第四個語句的LP1應(yīng)該在

次句前加以定義.

符號用EQU語句賦值后,不能重新賦值.除非用PURGE語句解除這些賦值關(guān)系,符

號才能賦新的值.PURGE語句的格式為:

PURGE符號1,符號2,…,符號n,

而另一個與EQU語句功能類似的語句,即=偽操作.=偽操作允許給符號賦一個常

量,或者結(jié)果是常數(shù)的表達式,并且允許對符號重新賦值.例如:

EMP=16

EMP=17

EMP=EMP+1

3.2.3段定義語句

前面我們已經(jīng)講過,8086和8088的存儲器的物理地址由段地址和偏移地址組合

而成.程序運行時,程序的指令和變量都存在某個段內(nèi).因此,匯編程序按段來組

織程序和數(shù)據(jù),變量.與段有關(guān)的主要偽操作有SEGMENT;ENDS;ASSUME;ORG.

段定義的格式如下:

segnameSEGMENT

segnameENDS

每個段必須有一個名字,每個段定義由SEGMENT開始,到ENDS結(jié)束,兩者少一不可,

并且其語句中的名字必須相同,否則,匯編程序無法辨認.省下的部分,數(shù)據(jù)段,附

加段和堆棧段來說,一般是變量,符號定義等偽操作,而對于代碼段則是指令及有

關(guān)偽操作.定義段之后,還需要用ASSUME偽操作語句,以確定段和段寄存器的關(guān)

系.其格式為:

ASSUMEseg-reg;segname[,,,,]

其中段寄存器名必須是CS,DS,ES,SS中的一個,而段名是由SEGMENT和ENDS定

義的段中的段名.欲取消前面的ASSUME語句確定的段與段寄存器的關(guān)系,可采

用ASSUMENOTHING語句.例如:

datalSEGMENT

XIDB?

X2DW?

X3DD?

datalENDS

extralSEGMENT

ylDB?

y2DW?

y3DD?

extralENDS

stacklSEGMENT

DW100HDUP(?)

TopEQUTHISWORD;THIS是個運算符,它建立一個新的存儲器地址操作數(shù),

stacklENDS;其地址為匯編時的當(dāng)時值,類型由THIS后的項指定.

CODESEGMENT

ASSUMECS:CODE,DS:datal,ES:extral,SS:stackl

BEGIN:MOVAX,datal

MOVDS,AX

MOVAX,extral

MOVES,AX

MOVAX,syackl

MOVSS,AX

CODEENDS

ENDBEGIN

ASSUME語句確定了短與段寄存器的對應(yīng)關(guān)系,供匯編時使用,而段地址裝入段寄

存器,即段寄存器的賦值,還需要代碼中的MOV指令來完成.不過,碼段寄存器例

外,它是在程序初始化時,由系統(tǒng)程序完成的,不需要也不允許用戶給CS賦值.用

戶程序模塊可以存放在一個或幾個碼段中,根據(jù)需要定.

SEGMENT偽操作還可以增加一些說明,格式如下:

SegnameSEGMENT[align-type][combine-type][,class']

這三種類型說明分別敘述如下:

(1)定位類型(align-type)

PARA該段的起始地址從段的邊界開始,也就是段地址的最低位必定為0(十六進

制數(shù)表示).通常隱含.

BYTE該段可以從任何有效地址開始.

WORD該段的起始地址必須是偶數(shù),即從字的邊界開始.

PAGE該段的起始地址從頁邊界開始,即段地址最低兩個十六進制數(shù)位為0(一頁

為256字節(jié)).

(2)組合類型(combine-type)

PUBLIC規(guī)定連接時該段要和其他具有相同的段名的段連接在一起,形成一個段,

連接的次序在調(diào)用LINK程序時由用戶指定.

COMMON規(guī)定連接時該段和其他同名段具有相同的起始地址.因而產(chǎn)生覆

蓋.COMMON的連接長度是同名段中的最大長度.

ATexpression規(guī)定表達式計算結(jié)果的16位二進制值為段的起始地址.但不能用

于指定代碼段,而用于固定地址的數(shù)據(jù)段,如ROM中的數(shù)據(jù)區(qū),或存儲區(qū)中的向量

表.

STACK規(guī)定該段在運行時是堆棧段的一部分.

MEMORY規(guī)定該段定在所有其他連接段的后面.

(3)類別('class')

它是一個名字,用于連接時組成同名段組.

偽操作指令ORG語句規(guī)定了程序段或數(shù)據(jù)塊在該段內(nèi)的起始地址,其格式為

ORGexpression

其中表達式expression的值即為段內(nèi)的起始地址或偏移地址,從此地址起連續(xù)

存放程序或數(shù)據(jù).

3.2.4過程定義語句

一個過程具有某一種功能,形成獨立的程序塊,它是匯編程序的基本單位.

過程定義的格式如下:

procedure-namePROC

RET

procedure-nameENDP

過程定義的偽操作PROC和ENDP必須成對出現(xiàn).在過程的首尾處,必須有過程名起

頭.過程結(jié)束處往往有RET語句,以返回調(diào)用它的程序處.有時RET語句也可以出

現(xiàn)在過程中間.過程至少有一個入口和出口,以供進入和脫離該程序.

按上面定義,只能在該程序的同一碼段中被調(diào)用.過程應(yīng)賦予FAR的屬性,格式如

下:

procedure-namePROCFAR

procedure-nameENDP

調(diào)用過程和從過程返回有兩種情況:段內(nèi)的和短間的.

段內(nèi)的調(diào)用和返回指令執(zhí)行時,推入堆棧和退出堆棧的僅僅是應(yīng)該返回處的段內(nèi)

的地址偏移量.

段間的調(diào)用和返回指令執(zhí)行時,推入堆棧和退出堆棧的僅僅是應(yīng)該返回處的段地

址和段內(nèi)偏移量.

在定義時,可以用NEAR屬性顯式地表示:

procedure-namePROCNEAR

procedure-nameENDP

3.2.5程序模塊定義

每一個程序模塊的開始,往往要用NAME或TITLE為其取一個名字,模塊結(jié)束,則需

要用END偽操作來告知匯編程序,在遇到END語句時結(jié)束匯編.

NAME的格式為:

NAMEmodule-name

匯編程序把NAME后面的module-name作為模塊的名字,這個名字不允許使用保留

字,可以使用標(biāo)識符.

TIYLE的偽操作,格式是:

TITLEtext

它為清單的每一頁指定打印的標(biāo)題.text

中最多允許60個字符.若無NAME偽操作,則把text

中的前6個字符作為模塊名.若既無NAME又無TITLE偽操作,則就吧源文件名作

為模塊名.

知NAME和TITLE偽操作并不是必須的.

但每個模塊的結(jié)束,必須要有END偽操作,格式為:

END[label]

其中,可選的標(biāo)號指示程序開始執(zhí)行的起始地址。如果若干個個程序??煜嗦?lián)接,

那么只有住程序??煨枰褂脦霕?biāo)號的語句,而其他程序模塊是被調(diào)用的,

不能使用帶入標(biāo)號的語句,只需要。

下面是一個兩個數(shù)差的絕對值的程序。

Titledifference

Datasegment

Dumldw250h

Dum2dwla9h

Resultdw?

Dataends

Codesegment

Assumecs:code,ds:data

Mainprocfar

Start:movax,data

Movds,ax

Movax,numl

Subax,num2

Jnbstore

Negax

Store:movresult,ax

Movah,4ch

Int21h

Mainendp

Codeends

Ends

Endstart

這個有一個程序??旖M成,他從為操作開始,為操作結(jié)束。語句制定了該程

序的入口地址,此入口地址在程序在該程序中正好是第一條執(zhí)行指令的地址,這

個程序丁宜樂了一個數(shù)據(jù)段和一個媽段,碼段中紙包裹一個過程,過程結(jié)束時,

通過調(diào)用的的功能,返回,程序結(jié)束運行。

3.3匯編語言程序設(shè)計程序

第二章介紹了指令系統(tǒng),結(jié)合指令也給出了一些程序段例子,本章的第一二節(jié)由

介紹了紅會變得基本語法和偽指令。有了這些基礎(chǔ)知識,就不難進行匯編語言的

程序設(shè)計。

從下一節(jié)起,介紹匯編語言程序設(shè)計的主要方法。這里次先介紹與匯編語言程序

有關(guān)的問題,以便在程序設(shè)計之前,引起大家的注意,少哦組一些彎路。

3.3.1程序的質(zhì)量標(biāo)準

再編程序時,首先要有一個質(zhì)量觀念,要編制質(zhì)量高的程序,而不僅僅是完成任

務(wù)。在進行學(xué)習(xí)時,要逐步養(yǎng)成良好的編程習(xí)慣。如同寫文章,撰寫的作品千只

百態(tài)一樣,用計算機敘述某個問題,也即編程,同樣千差萬別。衡量程序的質(zhì)量,

通稱有四個標(biāo)準:

(1)程序正確完整;

(2)程序易讀性;

(3)程序的執(zhí)行時間;

(4)程序所占內(nèi)存大小及程序行數(shù)。

其中,第一條是主要的,最基本的。往往有些程序基本功能是正確的,但隱藏著

一些問題,或者在某些情況下執(zhí)行是正確的,而在另外的情況下程序運行的結(jié)果

是不對的。程序的一讀性對軟件的維護和軟件設(shè)計的合作是大有裨益的,因此已

開始就養(yǎng)成良好的編程習(xí)慣,編程思路要清楚,畫一個流程圖,在程序前部隊變

量和算法加以說明,在程序中對有關(guān)語句加上注釋。程序的執(zhí)行時間對于實時處

理的問題環(huán)重要的。程序所占內(nèi)存大小對于復(fù)雜的大程序來說,也不能等閑視之,

而考慮到軟件的開發(fā)成本,程序的語句則是一個很重要的因素。

3.3.2

(1)把實際問題抽象,提煉成數(shù)學(xué)模型。

(2)確定解決該數(shù)學(xué)模型的算法.

(3)程序模塊分析。在分析復(fù)雜的實際問題時,往往需要把它分成若干功能塊,畫

出層次圖,確定各塊間的通信。對于簡單的問題,僅僅一個模塊足以完成其任務(wù),

就無須模塊分析.

⑷畫出模塊程序圖.

⑸分配內(nèi)存工作單元和寄存器.

(6)根據(jù)流程圖編制程序.

(7)上機調(diào)試,進行修改,最后檢測通過.

編制過程的第一步,數(shù)學(xué)抽象,是很重要的一環(huán),它關(guān)系到全局,不可輕視.實際

工作中,因為抽象不準確,以致返工的是屢見不鮮.確定算法亦是關(guān)鍵的一步,它

與程序質(zhì)量的高低密不可分,它決定了程序的復(fù)雜程度和執(zhí)行時間的長短.其后

的模塊分析,編制流程圖和程序,也往往要通過調(diào)試進行相應(yīng)的修正.

3.3.3程序流程圖

程序流程圖是一種算法表達工具,它根據(jù)算法,將結(jié)局問題的思路和方法用字符

和圖形表示出來,確定程序的結(jié)構(gòu)和程序的流向.

對于處學(xué)者,程序流程圖是比不可少的工具.對于熟練的編程者,在編制復(fù)雜的程

序時,仍然少不了流程圖的支持。它便于編制程序,便于調(diào)試程序,有利于減少程

序的錯誤,提高程序效率.

本書的流程圖,采用國際標(biāo)準,它與我國國標(biāo)也是基本一致的。所用主要的符號

如下:

(1)矩形框表示各種處理的功能,框中用簡明的語言表明所完成的處理功能.例

如執(zhí)行一個加法操作.這種處理有一個入口和一個出口,有箭頭表示.

(2)菱形框表示判斷,框內(nèi)表明判斷的條件.它有一個入口,但可以有若干個出

口,分別用箭頭表示。在各個出口處表明該出口的條件,例如條件滿足用y表示,

條件不滿足時用n表示.

(3)特定的方框表示特定處理,通常表示子程序,模塊??騼?nèi)表明程序名或模塊名,

框縱邊為雙數(shù),形如

(4)端點框六邊形表示程序流程的起點,扁圓形框表示程序的終點.

(5)流線帶箭頭的直線,表示程序的流向,它連接程序的各個流程圖,新的圖表

正向流線不帶箭頭,反向流線帶箭頭.

3.4數(shù)據(jù)輸入和輸出

程序通常要對數(shù)據(jù)進行處理,而后輸出結(jié)果.那么所需要的數(shù)據(jù)來自何處?他們可

能;來自:1程序的數(shù)據(jù)段,編程時預(yù)先設(shè)定;2磁盤,數(shù)據(jù)以數(shù)據(jù)文件的形式存在

盤上;3外設(shè),例如A/D轉(zhuǎn)換,把模擬信號轉(zhuǎn)成數(shù)字信號,送入計算機內(nèi)存;4鍵盤

輸入,這里,我們只討論鍵盤輸入的情況,其他的可以參考有關(guān)資料.

-一般高級語言的數(shù)據(jù)輸入輸出多有相應(yīng)的語句或函數(shù)倆處理,而匯編語言無法用

一條指令解決問題,他通過調(diào)用系統(tǒng)功能來完成這個任務(wù).調(diào)用系統(tǒng)功能猶如高

級語言中調(diào)用子程序,它需要先提供實際參數(shù)(又稱入口參數(shù))以及所調(diào)用的功

能號.調(diào)用結(jié)果返回結(jié)果,即可得到出口參數(shù).

3.4.1輸入字符串

從鍵盤上輸入字符串,可以得到一串字符的ASCII.如果是數(shù)字符,通過變換和組

合,就可以得到數(shù)據(jù).

輸入字符串,通過調(diào)用dos功能的Oah號功能來實現(xiàn).它需要一個字符緩沖區(qū),

以便存儲讀入的字符串。緩沖區(qū)的第一個字節(jié)保存字符去長度,它由用戶定義時

給出,不允許超過此限定數(shù).如果輸入的超過次數(shù),系統(tǒng)會拒絕接受,發(fā)出“嘟

嘟”聲,光標(biāo)也不再向右移動.

緩沖區(qū)的第二個字節(jié)是實際鍵入字符的個數(shù),鍵入完成后,系統(tǒng)程序會在那個單

元自動填入鍵入字符的個數(shù),它不是由用戶確定的,它也不包括最后結(jié)束字符串

輸入的回車字符,雖然此回車符還占用字符區(qū)的一個字節(jié).

緩沖區(qū)的的三個字節(jié)起,便是存放字符串的字符區(qū),它按字存放.例如.在數(shù)據(jù)區(qū)

定義了一個緩沖區(qū)BUFFER,字符區(qū)長度為20,可表示如下:

BUFFERDB20

REALENDB?

STRUNGDB20DUP(?)

調(diào)用A號功能的程序段如下:

LEADX,BUFFER;緩沖區(qū)首地址一WX

MOVAH,OAH;調(diào)用功能--aAH

INT21H;調(diào)用DOS的OAH功能

假如程序執(zhí)行時,鍵入字符

Thisisastring

那么,緩沖區(qū)BUFFER中各存儲單元的內(nèi)容如下所示:

其中第一個單元的14H是字符區(qū)長度,第二個單元的10H是實際鍵入字符的個數(shù),

字符區(qū)中是鍵入字符的ASCII串。ODH為回車符。

例從鍵盤上輸入一個字符串,并在串尾處加上字符串結(jié)束標(biāo)志。

;inputastringfromthekeyboard,

;thenwrite'$'attheendofthestring,asamark

?

DATASEGMENT

STRINGDB30,0,30DUP(?)

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

KEYINPROCFAR

BEGINMOVAX,DATA

MOVDS,AX

MOVDS,AX

MOVDX,OFFSETSTRING

MOVAH,OAH

INT21H

MOVCL,STRING+1

XORCH,CH

ADDDX,2

ADDDX,CX

MOVBX,DX

MOVBYTEPTR[BX]

MOVAH,4CH

INT21H

KEYINENDP

CODEENDS

ENDBEGIN

3.4.2輸出字符串

內(nèi)存中的字符傳送到顯示器顯示,可以通過調(diào)用DOS功能的9號功能來實現(xiàn)。該

功能要求被現(xiàn)實的字符串必須是以ASCH碼。例如:

MESSAGEDB'THATISALL,GOODBYE!',13,10,f$'

但是其他的控制碼,不能出現(xiàn)在字符串中。顯示字符串的程序段為:

MOVAH,9

MOVDX,SEGMESSAGE

MOVDS,DX

LEADX,MESSAGE

INT21H

若要顯示數(shù)據(jù),必須先把他們轉(zhuǎn)換成ASCH碼,然后才能調(diào)用DOS的9號功能,

顯示他們。

3.5順序程序設(shè)計

順序城市最常見的,也是最基本的程序設(shè)計方法。這種程序在計算機內(nèi)村種執(zhí)行

時,按照先后次序,逐句順序執(zhí)行。他沒有分支也沒有循環(huán),因此也成為線性程

序。下面是一個例子。

例兩個64位無符號數(shù)相加的程序。

在8086/8088CPU中,數(shù)據(jù)是16位的,他有8位和16位運算指令,但是沒有32

位,64位這種16位以上的運算指令。要進行64位相加運算可以利用16位加法

指令分別相加4次來實現(xiàn)。具體程序如下:

DATASEMENT

NUM1DW1357H,2468H,90BDH,0ACEH

NUM2DW9753H,8264H,0B09DH,OFAEH

SUBNDW5DUP(?)

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

ADD64PROCFAR

BEGIN:MOVAX,DATA

MOVDS,AX

LEABX,NUM1

MOVAX,[BX]

ADDAX,[BX+8]

MOV[BX+1OH],AX

INCBX

INCBX

MOVAX,[BX]

ADCAX,[BX+8]

MOV[BX+1OH],AX

INCBX

INCBX

MOVAX,[BX]

ADCAX,[BX+8]

MOV[BX+1OH],AX

INCBX

INCBX

MOVAX,[BX]

ADCAX,[BX+8]

MOV[BX+1OH],AX

MOVAX,0

ADCAX,0

MOVW[BX+12H],AX

MOVAH,4CH

INT21H;

ADD64ENDP

CODEENDS

ENDBEGIN

3.6分支程序設(shè)計

在程序中,除了最基本的順序結(jié)構(gòu)以外,通常還有各種分支,以滿足不同情況作

不同處理的需要。分支結(jié)構(gòu)有兩種形式,一種是引出兩個分支的,另一種是引出

多個分支的。前者類似于高級語言中的IF——THEN--ELSE語句,后者類似于

高級語言中的CASE語句,分若嘎呢請昂,進行不同的處理。程序在某種條件下

運行時,執(zhí)行其中一個分支。分支結(jié)構(gòu)如圖3—4所示。上述兩種結(jié)構(gòu)分別舉例

如下:

例從鍵盤上輸入兩個整數(shù),并求其和。

通過調(diào)用DOS功能,從鍵盤上輸入整數(shù)該數(shù)是以ASCII碼的形式存在內(nèi)存中的。

因此,需要把它轉(zhuǎn)化成二進制數(shù),在進行加法運算。如果計算機以一個字來表示

一個整數(shù)的話,整數(shù)的范圍應(yīng)在-32768于32767之間程序流程如圖3-5和-6所

/J、.O

DATASEGMENT

STR1DB7,?7DUP(?)

STR2DB7,?7DUP(?)

NUMDW?,?

BUFFERDW0

OVERDB'OVERFLOW!',13,10,'$

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

MAINPROCFAR

START:MOVAX,DATA

MOVDS,AX

MOVAH,OAH

LEAAX,STR1

INT21H

MOVAH,OAH

LEADXSTR2

INT21H

LEABX,STR1

LEADI,NUM

CALLCHANGE

LEABX,STR2

LEADI,NUM+2

CALLCHANGE

MOVAX,NUM

ADDAX,NUM+2

MOVBUFFER,AX

JNONEXT

LEADX,OVER

MOVAH,9

INT21H

NEXT:MOVAH,4CH

INT21H

MAINENDP

CHANGEPROC

MOVCL,[BX+1]

MOVCX,[BX+2]

MOVCH,AL

CMPAL/-<

JNZNEXT1

DECCL

INCBX

NEXT1:ADDBX,2

MOVAX,0

LP1:DECCL

JZNEXT2

MOVDH,0

MOVDL,[BX]

ANDDL,OFH

ADDAX,DX

MOVDX,.AX

ADDAX,AX

ADDAX,AX

ADDAX,DX

INCBX

JMPSHORTLP1

NEXT2:MOVDL,[BX]

ANDDL,OFH

MOVDH,0

ADDAX,DX

CMPCH,'-'

JNZNEXT3

NEGAX

NEXT3:MOV[DI],AX

RET

CHANGEENDP

CODEENDS

ENDSTART

例根據(jù)AL寄存器中的內(nèi)容,把程序轉(zhuǎn)移到不同的程序分支中去。

若AL中的內(nèi)容是1,則轉(zhuǎn)到ROUTINE1去執(zhí)行,若AL中的內(nèi)容是2,則轉(zhuǎn)到

R0UTINE2去執(zhí)行,。。。。。。。。這種設(shè)計發(fā)方法又稱為跳轉(zhuǎn)表法,在程序

設(shè)計中常見到,很有用。例如,以惡程序分成若干個功能塊,每個功能塊實現(xiàn)不

同的功能可以當(dāng)作一個分支程序,根據(jù)不同的情況,執(zhí)行不同的分支,完成相應(yīng)

的功能,之后再返回主程序。

TABLESEGMENT

BRATABLEDWROUTINE1,ROUTINE2,ROUTINES,ROUTINE4,ROUTINES,R0UTINE6

TABLEENDS

CODESEGMENT

ASSUMECS:CODE,DS:TABLE

MAINPROCFAR

BEGINMOVAX,TABLE

MOVDS,AX

MOVCH,6

MOVCL,0

NEXT:INCCL

CMPCL,AL

JZ,GORUN

INCBX

INCBX

DECCH

JNZNEXT

JMPCOUTINE

GORUN:JMPWORDPTR[BX]

ROUTINE1:

R0UTINE2:

ROUTINES:

?????????????,

R0UTINE4:

ROUTINE5:

R0UTINE6:

????????????

ROUTINE:

MOVAH,4CH

INT21H

MAINENDP

CODEENDS

ENDBEGIN

這個程序中,分支標(biāo)的首地址在中BX中,BX作為分支表的指針,分支號在CL

中隨著分支號的增加,BX的內(nèi)容也發(fā)生變化,紙箱下一個分支的地址,因此當(dāng)

AL中的內(nèi)容與CL的內(nèi)容相等時,程序控制就轉(zhuǎn)到BX所致的那個分支去,從哪

兒在繼續(xù)執(zhí)行。各個分支執(zhí)行完后,轉(zhuǎn)向何處,可以有變成者根據(jù)需要來確定。

比如,讓此程序中的各個分支轉(zhuǎn)向CONTINUE,然后在結(jié)束。

3.7循環(huán)程序設(shè)計

循環(huán)程序也是程序的一種基本結(jié)構(gòu)。程序中,往往有的程序段需要重復(fù)執(zhí)行多次,

以實現(xiàn)某種功能,這樣,可以大大簡化程序設(shè)計。循環(huán)程序通常有以下三部分組

成:

1.循環(huán)初始狀態(tài)循環(huán)過程中的工作單元,在循環(huán)開始前,往往要給他們賦初

值,以保證循環(huán)能正常地進行工作。循環(huán)初始狀態(tài)包括循環(huán)工作部分初態(tài)和循環(huán)

部分初態(tài)。例如:設(shè)某些標(biāo)志,懾地址指針。某些寄存器清零,某些變量付出

制,循環(huán)控制寄存器賦初值等等。

2.2o循環(huán)體這是循環(huán)程序重復(fù)執(zhí)行的部分,是循環(huán)的主體。循環(huán)體包括循

環(huán)的工作部分和循環(huán)的修改部分。循環(huán)的工作部分是實現(xiàn)程序功能的程序段,它

是循環(huán)的主要部分。循環(huán)的修改部分是修改部分是修改參加循環(huán)的信息的程序

段,循環(huán)每次執(zhí)行時,有關(guān)信息能發(fā)生信息的相應(yīng)變化,確保循環(huán)程序正常循環(huán)。

3.循環(huán)控制循環(huán)能正常進行和結(jié)束,循環(huán)控制是關(guān)鍵。循環(huán)控制條件不合理,

循環(huán)就無法按正常的預(yù)定進行,甚至導(dǎo)致死循環(huán)。循環(huán)控制條件的選擇很靈活。

如果循環(huán)次數(shù)是確定的,可以選擇循環(huán)次數(shù)作為循環(huán)控制條件。如果循環(huán)次數(shù)未

知,那么可以跟具體情況選擇或其他條件作為控制條件。

循環(huán)程序有兩種結(jié)構(gòu)形式,一種是先執(zhí)行循環(huán)體,然后根據(jù)控制條件進行判斷,

不滿足結(jié)束條件則繼續(xù)循環(huán)操作,滿足條件則退出循環(huán)。這一循環(huán)類似高級語言

中的repeat-until結(jié)構(gòu)。另一類類似while-do結(jié)構(gòu),先檢查是否滿足控制條件,

滿足循環(huán)條件就執(zhí)行循環(huán)體,否則就退出循環(huán)。這兩循環(huán)結(jié)構(gòu)如圖3-7所示。

下面舉例說明。

例在一串?dāng)?shù)中找出其中的最大值和最小值,放在指定的存儲單元中。

尋找最大數(shù)和最小數(shù),可以用逐個比較來發(fā)現(xiàn),這就需要循環(huán)體來執(zhí)行,這一串

數(shù)的個數(shù)是確定的,很能夠想到以他作為循環(huán)控制條件。程序的流程圖如3-8。

通過這個程序,讀者不難確定這些數(shù)的類型和位數(shù)。

循環(huán)可以嵌套,形成多重循環(huán)結(jié)構(gòu)。多重循環(huán)程序設(shè)計的方法與單循環(huán)程序設(shè)計

大致相同。另外應(yīng)該注意的是各種循環(huán)的控制條件及循環(huán)主體不能混淆,交錯,

要層次分明。例如從外層循環(huán)進入內(nèi)層循環(huán)時,等于重新開始一次新的內(nèi)循環(huán),

初始條件等內(nèi)循環(huán)參數(shù)必須重新的設(shè)置。下面,就我們以典型的起泡法分類排序

作為一個例子,加以說明。

例有一個n個子的數(shù)組,要求變成使該數(shù)組的元素按從大到小的次序排列。

起泡算法是這樣實現(xiàn)排序的:從第一個數(shù)開始,依次對相鄰兩個數(shù)輛輛進行比較,

如果大小次序不對,則是這兩個數(shù)交換為止,反之,則不交換。這樣這樣進行了

第一遍比計較,最小的數(shù)被置于隊尾。進行第二遍比較時,只需進行n-2次第三

遍比較,最多比較到nT遍就可以實現(xiàn)程序。

圖3-9是起泡算法的一個示例,圖3-10是其流程圖。

起泡排序的內(nèi)外循環(huán)次數(shù)是已知的外循環(huán)次數(shù)是確定的,為數(shù)組長度減1,既

(n-1),

內(nèi)循環(huán)的次數(shù)安每次減1的的規(guī)律在變化。這種排序算法不管原來排序情況如

何,只要進行nT次比較,總可以達到排序的目的。但實際上,常常不需要比較

n-1次就可以完成排序。因此對算法可以進行改進,一旦完成排序,就不再進行

比較。這里設(shè)立一個標(biāo)志位,如果進行了比較,就該將該標(biāo)志位置1,如果進行

一邊比較后,沒有交換,即該標(biāo)志位仍為零,說明排序已經(jīng)完成,程序可以結(jié)束。

該今后的程序如下:

3.8字程序設(shè)計

解決實際問題時,變成通常都采用模塊化程序設(shè)計方法。這種方法把一個程序分

成多個具有任務(wù)的程序模塊,程序模塊進一步分成獨立的子模塊,分別編成,調(diào)

試,然后連接在一起,形成一個完整的程序。模塊化設(shè)計的程序易于編程,調(diào)試,

修改,程序易讀性強。而子程序結(jié)構(gòu)是模塊化的程序設(shè)計的重要工具。

子程序在匯編語言中又稱為過程,它相當(dāng)于高級語言的過程,函數(shù)或子程序。

它具有獨立的功能,在程序需要的地方可以調(diào)用它。

子程序使用時;要注意寄存器內(nèi)容的保護。由于CPU的寄存器的數(shù)量有限,子程

序使用的寄存器往往會和調(diào)用程序所用得寄存器發(fā)生沖突,破壞了調(diào)用程序中寄

存器的內(nèi)容影響從寄存器返回后的繼續(xù)處理。為了避免這種現(xiàn)象的發(fā)生,應(yīng)當(dāng)在

子程序入口八所用寄存器的內(nèi)容推入堆棧,保存起來,而在退出子程序前恢復(fù)寄

存器的內(nèi)容。

子程序使用中,要解決的一個重要問題是參數(shù)傳頌。在調(diào)用子程序時,經(jīng)常要把

參數(shù)傳送給子程序,子程序在運行以后,也常常要送回一些信息給調(diào)用程序,

報告子程序運行狀態(tài)及結(jié)果等等。這種調(diào)用程序和子程序之間的信息傳送,成

為參數(shù)傳頌,也稱為變量傳送或者過程通信。

參數(shù)傳送可以通過以下幾種渠道進行:寄存器,變量,地指表,堆棧等,下面分

別舉例說明。

3.8.1寄存器傳送參數(shù)

例把十進制ASCII字符轉(zhuǎn)換為壓縮的BCD碼數(shù)。

通常,從鍵盤上輸入的十進制數(shù)字是ASCH字符,每個數(shù)值以逗號或分號間隔,

最后一回車結(jié)束。這里假定輸入的均是4位數(shù),轉(zhuǎn)換框圖如圖3T1程序如下:

DATASEGMENT

STRINGGB'12345678998123605031',13

ERRORDB'ERROR!',13,10,'$'

BUFERDB10DUP(?)

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

MAIN:PROCFAR

BEGIN:MOVAX,DATA

MOVDS,AX

LEABX,STRING

LEADI,BUFFER

LP:MOVAH,[BX]

INCBX

CMPAX,'O'

JBNEXT1

CMPAH'9'

JANEXT1

MOVAL,[BX]

INCBX

CMPAL,'O'

JBNEXT2

CMPAL,'9'

JANEXT2

LP1:CALLSPE1

MOV[DI],AH

INC,DI

JMPLP

NEXT1:CMPAH,''

JZLP

CMPAH,'

JZLP

CMPAH,13

JZDONE

NEXT2:LEADX,ERROR

MOVAH,9

INT21H

DONE:MOVAH,4CH

INT21H

MAINENDP

SPE1PROC

ANDAH,OFH

MOVCL,4

SHLAH,CL

ANDAL,OFH

ORAH,CL

RET

SPE1ENDP

CODEENDS

ENDBEGIN

在主程序中,得到要轉(zhuǎn)換的ASCH符通過AX寄存器傳到子程序中,子程序完成

轉(zhuǎn)換后,結(jié)果存在寄存器AH中,參數(shù)結(jié)果又通過寄存器返回主程序,在傳送參

數(shù)少的時候,利用寄存器完成參數(shù)傳送是最方便,最快捷的。

3.8.2利用變量傳送參數(shù)

例確定字符串長度,并顯示長度值。

字符串的長度不同于常用的整數(shù),系統(tǒng)并不規(guī)定于一個定值,在對字符串進行操

時,往往需要確定它的長度。字符串常常以回車符CR或者美元符$作為結(jié)束標(biāo)志,

因此,

從頭開始搜索字符串的結(jié)束標(biāo)志,統(tǒng)計搜索字符的個數(shù),便可以得到串長。

這里,假定串長最大不超過255。如果找不到串結(jié)束標(biāo)志,以至串長超過255,

程序

不再繼續(xù)搜索,而給出提示信息。正常時,通過DOS功能調(diào)用,顯示串長度。圖

3-12是其

流程圖。其程序如下:

DATASEGMENT

STRINGDB'Thisisastring:',13,'$'

LENGTH1DW?

CRDB13

MESSAGEDB'Thisistoolong!'

DB13,10,'$'

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

MAINPROCFAR

BEGINMOVAX,DATA

MOVES,AX

MOVDS,AX

CALLSTRLEN;確定字符串長度

MOVDX,LENGTH1

CMPDX,1OOH

JBNEXT1;如(DX)<1OOH,

;轉(zhuǎn)去EXT1

LEADX,MESSAGE;如(DX)>=100H,顯示提示信息

MOVAH,9

INT21H

JMPNEXT2

NEXT1:MOVDH,DL;串長暫存在DH

MOVCL,4

SHRDL,CL;取串長高4位

CMPDL,9

JBELP

ADDDL,7

LP:ADDDL,30H;DL中的高4位變?yōu)锳SCH

MOVAH,6

INT21H;顯示這個ASCII符

MOVDL,DH

ANDDL,0FH

CMPDL,9

JBELP1

ADDDL,7

LP1:ADDDL,30H;DL中的低4位變?yōu)锳SCH

MOVAH,6

INT21H;顯示該ASCH符

MOVDL,'H'

MOVAH,6

INT21H

NEXT2:MOVAH,4CH

INT21H

MAINENDP

STRLENPROC

LEADI,STRING

MOVCX,OFFFFH;(CX)=-l

MOVAL,CR;(AL)=13

MOVAH,'$';(AH)='$'

CLD

AGAIN:INCCX;串長加1

CMPCX,100H

JAEDONE;串長超過255,則結(jié)束

CMP[DI],AH

JEDONE;遇'$'則結(jié)束

SCASB;搜索回車

JNEAGAIN;沒找到,返回繼續(xù)

DONE:MOVLENGTH1,CX

RET

STRLENENDP

CODEENDS

ENDBEGIN

這個程序中,主程序和子程序直接訪問模塊中的變量,通過變量,實現(xiàn)調(diào)用程序

和子

程序之間的參數(shù)傳送。

3.8.3利用地址表傳送參數(shù)

這種傳送參數(shù)的辦法是建立一張地址表,把要傳給子程序的參數(shù)存放在地址表

中,調(diào)

用程序把地址表的首地址通過寄存器傳給子程序。子程序從該地址表獲得所需參

數(shù),也把

結(jié)果存入指定的存儲單元。下面是利用這種方法傳送參數(shù)的例子。

例求一個字符串的ASCII碼的和。

DATASEGMENT

STRINGDB'Thisisastring!),13

LENGTH1DB17

SUMDW?

TABLEDW3DUP(?);保留3個參數(shù)地址

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

MAINPROCFAR

START:MOVAX,DATA

MOVDS,AX

MOVTABLE,OFFSETSTRING

MOVTABLE+2,OFFSETLENGTH1

MOVTABLE+4,OFFSETSUM

LEABX,TABLE

CALLFINDSUM

MOVAH,4CH

INT21H

MAINENDP

FINDSUMPROC

PUSHAX

PUSHCX

PUSHSI

PUSHDI

MOVSI,[BX]

MOVDI,[BX+2]

MOVCL,[DI]

MOVDI,[BX+4]

MOVAX,0

MOVCH,AL

AGAIN:ADDAL,[SI]

ADCAH,0

INCSI

LOOPAGAIN

MOV[DI],AX

POPDI

POPSI

POPCX

POPAX

RET

FINDSUMENDP

CODEENDS

ENDSTART

3.8.4利用堆棧傳送參數(shù)

這種方法是在調(diào)用程序內(nèi)把參數(shù)或參數(shù)地址保存到堆棧中,而在子程序里從堆棧

取出參數(shù)或參數(shù)地址,從而實現(xiàn)參數(shù)傳送。請看下面的例子。

例從一個字符串中刪去一個字符。

相應(yīng)的程序如下:

DATASEGMENT

STRINGDB'

LENGTH1DW$-STRING

KEYDB'x';這是某個將從串中刪去的字符

DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATA

MAINPROCFAR

START:MOVAX,DATA

MOVDS,AX

MOVES,AX

LEABX,STRING

LEACX,LENGTH1

PUSHBX

PUSHCX;STRING和LENGTH1地址入棧

MOVAL,KEY

CALLDELCHAR;調(diào)用刪一個字符子程序

MOVAH,4CH

INT21H

MAINENDP

DELCHAPROC

PUSHBP;保存BP

MOVBP,SP;BP指向當(dāng)前棧頂

PUSHSI

PUSHDI

PUSHCX

CLD

MOVSI,[BP+4];得到LENGTH1地址

MOVCX,[SI];得到長度

MOVDI,[BP+6];得到STRING地址

REPNESCASB;重復(fù)搜索該字符

JNEDONE;沒找到,退出

MOVSI,[BP+4

溫馨提示

  • 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)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論