一、汇编语言特点
1、汇编语言程序设计特点
1.1、与机器相关性
汇编语言是机器指令的一种符号表示,而不同类型的 CPU 有不同的机器指令系统,所以汇编语言程序与机器密切相关,这就导致汇编语言的移植性很低。
1.2、执行的高效性
程序员直接在编译执行代码,可以做到优化程序的每一步、每一个细节。
1.3、编写程序的复杂性
汇编语言面向机器,汇编指令功能单一,每一步都需要程序员设计。
1.4、 调试的复杂性
(1)汇编语言涉及机器资源的细节,在调试过程中需要清楚每个资源的变化情况。
(2)程序员在编写汇编语言程序时,为了提高资源的利用率,经常使用各种技巧,而这些技巧会破坏程序的可读性。
2、汇编语言的格式
汇编语言的源程序语句包括指令性语句和指示性语句。
指令语句:在编译时产生机器代码。
指示语句:引导汇编程序在汇编进行操作,如数据定义、分配内存单元、只是程序结束。
2.1、标识符
标识符:一般表示符号地址,具有段基址、偏移量、类型三种属性。
定义规则:
- 可以由字母A~Z(不区分大、小写)、数字0-9、特殊符号(如“?”)等组成
- 不能以数字开头,句号“.”之恶能作为首字符,长度小于31个字符,不能与保留字重名
- 不能重复定义
标识符分为标号和名字两类
(1)标号:指令中出现的标识符为标号,以冒号(:)结束,是指令的符号地址,用来代替指令在存储器中的地址。
(2)名字:伪指令中出现的标号是伪指令的名字,通常为变量名、常量名、过程名。
2.2、操作符
操作符包含指令助记符和伪指令助记符。它由保留字组成。
(1)指令助记符:即指令规定的符号,各种指令。
(2)伪指令(指示性)助记符:8086宏汇编MASM5.0规定的常用伪指令。
2.3、操作数
被操作符操作的对象即为操作数,它可以是常量、寄存器、存储器、表达式。
2.4、注释
注释以分号(;)开头,可放在指令后,也可单独一行。
3、8086宏汇编源程序组成
3.1、源代码(输出HELLO!)
STACK SEGMENT PARA STACK ;定义堆栈段,段名为 STACK(可以取其他的)
DB 100 DUP('?') ;分配堆栈的大小,设置为100字节,以?填充
STACK ENDS ;堆栈段结束
DATA SEGMENT ;定义数据段,段名为 DATA (可以取其他的)
STRING DB 'HELLO!','$' ;定义字符串数据
DATA ENDS
CODE SEGMENT ;定义代码段,段名为 CODE (可以取其他的)
ASSUME CS:CODE, DS:DATA, SS:STACK ;特别重要,将 CS、DS、SS 指向定义的段
START: MOV AX, DATA ;程序开始的地方
MOV DS, AX
MOV AX, STACK
MOV SS, AX
LEA DX, STRING
MOV AH, 09H
INT 21H
MOV AH, 4CH
INT 21H
CODE ENDS
END START ;程序结束的地方
3.2、解释
8086包括代码段、数据段、堆栈段、附加段。
- 每个段有一个段名,以符号SEGMENT开始,以语句ENDS结束,这两者都要有名字,且名字必须相同。
- ASSUME指定 该段加载的段基址寄存器,将CS、DS、SS依次指向CODE、DATA、STACK的段,但是并没有给CS、SS赋值。
- 程序开始先用传送指令将数据段DATA和堆栈段STACK地址分别赋值到DS、SS。
二、8086宏汇编语言基本语法
数据项包括字符集、常量、保留字、标识符、表达式
1、字符集
(1)英文字母:包括大、小写字母(宏汇编中大、小写字母作用相同,不予区分)
(2)阿拉伯数字:0~9
(3)特使字符:
- 可打印字符:+ - * / = _ ( ) [ ] { } : ; ,? ‘ @ ¥ & # %
- 不可打印字符:空格、制表符(TAB键)、回车符、换行符
2、常量
源程序中具有固定值的数均称为常量
2.1、数值常量
(1)二进制:以 B 结尾,如:01001101B
(2)八进制:以 O 结尾,如:72O
(3)十进制:以 D 结尾,如:65
(4)十六进制:以 H 结尾,若最高位为字母A~F,前面应添加0,如:0FFFFH
2.2、字符串常量
字符串常量包含在两个单引号之间的一连串 ASCII 码字符。如:’ERROR‘
3、保留字
源程序中具有特定意义的、不可改动的字符序列称为保留字。
指令助记符、寄存器名、伪指令助记符等
4、标识符
标识符由用户自定义的、具有特殊意义的字符序列,由字母、数字、特殊字符组成,不能超过31个字符,且不能与任何保留字相同。
4.1、变量
变量是指存放在内存单元中的数据,所以可以变化。
包含三个属性
(1)段基址
(2)偏移地址
(3)类型:BYTE、WORD、DWORD 等
4.2、标号
用户为某条指令所取得名字,等于该指令对应的目标代码的存放地址。
具有三个属性
(1)段基址
(2)偏移地址
(3)类型:NEAR、FAR
4.3、段名
段名是用户为程序某个段所取得名字,等于该段的段地址。
4.4、过程名
过程名是用户为程序某个过程所取的名字,等于该过程的入口地址。
5、表达式
表达式是由若干操作数和运算符构成的有意义的组合序列。
5.1、算术运算符
仅允许整数为操作数,结果也为整数,包括加(+)减(-)乘(*)除(/)和MOD(取模运算)
注意:除(/)是取商,取模(MOD)是取余数。
5.2、逻辑运算符
与(AND)、或( OR)、异或( XOR)、非( NOT)运算符,只能对常数进行运算,结果也是常数。
5.3、关系运算符
两个无符号数进行大小关系比较,若关系满足则返回全1,否则返回全0。
相等EQ,不等NE,小于LT,大于GT,小于等于LE,大于等于GE
注意:
(1)关系运算的结果是一个逻辑值,即真或假
(2)关系运算符只对常数(或相当于常数)进行运算,参加运算的两个数是无符号数。
(3)关系为真,结果二进制全为 1,关系为假,结果二进制全为 0,二进制的长度取决于指令中的目的操作数的长度。
5.4、分析运算符
分析运算符对单个操作数进行属性分解,包括:SEG、OFFSET、TYPE、LENGTH、SIZE
(1)SEG:取变量或标号的段地址
(2)OFFSET:取变量或标号的偏移地址
(3)TYPE:取变量的类型,返回变量的长度1(字节)2(字)4(双字)6(三字)8(四字)10(五字);取标号的类型,返回-1(NEAR)或-2(FAR)
(4)LENGTH:取变量中元素的个数。若使用 DUP()定义数组的变量,结果为单元的个数,否则结果为 1。
(5)SIZE:取所定义存储区的字节数(TYPE*LENGTH)。若使用DUP()。取所定义的变量或字节个数;没使用DUP(),则取第一个数据的字节数。
5.5、合成运算符
合成运算符对单个操作数重新生成段地址、偏移量相同而类型不同的新操作数。
(1)PTR:用来指定地址操作数的类型。
PTR:<新类型> PTR <存储器操作数>
BYTE PTR, WORD PTR, DWORD PTR
NEAR PTR, FAR PTR
PTR还可以用来进行强制类型转换
(2)THIS:指定新类型
THIS: THIS <新类型>
三、伪指令
常用伪指令:符号定义伪指令、数据定义伪指令、段定义和段寄存器指定伪指令、过程定义伪指令、汇编结束伪指令。
1、符号定义伪指令
符号定义伪指令有两种: EQU 和 =。
① EQU 等值语句
格式: <名 字> EQU <表达式>
功能:把表达式的值赋给符号名。
举例:NUMBER EQU 8
② = 等号语句
格式: TMP = 6
功能:将符号TMP赋值为6。
EQU 和 = 的区别:
EQU 定义后的符号名(除非解除)不允许重复定义;
= 对定义后的符号名可以重复定义。
③ PURGE 解除语句
格式: PURGE 符号1,符号2,符号3
功能:解除对符号1、符号2、符号3的赋值。
举例:PURGE NUMBER
PORT1 EQU 3 ; PORT1=3
PORT2 EQU PORT1+2 ; PORT2=5
T1 EQU ADD ; 定义T1与ADD同义
CONT EQU CX ; 定义CONT与CX同义
N1=9
N1=6 ; 重复定义N1,其值最终为6
PURGE PORT1 ; 解除PORT1的赋值
PORT1 EQU 10 ; PORT1重新赋值为10
2、数据定义伪指令
一个字两个字节
字节 定义: 符号 DB 〈表达式〉
2字节 定义: 符号 DW 〈表达式〉
4字节 定义: 符号 DD 〈表达式〉
8字字 定义: 符号 DQ 〈表达式〉
10字节 定义: 符号 DT 〈表达式〉
2.1、定义变量
格式:
<变量名> 数据定义伪指令 <操作数,操作数,……>
操作数可以是常数、变量、表达式。
注意事项:
☆ 数据定义中的数据默认值均为十进制;
☆ 数据定义不能超过伪指令的有效范围;
☆ 数据存放遵循“高位在高端”的原则。
注意事项:
☆ 字符串必须用单引号括起来;
☆ 当定义的字符多于两个字符的字符串时,只能使用DB伪指令。
2.2、段定义伪指令
段定义伪指令用于将源程序划分成若干段,这些段按照用途,可分为代码段、数据段、堆栈段、附加段,但不是所有的程序都必须包含这四个段。
(1)定义段格式
<段名> SEGMENT [定位类型][组合方式][类别]
<汇编语言语句>
<段名> ENDS
(2)段定义的参数
(1)NONE:表示本段于其它段无连接关系,本段有自己的段地址。缺省选项。
(2)PUBLIC:本段与同名段邻接在一起形成新段,该新段内所有段公用一个段基址,所有偏移量调整为相对新段地址的偏移量。
(3)COMMON:本段与其它COMMON类型的同名段形成一个覆盖段,所有同名段将具有相同的段基址,共享该覆盖段存储区。覆盖段长度取同名段中最长段的长度。
(4)STACK:本段与同名段连接成一个连续段作为堆栈段,系统自动对段寄存器SS赋予该连续段的首址,并初始化堆栈指针寄存器SP。
(5)AT表达式:本段从表达式指定的地址(绝对地址)开始装入。
(6)MEMORY:本段定位于所有其它段之前(地址最高端),若有多个这样的段,则只对第一个MEMORY段这样定位,其它按PUBLIC类型处理。
3、ASSUME伪指令
ASSUME :给各程序段指定段寄存器,但并不赋值。
4、ORG伪指令
ORG 规定了段内的指令或数据存放的开始地址。
DATA SEGMENT
ORG 100H ;起始偏移地址
X DB 12H
DATA ENDS
注意:
☆ 默认情况从0000H开始存放数据。
5、过程定义伪指令PROC、ENDP
CALL调用格式:
CALL <过程名>
在汇编语言中,过程的含义和子程序是一样的。
过程定义伪指令格式:
<过程名> PROC [类型]
……
RET
<过程名> ENDP
两种类型:
(1)NEAR:段内调用,默认类型;
(2)FAR: 段间调用
6、汇编结束伪指令
汇编语言源程序的最后,要加入汇编结束伪指令END,以使汇编程序结束。
格式:END <表达式>;
表达式为程序第1条指令的标号。
四、宏指令
为了简化汇编语言的书写,把一些频繁出现的程序段定义为“宏指令”。
在汇编过程中,将宏指令所代替的程序段汇编成相应的机器代码,并插入到源程序中宏指令要使用前:
- 宏定义
- 宏调用
- 宏扩展
五、DOS 和 BIOS 功能调用
(1)DOS和BIOS系统功能调用
为用户提供一些常用的系统服务程序,主要是I/O设备使用与管理、文件管理和目录操作等,它们以中断服务子程序的方式呈现,通过使用INT N直接调用。
(2)DOS和BIOS系统功能调用的不同
与DOS相比,BIOS是在更低的层次上为用户提供系统服务,因此,对于DOS和BIOS都可实现的功能来说,BIOS中断调用的移植性更差,但运行效率更高。
1、DOS 功能调用
DOS系统功能调用占用20H到27H的中断类型码,常用INT 21H
DOS系统功能调用方法:
(1)设置该功能要求的入口参数;
(2)将功能号送入AH中;
(3)执行INT 21H;
(4)分析返回的结果参数
常用的DOS系统功能调用—键盘功能与显示功能
1. 从键盘输入一个字符并回显(功能号AH=1)
MOV AH, 1
INT 21H ;<输入的字符在AL中>
2. 从键盘输入字符串并到缓冲区(功能号AH=0AH)
LEA DX, BUF
MOV AH, 0AH
INT 21H ;<输入的字符串在DS:DX指定的缓冲区中>
3. 向显示器输出一个字符(功能号AH=2)
<输出的字符放在DL中>
MOV AH, 2
INT 21H ;
4. 向显示器输出字符串(功能号AH=9)
<输出的字符由DS:DX指定>
MOV AH, 9
INT 21H ;
5. 返回DOS(功能号AH=4CH)
MOV AH, 4CH
INT 21H ;
2、BIOS 功能调用
BIOS功能调用主要实现对系统中各种常用设备的输入/输出操作的管理常用的BIOS 调用占用10H到1AH的中断类型码
BIOS调用方法:
MOV AH, <功能号>
<设置入口参数,一般将参数放在寄存器中>
INT <中断类型号>