Skip to content

第 4 章 汇编语言程序设计

一. 汇编语言的格式

分段结构

8086/8088 的程序是分段的,并分别将段寄存器 CS 、DS 、ES 和 SS 的内容作为段基值,每段所占内存容量可达 64KB

程序共有 3 段,它们分别是数据段(段名 DATA)、堆栈段(段名 STACK)和代码段(段名 CODE),各段由命令 SEGMENT 开始,并由命令 ENDS 结束

NAME1 SEGMENT
语句
...
语句
NAME1 ENDS

二. 语句的格式

0. 基本格式

指令语句

又称执行性语句,用于表达处理器指令(也称为硬指令),汇编后对应一条指令代码

[<标号>: ]<指令助记符>[<操作数>][; <注释>]
LOADREG:MOVAX, BX; AX <- AX + BX
伪指令语句

又称说明性语句,用来指示、引导汇编程序在汇编时做一些操作,如定义符号、分配存储单元、初始化存储器、过程怎么设置等

伪指令本身不占用存储单元

[<名字>] <伪指令助记符> <参数>, <参数>, … ; <注释>

标号与名字

一个标识符是由最多为 31 个字母、数字及规定的特殊字符(? @ _ $)等组成的,且不能用数字打头(以免与十六进制数相混淆)。

标号和名字是符号汇编语言语法的用户自定义的有特定意义的标识符。例如:SUM、CYCLE、PORT_VAL 等。

助记符

助记符是帮助记忆指令的符号,反映指令的功能

指令助记符是指处理器指令,表示的是处理器的操作

伪指令助记符由汇编程序定义,表达一个汇编过程中的命令

操作数与参数

指令语句的操作数表示参与操作的对象:寄存器名常量(数字常量或字符串常量),存储器操作数

伪指令的参数可以是常量、变量名、表达式等,可以有多个,参数之间用逗号分隔。

注释

; 后的任意字符序列

1. 常量

1.1. 常数

二进制、八进制、十进制、十六进制形式表达的数值

1.2. 字符和字符串

在单引号内的 1 个或多个 ASCII 字符组成,汇编程序将它们表示成字节序列,一个字节对应一个字符,A 等价于 41HAB 等价于 4142H

1.3. 符号常量

用符号定义的常量

Example

PORT_VAL EQU 80H 就将 80H 定义为符号 PORT_VAL,则 MOV AL, PORT_VALMOV AL, 80H 等价。

1.4. 数值表达式

数值表达式指由运算符连接的各种常量所构成的表达式。

运算符包括算术运算符逻辑运算符关系运算符地址运算符类型运算符

mov bx, 32+((13/6) mod 3);
mov dh, 01100100b shr 2;
mov ax, 10h gt 16;
mov dx, offset msg;
mov cx, type bvar;

2. 变量

存放在存储单元中的操作数的是变量,因为它们的值是可以改变的。

变量需要事先定义而后才能使用。程序中出现的存储单元地址的符号即它们的名字。

三属性
  • 段属性 (SEGMENT) : 说明改变量在哪个存储段中
  • 偏移地址属性 (OFFSET) : 说明改变量的段内偏移量
  • 类型属性 (TYPE) : 说明该变量所在内存的数据类型(字节、字、双字等)

2.1. 变量定义

变量定义伪指令为变量申请固定长度为单位的存储空间,并将相应的存储单元初始化。

[<变量名>][<变量定义伪指令>][<初值表>]
用户自定义标识符DB DW DD DF DQ DT参数,由常量、数值表达式或 ? 组成

多个存储单元如果初值相同,可以用复制操作符 DUP 进行说明。

DUP利用给出的一个初值(或一组初值)以及这些值应该重复的次数,来初始化存储器。

[<重复次数>][DUP(<重复参数>)]
DW10DUP(?)

三. 伪指令语句

