一、循環(huán)是一種特殊的轉(zhuǎn)移流程,當(dāng)滿足(或不滿足)某條件時(shí),反復(fù)執(zhí)行一系列操作,直到不滿足(或滿足)條件為止。循環(huán)流成的條件一般都是循環(huán)計(jì)數(shù),在程序中用循環(huán)計(jì)數(shù)來控制循環(huán)次數(shù)。
LOOP LABEL ;CX←CX-1;若CX≠0,循環(huán):IP←IP+位移量;否則,順序執(zhí)行
LOOPZ/LOOPE LABEL ;CX←CX-1;若CX≠0且ZF=1,循環(huán):IP←IP+位移量;否則,順序執(zhí)行
LOOPNZ/LOOPNE LABEL ;CX←CX-1;若CX≠0且ZF=0,循環(huán):IP←IP+位移量;否則,順序執(zhí)行
LOOP指令首先將計(jì)數(shù)值CX減1,然后判斷計(jì)數(shù)值CX是否為零。CX不為0,則繼續(xù)執(zhí)行循環(huán)體內(nèi)的指令;CX等于0,表示循環(huán)結(jié)束,于是程序退出循環(huán),順序執(zhí)行后面的指令。LOOPZ和LOOPNZ指令中油要求同時(shí)ZF為1或0才能循環(huán),用于判斷結(jié)果是否為零或相等,以便提前結(jié)束循環(huán)。循環(huán)指令中的操作數(shù)LABEL采用相對尋址方式,表示循環(huán)的目標(biāo)地址,是一個(gè)8位位移量。循環(huán)指令不影響標(biāo)志。
例17-1:在字節(jié)數(shù)組中找出第一個(gè)非零元素,并顯示輸出第一個(gè)非零元素的下標(biāo)。
NAME LI17-1.ASM
DATA SEGMENT
ARRAY DB 0,0,0,7,0,0,4,34,25,30
COUNT EQU $-OFFSET ARRAY
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
BEGIN: MOV AX,DATA
MOV DS,AX
MOV CX,COUNT
MOV DI,0FFFFH
NEXT: INC DI
CMP ARRAY[DI],0
LOOPZ NEXT
JNE OKENTRY
MOV DL,'0'
JMP DISPLAY
OKENTRY:MOV DX,DI
OR DL,30H
DISPLAY:MOV AH,02H
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END BEGIN
例17-2:求兩個(gè)一維字?jǐn)?shù)組的和,數(shù)組元素個(gè)數(shù)為N,當(dāng)計(jì)算到兩個(gè)數(shù)組對應(yīng)元素之和為零時(shí)就停止求和(假設(shè)數(shù)組元素為無符號二進(jìn)制數(shù))。
NAME LI17-2.ASM
DATA SEGMENT
ARRAY1 DW 23,34,4,5,66,76,0,345,567,23,12,67
ARRAY2 DW 34,24,3,2,44,79,0,345,56,43,21,567
N EQU $-OFFSET ARRAY2
SUM DW 15 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE
BEGIN: MOV AX,DATA
MOV DS,AX
MOV AX,0
MOV SI,0FFFEH
MOV CX,N
SHR CX,1
NOZERO: INC SI
INC SI
MOV AX,ARRAY1[SI]
ADD AX,ARRAY2[SI]
MOV SUM[SI],AX
LOOPNZ NOZERO
JNZ L
MOV DL,'Y'
JMP Q
L: MOV DL,'N'
Q: MOV AH,02H
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END BEGIN
二、子程序指令
程序中有些部分可能要實(shí)現(xiàn)相同的功能,而且這些功能需要用到,用子程序?qū)崿F(xiàn)這個(gè)功能是很適合的。子程序通常是與主程序分開的、完成特定功能的一段程序。當(dāng)主程序(調(diào)用程序)需要執(zhí)行這個(gè)功能時(shí),就可以調(diào)用該子程序(被調(diào)用程序);于是,程序轉(zhuǎn)移到這個(gè)子程序的起始處執(zhí)行。當(dāng)運(yùn)行完子程序后,再返回調(diào)用它的主程序。子程序由主程序執(zhí)行子程序調(diào)用指令CALL來調(diào)用;而子程序執(zhí)行完后用子程序返回指令RET,返回主程序繼續(xù)執(zhí)行。CALL和RET指令均不影響標(biāo)志位。
1、子程序調(diào)用指令CALL
CALL指令用在主程序中,實(shí)現(xiàn)子程序的調(diào)用。子程序和主程序可以在同一個(gè)代碼段內(nèi),也可以在不同段內(nèi)。類似無條件轉(zhuǎn)移JMP指令,子程序調(diào)用CALL指令也可以分成段內(nèi)調(diào)用(近調(diào)用)和段間調(diào)用(遠(yuǎn)調(diào)用);同時(shí),CALL目標(biāo)地址也可以采用直接尋址或間接尋址方式。但是,子程序執(zhí)行結(jié)束時(shí)要返回的,所以,CALL指令不僅要同JMP指令一樣改變CS:IP以實(shí)現(xiàn)轉(zhuǎn)移,而且還要保留下一條要執(zhí)行指令的地址,以便返回時(shí)重新獲取它。保護(hù)CS:IP值的方法是壓入堆棧,獲取CS:IP值的方法就是彈出堆棧。
CALL指令的4種格式:
CALL LABEL ;段內(nèi)調(diào)用,直接尋址:SP←SP-2,SS:[SP]←IP,IP←IP+16位位移量
CALL R16/M16 ;段內(nèi)調(diào)用,間接尋址:SP←SP-2,SS:[SP]←IP,IP←R16/M16
CALL FAR PTR LABEL ;段間調(diào)用,直接尋址:SP←SP-2,SS:[SP]←CS,SP←SP-2,SS:[SP]←IP
;IP←LABEL偏移地址,CS←LABEL段地址
CALL FAR PTR MEM ;段間調(diào)用,間接尋址:SP←SP-2,SS:[SP]←CS,SP←SP-2,SS:[SP]←IP
;IP←[MEM],CS←[MEM+2]
根據(jù)過程偽指令,匯編程序可以自動(dòng)確定是段內(nèi)還是段間調(diào)用,同時(shí)可以采用NEAR或FAR偽指令強(qiáng)制成為近調(diào)用或遠(yuǎn)調(diào)用。
2、子程序返回指令RET
子程序執(zhí)行完后,應(yīng)返回主程序中繼續(xù)執(zhí)行,這一功能由RET指令完成。要回到主程序,只要能獲得離開主程序時(shí),由CALL指令保存于堆棧的指令地址即可。根據(jù)子程序與主程序是否同處于一個(gè)段內(nèi),返回指令分為段內(nèi)返回和段間返回。
RET指令的4種格式如下:
RET ;無參數(shù)段內(nèi)返回:IP←SS:[SP],SP←SP+2
RET I16 ;有參數(shù)段內(nèi)返回:IP←SS:[SP],SP←SP+2,SP←SP+I16
RET ;無參數(shù)段間返回:IP←SS:[SP],SP←SP+2,CS←SS:[SP],SP←SP+2
RET I16 ;有參數(shù)段間返回:IP←SS:[SP],SP←SP+2,CS←SS:[SP],SP←SP+2,SP←SP+I16
盡管段內(nèi)返回和段間返回具有相同的匯編助記符,但匯編程序會(huì)自動(dòng)產(chǎn)生不同的指令代碼;也可以分別采用RETN和RETF表示段內(nèi)和段間返回。返回指令還可以帶有一個(gè)立即數(shù)I16,則堆棧指針SP將增加,即SP←SP+I16。這個(gè)特點(diǎn)使得程序可以方便的廢除若干執(zhí)行CALL指令以前入棧的參數(shù)。