汇编 Memo
int 21h DOS 中断的核心功能集
在 8086 汇编的int 21h执行时,CPU 会自动暂停当前程序、保存 “现场” 到堆栈,压栈的顺序是固定的,从栈顶到栈底的顺序为:
- 标志寄存器(Flags)(2 字节):先把当前程序的状态标志(比如进位、溢出等)压入栈;
- 代码段寄存器(CS)(2 字节):再把当前程序的代码段地址压入栈;
- 指令指针寄存器(IP)(2 字节):最后把当前程序的指令偏移地址压入栈。
这个顺序是 8086 中断机制的固定逻辑(因为后续iret返回时,会按 “IP → CS → Flags” 的顺序弹出恢复现场)。
一、控制台输入 / 输出功能
| AH 值 |
功能描述 |
参数要求 |
返回结果 |
| 01H |
键盘输入字符(带屏幕回显) |
无 |
AL = 输入的 ASCII 字符 |
| 02H |
屏幕输出单个字符 |
DL = 要输出的 ASCII 字符 |
无 |
| 07H |
键盘输入字符(无回显) |
无 |
AL = 输入的 ASCII 字符 |
| 09H |
屏幕输出字符串 |
DS:DX = 字符串首地址(字符串必须以$结尾) |
无 |
| 0AH |
键盘输入字符串到缓冲区 |
DS:DX = 缓冲区首地址(缓冲区第 1 字节 = 最大长度,第 2 字节 = 实际输入长度) |
缓冲区第 3 字节开始存输入的字符串 |
二、文件操作功能
| AH 值 |
功能描述 |
参数要求 |
返回结果 |
| 3CH |
创建新文件 |
DS:DX = 文件名首地址;CX = 文件属性(0 = 普通文件) |
AX = 文件句柄(失败则 AX = 错误码) |
| 3DH |
打开已存在的文件 |
DS:DX = 文件名首地址;AL = 打开方式(0 = 读,1 = 写,2 = 读写) |
AX = 文件句柄(失败则 AX = 错误码) |
| 3FH |
从文件读数据 |
BX = 文件句柄;CX = 要读取的字节数;DS:DX = 数据缓冲区地址 |
AX = 实际读取的字节数(0 = 文件结束) |
| 40H |
向文件写数据 |
BX = 文件句柄;CX = 要写入的字节数;DS:DX = 数据缓冲区地址 |
AX = 实际写入的字节数 |
| 3EH |
关闭文件 |
BX = 文件句柄 |
无(失败则 AX = 错误码) |
三、程序控制 / 系统功能
| AH 值 |
功能描述 |
参数要求 |
返回结果 |
| 25H |
设置中断向量 |
AL = 中断号;DS:DX = 中断服务程序首地址 |
无 |
| 35H |
获取中断向量 |
AL = 中断号 |
ES:BX = 中断服务程序首地址 |
| 4CH |
程序退出并返回 DOS |
AL = 程序返回码 |
无 |
逻辑运算
-
乘法

-
除法