在IBM宏汇编中有以下几种伪指令语句

  • 符号定义语句(Symbol definition)
  • 数据定义语句(Data definition)
  • 段定义语句(Segmentation definition)
  • 过程定义语句(Procedure definition)
  • 结束语句(Termination)

1. 符号定义语句

1.1. 等值语句 EQU

给符号定义一个值或定义别的符号名,甚至可以定义为一条可执行的指令

BOILING_POINT EQU 212
BUFFER_SIZE EQU 32 ; 给符号定义常量
COUNT EQU CX ; 定义寄存器CX的同义语

EQU 语句未解除前不能重新定义

1.2. 等号语句 =

能对符号进行再定义

EMP = 7
EMP = EMP + CX

1.3. 解除语句 PURGE

已经用 EQU 命令定义的符号可以用 PURGE 命令来解除

PURGE[<符号1>][<符号2>]
PURGEBOILING_POINTBUFFER_SIZE

2. 数据定义语句

2.1. 数据定义语句

为一个数据项分配存储单元用一个符号名与这个存储单元相联系,且为这个数据提供一个任选的初始值

THING DB ? ; 定义一个字节
BIGGER_THING DW ? ; 定义一个字
BIGGEST_THING DD ? ; 定义一个双字

2.2. 地址运算符

将存储器地址操作数分解为它们的各个组成部分

运算符功能
SEG返回段地址
OFFSET返回段内偏移地址
TYPE返回存储器操作数的类型部分
SIZE返回为存储器地址操作数所分配的字节数
LENGTH返回与存储器地址操作数相联系的基本单元数

2.3. 定义一个数据段

DATA_TABLES SEGMENT
BUFFER1 DB 100 DUP(0)
BUFFER2 DW 200 DUP(20H)
BUFFER3 DD 100 DUP(13)
DATA_TABLES ENDS

三个 BUFFER 都定义在同一个段内,所以 SEG BUFFER 均会得到 DATA_TABLE 的地址;三者的段内偏移量不同;数据类型不同。

3. 段定义语句

8086 的存储器是分段的,所以 8086 必须按段来组织程序和利用存储器。

段定义语句含义
SEGMENT段开始
ENDS段结束
ASSUME指明段内变量寻址时采用的寄存器
ORG规定段内起始地址

一个段由命令 SEGMENT 开始,由命令 ENDS 结束,它们必须成对出现,而且它们的语句中必须有名字,名字必须相同。最后用语句 END 来结束整个源程序。

ASSUME 语句,只是使汇编程序知道在程序执行时各个段寄存器的值,而这些段寄存器的实际值(除了代码段寄存器 CS 以外),还必须在程序执行时,用 MOV 指令来赋给。

MY_EXTRA SEGMENT
ALPHA DB ?
BETA DW ?
GAMMA DD ?
MY_EXTRA ENDS
MY_STACK SEGMENT
DW 100 DUP(?)
TOP EQU THIS_WORD
MY_STACK ENDS

4. 过程定义语句

过程是程序的一部分,它们可被程序调用。每次可调用过程的指令执行完后,控制返回调用它的地方。

在8086中调用过程和从过程返回的指令是 CALLRET:段内 NEAR 和段交叉 FAR

  • 段交叉指令把过程应该返回处的段地址段内偏移量这两者都入栈保护(CALL 指令)和退栈(RET 指令)
  • 段内的调用与返回指令只入栈和退栈段内的地址偏移量
<PROCEDURE_NAME> PROC <NEAR/FAR>
...
RET
<PROCEDURE_NAME> ENDP

5. 结束语句

一般来说每一个结束语句都与某个开始语句成对出现。END 语句标志着整个源程序的结束。

END[<表达式>]
ENDSTART

表达式产生一个存储器地址值,这个地址是程序执行时第一条要执行的指令地址

四. 指令语句

一条 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 处理器控制指令]]

CYCLE: LOCK DEC COUNT

3. 操作数寻址方式

4. 串操作指令

[[undergraduate/Intel8086/c3-instructions#5 串操作指令]]