分享

汇编(十七)——控制转移类指令三

 shamo9966 2015-09-29
环指令,子程序指令

一、循环是一种特殊的转移流程,当满足(或不满足)某条件时,反复执行一系列操作,直到不满足(或满足)条件为止。循环流成的条件一般都是循环计数,在程序中用循环计数来控制循环次数。
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指令以前入栈的参数。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多