这里写目录标题
- 1.基础概念
- 1.1. 什么是汇编语言?
- 1.2. 8086微处理器简介
- 2.快速入门
- 3.寄存器
- 3.1. 8086的寄存器分类
- 3.2. 寄存器的典型使用示例
- 4. 简单语法
- 4.1. 赋值、输入输出
- 4.2. 算数运算符
- 4.3. 比较运算符
- 4.4. 转移运算符
- 4.5.逻辑命令
- 5. 案例
- 5.1. 输出从 A 到 z 的字符
- 5.2. 判断键盘输入的字符是否为字母
- 5.3. 输出一个数对应ASCII表的2进制数
- 5.4. 三角形
- 5.5. 输出0-9十进制数的二进制数
- 5.6.输出字母塔
8086汇编语言是经典的低级语言之一,用于编程8086系列处理器。它以其简洁的指令集、灵活的内存操作和硬件控制能力成为学习汇编语言和计算机底层知识的理想起点。本文将带你从基础入门,逐步掌握8086汇编语言的核心概念和简单编程技巧。
1.基础概念
1.1. 什么是汇编语言?
汇编语言是一种接近硬件的低级语言,它使用助记符代替机器语言中的二进制指令,便于人类理解和编写。汇编语言直接与硬件交互,是操作系统开发和底层硬件编程的重要工具。
1.2. 8086微处理器简介
8086是Intel公司开发的一种16位微处理器,拥有以下特点:
- 寄存器: 8086处理器有多种寄存器,包括通用寄存器(如
AX
、BX
)、段寄存器(如CS
、DS
)、指针与索引寄存器(如SP
、SI
)、标志寄存器。 - 地址总线: 20位地址总线,可以寻址1MB内存。
- 工作模式: 支持实模式(16位地址空间)操作。
2.快速入门
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS
START:; 初始化数据段寄存器MOV AX,DATASMOV DS,AX;此处输入代码段代码; 终止程序MOV AH,4CHINT 21HCODES ENDS
END START
3.寄存器
汇编语言的变量并不能随意调,每个寄存器都要有一定使用规范,如不规范使用将有很多问题出现。因此重点讲解一下寄存器相关方面内容。
3.1. 8086的寄存器分类
8086的寄存器总共有 14个,每个寄存器为 16位,根据用途分为以下几类:
通用寄存器(General Purpose Registers)
通用寄存器既可以存储数据,也可以用于算术和逻辑操作。包括以下4个寄存器,每个寄存器可以按高8位(H)和低8位(L)分开使用。
寄存器 | 全16位 | 高8位 | 低8位 | 用途 |
---|---|---|---|---|
AX | AX | AH | AL | 累加器,常用于算术运算和I/O操作。 |
BX | BX | BH | BL | 基址寄存器,用于内存地址计算。 |
CX | CX | CH | CL | 计数器,常用于循环和移位操作。 |
DX | DX | DH | DL | 数据寄存器,常用于I/O端口访问和乘除法操作。 |
特性:
- 例如,
MOV AX, 1234H
将16位数据1234H
(十六进制)加载到AX
中;MOV AL, 56H
将56H
加载到AX
的低8位。 - 某些指令对特定寄存器有优先使用规则,如
DIV
和MUL
操作时默认使用AX
和DX
。
段寄存器(Segment Registers)
段寄存器是8086特有的,用于分段管理内存。8086的实模式采用 段:偏移 的地址方式,通过段寄存器和偏移寄存器组合访问内存。
寄存器 | 用途 | 功能 |
---|---|---|
CS | 代码段寄存器(Code Segment) | 存放当前执行代码所在的段地址。 |
DS | 数据段寄存器(Data Segment) | 存放数据所在的段地址。 |
SS | 堆栈段寄存器(Stack Segment) | 存放堆栈段地址。 |
ES | 附加段寄存器(Extra Segment) | 用于字符串操作的附加数据段。 |
段地址与物理地址计算公式:
物理地址 = 段地址 × 16 + 偏移地址
例如,CS:IP = 1000H:2000H
,则物理地址为 10000H + 2000H = 12000H
。
指针与索引寄存器(Pointer and Index Registers)
这类寄存器用于指向内存中的某个地址,常用于数组操作、堆栈操作和字符串处理。
寄存器 | 全称 | 用途 |
---|---|---|
SP | 堆栈指针(Stack Pointer) | 指向当前堆栈的栈顶偏移地址,配合 SS 使用。 |
BP | 基址指针(Base Pointer) | 用于访问堆栈中的数据,常用在子程序中。 |
SI | 源变址寄存器(Source Index) | 用于字符串操作时指向源数据地址。 |
DI | 目的变址寄存器(Destination Index) | 用于字符串操作时指向目标数据地址。 |
特性:
SP
和BP
默认以SS
为段寄存器,而SI
和DI
默认以DS
为段寄存器。- 常用于内存地址计算,例如:
[BX + SI]
表示内存地址BX + SI
的内容。
标志寄存器(Flag Register)
标志寄存器用于记录程序运行过程中CPU的状态。8086的标志寄存器共有 16位,但只定义了9个位。
标志位 | 名称 | 用途 |
---|---|---|
CF | 进位标志位 | 算术运算中最高位进位或借位标志。 |
ZF | 零标志位 | 运算结果是否为零。 |
SF | 符号标志位 | 运算结果是否为负(符号位)。 |
OF | 溢出标志位 | 有符号运算结果是否溢出。 |
PF | 奇偶标志位 | 结果的二进制位中1的个数是奇数还是偶数(偶数为1,奇数为0)。 |
AF | 辅助进位标志位 | 用于二进制编码的十进制加法,标志是否发生进位。 |
DF | 方向标志位 | 控制字符串操作的方向(递增或递减)。 |
IF | 中断标志位 | 决定是否允许外部中断。 |
标志位常见操作:
- 通过条件跳转指令(如
JE
、JG
)根据标志位的值跳转。 - 通过
PUSHF
和POPF
保存或恢复标志寄存器。
3.2. 寄存器的典型使用示例
数据传送
将一个数从内存加载到寄存器,或从一个寄存器传送到另一个寄存器。
asm复制代码
MOV AX, 1234H ; 将1234H加载到AX中
MOV BX, AX ; 将AX的值传送到BX
MOV AL, [SI] ; 将内存地址[SI]中的值加载到AL中
** 算术运算**
利用寄存器进行加法、减法、乘法等运算。
asm复制代码
MOV AX, 10H ; AX = 10H
MOV BX, 20H ; BX = 20H
ADD AX, BX ; AX = AX + BX,结果为30H
内存寻址
通过段寄存器和偏移寄存器访问内存。
asm复制代码
MOV AX, DS ; 将数据段地址加载到AX中
MOV SI, 1234H ; 偏移地址为1234H
MOV AL, [SI] ; 读取DS:1234H处的值到AL
条件跳转
通过标志寄存器控制程序的执行流程。
asm复制代码
CMP AX, BX ; 比较AX和BX
JE Equal ; 如果相等,跳转到Equal标号
MOV CX, 1 ; 不相等时执行
Equal:
MOV CX, 0 ; 相等时执行
4. 简单语法
4.1. 赋值、输入输出
MOV AX,BX
;输入MOV AH,1INT 21H;(用户所输入的字符将被自动存入AL中)MOV BL,AL;输出MOV DL,BL;(BL为要输出的字符)MOV AH,2INT 21H
4.2. 算数运算符
ADD +
INC +1
SUB -
DEC -1
格式:算数运算符(+,-) AL,BL (运算的结果会被赋值到左边的AL,例如:ADD AL,1)
算数运算符(+1,-1) AL (运算的结果会被赋值到AL,例如:INC AL)
4.3. 比较运算符
CMP 比较
;(比较运算下一行一般接转移类运算符,根据上一行的比较结果进行跳转)
格式:CMP AL,BL (运算时相当于BL-AL)
4.4. 转移运算符
JMP 直接跳转
条件跳转
JZ ==
JNZ !=
JG >
JGE >=
JL <
JLE <=
格式:
(先于跳转前后写上范围)
CMP BL, 'A'JL A1(A1为跳转地址) ; 如果小于 'A',跳到A1
A1:
; 输出当前字符MOV DL, BLMOV AH, 02HINT 21H
4.5.逻辑命令
按位逻辑操作指令
**AND**
(按位与)
对两个操作数的每一位执行逻辑与(1 & 1 = 1
,其余为0)。
asm复制代码
AND AL, BL ; AL = AL AND BL
应用场景:
- 清零某些特定位,例如 `AND AL, 0F0H` 保留 AL 的高4位,清零低4位。
**OR**
(按位或)
对两个操作数的每一位执行逻辑或(0 | 0 = 0
,其余为1)。
asm复制代码
OR AL, BL ; AL = AL OR BL
应用场景:
- 设置某些特定位,例如 `OR AL, 00001111B` 设置 AL 的低4位为1。
**XOR**
(按位异或)
对两个操作数的每一位执行逻辑异或(相同为0,不同为1)。
asm复制代码
XOR AL, BL ; AL = AL XOR BL
应用场景:
- 清零操作:`XOR AX, AX` 快速将 AX 寄存器清零。
- 数据加密:异或常用于加解密算法。
**NOT**
(按位取反)
对操作数的每一位取反(0变1,1变0)。
asm复制代码
NOT AL ; AL = NOT AL
应用场景:
- 数据取反,例如用于生成补码。
位移操作指令
**SHL**
(逻辑左移)
将操作数按位左移,空出的低位补0,高位移出。
asm复制代码
SHL AL, 1 ; AL 左移1位,低位补0
效果:相当于将操作数乘以2。
应用场景:
- 位乘法:`SHL AX, 1` 等价于 `AX = AX * 2`。
**SAL**
(算术左移)
和SHL
的功能相同,用于有符号数运算。**SHR**
(逻辑右移)
将操作数按位右移,空出的高位补0,低位移出。
asm复制代码
SHR AL, 1 ; AL 右移1位,高位补0
效果:相当于将操作数无符号除以2。
**SAR**
(算术右移)
将操作数按位右移,空出的高位用符号位补齐(符号位是1补1,是0补0)。
asm复制代码
SAR AL, 1 ; AL 算术右移1位
效果:相当于有符号数的除法,保留符号位。
旋转操作指令
旋转操作是将位循环移动,高位溢出部分移入低位,或低位溢出部分移入高位。
**ROL**
(循环左移)
将操作数按位左移,移出的最高位送入最低位。
asm复制代码
ROL AL, 1 ; AL 循环左移1位
**ROR**
(循环右移)
将操作数按位右移,移出的最低位送入最高位。
asm复制代码
ROR AL, 1 ; AL 循环右移1位
**RCL**
(带进位循环左移)
和ROL
类似,但进位标志(CF)也参与旋转。
asm复制代码
RCL AL, 1 ; AL 左移1位,CF移入最低位
**RCR**
(带进位循环右移)
和ROR
类似,但进位标志(CF)也参与旋转。
asm复制代码
RCR AL, 1 ; AL 右移1位,CF移入最高位
测试和比较指令
**TEST**
(按位测试)
对两个操作数执行按位与运算,但不保存结果,仅影响标志位。
asm复制代码
TEST AL, BL ; 测试 AL 和 BL 的按位与
应用场景:
- 检查某些特定位是否为1。例如:
asm复制代码
TEST AL, 00001000B ; 检查 AL 的第3位是否为1
JNZ BitSet ; 如果不为0,跳转到 BitSet
逻辑指令总结
指令 | 功能 | 典型用途 |
---|---|---|
AND | 按位与 | 清零某些位,屏蔽不需要的数据。 |
OR | 按位或 | 设置某些位,合并标志位。 |
XOR | 按位异或 | 清零寄存器,加密与解密。 |
NOT | 按位取反 | 数据反转或生成补码。 |
SHL | 逻辑左移 | 位移乘法,二进制操作。 |
SHR | 逻辑右移 | 位移除法,无符号数处理。 |
TEST | 按位与并设置标志位 | 检测某些位的状态。 |
5. 案例
5.1. 输出从 A 到 z 的字符
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES, DS:CODES, SS:CODESSTART:; 初始化数据段寄存器MOV AX, CODESMOV DS, AX; 输出从 A 到 z 的字符MOV BL, 'A' ; 初始字符为 'A'OUTPUT_LOOP:; 检查当前字符是否在 'A' 到 'Z' 或 'a' 到 'z' 之间CMP BL, 'A'JL SKIP_OUTPUT ; 如果小于 'A',跳过输出CMP BL, 'Z'JLE PRINT_CHAR ; 如果在 'A' 到 'Z' 之间,打印字符CMP BL, 'a'JL SKIP_OUTPUT ; 如果小于 'a',跳过输出CMP BL, 'z'JG SKIP_OUTPUT ; 如果大于 'z',跳过输出PRINT_CHAR:; 输出当前字符MOV DL, BLMOV AH, 02HINT 21HSKIP_OUTPUT:; 更新字符INC BL; 检查是否达到 'z'CMP BL, 'z'JBE OUTPUT_LOOP ; 如果小于等于 'z',继续循环; 终止程序MOV AH, 4CHINT 21HCODES ENDSEND START
5.2. 判断键盘输入的字符是否为字母
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES, DS:CODES, SS:CODES
START:; 初始化数据段寄存器MOV AX, CODESMOV DS, AX; 从键盘读取一个字符MOV AH, 01HINT 21HMOV BL, AL ; 将输入的字符保存到 BL 寄存器; 判断字符是否为字母CMP BL, 'A'JB NOT_LETTER ; 如果小于 'A',跳转到 NOT_LETTERCMP BL, 'Z'JBE IS_LETTER ; 如果在 'A' 到 'Z' 之间,跳转到 IS_LETTERCMP BL, 'a'JB NOT_LETTER ; 如果小于 'a',跳转到 NOT_LETTERCMP BL, 'z'JA NOT_LETTER ; 如果大于 'z',跳转到 NOT_LETTERIS_LETTER:; 输出 'Y'MOV DL, 'Y'MOV AH, 02HINT 21HJMP END_PROGRAMNOT_LETTER:; 输出 'N'MOV DL, 'N'MOV AH, 02HINT 21HEND_PROGRAM:; 终止程序MOV AH, 4CHINT 21HCODES ENDSEND START
5.3. 输出一个数对应ASCII表的2进制数
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS
START:MOV AX,DATASMOV DS,AX;此处输入代码段代码mov ah,1int 21hmov bl,alxor cl, cl ;循环开始时将CL清零,确保只输出8位
a2: cmp cl,7jle a3jmp jieshu
a3: test bl,80h ;检测最高位是否为1 80h:10000000jz output0 ;如果最高位是0,跳转output0 jmp output1 ;最高位为1
output0: mov ah,2mov dl,'0'int 21hrol bl,1inc cljmp a2
output1:mov ah,2mov dl,'1'int 21hrol bl,1inc cljmp a2
jieshu: MOV AH,4CHINT 21H
CODES ENDSEND START
5.4. 三角形
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS
START:MOV AX,DATASMOV DS,AX;此处输入代码段代码mov ch,1 ;从第一行开始
a2: mov cl,1
outputKongGe: mov ah,2mov dl,' 'int 21hinc clcmp cl,35jle outputKongGemov cl,1
outputXingZhuang: mov ah,2mov dl,'#'int 21hinc clcmp cl,ch ;形状数要和当前行相等jle outputXingZhuang;换行mov ah,2mov dl,0dhint 21hmov dl,0ahint 21h;内存循环结束inc chcmp ch,10 ;外循环控制行jle a2MOV AH,4CHINT 21H
CODES ENDSEND START
5.5. 输出0-9十进制数的二进制数
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS
START:MOV AX,DATASMOV DS,AX;此处输入代码段代码; 作业1 由用户从键盘输入一个十进制数字(0-9),输出该数的二进制mov ah,1int 21hmov bl,alsub bl,'0'xor cl,cl
a3: test bl,80hjz output0jmp output1
output0:mov ah,2mov dl,'0'int 21hjmp a2
output1:mov ah,2mov dl,'1'int 21hjmp a2
a2:rol bl,1inc clcmp cl,7jle a3 MOV AH,4CHINT 21H
CODES ENDSEND START
5.6.输出字母塔
DATAS SEGMENT;此处输入数据段代码
DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码
STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS
START:MOV AX,DATASMOV DS,AX;此处输入代码段代码;输出字母塔 作业3mov ch,1 ;当前行mov bl,'A'
a2: cmp ch,4jle outputZiMu;已经输出完 结束程序jmp endProgram
outputZiMu:
; 输出空格
a4: mov ah,2mov dl,' 'int 21hinc clcmp cl,35jle a4mov dh,0 ;用dh记录打印的字母数;输出字母
a3: mov ah,2mov dl,blint 21hinc bl ;更新下一次打印字母inc dh ;已打印字母数递增;输出空格mov ah,2mov dl,' 'int 21h;计算当前行打印次数mov cl,chadd cl,cl;2*elsub cl,1 ;el-1cmp dh,cl ;比较已打印字母数和应当打印字母数的关系 2*ch-1 jl a3;换行mov ah,2mov dl,0ahint 21hmov ah,2mov dl,0dhint 21hinc ch jmp a2endProgram: MOV AH,4CHINT 21H
CODES ENDSEND START