文章目录
8086汇编复习手册
声明 : 本文全部内容的背景均为8086平台;文中代码基本都经实际验证过。文章内容均个人(PGZXB pgzxb@qq.com)整理,未经校正,欢迎勘误!
8086平台基础
大小端
- 8086平台为小端机, 即低字节存放在低地址, 高字节存放在高地址
寄存器
-
通用寄存器
(1) 数据寄存器
AX: 累加器, 所有的I/O指令都使用累加器与外设接口传送信息;
BX: 基址寄存器, 可用来存放偏移地址;
CX: 计数寄存器, LOOP指令用作计数器;
DX: 数据寄存器;
注: DX和AX常用来作为整体存放32位数, 高位存在DX, 低位存在AX (MUL指令、CWD指令)。
(2) 地址指针寄存器
SP: 堆栈指针寄存器,指向堆栈的栈顶;
BP: 基址指针寄存器,通常是与SS寄存器配对使用。
(3)变址寄存器
SI: 源变址寄存器。
DI: 目的变址寄存器。
它们常常在处理数组(或串)中作为索引(Index)。
注意: 通用寄存器是通用的,都可用来存放普通数据(地址寄存器存个数字也是可以的),但以上三类每一类寄存器都专有用途。
-
段寄存器
CS: 代码段寄存器, 指令存放在代码段内
SS: 堆栈段寄存器, PUSH, POP
DS: 数据段寄存器, 变量(常量)一般都定义于数据段
ES: 附加段寄存器, 不常用,串指令用到过
存放段基地址, 即段起始地址的高16位。
-
注意事项
- CS不能被指令修改
- 只有BX, BP, SI, DI能当作地址寄存器被使用, SP能作地址寄存器但是不能被使用(修改)
- 不是地址寄存器的寄存器也可以用来存地址(所谓地址只是16位无符号数而已), 只不过不能用来寄存器寻址、寄存器相对寻址、基址变址寻址、相对基址变址寻址(总之就是用寄存器存地址的寻址方式都不能)
- BP默认段寄存器是SS, 其他默认均为DS
标志位
- 注意: 标志位设置和指令有关, 当指令要求与一般规律冲突时, 以指令要求为准.
标志名 | 英文简称 | 标志表示 1/0 | 标志位设置的一般规律 |
---|---|---|---|
溢出 | OF | OV/NV | 正 + 正 得 负 时为1 负 + 负 得 正 时为1 正 - 负 得 负 时为1 负 - 正 得 正 时为1 |
方向 | DF | DN/UP | |
中断 | IF | EI/DI | |
符号 | SF | NG/PL | 符号位为1时为1 符号位为0时为0 |
零 | ZF | ZR/NZ | 运算结果为0时为1 |
辅助进位 | AF | AC/NA | |
奇偶 | PF | PE/PO | 结果最后一个字节 二进制形式1的个数 为偶数时为1, 反之为0 |
进位 | CF | CY/NC | 最高位有进位(借位)时为1, 反之为0 |
-
标志位的设置总结(每条指令的标志位的设置查看指令速查表):
-
数据传送类指令除了标志寄存器传送指令均不影响标志位
-
INC, DEC不影响CF, 其他标志位的设置按一般规律
-
加减法指令除了INC, DEC设置标志位均按一般规律
-
乘法指令如果乘积结果的高一半为0则设置CF=OF=0, 否则设置CF=OF=1. 乘法指令对于CF和OF以外的标志位设置无定义(无定义不意味不影响)
-
除法指令对所有标志位的设置均无定义
-
NOT指令不影响标志位
-
除NOT以外的逻辑指令(& | ^ TEST)设置CF=OF=0, AF无定义, 其他标志位的设置按一般规律
-
移位指令对标志位的设置比较复杂
- 移位指令都会影响CF, 影响方式如下图
-
移位指令只有当CNT为1时才会设置OF, 高位变换OF=1, 否则OF=0
-
循环移位指令不影响除CF,OF以外的标志位
-
循环移位以外的移位指令对AF无定义, 其他标志位的设置按一般规律
-
串传送 MOVSB / MOVSW不影响条件码。
-
存串 STOSB / STOSW 不影响条件码。
-
取串LODSB / LODSW不影响条件码。
-
串比较 CMPSB / CMPSW 对条件码的影响 : 看书
-
串扫描 SCASB / SCASW对条件码的影响 : 看书
-
寻址方式及其使用和注意事项
- 寻址方式一共七种
- 立即寻址方式
- 寄存器寻址方式
- 直接寻址方式
- 寄存器间接寻址方式
- 寄存器相对寻址方式(常用于处理数组)
- 基址变址寻址方式
- 相对基址变址寻址方式
寻址方式 | 示例 | 注意事项 |
---|---|---|
立即寻址方式 | MOV AX, 10H | |
寄存器寻址方式 | MOV AX, BX | |
直接寻址方式 | MOV AX, [2000H] | |
寄存器间接寻址方式 | MOV AX, DS:[BX] | only BX BP SI DI |
寄存器相对寻址方式 | MOV AX, ARR[SI] MOV AX, [ARR + SI] |
only BX BP SI DI |
基址变址寻址方式 | MOV AX, [BX][DI] | 基址寄存器 : BX BP 变址寄存器 : SI DI |
相对基址变址寻址方式 | MOV AX, ARR[BX][DI] MOV AX, ARR[BX + DI] MOV AX, [ARR + BX + DI] |
基址寄存器 : BX BP 变址寄存器 : SI DI |
8086对段寄存器使用的约定
序号 | 内存访问类型 | 默认段寄存器 | 可重设的段寄存器 | 段内偏移地址来源 |
---|---|---|---|---|
1 | 取指令 | CS | 无 | IP |
2 | 堆栈操作 | SS | 无 | SP |
3 | 串操作之源串 | DS | ES、SS | SI |
4 | 串操作之目标串 | ES | 无 | DI |
5 | BP用作基址寻址 | SS | ES、DS | 按寻址方式计算得有效地址 |
6 | 一般数据存取 | ES | ES、SS | 按寻址方式计算得有效地址 |
注: 除BP外其他可用来当地址寄存器的默认段均为DS
8086汇编模板(熟练记忆, 考试要写)
DATA SEGMENT ; 数据段, 对应DS段, 习惯将变(常)量定义于此
DATA ENDS ; ENDS : END of SEGMENT
CODE SEGMENT ; 代码段
ASSUME DS: DATA, CS: CODE ; 声明DATA段是DS段, CODE段是CS段
;; 一般在这里定义函数
;; 示例:
;;;; FUNC PROC ; FUNC是函数名
;;;; ;; 函数代码
;;;; RET ; return
;;;; FUNC ENDP
START: ; 程序从这里开始执行
; 手动设置DS的值
MOV AX, DATA
MOV DS, AX
; 写自己的代码
;
; 调用DOS中断返回DOS
MOV AH, 4CH
INT 21H
CODE ENDS
END START
8086汇编指令速查表
指令 | 作用 | 对标志位的影响 | 备注 |
---|---|---|---|
MOV | MOV 1, 2 将2的内容移到1 |
不影响 | 不能直接MOV立即数到段寄存器 不能修改CS寄存器 两个操作数不能都是内存(CMP, XCHG也是) |
PUSH | 入栈 | 不影响 | 只能操作字; 不能搞立即数 |
POP | 出栈 | 不影响 | 只能操作字; 不能搞立即数 |
XCHG | 交换两个的值 | 不影响 | 两个操作数不能都是内存 两个操作数必须有一个在寄存器中 操作数不能使用段寄存器 两个操作数类型要匹配 |
IN | 输入 | 不影响 | 仅限于AX,AL传送信息 用法: IN AL, PORT(字节) IN AX, PORT(字节) IN AL, DX(字节) IN AX, DX(字) |
OUT | 输出 | 不影响 | 仅限于AX,AL传送信息 用法: OUT PORT, AL(字节) OUT PORT, AX(字节) OUT DX, A(字节)L OUT DX, AX(字) |
XLAT | 换码指令 | 不影响 | |
LEA | 有效地址送寄存器 | 不影响 | 目的操作数可使用16/32位寄存器, 不能使用段寄存器 操作数长度, 地址长度, 操作 16, 16, 正常送 16, 32, 截取低位 32, 16, 零扩展到32位 32, 32, 正常送 |
CBW | 字节扩展到字 | 不影响 | AL -(有符号扩展)-> AX |
CWD | 字扩展到双字 | 不影响 | AX -(有符号扩展)-> DX, AX |
ADD | 加法 | 一般规律 | 两个操作数不能同时是内存 |
ADC | 带进位加法 | 一般规律 | 两个操作数不能同时是内存 |
INC | 加1 | 不影响CF, 其他一般 | |
SUB | 减法 | 一般规律 | 两个操作数不能同时是内存 |
SBB | 带借位减法 | 一般规律 | 两个操作数不能同时是内存 |
DEC | 减1 | 一般规律 | |
NEG | 求补 | 不影响CF, 其他一般 | |
CMP | 比较 | 一般规律 | 两个操作数不能同时是内存 没有结果, 仅设置标志位 |
MUL/IMUL | 乘法 | 乘积结果的高一半为0设置CF=OF=0, 否则设置CF=OF=1. 对于CF和OF以外的标志位无定义 | 操作数不能是立即数、段寄存器 内存操作数指定是WORD PTR 还是BYTE PTR |
DIV/IDIV | 除法 | 无定义 | 操作数不能是立即数、段寄存器 内存操作数指定是WORD PTR 还是BYTE PTR |
AND | 位与 | 设置CF=OF=0, AF无定义, 其他标志位的设置按一般规律 | |
OR | 位或 | 设置CF=OF=0, AF无定义, 其他标志位的设置按一般规律 | |
NOT | 按位求反 | 不影响 | |
XOR | 位异或 | 设置CF=OF=0, AF无定义, 其他标志位的设置按一般规律 | |
TEST | 测试 | 设置CF=OF=0, AF无定义, 其他标志位的设置按一般规律 | |
SHL/SHR | 逻辑左右移 | 见标志位设置总结 | 所移位数要么为1, 要么为CL |
SAL/SAR | 算术左右移 | 见标志位设置总结 | 所移位数要么为1, 要么为CL |
ROL/ROR | 循环左右移 | 见标志位设置总结 | 所移位数要么为1, 要么为CL |
RCL/RCR | 循环带借位左右移 | 见标志位设置总结 | 所移位数要么为1, 要么为CL |
MOVS | 串转移 | 不影响 | |
CMPS | 串比较 | 见标志位设置总结 | |
LODS | 从串取 | 不影响 | |
STOS | 存入串 | 不影响 | |
SCANS | 扫描串 | 见标志位设置总结 | |
INS | 串输入 | 不影响 | |
OUTS | 串输出 | 不影响 | |
JMP | 无条件跳转 | 不影响 | |
LOOP | 循环 | 不影响 | |
LOOPZ/LOOPE | 循环 | 不影响 | |
LOOPNZ/LOOPNE | 循环 | 不影响 | |
J__ | 有条件跳转 | 不影响 | 三类: 标志位类JZ, JS, JO, JC 无符号JA, JB 有符号JG, JL (‘不’ : J后加N, ‘等于’ : 后面跟E) |
CALL | 子程序调用 | 不影响 | |
RET | 子程序返回 | 不影响 |
常用DOS调用
-
1号调用
MOV AH, 01H INT 21H ; 控制台等待输入, 输入字符的ASCII存在AL中
-
2号调用
MOV AH, 02H MOV DL, 'A' INT 21H ; 控制台输出一个字符, 其ASCII码在DL中
-
9号调用
; 输出字符串, 以'$'为结尾标志, 字符串起始地址需要存在DX中 MOV AH, 09H LEA DX, STRING ; STRING DB "Hello, World!$" INT 21H
-
10号调用
; 输入字符串, 要求较复杂 ; 定义缓冲区 : BUF DB 80, ?, 80 DUP('$') ; 规则 : 调用前将BUF的地址传入DX, 调用后实际字符串存到了BUF的第三个字节开始之后 ; 最多输入字符的个数有BUF的第一个字节指定, 这也意味着10号调用一次最多可读入255个 ; 输入字符串实际大小将被存放在BUF的第2个字节 MOV AH, 0AH LEA DX, BUF INT 21H
-
4CH号调用
; 返回DOS, 程序结束应调用它, 否则会出运行时错误 MOV AH, 4CH INT 21H ;调用4CH号功能,结束程序
汇编子程序设计
-
函数定义
函数名 PROC ; 函数体 RET ; 函数一定有RET语句作为返回调用处的出口 函数名 ENDP
-
函数调用
CALL 函数名
-
函数参数和返回值
; 汇编函数没有所谓参数和返回值 ;; 作为参数功能的寄存器, 即利用全局变量传递数据 ; 例子: ; MOD函数, 参数为AX, BL, 返回值为DL, 为AX % BL的值, 均为无符号数 MOD PROC DIV BL MOV DL, AH MOD ENDP
-
避免寄存器被破坏
; 函数内可能会用到除了用作参数和返回值的寄存器, ; 为了避免调用方的数据被破坏, 应该在函数体内对适当的寄存器进行保护, 利用PUSH,POP ;;;;;;;;;;;;;;;;;;;;;;;;; ; function : print \r\n ; ; 打印回车换行 ;;;;;;;;;;;;;;;;;;;;;;;;; FUNC_PRINT_CRLF PROC PUSH DX ; 保护DX, AX PUSH AX ; print \r\n MOV DL, 0DH ; '\r' MOV AH, 02H INT 21H MOV DL, 0AH ; '\n' MOV AH, 02H INT 21H POP AX ; 恢复DX, AX POP DX ; return RET FUNC_PRINT_CRLF ENDP
汇编常用技法
-
灵活使用栈(PUSH & POP)
- 暂存(保护)寄存器的值
- 逆序数组
- 加个特殊标记当栈底(我常用-1(0FFFFH)做栈底)
-
字符串加个特殊标记当结尾(常用’$’)
汇编编程实战
输入输出
0.输入以回车结束的字符串
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; function : input a string into addr-BX, ;
; whose length must be less ;
; than CX ;
; params : BX, addr; CX, max-length ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FUNC_INPUT_STRING_TO_BX PROC
PUSH AX
PUSH SI
MOV SI, 0
FISTB_BEGIN:
; 如果长度大于CX, 直接结束
CMP SI, CX
JE FISTB_END2
; 从键盘获取一个ASCII, 存放在AL
MOV AH, 1
INT 21H
CMP AL, 0DH
JE FISTB_END ; 遇到回车直接跳出
MOV [BX][SI], AL ; 存放到..
INC SI
JMP FISTB_BEGIN
FISTB_END:
; End of loop of inputing & saving
MOV AL, '$'
MOV [BX][SI], AL ; 字符串以'$'结尾
FISTB_END2:
POP SI
POP AX
RET
FUNC_INPUT_STRING_TO_BX ENDP
1.输出有结束标志的字符串
结尾为 ‘$’
; 结尾 : '$'
LEA DX, 字符串名
MOV AH, 09H
INT 21H
2.输出N进制数
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; function : print CX base 10 ; ; 打印CX的值以10进制无符号
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FUNC_PRINT_CS_BASE10 PROC
PUSH AX
PUSH DX
MOV AX, CX
MOV DX, -1
PUSH DX ; -1为栈底标志
; 除10取余获取各位数字并压栈
FUNC_PRINT_CS_BASE10_GET_NUMBER_BIT_LOOP_BEGIN:
CBW ; 将上一步的商扩展到字以作为这一步的被除数
MOV DL, 10
DIV DL
PUSH AX
CMP AL, 0
JNE FUNC_PRINT_CS_BASE10_GET_NUMBER_BIT_LOOP_BEGIN
; 出栈并打印
FUNC_PRINT_CS_BASE10_PRINT_BIT_BY_BIT_BEGIN:
POP AX
CMP AX, -1
JE FUNC_PRINT_CS_BASE10_PRINT_BIT_BY_BIT_END
; 打印一位数字
ADD AH, 30H ; bitNumber + '0'
MOV DL, AH
;;;;;;;;;;;;; ; 打印DL
MOV AH, 02H
INT 21H
;;;;;;;;;;;;;
JMP FUNC_PRINT_CS_BASE10_PRINT_BIT_BY_BIT_BEGIN
FUNC_PRINT_CS_BASE10_PRINT_BIT_BY_BIT_END:
POP DX
POP AX
RET
FUNC_PRINT_CS_BASE10 ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; function : print CX base 16 ; ; 打印CX的值以16进制无符号
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FUNC_PRINT_CS_BASE16 PROC
PUSH AX
PUSH DX
MOV AX, CX
MOV DX, -1
PUSH DX ; -1为栈底标志
; 除10取余获取各位数字并压栈
FUNC_PRINT_CS_BASE16_GET_NUMBER_BIT_LOOP_BEGIN:
CBW ; 将上一步的商扩展到字以作为这一步的被除数
MOV DL, 16
DIV DL
PUSH AX
CMP AL, 0
JNE FUNC_PRINT_CS_BASE16_GET_NUMBER_BIT_LOOP_BEGIN
; 出栈并打印
FUNC_PRINT_CS_BASE16_PRINT_BIT_BY_BIT_BEGIN:
POP AX
CMP AX, -1
JE FUNC_PRINT_CS_BASE16_PRINT_BIT_BY_BIT_END
; 打印一位数字
CMP AH, 9
JNA FUNC_PRINT_CS_BASE16_PRINT_BIT_LESS10
ADD AH, 7
FUNC_PRINT_CS_BASE16_PRINT_BIT_LESS10:
ADD AH, 30H ; bitNumber + '0'
MOV DL, AH
;;;;;;;;;;;;; ; 打印DL
MOV AH, 02H
INT 21H
;;;;;;;;;;;;;
JMP FUNC_PRINT_CS_BASE16_PRINT_BIT_BY_BIT_BEGIN
FUNC_PRINT_CS_BASE16_PRINT_BIT_BY_BIT_END:
POP DX
POP AX
RET
FUNC_PRINT_CS_BASE16 ENDP
;#######################################################################;
; 打印16位无符号数(比上面的更好, 上面的打印比较大的数会出BUG)
DATA SEGMENT
VAL DW 65535
DATA ENDS
STACK SEGMENT
STACK ENDS
CODE SEGMENT
ASSUME DS: DATA, CS: CODE, SS: STACK
START:
MOV AX, DATA
MOV DS, AX
MOV AX, VAL
MOV DX, -1
PUSH DX
GET_NUMBER_BIT_LOOP_BEGIN:
MOV DX, 0
MOV BX, 10
DIV BX
PUSH DX
CMP AX, 0
JNE GET_NUMBER_BIT_LOOP_BEGIN
PRINT_LOOP_BEGIN:
POP DX
CMP DX, -1
JE PRINT_LOOP_END
ADD DL, 30H
MOV AH, 02H
INT 21H
JMP PRINT_LOOP_BEGIN
PRINT_LOOP_END:
MOV AX, 4C00H
INT 21H
CODE ENDS
END START
3.输入N进制数
; 10进制为例
; 其他进制注意除数, 字母的处理(A-F)
MOV BX, 0
INPUT_BEGIN:
MOV AH, 01H
INT 21H ; 输入字符到AL
CMP AL, 0DH
JE INPUT_END ; 回车, 结束
SUB AL, 30H ; AL <- AL - '0', 获取字符对应的数字(0-9)
PUSH AX ; 保护AX
MOV AX, 10
MUL BX ; AX <- BX * 10
MOV BX, AX ; 将乘法结果存回BX, 即相当于 : BX <- BX * 10
POP AX ; 恢复AX
CBW ; 扩展AL -> AX, 以便于将AL(最新输入的数位)累加到BX
ADD BX, AX ; 此条及以上 : BX <- BX * 10 + AL
JMP INPUT_BEGIN ; next-loop
INPUT_END:
数组
0.找出数组中的最大值
新增代码示例
DATA SEGMENT ; 数据段, 对应DS段, 习惯将变(常)量定义于此
ARR DW 45H, 32H, 12H, 54H, 2H, 23H, 12H, 11H ; 数组
ARR_LEN DW 8 ; 数组大小
DATA ENDS ; ENDS : END of SEGMENT
CODE SEGMENT ; 代码段
ASSUME DS: DATA, CS: CODE ; 声明DATA段是DS段, CODE段是CS段
START: ; 程序从这里开始执行
MOV AX, DATA
MOV DS, AX
; [1]写自己的代码, 要求找出ARR数组中的最大值, 将结果存在AX中
MOV AX, ARR[0]
MOV SI, 2
LOOP_BEGIN:
CMP SI, ARR_LEN
JAE LOOP_END
CMP AX, ARR[SI]
JAE NEXT_LOOP
MOV AX, ARR[SI]
NEXT_LOOP:
ADD SI, 2
JMP LOOP_BEGIN
LOOP_END:
; 调用DOS中断返回DOS
MOV AH, 4CH
INT 21H
CODE ENDS
END START
1.插入元素到升序序列
新增代码示例
DATA SEGMENT ; 数据段, 对应DS段, 习惯将变(常)量定义于此
ARR DW 10H, 20H, 30H, 43H, ? ; 数组
DATA ENDS ; ENDS : END of SEGMENT
CODE SEGMENT ; 代码段
ASSUME DS: DATA, CS: CODE ; 声明DATA段是DS段, CODE段是CS段
START: ; 程序从这里开始执行
MOV AX, DATA
MOV DS, AX
MOV CX, 90H
; [2]写自己的代码, 要求将CX中的数字插入ARR中, 使得ARR仍然保持升序
MOV SI, 8
LOOP_BEGIN:
CMP CX, ARR[SI - 2]
JA LOOP_END
MOV DX, ARR[SI - 2]
MOV ARR[SI], DX
SUB SI, 2
CMP SI, 0
JE LOOP_END
JMP LOOP_BEGIN
LOOP_END:
MOV ARR[SI], CX
; 调用DOS中断返回DOS
MOV AH, 4CH
INT 21H
CODE ENDS
END START
2.排序数组(冒泡排序)
DATA SEGMENT
ARR DW 45H, 32H, 12H, 54H, 2H, 23H, 12H, 11H
ARR_LEN DW 8
DATA ENDS
CODE SEGMENT
ASSUME DS: DATA, CS: CODE
START:
MOV AX, DATA
MOV DS, AX
; 将ARR升序排列
MOV CX, ARR_LEN ; 数组大小为8 ; 外循环采用CX计数
DEC CX
MOV DX, CX ; 内循环采用DX进行计数
OUTER_LOOP_BEGIN:
MOV SI, 0
MOV DX, ARR_LEN
DEC DX
INNER_LOOP_BEGIN:
; if arr[SI] > arr[SI + 2] : swap
MOV BX, ARR[SI]
CMP BX, ARR[SI + 2]
JNA INNER_LOOP_CONTINUE ; else continue
XCHG BX, ARR[SI + 2] ; swap
MOV ARR[SI], BX
INNER_LOOP_CONTINUE:
ADD SI, 2 ; 数组元素为DW, 注意SI每次加2
DEC DX
CMP DX, 0
JNZ INNER_LOOP_BEGIN
LOOP OUTER_LOOP_BEGIN
MOV AH, 4CH
INT 21H
CODE ENDS
END START
字符串
0.比较字符串是否相等
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; function : compare string a and string b ;
; compare-max-len is in CX ;
; params : CX, maxlen; ; ; 比较两个字符串,
; AX, a's addr; ; ; 它们的起始地址在AX, BX里
; BX, b's addr ; ; 要求字符串均已'$'结尾
; return : DL, 0 if ==, else 1 ; ; CX被用来指定比较最大长度
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FUNC_CMP_STRING_A_AND_B PROC
PUSH BP
PUSH SI
PUSH DX
MOV BP, AX
MOV SI, 0
FCSAAB_LOOP_BEGIN:
MOV DH, DS:[BX][SI]
CMP DS:[BP][SI], DH ; CMP不可直接比较两块内存
JNE FCSAAB_LOOP_END_NE
CMP DH, '$'
JE FCSAAB_LOOP_END_E
INC SI
LOOP FCSAAB_LOOP_BEGIN
FCSAAB_LOOP_END_E:
POP DX
MOV DL, 0
POP SI
POP BP
RET
FCSAAB_LOOP_END_NE:
POP DX
MOV DL, 1
POP SI
POP BP
RET
FUNC_CMP_STRING_A_AND_B ENDP
1.翻转字符串(同样适用于数组)
DATA SEGMENT
S DB "Hello World!!"
S_LEN EQU 13
DATA ENDS
CODE SEGMENT
ASSUME DS: DATA, CS: CODE
START:
MOV AX, DATA
MOV DS, AX
; 思路, 两个下标分别从头向后和从尾向前, 每次循环将两者交换, if SI >= DI : break
MOV SI, 0 ; 从头向后的下标
MOV DI, S_LEN - 1 ; 从尾向前的下标
REVERSE_LOOP_BEGIN:
; swap
MOV CL, S[SI] ; 注意数据类型匹配
XCHG CL, S[DI]
MOV S[SI], CL
INC SI
DEC DI
CMP SI, DI
JAE REVERSE_LOOP_END ; if SI >= DI : break
JMP REVERSE_LOOP_BEGIN ; else continue
REVERSE_LOOP_END:
MOV AH, 4CH
INT 21H
CODE ENDS
END START
综合示例
0.输入字符串找出出现数量最多的字符输出该字符及其数量
新增代码示例
(见期末模拟(一), 参考程序随答案公布)
- 输入格式 : 输入一行字符串, 以回车结尾, 输入字符个数不会多于200个
- 输出格式 : 输出两行, 每一行均以回车换行结尾, 第一行为出现最多的字符, 第二行为出现的次数
- (最多出现的字符由多个时, 随意输出一个即可)
- 思路 : 内外两层循环,当外循环找到一个ASCII不为0的字符时进入内循环否则一直向后找,内循环统计和外循环找到的不为0的字符相同的字符个数,最后加上外循环找到的那一个,和CNT变量比大小,若大于CNT则更新CNT为新的计数,更新CHAR为新的最多出字符,为了避免重复,统计完即刻将当前位置字符赋为ASCII 0,将外循环那个字符也赋成ASCII 0
DATA SEGMENT ; 数据段, 对应DS段, 习惯将变(常)量定义于此
CNT DB 0
CHAR DB 0
HELPER DB 200, ?
STR DB 200 DUP('$')
DATA ENDS ; ENDS : END of SEGMENT
CODE SEGMENT ; 代码段
ASSUME DS: DATA, CS: CODE ; 声明DATA段是DS段, CODE段是CS段
START: ; 程序从这里开始执行
MOV AX, DATA
MOV DS, AX
LEA DX, HELPER
MOV AH, 0AH
INT 21H
MOV SI, 0
OUTER_LOOP:
MOV AL, HELPER[1]
MOV AH, 0
CMP SI, AX
JAE OUTER_LOOP_END
MOV DL, STR[SI]
CMP DL, 0
JNE OUTER_NOT_0
INC SI
JMP OUTER_LOOP
OUTER_NOT_0:
MOV CL, 1
MOV DI, SI
INC DI
INNER_LOOP:
MOV AL, HELPER[1]
MOV AH, 0
CMP DI, AX
JAE OUTER_NEXT_LOOP
MOV DL, STR[SI]
CMP DL, STR[DI]
JNE INNER_NEXT_LOOP
INC CL
MOV STR[DI], 0
INNER_NEXT_LOOP:
INC DI
JMP INNER_LOOP
OUTER_NEXT_LOOP:
CMP CL, CNT
JBE OUTER_NEXT_LOOP2
MOV CNT, CL
MOV CHAR, DL
OUTER_NEXT_LOOP2:
MOV STR[SI], 0
INC SI
JMP OUTER_LOOP
OUTER_LOOP_END:
MOV DL, CHAR
MOV AH, 02H
INT 21H
MOV AL, CNT
MOV AH, 0
; 以十进制打印AX
MOV DX, -1
PUSH DX ; -1为栈底标志
; 除10取余获取各位数字并压栈
GET_NUMBER_BIT_LOOP_BEGIN:
MOV AH, 0 ; 将上一步的商扩展到字以作为这一步的被除数
MOV DL, 10
DIV DL
PUSH AX
CMP AL, 0
JNE GET_NUMBER_BIT_LOOP_BEGIN
; 出栈并打印
PRINT_BIT_BY_BIT_BEGIN:
POP AX
CMP AX, -1
JE PRINT_BIT_BY_BIT_END
; 打印一位数字
ADD AH, 30H ; bitNumber + '0'
MOV DL, AH
MOV AH, 02H
INT 21H
JMP PRINT_BIT_BY_BIT_BEGIN
PRINT_BIT_BY_BIT_END:
MOV AH, 4CH
INT 21H
CODE ENDS
END START
1.输入若干数字求平均值, 最大值, 最小值并输出
- 思路
- 边输入边求和并计数以及记录最大最小值
- 输出
2.输入字符串反向输出
- 格式 : 输入一行字符串, 要求倒序输出, 末尾要求打印回车换行
- 思路
- 边输入边压栈
- 边弹栈边输出
DATA SEGMENT
DATA ENDS
CODE SEGMENT
ASSUME DS: DATA, CS: CODE
START:
MOV AX, DATA
MOV DS, AX
MOV DX, -1
PUSh DX ; 以0FFFFH为栈底标志
INPUT_LOOP_BEGIN: ; 边输入边压栈
MOV AH, 01H
INT 21H
CMP AL, 0DH
JE INPUT_LOOP_END
PUSH AX ; 入栈
JMP INPUT_LOOP_BEGIN
INPUT_LOOP_END:
OUTPUT_LOOP_BEGIN: ; 边弹栈边输出
POP DX
CMP DX, -1
JE OUTPUT_LOOP_END
MOV AH, 02H
INT 21H ; print DL
JMP OUTPUT_LOOP_BEGIN
OUTPUT_LOOP_END:
; print \r\n
MOV DL, 0DH ; '\r'
MOV AH, 02H
INT 21H
MOV DL, 0AH ; '\n'
MOV AH, 02H
INT 21H
MOV AH, 4CH
INT 21H
CODE ENDS
END START
3.输入N求斐波那契数列第N项并输出
- 思路 : 三个变量(寄存器)来回倒腾
4.判断输入括号形式是否合法[拓展, 栈的应用]
附录
流程图速学
-
开始/结束 : 圆边矩形
-
执行语句 : 矩形
-
条件 : 菱形
ASCII码表
-
考试要用单步给出, 注意记住一些特殊的字符的ASCII
- 回车 : 0DH
- 换行 : 0AH
- ‘A’ : 41H
- ‘a’ : 61H
- ‘0’ : 30H
(其实除了回车换行其他的记不住也没啥事, 程序中直接写其字符形式即可, 比如将0-9数字转换成字符, 直接 + 30H也可以直接+‘0’, 回车换行必须要记住, 因为汇编编译器不支持转义字符(’\n’这种没意义))
DEC | HEX | 缩写/符号 | 描述 |
---|---|---|---|
0 | 00 | NUL | Null char (空字符) |
1 | 01 | SOH | Start of Heading (标题开始) |
2 | 02 | STX | Start of Text (正文开始) |
3 | 03 | ETX | End of Text (正文结束) |
4 | 04 | EOT | End of Transmission (传输结束) |
5 | 05 | ENQ | Enquiry (请求) |
6 | 06 | ACK | Acknowledgment (收到通知) |
7 | 07 | BEL | Bell (响铃) |
8 | 08 | BS | Back Space (退格) |
9 | 09 | HT | Horizontal Tab (水平制表符) |
10 | 0A | LF | Line Feed (换行键) |
11 | 0B | VT | Vertical Tab (垂直制表符) |
12 | 0C | FF | Form Feed (换页键) |
13 | 0D | CR | Carriage Return (回车键) |
14 | 0E | SO | Shift Out / X-On (不用切换) |
15 | 0F | SI | Shift In / X-Off (启用切换) |
16 | 10 | DLE | Data Line Escape (数据链路转义) |
17 | 11 | DC1 | Device Control 1 (设备控制1) |
18 | 12 | DC2 | Device Control 2 (设备控制2) |
19 | 13 | DC3 | Device Control 3 (设备控制3) |
20 | 14 | DC4 | Device Control 4 (设备控制4) |
21 | 15 | NAK | Negative Acknowledgement (拒绝接收) |
22 | 16 | SYN | Synchronous Idle (同步空闲) |
23 | 17 | ETB | End of Transmit Block (传输块结束) |
24 | 18 | CAN | Cancel (取消) |
25 | 19 | EM | End of Medium (介质中断) |
26 | 1A | SUB | Substitute (替补) |
27 | 1B | ESC | Escape (溢出) |
28 | 1C | FS | File Separator (文件分割符) |
29 | 1D | GS | Group Separator (分组符) |
30 | 1E | RS | Record Separator (记录分离符) |
31 | 1F | US | Unit Separator (单元分隔符) |
32 | 20 | Space (空格) | |
33 | 21 | ! | Exclamation mark |
34 | 22 | " | Double quotes |
35 | 23 | # | Number |
36 | 24 | $ | Dollar |
37 | 25 | % | Procenttecken |
38 | 26 | & | Ampersand |
39 | 27 | ’ | Single quote |
40 | 28 | ( | Open parenthesis |
41 | 29 | ) | Close parenthesis |
42 | 2A | * | Asterisk |
43 | 2B | + | Plus |
44 | 2C | , | Comma |
45 | 2D | - | Hyphen |
46 | 2E | . | Period, dot or full stop |
47 | 2F | / | Slash or divide |
48 | 30 | 0 | Zero |
49 | 31 | 1 | One |
50 | 32 | 2 | Two |
51 | 33 | 3 | Three |
52 | 34 | 4 | Four |
53 | 35 | 5 | Five |
54 | 36 | 6 | Six |
55 | 37 | 7 | Seven |
56 | 38 | 8 | Eight |
57 | 39 | 9 | Nine |
58 | 3A | : | Colon |
59 | 3B | ; | Semicolon |
60 | 3C | < | Less than |
61 | 3D | = | Equals |
62 | 3E | > | Greater than |
63 | 3F | ? | Question mark |
64 | 40 | @ | At symbol |
65 | 41 | A | Uppercase A |
66 | 42 | B | Uppercase B |
67 | 43 | C | Uppercase C |
68 | 44 | D | Uppercase D |
69 | 45 | E | Uppercase E |
70 | 46 | F | Uppercase F |
71 | 47 | G | Uppercase G |
72 | 48 | H | Uppercase H |
73 | 49 | I | Uppercase I |
74 | 4A | J | Uppercase J |
75 | 4B | K | Uppercase K |
76 | 4C | L | Uppercase L |
77 | 4D | M | Uppercase M |
78 | 4E | N | Uppercase N |
79 | 4F | O | Uppercase O |
80 | 50 | P | Uppercase P |
81 | 51 | Q | Uppercase Q |
82 | 52 | R | Uppercase R |
83 | 53 | S | Uppercase S |
84 | 54 | T | Uppercase T |
85 | 55 | U | Uppercase U |
86 | 56 | V | Uppercase V |
87 | 57 | W | Uppercase W |
88 | 58 | X | Uppercase X |
89 | 59 | Y | Uppercase Y |
90 | 5A | Z | Uppercase Z |
91 | 5B | [ | Opening bracket |
92 | 5C | \ | Backslash |
93 | 5D | ] | Closing bracket |
94 | 5E | ^ | Caret - circumflex |
95 | 5F | _ | Underscore |
96 | 60 | ` | Grave accent |
97 | 61 | a | Lowercase a |
98 | 62 | b | Lowercase b |
99 | 63 | c | Lowercase c |
100 | 64 | d | Lowercase d |
101 | 65 | e | Lowercase e |
102 | 66 | f | Lowercase f |
103 | 67 | g | Lowercase g |
104 | 68 | h | Lowercase h |
105 | 69 | i | Lowercase i |
106 | 6A | j | Lowercase j |
107 | 6B | k | Lowercase k |
108 | 6C | l | Lowercase l |
109 | 6D | m | Lowercase m |
110 | 6E | n | Lowercase n |
111 | 6F | o | Lowercase o |
112 | 70 | p | Lowercase p |
113 | 71 | q | Lowercase q |
114 | 72 | r | Lowercase r |
115 | 73 | s | Lowercase s |
116 | 74 | t | Lowercase t |
117 | 75 | u | Lowercase u |
118 | 76 | v | Lowercase v |
119 | 77 | w | Lowercase w |
120 | 78 | x | Lowercase x |
121 | 79 | y | Lowercase y |
122 | 7A | z | Lowercase z |
123 | 7B | { | Opening brace |
124 | 7C | | | Vertical bar |
125 | 7D | } | Closing brace |
126 | 7E | ~ | Equivalency sign (tilde) |
127 | 7F | Delete |