第 4 章 汇编语言程序设计
一. 汇编语言的格式
分段结构
8086/8088 的程序是分段的,并分别将段寄存器 CS 、DS 、ES 和 SS 的内容作为段基值,每段所占内存容量可达 64KB
程序共有 3 段,它们分别是数据段(段名 DATA)、堆栈段(段名 STACK)和代码段(段名 CODE),各段由命令 SEGMENT 开始,并由命令 ENDS 结束
二. 语句的格式
0. 基本格式
指令语句
又称执行性语句,用于表达处理器指令(也称为硬指令),汇编后对应一条指令代码
[<标号>: ] | <指令助记符> | [<操作数>] | [; <注释>] |
---|---|---|---|
LOADREG: | MOV | AX, BX | ; AX <- AX + BX |
伪指令语句
又称说明性语句,用来指示、引导汇编程序在汇编时做一些操作,如定义符号、分配存储单元、初始化存储器、过程怎么设置等
伪指令本身不占用存储单元
[<名字>]
<伪指令助记符>
<参数>
, <参数>
, … ; <注释>
标号与名字
一个标识符是由最多为 31 个字母、数字及规定的特殊字符(? @ _ $)等组成的,且不能用数字打头(以免与十六进制数相混淆)。
标号和名字是符号汇编语言语法的用户自定义的有特定意义的标识符。例如:SUM、CYCLE、PORT_VAL 等。
助记符
助记符是帮助记忆指令的符号,反映指令的功能。
指令助记符是指处理器指令,表示的是处理器的操作。
伪指令助记符由汇编程序定义,表达一个汇编过程中的命令。
操作数与参数
指令语句的操作数表示参与操作的对象:寄存器名,常量(数字常量或字符串常量),存储器操作数。
伪指令的参数可以是常量、变量名、表达式等,可以有多个,参数之间用逗号分隔。
注释
;
后的任意字符序列
1. 常量
1.1. 常数
二进制、八进制、十进制、十六进制形式表达的数值
1.2. 字符和字符串
在单引号内的 1 个或多个 ASCII 字符组成,汇编程序将它们表示成字节序列,一个字节对应一个字符,A
等价于 41H
,AB
等价于 4142H
1.3. 符号常量
用符号定义的常量
Example
PORT_VAL EQU 80H
就将 80H
定义为符号 PORT_VAL
,则 MOV AL, PORT_VAL
与 MOV AL, 80H
等价。
1.4. 数值表达式
数值表达式指由运算符连接的各种常量所构成的表达式。
运算符包括算术运算符、逻辑运算符、关系运算符、地址运算符和类型运算符等
2. 变量
存放在存储单元中的操作数的是变量,因为它们的值是可以改变的。
变量需要事先定义而后才能使用。程序中出现的存储单元地址的符号即它们的名字。
三属性
- 段属性 (SEGMENT) : 说明改变量在哪个存储段中
- 偏移地址属性 (OFFSET) : 说明改变量的段内偏移量
- 类型属性 (TYPE) : 说明该变量所在内存的数据类型(字节、字、双字等)
2.1. 变量定义
变量定义伪指令为变量申请固定长度为单位的存储空间,并将相应的存储单元初始化。
[<变量名>] | [<变量定义伪指令>] | [<初值表>] |
---|---|---|
用户自定义标识符 | DB DW DD DF DQ DT | 参数,由常量、数值表达式或 ? 组成 |
多个存储单元如果初值相同,可以用复制操作符 DUP 进行说明。
DUP利用给出的一个初值(或一组初值)以及这些值应该重复的次数,来初始化存储器。
[<重复次数>] | [DUP(<重复参数>)] | |
---|---|---|
DW | 10 | DUP(?) |
三. 伪指令语句
在IBM宏汇编中有以下几种伪指令语句
- 符号定义语句(Symbol definition)
- 数据定义语句(Data definition)
- 段定义语句(Segmentation definition)
- 过程定义语句(Procedure definition)
- 结束语句(Termination)
1. 符号定义语句
1.1. 等值语句 EQU
给符号定义一个值或定义别的符号名,甚至可以定义为一条可执行的指令
EQU
语句未解除前不能重新定义
1.2. 等号语句 =
能对符号进行再定义
1.3. 解除语句 PURGE
已经用 EQU
命令定义的符号可以用 PURGE
命令来解除
PURGE | [<符号1>] | [<符号2>] | … |
---|---|---|---|
PURGE | BOILING_POINT | BUFFER_SIZE |
2. 数据定义语句
2.1. 数据定义语句
为一个数据项分配存储单元,用一个符号名与这个存储单元相联系,且为这个数据提供一个任选的初始值
2.2. 地址运算符
将存储器地址操作数分解为它们的各个组成部分
运算符 | 功能 |
---|---|
SEG | 返回段地址 |
OFFSET | 返回段内偏移地址 |
TYPE | 返回存储器操作数的类型部分 |
SIZE | 返回为存储器地址操作数所分配的字节数 |
LENGTH | 返回与存储器地址操作数相联系的基本单元数 |
2.3. 定义一个数据段
三个 BUFFER
都定义在同一个段内,所以 SEG BUFFER
均会得到 DATA_TABLE
的地址;三者的段内偏移量不同;数据类型不同。
3. 段定义语句
8086 的存储器是分段的,所以 8086 必须按段来组织程序和利用存储器。
段定义语句 | 含义 |
---|---|
SEGMENT | 段开始 |
ENDS | 段结束 |
ASSUME | 指明段内变量寻址时采用的寄存器 |
ORG | 规定段内起始地址 |
一个段由命令 SEGMENT
开始,由命令 ENDS
结束,它们必须成对出现,而且它们的语句中必须有名字,名字必须相同。最后用语句 END
来结束整个源程序。
ASSUME
语句,只是使汇编程序知道在程序执行时各个段寄存器的值,而这些段寄存器的实际值(除了代码段寄存器 CS
以外),还必须在程序执行时,用 MOV
指令来赋给。
4. 过程定义语句
过程是程序的一部分,它们可被程序调用。每次可调用过程的指令执行完后,控制返回调用它的地方。
在8086中调用过程和从过程返回的指令是 CALL
和 RET
:段内 NEAR 和段交叉 FAR
- 段交叉指令把过程应该返回处的段地址和段内偏移量这两者都入栈保护(
CALL
指令)和退栈(RET
指令) - 段内的调用与返回指令只入栈和退栈段内的地址偏移量
5. 结束语句
一般来说每一个结束语句都与某个开始语句成对出现。END
语句标志着整个源程序的结束。
END | [<表达式>] |
---|---|
END | START |
表达式产生一个存储器地址值,这个地址是程序执行时第一条要执行的指令地址。
四. 指令语句
一条 8086 指令是由一个操作码字段和一些由操作数寻址方式所指定的字段组成的。
1. 指令助记符
2. 指令前缀
2.1. 段超越前缀
改变默认段寻址
Example
SI
的默认段寄存器为 DS
,即指令 MOV AX, [SI]
与 MOV AX, DS:[SI]
等价
通过添加前缀,可以改变段寄存器 MOV AX, CS:[SI]
2.2. 重复
[[undergraduate/Intel8086/c3-instructions#^repeat-op]]
2.3. 锁定
[[undergraduate/Intel8086/c3-instructions#6 处理器控制指令]]
3. 操作数寻址方式
4. 串操作指令
[[undergraduate/Intel8086/c3-instructions#5 串操作指令]]