串处理指令
一、核心规则
- 固定寄存器/段关联:
- 源串:
DS:SI(数据段+源变址寄存器),仅 LODS 指令可单独使用 DS:SI;
- 目标串:
ES:DI(附加段+目的变址寄存器),MOVS/STOS/SCAS 强制依赖 ES:DI,不可替换;
- 计数器:
CX(存储串长度,所有重复前缀均依赖 CX 控制循环次数);
- 方向标志:
DF(控制 SI/DI 的增减方向:CLD 指令置 DF=0,正向递增;STD 指令置 DF=1,反向递减)。
- 段寄存器初始化要求:
ASSUME 伪指令仅声明段寄存器与段的关联关系,不实际给段寄存器赋值;
- 8086 架构不允许段寄存器直接接收立即数赋值(如
mov ds, data 非法),必须通过通用寄存器(如 AX)中转;
- 示例模板:
mov ax, data → mov ds, ax(初始化数据段)、mov ax, extra → mov es, ax(初始化附加段)。
- 操作单位区分:
- 字节操作(指令后缀
B):每次处理 1 字节,SI/DI 按 1 递增/递减;
- 字操作(指令后缀
W):每次处理 2 字节(1 个字),SI/DI 按 2 递增/递减。
二、核心串操作指令(按用途分类)
| 指令 |
功能说明 |
核心操作(DF=0 正向场景) |
适用重复前缀 |
MOVSB |
字节串复制 |
ES:[DI] = DS:[SI],随后 SI+1、DI+1 |
REP |
MOVSW |
字串复制 |
ES:[DI] = DS:[SI],随后 SI+2、DI+2 |
REP |
CMPSB |
字节串比较(判断是否相等) |
DS:[SI] - ES:[DI](仅影响标志位,不改变操作数),随后 SI+1、DI+1 |
REPE/REPZ、REPNE/REPNZ |
CMPSW |
字串比较(判断是否相等) |
DS:[SI] - ES:[DI](仅影响标志位),随后 SI+2、DI+2 |
REPE/REPZ、REPNE/REPNZ |
SCASB |
字节串查找(查找 AL 中的目标字符) |
AL - ES:[DI](仅影响标志位),随后 DI+1 |
REPE/REPZ、REPNE/REPNZ |
SCASW |
字串查找(查找 AX 中的目标字) |
AX - ES:[DI](仅影响标志位),随后 DI+2 |
REPE/REPZ、REPNE/REPNZ |
LODSB |
加载字节串到 AL |
AL = DS:[SI],随后 SI+1 |
极少使用(重复加载无实际意义) |
LODSW |
加载字串到 AX |
AX = DS:[SI],随后 SI+2 |
极少使用 |
STOSB |
将 AL 内容存储到字节串 |
ES:[DI] = AL,随后 DI+1 |
REP |
STOSW |
将 AX 内容存储到字串 |
ES:[DI] = AX,随后 DI+2 |
REP |
三、重复前缀(控制指令循环逻辑)
| 重复前缀 |
含义 |
循环终止条件 |
典型应用场景 |
REP |
无条件重复 |
当 CX = 0 时终止 |
串复制(MOVS)、串填充(STOS) |
REPE/REPZ |
相等/结果为零则重复 |
① CX = 0;② ZF = 0(比较结果不相等),满足任一即终止 |
串比较(验证两串是否完全相等,找第一个不相等字符) |
REPNE/REPNZ |
不相等/结果非零则重复 |
① CX = 0;② ZF = 1(比较结果相等),满足任一即终止 |
串查找(找第一个匹配目标字符/字的位置) |
四、典型实用示例(可直接复用)
1. 字节串复制(MOVSB + REP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| .8086 data segment src_db 'asd$' ; 源字节串(4字节:a、s、d、$) data ends extra segment dst_db 4 dup(?) ; 目标字节串(预留4字节空间) extra ends code segment assume cs:code, ds:data, es:extra main: ; 初始化数据段寄存器DS mov ax, data mov ds, ax ; 初始化附加段寄存器ES(目标串依赖ES:DI,必须初始化) mov ax, extra mov es, ax
lea si, src_db ; SI指向源串偏移地址(DS:SI定位源串) lea di, dst_db ; DI指向目标串偏移地址(ES:DI定位目标串) mov cx, 4 ; 复制长度=4字节(与源串长度一致) cld ; 置DF=0,正向递增复制 rep movsb ; 重复复制:直到CX=0
; 程序正常退出 mov ah, 4Ch int 21h code ends end main
|
2. 字节串填充(STOSB + REP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| .8086 extra segment buf_db 10 dup(?) ; 预留10字节缓冲区 extra ends code segment assume cs:code, es:extra main: mov ax, extra mov es, ax ; 初始化ES指向目标段(填充操作依赖ES:DI) lea di, buf_db ; DI指向缓冲区偏移地址 mov al, 0 ; 填充值:0(可改为任意字节值,如'A'、0FFh等) mov cx, 10 ; 填充长度=10字节 cld ; 正向填充 rep stosb ; 重复填充:ES:[DI] = AL,DI递增,直到CX=0
mov ah, 4Ch int 21h code ends end main
|
3. 字节串查找(SCASB + REPNE)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| .8086 extra segment str_db 'hello8086$' ; 待查找的字节串(长度=7字节) extra ends code segment assume cs:code, es:extra main: mov ax, extra mov es, ax ; 初始化ES指向待查找串所在段 lea di, str_db ; DI指向串偏移地址 mov al, '8' ; 目标查找字符(存储在AL中) mov cx, 7 ; 查找范围:前7字节 cld ; 正向查找 repne scasb ; 不相等则继续,找到则ZF=1,终止循环
; 查找结果判断 jz find_ok ; ZF=1 → 找到目标字符 jmp find_fail ; ZF=0 → 未找到
find_ok: ; 此处可添加找到后的处理逻辑(如记录位置) jmp exit find_fail: ; 此处可添加未找到的处理逻辑 exit: mov ah, 4Ch int 21h code ends end main
|
4. 字节串比较(CMPSB + REPE)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| .8086 data segment str1_db 'abc$' ; 第一个比较串(长度=3字节) data ends extra segment str2_db 'abd$' ; 第二个比较串(长度=3字节) extra ends code segment assume cs:code, ds:data, es:extra main: ; 初始化DS和ES,分别指向两个比较串所在段 mov ax, data mov ds, ax mov ax, extra mov es, ax
lea si, str1_db ; SI指向str1偏移(DS:SI) lea di, str2_db ; DI指向str2偏移(ES:DI) mov cx, 3 ; 比较长度=3字节 cld ; 正向比较 repe cmpsb ; 相等则继续,直到CX=0或找到不相等字符
; 比较结果判断 jz str_equal ; ZF=1且CX=0 → 两串完全相等 jmp str_not_equal ; 否则 → 不相等
str_equal: ; 两串相等的处理逻辑 jmp exit str_not_equal: ; 两串不相等的处理逻辑 exit: mov ah, 4Ch int 21h code ends end main
|
五、易错点速记
- 遗漏
ES 初始化:MOVS/STOS/SCAS 指令强制依赖 ES:DI,未初始化ES 会导致访问非法内存,程序崩溃;
- 方向标志未显式设置:默认
DF 状态不确定,务必用 CLD(正向)或 STD(反向)显式指定,避免 SI/DI 增减方向错误;
- 串长度与
CX 不匹配:CX 值大于串实际长度会导致内存越界,小于则复制/比较/查找不完整;
- 混淆重复前缀适用场景:
REP 不可用于 CMPS/SCAS,REPE/REPNE 不可用于 MOVS/STOS,否则逻辑错误;
- DOS 中断
09h 地址限制:该中断输出字符串要求地址为 DS:DX,若需输出 ES段的串,需临时将 DS 切换为 ES 对应的段基址。
ASCII码表
| 二进制 |
十进制 |
十六进制 |
字符/缩写 |
解释 |
| 00000000 |
0 |
00 |
NUL (NULL) |
空字符 |
| 00000001 |
1 |
01 |
SOH (Start Of Headling) |
标题开始 |
| 00000010 |
2 |
02 |
STX (Start Of Text) |
正文开始 |
| 00000011 |
3 |
03 |
ETX (End Of Text) |
正文结束 |
| 00000100 |
4 |
04 |
EOT (End Of Transmission) |
传输结束 |
| 00000101 |
5 |
05 |
ENQ (Enquiry) |
请求 |
| 00000110 |
6 |
06 |
ACK (Acknowledge) |
回应/响应/收到通知 |
| 00000111 |
7 |
07 |
BEL (Bell) |
响铃 |
| 00001000 |
8 |
08 |
BS (Backspace) |
退格 |
| 00001001 |
9 |
09 |
HT (Horizontal Tab) |
水平制表符 |
| 00001010 |
10 |
0A |
LF/NL (Line Feed/New Line) |
换行键 |
| 00001011 |
11 |
0B |
VT (Vertical Tab) |
垂直制表符 |
| 00001100 |
12 |
0C |
FF/NP (Form Feed/New Page) |
换页键 |
| 00001101 |
13 |
0D |
CR (Carriage Return) |
回车键 |
| 00001110 |
14 |
0E |
SO (Shift Out) |
不用切换 |
| 00001111 |
15 |
0F |
SI (Shift In) |
启用切换 |
| 00010000 |
16 |
10 |
DLE (Data Link Escape) |
数据链路转义 |
| 00010001 |
17 |
11 |
DC1/XON (Device Control 1/Transmission On) |
设备控制1/传输开始 |
| 00010010 |
18 |
12 |
DC2 (Device Control 2) |
设备控制2 |
| 00010011 |
19 |
13 |
DC3/XOFF (Device Control 3/Transmission Off) |
设备控制3/传输中断 |
| 00010100 |
20 |
14 |
DC4 (Device Control 4) |
设备控制4 |
| 00010101 |
21 |
15 |
NAK (Negative Acknowledge) |
无响应/非正常响应/拒绝接收 |
| 00010110 |
22 |
16 |
SYN (Synchronous Idle) |
同步空闲 |
| 00010111 |
23 |
17 |
ETB (End of Transmission Block) |
传输块结束/块传输终止 |
| 00011000 |
24 |
18 |
CAN (Cancel) |
取消 |
| 00011001 |
25 |
19 |
EM (End of Medium) |
已到介质末端/介质存储已满/介质中断 |
| 00011010 |
26 |
1A |
SUB (Substitute) |
替补/替换 |
| 00011011 |
27 |
1B |
ESC (Escape) |
逃离/取消 |
| 00011100 |
28 |
1C |
FS (File Separator) |
文件分割符 |
| 00011101 |
29 |
1D |
GS (Group Separator) |
组分隔符/分组符 |
| 00011110 |
30 |
1E |
RS (Record Separator) |
记录分离符 |
| 00011111 |
31 |
1F |
US (Unit Separator) |
单元分隔符 |
| 00100000 |
32 |
20 |
(Space) |
空格 |
| 00100001 |
33 |
21 |
! |
|
| 00100010 |
34 |
22 |
" |
|
| 00100011 |
35 |
23 |
# |
|
| 00100100 |
36 |
24 |
$ |
|
| 00100101 |
37 |
25 |
% |
|
| 00100110 |
38 |
26 |
& |
|
| 00100111 |
39 |
27 |
’ |
|
| 00101000 |
40 |
28 |
( |
|
| 00101001 |
41 |
29 |
) |
|
| 00101010 |
42 |
2A |
* |
|
| 00101011 |
43 |
2B |
+ |
|
| 00101100 |
44 |
2C |
, |
|
| 00101101 |
45 |
2D |
- |
|
| 00101110 |
46 |
2E |
. |
|
| 00101111 |
47 |
2F |
/ |
|
| 00110000 |
48 |
30 |
0 |
|
| 00110001 |
49 |
31 |
1 |
|
| 00110010 |
50 |
32 |
2 |
|
| 00110011 |
51 |
33 |
3 |
|
| 00110100 |
52 |
34 |
4 |
|
| 00110101 |
53 |
35 |
5 |
|
| 00110110 |
54 |
36 |
6 |
|
| 00110111 |
55 |
37 |
7 |
|
| 00111000 |
56 |
38 |
8 |
|
| 00111001 |
57 |
39 |
9 |
|
| 00111010 |
58 |
3A |
: |
|
| 00111011 |
59 |
3B |
; |
|
| 00111100 |
60 |
3C |
< |
|
| 00111101 |
61 |
3D |
= |
|
| 00111110 |
62 |
3E |
> |
|
| 00111111 |
63 |
3F |
? |
|
| 01000000 |
64 |
40 |
@ |
|
| 01000001 |
65 |
41 |
A |
|
| 01000010 |
66 |
42 |
B |
|
| 01000011 |
67 |
43 |
C |
|
| 01000100 |
68 |
44 |
D |
|
| 01000101 |
69 |
45 |
E |
|
| 01000110 |
70 |
46 |
F |
|
| 01000111 |
71 |
47 |
G |
|
| 01001000 |
72 |
48 |
H |
|
| 01001001 |
73 |
49 |
I |
|
| 01001010 |
74 |
4A |
J |
|
| 01001011 |
75 |
4B |
K |
|
| 01001100 |
76 |
4C |
L |
|
| 01001101 |
77 |
4D |
M |
|
| 01001110 |
78 |
4E |
N |
|
| 01001111 |
79 |
4F |
O |
|
| 01010000 |
80 |
50 |
P |
|
| 01010001 |
81 |
51 |
Q |
|
| 01010010 |
82 |
52 |
R |
|
| 01010011 |
83 |
53 |
S |
|
| 01010100 |
84 |
54 |
T |
|
| 01010101 |
85 |
55 |
U |
|
| 01010110 |
86 |
56 |
V |
|
| 01010111 |
87 |
57 |
W |
|
| 01011000 |
88 |
58 |
X |
|
| 01011001 |
89 |
59 |
Y |
|
| 01011010 |
90 |
5A |
Z |
|
| 01011011 |
91 |
5B |
[ |
|
| 01011100 |
92 |
5C |
\ |
|
| 01011101 |
93 |
5D |
] |
|
| 01011110 |
94 |
5E |
^ |
|
| 01011111 |
95 |
5F |
_ |
|
| 01100000 |
96 |
60 |
` |
|
| 01100001 |
97 |
61 |
a |
|
| 01100010 |
98 |
62 |
b |
|
| 01100011 |
99 |
63 |
c |
|
| 01100100 |
100 |
64 |
d |
|
| 01100101 |
101 |
65 |
e |
|
| 01100110 |
102 |
66 |
f |
|
| 01100111 |
103 |
67 |
g |
|
| 01101000 |
104 |
68 |
h |
|
| 01101001 |
105 |
69 |
i |
|
| 01101010 |
106 |
6A |
j |
|
| 01101011 |
107 |
6B |
k |
|
| 01101100 |
108 |
6C |
l |
|
| 01101101 |
109 |
6D |
m |
|
| 01101110 |
110 |
6E |
n |
|
| 01101111 |
111 |
6F |
o |
|
| 01110000 |
112 |
70 |
p |
|
| 01110001 |
113 |
71 |
q |
|
| 01110010 |
114 |
72 |
r |
|
| 01110011 |
115 |
73 |
s |
|
| 01110100 |
116 |
74 |
t |
|
| 01110101 |
117 |
75 |
u |
|
| 01110110 |
118 |
76 |
v |
|
| 01110111 |
119 |
77 |
w |
|
| 01111000 |
120 |
78 |
x |
|
| 01111001 |
121 |
79 |
y |
|
| 01111010 |
122 |
7A |
z |
|
| 01111011 |
123 |
7B |
{ |
|
| 01111100 |
124 |
7C |
|
|
| 01111101 |
125 |
7D |
} |
|
| 01111110 |
126 |
7E |
~ |
|
| 01111111 |
127 |
7F |
DEL (Delete) |
删除 |