第七周 汇编语言程序设计
大家好,又是我,沉迷学习无法自拔的小笨蛋康sir。
这个文集(点我)将会同步更新我观看吴宁老师的《微机原理与接口技术》教学视频写的笔记,学习笔记,大概每周一章。
有问题大家可以在评论下面留言讨论,欢迎纠错!
欢迎收藏阅读,动动小手给个硬币点个赞。
——@正能量的康sir
也可移步我的博客(https://blog.csdn.net/qq_33956508)会更新一些其它技术类文章。

第35讲 汇编语言源程序
主要内容
汇编程序与汇编语言源程序
汇编语言语句类型与格式
汇编语言语句中的操作数
1. 汇编语言源程序与汇编程序
汇编语言源程序——用助记符编写
汇编程序——源程序的编译程序
汇编语言源程序——>汇编程序——>机器语言目标程序
汇编语言程序设计与执行过程
输入汇编语言源程序(EDIT) ---源文件.ASM
汇编(MASM)----目标文件.OBJ
链接(LINK)----可执行文件.EXE
调试(TD)-----最终程序
2.汇编语言语句类型和格式
汇编语言语句类型:
指令性语句->CPU执行的语句,能够生成目标代码
指示性语句->CPU不执行,而由汇编程序执行的语句,不生成目标代码
汇编语言语句格式:
指令性语句格式:
[标号:][前缀] 助记符 [操作数],[操作数][;注释]
(助记符就是操作码,不可缺少,[ ]中是可以没有的)
(标号Label是指令的符号地址,标号后要有冒号)
指示性语句格式:
[名字] 伪指令助记符 操作数[,操作数,…][;注释]
(指示性语句中至少有一个操作数)
(名字,变量的符号地址,后面不加冒号)
3汇编语言语句中的操作数
寄存器
存储器单元
常量
变量或标号
表达式
常量:
数字常量,1234…
字符常量,用单引号引起的字符或字符串,’A’ ’a’ ’ABCD’
例
MOV AL,’A’ AL=41H
定义字符串:’ABCD’汇编时被译成对应的ASCII码 41H,42H,43H,44H
标号(也叫 变量):
内存单元的符号地址,为存储器操作数
标号的属性:
段值 变量所在段的段地址
偏移量 变量所指单元的偏移地址
类型 字节型\字型\双字类型
标号的命名
不能与指令助记符或伪指令重名(注意 汇编语言不区分大小写 所以变量也不能是小写的注记符或伪指令)
不允许由数字打头
字符个数不超过 31 个。

表达式:
算数运算
逻辑运算
关系运算
取值运算和属性运算
其他运算
取值运算符
用于分析存储器操作数的属性
获取变量的属性值
OFFSET 取得其后变量或标号的偏移地址. (用LEA也可以做到)
SEG 取得其后变量或标号的段地址
例:
MOV AX,SEG DATA
MOV DS,AX
MOV BX,OFFSET DATA等价于LEA BX,DATA
属性运算符
用于指定其后存储器操作数的类型
运算符PTR
例子
MOV BYTE PTR[BX],12H
指定存储器操作数[BX]是字节型
第36讲 数据定义伪指令
伪指令
由汇编程序执行的”指令系统”
作用:
定义变量
分配存储器
定义逻辑段
指示程序开始和结束
定义过程等.
帮助计算机理解助记符指令编写的汇编语言源程序
常用伪指令:
数据定义伪指令
符号定义伪指令
段定义伪指令
结束伪指令
过程定义伪指令
宏命令伪指令
数据定义伪指令
用于定义数据区中变量的类型及其所占内存空间大小
格式:[变量名] 伪指令助记符 操作数,… ;[注释]
变量名:符号地址
伪指令助记符:定义变量类型
操作数:变量值,可以是常数,表达式或字符串。其大小不能超过伪指令助记符所限定的范围
变量的类型及其操作数的个数决定了该变量所在内存空间的大小
1. 数据定义伪指令助记符
DB(Define Byte):定义的变量为字节型 指向的每一个操作数占1个字节单元
DW (Define Word) :定义的变量为字类型 指向的每一个操作数占1个字单元
DD (Define Double Word) :定义的变量为双字型
DQ (Define Quadword) :定义的变量为4字型
DT (Define Tenbytes) :定义的变量为10字节型
例
DATA1 DB 11H,22H,33H,44H
DATA2 DW 11H,22H,3344H
DATA3 DD 11H*2,22H,33445566H
以上变量在内存中的存放形式?

数据定义伪指令的几点说明
数据定义伪指令决定所定义变量的类型;
定义字符串必须用DB伪指令
例: DATA1 DB ‘ABCD’ ,66H

2. 重复操作符
当同样的操作数重复多次时,可以使用重复操作符。
作用:为一个数据区的各单元设置相同的初值
格式:[变量名] 伪指令助记符 n DUP(初值 [,初值,… ] )
n:重复次数
(初值 [,初值,… ] ):重复的内容
例: M1 DB 10 DUP(0)
常用于声明一个数据区
3. “?”的作用
表示随机值,用于预留存储空间
例:
MEM1 DB 34H, ’A’ ,? 随机数占1个字节单元
DW 20 DUP(?) 预留40个字节单元,每单元为随机值
数据定义伪指令例
M1 DB ‘How are you?’
M2 DW 3 DUP(11H),3344H
DB 4 DUP(?)
M3 DB 3 DUP(22H,11H,?)

第37讲 符号与段定义伪指令
一、符号定义伪指令
将表达式的值赋给一个名字。当源程序中需多次引用某一表达式时,可以利用EQU伪指令,用一个符号代替表达式,以便于程序维护。
格式:
符号名 EQU 表达式
(EQU说明的表达式不占用内存空间)
(类似于c语言中的#define)
操作:
用符号名取代后边的表达式,不可重新定义
例:
CONSTANT EQU 100
后面的程序就可以用CONSTANT代替100了
二、段定义伪指令
在汇编语言源程序中定义逻辑段
说明逻辑段的起始和结束
说明不同程序模块中同类逻辑段之间的联系形态
格式:
段名 SEGMENT [定位类型] [组合类型] [’类别’]
┇(中间的是内容,可以是代码,可以是数据,看是什么段了)
段名 ENDS
段名 逻辑段的段基地址
定位类型 说明逻辑段的起点。(默认以节为边界,被16整除)
组合类型 装入内存时各逻辑段的组合方式(默认不组合)
类别 链接时不同程序模块中的同类逻辑段将被装入连续存储区。
段定义伪指令例
DATA SEGMENT
MEM1 DB 11H,22H
MEM2 DB ‘Hello!’
MEM3 DW 2 DUP(?)
DATA ENDS
DATA段名代表逻辑段的段地址
MEM1\ MEM2 \MEM 3变量在逻辑段中的位置就代表了它的偏移地址
DW、DB表示变量的类型
DATA段名也代表逻辑段的段地址
三、设定段寄存器伪指令
说明所定义逻辑段的性质。设定段寄存器为指令助记符
格式:
ASSUME 段寄存器名:段名[,段寄存器名:段名,…]
因为一个程序模块里有四种逻辑段,每个段寄存器对应每种逻辑段,所以可以用段寄存器来定义逻辑段性质。
例如ASSUME CS:代码段名字 代码段一定有
定义数据段 ASSUME DS:段名
有串操作声明附加段 ASSUME ES:段名
堆栈声明堆栈段 ASSUME SS:段名
四、结束伪指令
表示源程序结束
格式: END [标号]
汇编语言源程序结构:
数据段名 SEGMENT
…
数据段名 ENDS
附加段名 SEGMENT
…
附加段名 ENDS
堆栈段名 SEGMENT
…
堆栈段名 ENDS
代码段名 SEGMENT
…
代码段名 ENDS
END
一定有代码段,大多需要定义数据段,有串操作需要定义附加段,有PUSH\POP\过程中断等需要堆栈的需要定义堆栈段
一个完整源程序结构例:
DSEG SEGMENT
DATA1 DB 1, 2, 3 DUP (?)
DATA2 DW 1234H
DSEG ENDS
ESEG SEGMENT
DB 20 DUP(?)
ESEG ENDS
SSEG SEGMENT STACK ‘STACK‘
DB 200 DUP (?)
SSEG ENDS
CSEG SEGMENT
ASSUME CS: CSEG, DS: DSEG,
ES: ESEG. SS: SSEG;这里可以换行,但是上一句的逗号不能缺省
START: MOV AX, DSEG;因为当目的操作数是段寄存器时,源操作数不能是立即数,所以通过AX.
MOV DS, AX
MOV AX, ESEG
MOV ES, AX
MOV AX, SSEG
MOV SS, AX;这几行叫做段寄存器的初始化,将段地址送给相应的段寄存器
……省略的地方才是前面学的那些源代码程序
CSEG ENDS
END START
第38讲 其它伪指令
过程定义伪指令
宏定义伪指令
调整偏移量伪指令
过程定义伪指令
用于定义一个过程体
格式:
过程名 PROC [ NEAR / FAR ]
┇
RET
过程名 ENDP
过程名:过程入口的符号地址
若为近过程,NEAR可省略。(没有的话默认NEAR)
过程体的最后一条指令必须是RET
过程定义及调用例:
定义延时子程序
DELAY PROC
PUSH BX
PUSH CX;这两条参数保护。和后面POP搭配起来
MOV BL,2
NEXT:MOV CX,4167
W10M: LOOP W10M
DEC BL
JNZ NEXT
POP CX
POP BX
RET
DELAY ENDP
调用延时子程序
CALL DELAY
宏命令伪指令
宏:源程序中由汇编程序识别的具有独立功能的一段程序代码
当源程序中需要多次使用同一个程序段时,可以将该程序段定义为一个宏
格式:宏命令名 MACRO <形式参数>
┇
┇(省略掉的地方是宏体)
ENDM
形式参数 通过参数传递方式引用宏
宏定义与宏调用例
定义宏:
DADD MACRO X,Y,Z
MOV AX,X
ADD AX,Y
MOV Z,AX
ENDM
宏调用:
DADD DATA1,DATA2,SUM
汇编后源程序中的宏展开:
MOV AX,DATA1
ADD AX,DATA2
MOV SUM,AX
调整偏移量伪指令
规定程序或变量在逻辑段中的起始地址。
(默认情况下,程序或变量在逻辑段中的起始偏移地址为0。利用ORG指令,可以改变)
格式: ORG 表达式 (表达式的计算值为非负常数)
例:
DATA SEGMENT
ORG 1200H
BUFF DB 1,2; 变量BUFF的偏移地址=1200H
DATA ENDS
第39讲 系统功能调用
BIOS、DOS功能调用
BIOS:驻留在ROM中的基本输入/输出系统. 加电自检,装入引导,主要I/O设备处理程序及接口控制
DOS:磁盘操作系统
DOS功能/BIOS功能调用是调用系统内核子程序
DOS功能与BIOS功能均通过中断方式调用,所以调用BIOS和调用DOS可以说成BIOS中断、DOS中断
DOS软中断
DOS中断包括:设备管理,目录管理,文件管理,其它
用中断类型码区分
DOS软中断:类型码为21H
关于DOS软中断说明:
包含多个子功能的功能包;
各子功能用功能号区分;
用软中断指令调用,中断类型码固定为21H
DOS功能调用的基本步骤
将调用参数(入口参数/出口参数)装入指定的寄存器;
将功能号装入AH;
按中断类型号调用DOS中断;
检查返回参数是否正确。
调用格式:
MOV AH,功能号
<置相应参数>
INT 21H
1. 单字符输入
调用方法:
MOV AH,01
INT 21H
输入的字符在AL中
例子
GET_KEY: MOV AH,1
INT 21H
CMP AL,’Y’;(交互式应答程序)
JZ YES
CMP AL,’N’
JZ NO
JMP GET_KEY
YES: ┇
NO: ┇
2. 字符串输入
接收由键盘输入一串字符
输入的字符串存储在内存指导区域中(字符输入缓冲区)
用户自定义缓冲区格式:

(敲入的字符从第三个单元开始放。存放键入的字符数比最大少一个,ODH回车要占用一个字符位置)
字符串输入功能号:10
缓存区须定义在数据段
方法:
AH 功能号
DS:DX 字符串在内存中的存放地址。缓冲区必须定义在数据段,规定偏移地址必须送给DX
INT 21H
输入字符串程序段
DAT1 DB 20,?,20 DUP(?); 在数据段中定义
┇
LEA DX,DAT1
MOV AH,0AH
INT 21H
输入缓冲区
定义后的输入缓冲区初始状态:(敲入的字符从第三个单元开始放。20个字节只能输入19个字符哦,因为回车0DH占一个)

3. 单字符显示输出
AH 功能号2
DL 待输出字符
INT 21H
例:
MOV AH,2
MOV DL,41H
INT 21H
执行结果:屏幕显示A
4. 字符串输出显示
AH 功能号09H
DS:DX 待输出字符串的偏移地址
INT 21H
注意点:
被显示的字符串必须以‘$’结束;
所显示的内容不应出现非可见的ASCII码;
若考虑输出格式需要,在定义字符串后,加上回车符和换行符。
字符串输出显示例
DATA SEGMENT
MESS1 DB ‘Input String:’, 0DH,0AH,’$’
DATA ENDS
CODE SEGMENT
┇
MOV AH,09
MOV DX,OFFSET MESS1
INT 21H
┇
(0DH回车 光标会在字符后面闪烁
0AH换行
ODH 和0AH 下一行闪烁)

5. 返回操作系统(DOS)功能
功能号: 4CH
调用格式:
MOV AH,4CH
INT 21H
功能:
程序执行完该2条语句后能正常返回OS
常位于程序结尾处。
DOS功能调用小结
通过中断指令调用。1个中断类型码对应1个功能程序包;
每个程序包中的子功能通过功能号区分,调用时功能号须送AH;
注意不同子功能的入口/出口参数要求;
DOS和BIOS中断均可能影响AX (需要用PUSH\POP保护数据)
第40讲 汇编语言程序设计示例详解
实例4:
DATA SEGMENT
STR1 DB ‘HELLO WORLD!‘
STR2 DB ‘HELLO WOOLD!’
COUNT DW 12;16位
FLAG DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA, ES: DATA;DATA既是数据段又是逻辑段
START: MOV AX, DATA
MOV DS, AX
MOV ES, AX
LEA BX, FLAG
LEA SI, STR1
LEA DI, STR2
MOV CX,COUNT
CLD
REPE CMPSB
JZ NEXT1
MOV Byte PTR[BⅪ],00H
JMP STOP
NEXT1: MOV Byte PTR(BX], OFFH
STOP:……
问 当程序执行到STOP时
SI\DU\CX\FLAG\ZF的值
SI=9,DI=0015H,CX=3,FLAG=0,ZF=0
开始SI=0 DI=12=0CH
到R和O不同的位置是9次
SI=0+9=9
DI=12+9=21=0015H
遇到不同的,结果不为0,ZF=0
00H给了BX,FLAG=0
CX=12-9=3

实例5
DATA SEGMENT
SUM DB 8 DUP (0)
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
LEA BX, SUM
MOV DX, 380H
IN AL, DX
MOV CX, 8
NEXT: ROR AL, 1;不含CF的循环右移指令
JNC NEXT1
MOV Byte PTR[BX], 0FFH
JMP NEXT2
NEXT1: MOV Byte PTR [BX], 0
NEXT2: INC BX
LOOP NEXT
……
如果从380H端口输入的是45H,则程序执行完后:
BX=(8)
AL=(45H)
SUM0-SUM7的内容是(FF,0,FF,0,0,0,FF,0)
AL=01000101 最低位存入CF,存入最高位 AL=10100010
因为CF=1 JNC不会转向NEXT1
[BX]的内容FFH
NEXT2 BX+1
循环8次NEXT
去NEXT
CF=0,AL=01010001
跳到NEXT1
[BX]的内容FFH
。。。
汇编语言程序设计小结
汇编语言程序设计一般步骤
根据实际问题抽象出数学模型
确定算法
画程序流程图
分配内存工作单元和寄存器
程序编码
调试
内容提要
汇编语言源程序的结构
汇编语言语句---变量、表达式中的运算符
伪指令
DOS功能调用:5个子功能的应用
简单汇编语言源程序的设计
注意点
变量的定义与应用:明确所定义变量在内存中的分布
存储区的定义:不能定义没有变量的存储区
完整的汇编语言源程序结构:定义逻辑段,说明段的含义,初始化段寄存器
伪指令:数据定义方式
字符及字符串的输入和显示输出:字符输入缓冲区的定义,输出字符串的定义
汇编语言程序结构:顺序结构、循环结构(使用LOOP指令或条件转移指令实现) 、分支结构(一般用条件转移指令实现)
子程序结构:子程序的定义和调用方式
例:
定义20B的字符输入缓冲区BUFF以及20B的字节变量DATA;
显示字符串输入提示信息,然后从键盘接收字符‘Hello,my friends!’;
将BUFFER中的字符串按从左到右的方向传送到DATA中。
分析:
字符串显示输出 字符串输入 串操作指令
DSEG SEGMENT
MESS DB ‘Please input string:’,0DH,0AH,’$’
BUFF DB 20,?,20 DUP (?)
DATA DB 20 Dup(?)
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG,ES:ESEG
START:MOV AX,DSEG
MOV DS,AX
MOV ES,AX
AGAIN:LEA DX,MESS
MOV AH,9
INT 21H
LEA DX,BUFF
MOV AH,10
INT 21H
XOR CX,CX
MOV CL,BUFF+1;BUFF+1的地址是存放放字符串实际长度值的单元
LEA DI,DATA
LEA SI,BUFF+2;开始存字符串内容的地方
CLD
REP MOVSB
MOV AH,4CH
INT 21H
CSEG ENDS
END SATRT