分类:
2005-09-13 16:08:10
一、循环是一种特殊的转移流程,当满足(或不满足)某条件时,反复执行一系列操作,直到不满足(或满足)条件为止。循环流成的条件一般都是循环计数,在程序中用循环计数来控制循环次数。
LOOP LABEL ;CX←CX-1;若CX≠0,循环:IP←IP+位移量;否则,顺序执行
LOOPZ/LOOPE LABEL ;CX←CX-1;若CX≠0且ZF=1,循环:IP←IP+位移量;否则,顺序执行
LOOPNZ/LOOPNE LABEL ;CX←CX-1;若CX≠0且ZF=0,循环:IP←IP+位移量;否则,顺序执行
LOOP指令首先将计数值CX减1,然后判断计数值CX是否为零。CX不为0,则继续执行循环体内的指令;CX等于0,表示循环结束,于是程序退出循环,顺序执行后面的指令。LOOPZ和LOOPNZ指令中油要求同时ZF为1或0才能循环,用于判断结果是否为零或相等,以便提前结束循环。循环指令中的操作数LABEL采用相对寻址方式,表示循环的目标地址,是一个8位位移量。循环指令不影响标志。
例17-1:在字节数组中找出第一个非零元素,并显示输出第一个非零元素的下标。
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:求两个一维字数组的和,数组元素个数为N,当计算到两个数组对应元素之和为零时就停止求和(假设数组元素为无符号二进制数)。
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
二、子程序指令
程序中有些部分可能要实现相同的功能,而且这些功能需要用到,用子程序实现这个功能是很适合的。子程序通常是与主程序分开的、完成特定功能的一段程序。当主程序(调用程序)需要执行这个功能时,就可以调用该子程序(被调用程序);于是,程序转移到这个子程序的起始处执行。当运行完子程序后,再返回调用它的主程序。子程序由主程序执行子程序调用指令CALL来调用;而子程序执行完后用子程序返回指令RET,返回主程序继续执行。CALL和RET指令均不影响标志位。
1、子程序调用指令CALL
CALL指令用在主程序中,实现子程序的调用。子程序和主程序可以在同一个代码段内,也可以在不同段内。类似无条件转移JMP指令,子程序调用CALL指令也可以分成段内调用(近调用)和段间调用(远调用);同时,CALL目标地址也可以采用直接寻址或间接寻址方式。但是,子程序执行结束时要返回的,所以,CALL指令不仅要同JMP指令一样改变CS:IP以实现转移,而且还要保留下一条要执行指令的地址,以便返回时重新获取它。保护CS:IP值的方法是压入堆栈,获取CS:IP值的方法就是弹出堆栈。
CALL指令的4种格式:
CALL LABEL ;段内调用,直接寻址:SP←SP-2,SS:[SP]←IP,IP←IP+16位位移量
CALL R16/M16 ;段内调用,间接寻址:SP←SP-2,SS:[SP]←IP,IP←R16/M16
CALL FAR PTR LABEL ;段间调用,直接寻址:SP←SP-2,SS:[SP]←CS,SP←SP-2,SS:[SP]←IP
;IP←LABEL偏移地址,CS←LABEL段地址
CALL FAR PTR MEM ;段间调用,间接寻址:SP←SP-2,SS:[SP]←CS,SP←SP-2,SS:[SP]←IP
;IP←[MEM],CS←[MEM+2]
根据过程伪指令,汇编程序可以自动确定是段内还是段间调用,同时可以采用NEAR或FAR伪指令强制成为近调用或远调用。
2、子程序返回指令RET
子程序执行完后,应返回主程序中继续执行,这一功能由RET指令完成。要回到主程序,只要能获得离开主程序时,由CALL指令保存于堆栈的指令地址即可。根据子程序与主程序是否同处于一个段内,返回指令分为段内返回和段间返回。
RET指令的4种格式如下:
RET ;无参数段内返回:IP←SS:[SP],SP←SP+2
RET I16 ;有参数段内返回:IP←SS:[SP],SP←SP+2,SP←SP+I16
RET ;无参数段间返回:IP←SS:[SP],SP←SP+2,CS←SS:[SP],SP←SP+2
RET I16 ;有参数段间返回:IP←SS:[SP],SP←SP+2,CS←SS:[SP],SP←SP+2,SP←SP+I16
尽管段内返回和段间返回具有相同的汇编助记符,但汇编程序会自动产生不同的指令代码;也可以分别采用RETN和RETF表示段内和段间返回。返回指令还可以带有一个立即数I16,则堆栈指针SP将增加,即SP←SP+I16。这个特点使得程序可以方便的废除若干执行CALL指令以前入栈的参数。