文章目录
- 语句类型
- 语句格式
- 指令助记符
- 操作数
- 常量
- 变量和符号
- 运算符
- 算数运算符
- 逻辑运算符
- 关系运算符
- 分析运算符
- 综合运算符
- 优先级
- 伪指令
- 数据定义伪指令
- 符号定义伪指令
- 标号定义伪指令?
- 段定义伪指令
- 段寻址伪指令
- 过程定义伪指令
- 程序计数器和定位伪指令?
- 宏定义伪指令
- 汇编结束伪指令
- 源程序的结构
- 作为子过程
- 作为独立代码段
- DOS系统调用
- 读取一个输入字符(01H)
- 读取字符串(0AH)
- 显示一个字符(02H)
- 显示字符串(09H)
- BIOS系统调用
-
基本汇编:
汇编相应指令系统提供的指令语句和少量的伪指令语句 -
小汇编:
能力有限,对于指令语句中的符号地址都不能翻译 -
宏汇编:
对包含宏指令和大量伪指令的汇编语言程序进行汇编,功能强大;支持多模块程序设计,由MASM生成的目标程序可直接和其他模块的汇编语言程序的目标程序相连接,也可直接和其他高级语言的目标程序块相连。常用于8086﹏Pentium系列的微机中。 -
汇编语言程序是按段来组织程序和数据的。和存储器的物理段相对应,汇编语言程序中的段称为逻辑段。汇编连接后被映射到物理段中。
语句类型
-
指令语句
以指令系统的助记符指令为基础构成;汇编后产生相应的机器代码,构成目标程序供执行。 -
伪指令语句
为汇编程序和连接程序提供必要的控制信息,由伪指令构成的管理性语句;其对应的伪操作在汇编过程中完成,汇编后不产生机器代码。即:伪指令只出现在源程序中,当汇编完成形成目标程序后,则不复存在。 -
宏指令语句
按宏指令语句定义规则,自行将一组反复出现的指令集中定义为一条宏大指令;宏指令可替代一组指令,从而使书写简洁。经汇编后再还原为这一组指令对应的目标代码。宏指令只节省源程序篇幅,不节省目标代码
语句格式
[名字] 操作符 操作数 [;注释]
; 中括号内的内容可以省略
- [标号:]
<指令助记符>
[操作数]
[;注释]
这是一条硬指令,必定会翻译成一段机器码,并且CPU会执行它
- [符号名]
<伪指令助记符>
[操作数]
[;注释]
这是一段伪指令,起到说明性的作用,不会被翻译成机器码,自然也不会被执行。
指令助记符
数据传送
逻辑运算
算数运算
串操作
控制转移
操作数
常量
- 二进制:B结尾,
01011101B
- 八进制:Q结尾,
235Q
- 十进制:D结尾或没有结尾字母,
98D或98
- 十六进:H结尾,
5BH
- 字符串:用单引号括起来的一个或多个字符,ASCII存储,
ABC
- 可用作立即数
MOV CX, 100
- 偏移量
MOV AX, 34[SI]
- 数据定义语句的初值
X DB 12H,34H
变量和符号
- 变量
- 段属性
变量所在段的起始地址 - 偏移属性
从段起始地址到定义变量的位置之间的字节数 - 类型属性
该变量所保留的字节数
- 段属性
DB 1个字节
DW 2 个字节
DD 4个字节
DQ 8个字节
DT 10个字节
运算符
高低分离符:HIGH(高字节)LOW(低字节)HIGHWORD(高字)LOWWORD(低字)
mov ah, HIGH 8765h ; 等价于mov ah, 87h
mov ax,LOWWORD 0ffff1234h ;等价于mov ax,1234h
算数运算符
逻辑运算符
关系运算符
分析运算符
- SEG
获得当前标号的段地址,即seg SEGMENT
和seg ENDS
之间的都是同一个段地址。 - OFFSET
符号的偏移地址,从seg SEGMENT
开始数。 - TYPE
字节(DB) = 1,字(DW) = 2,双字(DD) = 4,NEAR指令单元 = -1, FAR指令单元 = -2。 - LENGTH
DUP变量中变量的个数 - SIZE
DUP变量的总字节数
DATA SEGMENT
V1 DB 2AH, 3FH
V2 DW 2A3FH, 3040H
V3 DD 12345678H, 12ABCDEFH
V4 DW 20 DUP(1)
DATA ENDS
; --------------------------------------------------------
MOV AX, SEG V1 ; AX = 4000H
MOV BX, SEG V2 ; BX = 4000H
MOV CX, SEG V3 ; CX = 4000H
; V1, V2, V3 都在同一个段,所以相同
MOV AX, OFFSET V1 ; AX = 0
MOV BX, OFFSET V2 ; BX = 2
MOV CX, OFFSET V3 ; CX = 6
; V1, V2, V3 的偏移地址0,2,6
MOV AX, TYPE V1 ; AX = 1
MOV BX, TYPE V2 ; BX = 2
MOV CX, TYPE V3 ; CX = 4
; 就是变量的长度
MOV AX, LENGTH V4 ; AX = 20
MOV BX, SIZE V4 ; BX = 40
; SIZE = LENGTH * TYPE
综合运算符
- 属性修改运算符(PTR, THIS)
- PTR:指定变量名或标号的数据类型
格式:类型 PTR 标号\变量名
操作: 对存储器表达式,类型可为BYTE
,WORD
,DWORD
,QWORD
和TBYTE
;表达式为标号时,类型可为NEAR或FAR。 - THIS:作用类似于PTR
格式:THIS 类型
操作:为相应的变量名或标号指定属性,使其与下一条邻接语句的变量或标号的属性相同
- PTR:指定变量名或标号的数据类型
DATA1 DB 10H, 20H, 30H
DATA2 DW 4023H, 1A00H
; PTR
MOV AX, WORD PTR DATA1 ; AX <-- 2010H
MOV BL, BYTE PTR DATA2 ; BL <-- 23H
; THIS
B_VAR EQU THIS BYTE ; 这个伪指令不占用段空间
W_VAR DW 10 DUP(0) ; B_VAR和W_VAR的地址相同
优先级
伪指令
伪指令不会被翻译成机器码,自然也不会被CPU执行,不会占用内存。(但是数据定义伪指令是个例外)
数据定义伪指令
格式:名字 DB/DW/DD/DQ/DT 数据项表
功能:为程序分配指定数目的存储单元,并根据实际情况初始化
伪指令 | 占字节数 |
---|---|
DB | 1 |
DW | 2 |
DD | 4 |
DQ | 8 |
DT | 10 |
重复操作符DUP
格式:名字 DB/DW/DD/DQ/DT 个数 DUP(内容)
功能:当一个定义的存储区内的每个单元要放置同样的数据时,可用DUP操作符。
符号定义伪指令
符号定义伪指令(EQU,=)
格式:符号名 EQU 表达式
符号名 = 表达式
操作:为表达式取一个名字,供以后引用
说明:
1、表达式可为常数、变量、标号、指令助记符、字符
串
2、用EQU定义的符号未清除前,不能重新定义。
清除EQU定义可用PURGE伪指令。
3、用”=”定义的符号可在任何时候进行重定义,但是EQU的变量名不能改变
4、二者均不占用存储空间,仅是给符号赋值
标号定义伪指令?
标号定义伪指令LABLE
格式:标号 LABLE 类型(FAR,NEAR)
变量 LABLE 类型(BYTE,WORD,...)
操作:在原有变量或标号的基础上定义一个新的类型不同的变量或标号。
VAR1 LABLE BYTE;后定义
VAR2 DW 10 DP(?);原有
VAR1与VAR2地址相同,但类型不同
段定义伪指令
定义逻辑段,段名字不重要,但一般都用代码(CODE)、数据(DATA)、堆栈(STACK)
格式:SEGMENT和ENDS承兑出现
段名 SEGMENT [定位类型][组合类型]['类别名']......
段名 ENDS
注意:段定义伪指令并不会给段寄存器赋值,所以通常会在代码段的最开始给段寄存器赋值
对数据段和堆栈段,段中的语句一般是变量定义。而代码段则是指令语句。
中括号内是可有可无的部分,是对段地址的特殊限定。
-
定位类型
规定对该段的起始边界地址的要求- PAGE:段的起始地址为一页(PAGE)的开始,即
×××× ×××× ×××× 0000 0000
,低8位为0, 256字节称为一页 - PARA:段起始地址为一节(PARAGRAPH)的开始,即
×××× ×××× ×××× ×××× 0000
,低4位为0 - WORD:段起始地址为一规则字的开始 ,即偶地址开始,
×××× ×××× ×××× ×××× ×××0
,最低位为0 - BYTE:段起始地址为任意值,即从任何字节开始都行。
注意:这里说的是20位的物理地址
- PAGE:段的起始地址为一页(PAGE)的开始,即
-
组合类型
表示该段与程序中其他段的关系(即相对位置)- NONE:该段独立,与其他段无关
- PUBLIC:该段可与其他同名同类别的段相邻地连接在一起,共同拥有一个段基址
- STACK:与PUBLIC相同,但作为堆栈段处理
- COMMON:该段可能与其他同名同类型的段发生覆盖,共同拥有一个段基址,段的长度取决于最长的COMMON段
- AT表达式:该段应放在AT后的表达式值(16位)所指定的段地址上。这种方式用于代码段。
- MEMORY:该段位于被连接在一起的其它所有段之上
-
类别
在SEGMENT后面用单引号括起来的字符串。所有同类别的段会成为一个段组,其中地这些段,不管是一个挨着一个地存放,还是发生覆盖。
seg1 SEGMENT PARA STACK ‘stack’ … seg1 ENDS seg2 SEGMENT PARA STACK ‘stack’ … seg2 ENDS ; 这样,seg1和seg2会被安排在一起
段寻址伪指令
明确段名与段寄存器的关系。当然这个只是给程序员看的,并不会变成机器指令,自然也不会改变的段寄存器的值。
格式:
ASSUME 段寄存器 : 段名 . . .
CODE SEGMENTASSUME CS:CODE, DS:DATA; CODE和DATA位段名MOV AX, DATAMOV DS, AX; 将DATA装入DS段寄存器
- 代码段中必须至少有一个ASSUME语句
- ASSUME可以出现在源程序中的任意地方
- 只是说明段名与段寄存器的对应关系,并没有把段基址值送入段寄存器
注意:这里不用给CS
段寄存器赋值,当然你也没办法用MOV
给它赋值,只用关注DS
,SS
,ES
过程定义伪指令
格式:
过程名 PROC 属性过程体RET过程体
过程名 ENDP
- 过程名是该子程序名,也是指令CALL的目标操作数
- 过程的属性有两种:
NEAR
和FAR
,分别表示段内调用和段间调用。若省略,则默认为NEAR
- 至少有一条
RET
指令,可在过程中的任何位置,但是所有分支最后必须执行一次RET
指令
程序计数器和定位伪指令?
-
程序计数器$
$:表示程序下一个所能分配的存储单元的偏移地址 -
定位伪指令ORG
格式1: ORG 表达式
格式2: ORG $+表达式
功能:指定下一条指令语句或变量的偏移地址
宏定义伪指令
就像c语言的宏定义一样
格式:
宏名 MACRO [形参列表]宏定义体ENDM
DADD MACRO X,Y,Z
MOV AX,X
ADD AX,Y
MOV Z,AX
ENDM
; Z = X + Y
DADD DATA1, DATA2, SUM
; 宏调用
嗐,还会有人不知道宏调用和过程调用的区别吗?
- 类比C语言的宏函数和函数。
- 宏调用,只是简化的源程序,不能简化机器码长度,所以还是不能节省内存单元。
- 宏调用比较快,没有那堆出栈入栈保存现场的操作。
汇编结束伪指令
格式: END [表达式]
END后跟的表达式通常就是程序第一条指令的标号(CPU要执行的第一条指令的地址)
注意:这个标号一定不会是一个伪指令的标号,因为伪指令不会被CPU执行
源程序的结构
作为子过程
XOR AX, AX
是AX寄存器清零的写法,保护AX
; ---------------------------定义DATA段
DATA SEGMENT<数据、变量在此定义>
DATA ENDS
; ---------------------------定义CODE段和子过程
CODE SEGMENTASSUME CS:CODE, DS:DATA
MY_PROC PROC NEAR
; ---------------------------代码先改变段寄存器
START: PUSH DSXOR AX, AXPUSH AXMOV AX, DATAMOV DS, AX
; --------------------------这里写程序,一定要用RET作为结束
; --------------------------
MY_PROC ENDP
CODE ENDS
END START
作为独立代码段
; ---------------------------堆栈段
stack SEGMENT PARA ‘stack‘
DB 100 DUP(‘stack’)
stack ENDS
; ---------------------------数据段
data SEGMENT
<数据、变量在此定义>
data ENDS
; ---------------------------代码段
code SEGMENT
ASSUME CS:code, DS:data, ES:data
; 改变段寄存器
start: MOV AX, data
MOV DS, AX
MOV ES, AX
; ---------------------------
<此处加入你自己的程序段>
; ---------------------------返回DOS
MOV AL, 4CH
INT 21H
; ---------------------------结束
code ENDS
END start
DOS系统调用
系统功能调用有两种,一种称为DOS功能调用,另一种称为BIOS功能调用
用户程序在调用这些系统服务程序时,不是用CALL命令,而是采用软中断指令INT n来实现。
格式:
MOV AH, <功能号>
INT 21H ; 进入DOS系统调用
读取一个输入字符(01H)
MOV AH, 1
INT 21H
<AL中是字符的ASCII码>
读取字符串(0AH)
str_input DB 10,?, 10 DUP(?) ; 定义输入缓冲区MOV AH, 0AH
LEA DX, str_input
INT 21H
若用户键入的字符数(包括回车)≥定义的N1,本功能调用将不再接收新的键入,且光标不再向右移动。
显示一个字符(02H)
MOV AH, 2
MOV DL, <字符>
INT 21H
显示字符串(09H)
MOV AH, 9
LEA DX, <字符串>
INT 21H
注意:被显示的字符串必须以’$’结束。
BIOS系统调用
BIOS系统调用的代码固化在了EPROM里