5.1 顺序程序设计
从键盘获取一个字节
- 说明:存入AL
- 代码
MOV AH, 01H INT 21H
输出一个字节
- 说明:输出DL的对应ASCII值
- 代码
MOV DL, * MOV AH, 02H INT 21H
输出字符串
- 说明:输出偏移地址存入DX
代码
MOV DX, OFFSET LABLE MOV AH, 09H INT 21H
5.2 分支程序设计
CMP的详细解释
ZF标志位
- ZF = 1:DST = SRC
- ZF = 0:DST != SRC
CF标志位(无符号数)
- CF = 0 且 ZF = 0:DST > SRC
- CF = 1:DST < SRC
OF标志位(带符号数)
- OF = 0 且 SF = 0:DST > SRC
- OF = 0 且 SF = 1:DST < SRC
- OF = 1 且 SF = 0:DST < SRC
- OF = 0 且 SF = 1:DST > SRC
单标志条件转移指令
- JC/JNC
- JZ/JNZ:结果为0/不为0
- JS/JNS:结果为负/为正
无符号数条件转移指令
- JA/JNBE:A > B
- JAE/JNB:A >= B
- JB/JNAE:A < B
- JBE/JNA:A <= B
带符号数条件转移指令
- JG/JNLE:A > B
- JGE/JNL:A >= B
- JL/JNGE:A < B
- JLE/JNG:A <= B
CX寄存器条件转移指令
- JCXZ/JECX:CX/ECX = 0 时转移
- OF = 0 的情况比较方便记忆,OF = 1的情况可以相反记忆
- JS是值为负时转移,应当特别关注
SET*条件设置指令
跳转表
- 方式:标号 + 跳转指令
- 重要代码
MOV AH, 0H SHL AX, 1 ADD AX, OFFSET TABLE JMP AX
5.3 循环程序结构
核心思想:Do - While
循环控制指令
- LOOP/LOOPW/LOOPD:CX不等于0,继续循环
- LOOPE/LOOPZ:CX不等于0且ZF等于1,继续循环
- LOOPNE/LOOPNZ:CX不等于0且ZF等于0,继续循环
串操作指令
要求
- 源操作数存放在 DS:[SI] 中,目的操作数存放在 ES:[DI] 中(相对重要)
- DF = 0 为自动增量,反之为自动减量
- 重复次数保存在CX中
重复前缀指令
- 指令:REP
- 适用指令:MOVS/STOS/LODS/INS/OUTS
- 作用:使串操作能重复进行
- 指令:REPZ/REPE
- 适用指令:CMPS/SCAS
- 作用:CX != 0 且 ZF = 1 时重复操作
- 指令:REPNZ/REPNE
- 适用指令:CMPS/SCAS
- 作用:CX != 0 且 ZF = 0 时重复操作
- 指令:REP
串传送
- 指令:MOVS
- 功能:将DS:[SI]中存放的数据传入 ES:[DI],并将SI、DI分别移动一个 字节/字/双字
- 注意点:该指令的操作数可以同为内存操作数,偏移寄存器的移动方向由DF决定
串存储
- 指令:STOS
- 功能:将AL/AX/EAX内容存入ES:[DI]中,并将DI移动一个 字节/字/双字
- 注意点:重复操作时,将AL/AX/EAX 存入一个长度为CX的缓冲区中
串装入
- 指令:LODS
- 功能:将DS:[SI] 中的内容存入AL/AX/EAX,并将SI移动一个 字节/字/双字
- 注意点:一般不与REP联用,若联用,其实只装入串末尾,CX变为串长
串比较
- 指令:CMPS
- 功能:DS[SI] - ES:[DI],并将SI、DI分别移动一个 字节/字/双字
串搜索
- 指令:SCAS
- 功能:AL/AX/EAX - DST,并将DI移动一个 字节/字/双字
- 注意点:一般都与REPE/REPZ联用,CX存放搜索空间长度
串输入
- 适用型号:80386以上
- 指令:INS
- 功能:将DX端口号所指空间的一个 字节/字/双字 送入ES:[DI],并自增DI
串输出
- 适用型号:80386以上
- 指令:OUTS
- 功能:将ES:[DI]所指内存的一个 字节/字/双字 送入DX端口,并自增DI
常用初始化指令:CLD/STD(设置DF的值)
例题经典部分
巧妙解决上述问题只有两个偏移地址寄存器
XCHG BX, DI STOSW XCHG BX, DI
输出一个两位数(原值存放在BX中)
MOV AX, BX MOV BL, 10 DIV BL ;因为是两位数,所以不需要DX ;先输出十位数,存放在AL中 MOV BH, AH ;保存余数 MOV DL, AL MOV AH, 2 OR DL, 30H INT 21H ;输出个位数,现存放在BH中 MOV DL, BH OR DL, 30H INT 21H
注:DI/SI 名字的含义值得深思
值得关注的例题
把寄存器EBX中的二进制以十六进制的形式显示
START: MOV EBX 11AA22BBH MOV CH, 8 ;8位十六进制数,每次处理一位,共8次 ROTATE: MOV CL, 4 ROL EBX, CL ;循环移动,每次将最高位移动到最低位 MOV AL, BL AND AL, 0FH ADD AL, 30H CMP AL, 39H JBE DISP ADD AL, 7
将字变量X转换为十进制输出(逐个输出)
DATA SEGMENT DIV1 DW 10000,1000,100,10,1 DATA ENDS CODE SEGMENT ASSUME:CS:CODE, DS:DATA START: MOV AX, DATA MOV DS, AX MOV AX, X MOV CX, 5 MOV SI, OFFSET DIV1 REP1: XOR DX, DX DIV WORD PTR [SI] PUSH DX ;保存余数 OR AL, 30H MOV DL, AL MOV AH, 2 INT 21H INC SI INC SI POP AX ;将余数存入AX LOOP REP1 MOV AX, 4C00H INT 21H CODE ENDS END START
注:关键代码是循环,但机械化的循环5次会有多余的0输出
将字变量X转换为十进制输出(一起输出)
REP1: XOR DX, DX MOV BX, 10 DIV BX OR DL, 30H PUSH DX LOOP REP1 MOV CX, 5 REP2: POP DX MOV AH, 2 INT 21H LOOP REP2
连接三个字符串
MOV DI, OFFSET BUFF LP1: MOV BX, LEN SUB BX, 2 CMP DI, BX JZ DEL_END ;输出字符串 CMP WORD PTR[DI], 0A0DH JNZ CONTINUE ;不是回车换行就继续查找 PUSH DI MOV SI, DI INC SI INC SI ;跳过换行 MOV CX, LEN SUB CX, DI ;计算移动总长度 CLD REP MOVSB ;将DS/ES定义在同一个DATA段,巧用SI/DI MOV AX, LEN SUB AX, 2 POP DI ;巧妙的承接,递增了DI CONTINUE: INC DI JMP LP1
注:不足为也删除了空格
将字节变量BUFFER中的10个压缩的BCD码转换成非压缩的BCD码存入RESULT中
... LEA SI, BUFFER LEA DI, RESULT MOV CX, 10 L1: MOV DL, [SI] MOV AL, DL PUSH CX MOV CL, 4 SHR AL, CL ;右移一个BCD码 POP CX MOV [DI], AL ;存入高位BCD码 INC DI AND DL, 0FH ;高位清零 MOV [DI], DL ;存入低位BCD码 INC DI INC SI LOOP L1