汇编语言
1
内容简介
PART PART PART PART PART PART
1. 2. 3. 4. 5. 6.
汇编语言 简介 8086/8088 指令系统 汇编语言 的指令格 式 循环与分 支程序设 计 子程序结 构 高级汇编 语言技术
一、宏 汇编; 二、 重复汇 编; 三、 条件汇 编 输入输 出; BIOS/DOS 中断; 磁 盘文 件存 取;图 形与 I/O 控制
2
PART 1. 汇编语言简介
汇编语言是通过 翻译而不是 通过解释实 现的。 一、翻译器( translator )
翻译器 是一种 程序 ,它可 以将 一种语 言编 写 的用户 程序转 换成 另一种 语言 的程序 。 转换前 程序使 用的 语言称 为源 语言( source language ),转 换后程 序使 用的语 言称 为目 标语言 ( target language )。 如果处 理器可 以直 接执行 源语 言编写 的程 序 ,就不 需要翻 译器 。反之 ,如 果处理 器只 能 执行目 标语言 编写 的程序 ,就 需要使 用翻 译 器。 3
汇编语言简介
二、翻 译过程
在翻 译过程 中, 源语言 编写 的源程 序并 不直 接执 行,在 翻译 结束后 ,它 们被翻 译成 可直 接执 行的目标程 序( object program )或 ,可 执行的 二进 制程序 ( executable binary program )。 实际 上在整 个过 程中, 有两 个不同 的过 程, 即翻 译和执 行, 它们是 不同 步的。
解释执 行只有一个 步骤:执 行源程序 (有时 源程序会被 转换成一 种易于解释 的中间 形式,如 JAVA 的字节码) 。
4
汇编语言简介
三、翻 译器分类
1. 汇编器( assembler ) :
根据 源语言 与目 标语言 的关 系不同 ,可 以把 翻译 器分成 两大 类: 如果 源语言 基本 上是数字型 机器语 言的 符号 表示 ,就把 这种 翻译器 称为 汇编器 ,源 语言 相应 地称为 汇编 语言。
2. 编译器( complier ) :
如果 源语言 是像 如 C 语言 等高 级语言 ,而 目 标语 言是数 字型 机器语 言或 者是机 器语 言的 符号 表示, 就把 这种翻 译器 称编译 器。 5
汇编语言的特性
在纯粹 的汇 编语言 中, 每条语 句都 精确地 产生 一条机 器指 令,也 就是 说,在 机器 指令和 汇编 语言之 间存 在着一一对 应的关 系。 与机器 语言 相比( 以 16 位 INTEL 为例) ,人 们更愿 意使 用汇编 语言 ,因为 16 进制 的指令 难记, 而容 易记住 表示 加、减 、乘 、除的 符号 ADD 、 SUB 、 MUL 和 DIV 。同 样,对 地址 , 更好记 的是 表示地 址的 符号名 称, 而不是 数字 。 汇编器 就是 将把符 号翻 译成机 器指 令。
6
汇编语言的特性
汇编 语言 除了和 机器 指令之 间存 在着 一一对 应的关系 之外 ,汇 编语言 的程 序员可 以访 问目标 计算 机的所 有 指令 ,可 以利用 目标 计算机 的所 有特性 ,而 高级语 言 程序 员没 有这样 的能 力。也 就是 说机器 语言 能做的 事 汇编 语言 全部可 以, 但高级 语言 则不行 。 用于 系统 编程的 语言 ,如 C 语言, 则同时 具有高 级语 言和 汇编 语言的 特性 ,它使 用高 级语言 的语 法,但 同 时又 具有 许多汇 编语 言才能 使用 的特性 。 汇编 语言 和高级 语言 的另一 个重 要区别 在于 汇编语 言 只能 运行 在指令 系统 相同的 机器 上,而 高级 语言具 有 很好 的可 移植性 。 7
为什么使用汇编语言
使用汇 编语 言编程 很困 难,这 一点 是千真 万确 的。而 且, 编写同 样的 程序, 它要 比高级 语言 花费更 多的 时间, 除此 之外, 还要 花更多 的时 间区调 试和 维护。 即然 如此, 为什 么还要 学习 汇编语 言呢 ?
主要有 两个 原因: 性能 和对计 算机 的完全 控制
1. 好的汇 编语 言生成 的代 码, 要比高 级语言 写的 代 码更 小更 快。而 这个 特性对 如: 智能卡 、蜂窝 电话 、设 备驱 动程序 、 BIOS 程序和关 键性 能应用 的内部 循环 是必 须的。 2. 操作系 统中 的低级 中断 处理 和陷阱 处理程 序, 及 8
为什么使用汇编语言
除了 性能 和对计 算机 的完全 控制 的原因 外, 还有以 下 四个 方面 的原因 :
1. 大项目 的关键往往 在于某些 关键 代码 段的性 能能否再 提高 2~3 倍。 2. 某些情 况下由于 缺乏内存 ,使用 汇编语言 可能是唯 一的方 法。智 能卡很难有 1MB 以上 的内存,也 不可能有 硬盘。但又 必须执 行复杂的加 密和解密计算 。 PAD 为了省 电也需要 小的 内存, 同时也都需 要短小精悍的 具有高效的 代码。 3. 为了 理解编 译器 的工作 原理,必 须首先理解 汇编语言 。因 为编译 器和汇编器 毕竟是人写的 。 4. 研究汇 编语言可以 使我们看 清楚 实际计算机 的结构 。对 于 学习计 算机体系结 构的学生, 编写汇编语言 是在体系结 构层 理解计 算机的唯一 的途径 。 9
为什么使用汇编语言
在多 数情 况下, 很小 的程序 会占 很多的 时间 。 %1 代 码有 可能 占 %50 的时间 , %10 的代 码占 %90 的执行 时间 是很 常见的 。 执行时 高 级 组 成
调 整
高级语 言
10 人年
100s
汇编语 言
50 人年
33s
关键 %10
1 人年
90s
其它 %90
9 人年
10s
关键 %10
6 人年
30s
其它 %90
9 人年
10s
间
10
高级语言和汇编语言程序 员
高级 程序 员从不 考虑 细节问 题, 他们往 往能 够直接 看 清问 题的 本质, 对全 局有清 楚的 认识, 从而 能够想 出 实际 提高 性能的 方法 。
汇编 语言 程序员 则不 同,他 们修 改程序 往往 只是为 了 节省 几个 时间周 期。
例如 在某 个用 PL/1 开发的 系统 中,发 生了 以下 著名的 两个 例子 :
用 3 个月 修改一个过 程,代码 是原来的 1/26 ,速度提高 50 倍;用 2 个月修 改一个过程, 代码是原来 的 1/20 ,速度 提高 40 倍。 用 1 个月 修改一个程 序,代码 由 50000BYTE 减少到 10000BYTE ;用 4 个月修改一 个程序,代 码由 65000BYTE 减少到 30000BYTE ,速度提 高 8 倍。 11
计算机的功能描述 操作系统 (数据源或目标) 数据 传送 装置
数据 存储 装置
控制 装置
数据 处理 装置
12
存储程序计算机硬件系统组 成 控制器
运算器 ( ALU )
输入设备
输入设备
存储器 数据流
控制流 13
8086/8088CPU 内部结构 数据寄存器
指针寄存器
通用寄存器 AH AL BH BL CH CL DH DL SP BP DI SI
AB 20 位
AX BX CX DX
地址加法 器
DB 16 位
CS DS SS ES IP
ALU 数据 总线 16 位
内部寄存器
总线 控制
暂存寄存器
ALU
EU 控制电路
标志寄存器 执行单元 EU
123455 队列总线 总线接口 单元 BIU 14
运算器简图
ALU 寄存器组
累加器
15
8086/8088CPU 寄存器 数据寄存器
通用寄存 器
指针寄存器
AH BH CH DH
AL BL CL DL
Prity Auxiliary Carry
段寄存器
Zero Sign
CS DS SS ES
Direction
OF DF IF TF SF ZF
Interrupt Trap Overflow
1 5
8
累加器寄存器 基数寄存器 计数寄存器 数据寄存器
堆栈指针 基数指针 源变址 目的变址
SP BP SI DI IP FLAGSH FLAGSL
Carry
AX BX CX DX
7
指令指针 标志寄存器 代码段寄存器 数据段寄存器 堆栈段寄存器 附加段寄存器
AF
PF
CF 0
16
8086 寄存器组织 15
FFFFF H
0
逻辑地 址
码段 15
19
段寄存 器
0000 0
CS SS DS ES
加法器
物理地 址
堆栈段
6 4KB OFFSET
数据段
0
附加 数据段 00000 H
17
8086/286/386/486/586 寄存 器 ID VIPVIF AC VM RF 3 1
2 4
2 3
1 6
EAX EBX ECX EDX
1 5
8
AH BH CH DH
ESP EBP ESI EDI
AL BL CL DL
段大小 20
AF
7
PF
CF 0
AX BX CX DX 堆栈指针 基数指针 源变址 目的变址
SP BP SI DI
EIP EFLAG S
段属性 段基地址 12 32 64 位描述符寄存器
NT IOPL OF DF IF TF SF ZF
IP FLAGS
指令指针 标志寄存器
CS DS SS ES FS GS
代码段寄存器 数据段寄存器 堆栈段寄存器 附加段寄存器
TI RPL TI RPL 18
PART 2. 8086/8088 指 令 系 统
指令就 是计 算机用 以控 制机 器各部 件协 调工作 的命 令 。 一条指 令对 应一种 规定 的基 本操作 ,用 一组特 定的 二 进制数 表示 ,称为 指令 字。 我们把 CPU 全部的 指令 集称为 指令系 统。 指令的 内容 通常包 括两 部分 :操作 性质 和操作 对象 。 对应的 指令 格式也 由两 部分 组成: 操作 码和操 作数 (或地 址码 );两 者可 以组 合,构 成具 体的指 令。 8086/8088 指令系统 特性如 下:
采用可变长 指令,指令 格式比较复 杂 寻址方式多 样灵活,处 理数据能力 较强,可处 理字节、 字、符 号等 有重复指令 和乘、除运 算指令。扩 充了条件转 移、移位 / 循环 指令
19
8086/8088 指令系统
8086/8088 指令 格式 操作 码
操作 数
操作 数
一地 址
二地址
三地 址
可分为 无操作 数指 令、单 操作 数指令 (一 地址指 令)、 二操作 数指 令(二 地址 指令) 和三 操作数 指令( 三地址 指令 ) 操作码 很简单 、普 通的二 进制 即可 操作数 较为复 杂
操作 数
如果操 作数在寄存 器中 ,由 于寄存 器个 数少, 编码 简 单。 如果操 作数在存储 器中 ,则 最少需 要 20 个 BIT 。
现在的 问题是 怎样 能使指 令较 短?也 就是 怎样来 表示地 址 20
8086 寻址方式
为了简单我们不 使用二进制 来表示操作 码,而是使用汇 编语言(符 号)来表示 操作码。 1. 与数据有 关的操作 码 为了讨 论寻址 方式 ,我们 使用 传送指 令: MOV d, s 为例来 进行说 明。
8086 为 16 位元系统,通 常可处理 8 和 16 位元数据, 在乘除时也 会产生 32 位 元数据。操作码 很简单、普 通的二进制
21
8086 寻址方式
1.1 立即寻址方式 (immediate addressing)
操作数 直接存 放在 指令中 ,紧 跟着操 作码 之 后,它 作为指 令的 一部分 存放 在代码 段里 , 这种操 作数称 为立即数。 立即数 可以是 8 位或 16 位。立即 寻址 方式用 来表示 常数, 通常 用来对 寄存 器赋初 值。 例 : MOV AL, 15 ;AL=0FH MOV AX, 1000H ;AX=1000H MOV EAX, 12345678H 立即数 只可以 用于源 操作 数,并 且操 作数的
22
8086 寻址方式
1.2 寄存器寻址方式 (register addressing)
操作数 在寄存 器中 ,指令 指定 寄存器 号。
例:
MOV
AX , BX
如果执 行前 AX=1000H , BX=1234H ,执行 后 AX=1234H , BX 不变。 MOV
BH , AL
;?
上述两 种寻址 方式 都是在 代码 段进行 ,其 中 寄存器 方式最 快, 下面我 们将 讨论新 的方 式
23
8086 寻址方式
其它方 式都是 先求 出操作 数的 地址, 再得 到操 作数。 在 8086 中地 址是由 段基地址 + 偏移地 址得到 ,偏移地址也称为 有效 地址 (effective address, EA) EA 可以 由下面 四种 成份组 成
位移量 :是 存放 在指令 中的 一个数 ,他 不是立 即数 ,而是 地址 。 基址 :是存 放在基 址寄 存器中 的内 容, 通常指向 数 据段中 数组 或字串 的首 地址 。 变址 :存放 在变址 寄存 器中的 内容 ,通 常用来访 问 数组或 字串 中的某 个字 符。 比例因 子:是 386 及以后 增加的 术语, 值为 1,2,4,8 等
24
8086 寻址方式
有效地址的计算 公式为 EA= 基址 +( 变址 X 比例因子 )+ 位移量
其中除 比例因 子外 ,其它 都可 正可负 。 基址寄 存器: BX , BP(32 位是 任何 通用寄 存 器) 变址寄 存器: SI , DI ( 32 位是除 ESP 外 的) 位移量 : 0 , 8 , 16 ( 32 位是 0 , 8 , 32 ) 比例因 子:( 32 位是 1,2,4,8 ) 25
8086 寻址方式
在某 些情况下, 8086 允许程 序员用跨 段 前缀 来改变系统 指定的默认 段,但有些 情 况不 允许使用跨 段前缀:
串处理 指令必 须使 用 ES 段 PUSH 、 POP 必须用 SS 段 指令必 须放在 CS 段
访问 类型:
指令: CS 用于取 指 堆栈: SS 所有 的堆栈 的进 栈和出 栈 目的串 : ES 串处 理指令 的目 的串 局部数 据: DS (可 用于除 堆栈 和目的 串外 的 所有数 据访问 ) 26
8086 寻址方式
OP 00 20
1.3 直接寻址 方式 (direct addressing)
操作数的有 效地址只包 含位移量。
例:
MOV
30000
AX , [2000H]
如右图 所示,执行 结果为 AX=2030H 。
…
…
如果 DS=3000H , 32000
CS
30 20
DS
我们可以用 符号地址来 代替数值地 址
如: MOV AX , VALUE 或 MOV AX , [VALUE] 如果 VALUE 在 ES 段,则应指定 跨段前缀 如: MOV AX , ES:VALUE 或 MOV AX , ES:[VALUE]
直接寻址适 合处理单个 变量,因为 8086 为了使 得指令字 节不 要过长, 规定双操作数 指令的两个 操作数中 ,只能有一 个使用 存储器 寻址 方式 。 27
8086 寻址方式
1.4 寄存器 间接 寻址方 式 (register indirect addressing) 操作数 的有 效地址 只包 含基 址寄存 器内 容或变 址寄 存器内 容。 例: MOV AX , [BX] 2000 如果 DS=200H , BX=1000H 如右 图所 示,执 行结 果为 … AX AX=3040H 。 DS 同样也 可以 跨段 3000 40 30 如: MOV AX , ES:[BX]
28
8086 寻址方式
1.5 寄存器 相对 寻址方 式 (register relative addressing) 也称为 直接 变址寻 址方 式, 操作数 的有 效地址 为基 址寄存 器或 变址寄 存器 的内 容和指 令中 指定的位 移 量之和 。 例: MOV AX , TABLE[SI] 也可 写成 MOV AX , [TABLE+SI] 如果 DS=3000H , SI=2000H , COUNT=2000H 则物 理地 址为: 30000+2000+3000=35000H 同样也 可以 跨段 如: MOV DL , ES:STRING[DI]
29
8086 寻址方式
1.6 基址变 址寻 址方式 (based indexed addressing) 操作数 的有 效地址 是一 个基 址寄存 器( BX 或 BP ) 和一个变址 寄存 器( SI 或 DI )的内容 之和 。 例: MOV AX , [BX][DI] 也可 写成 MOV AX , [BX+DI] 如果 DS=1234H , BX=111H , DI=19H 则物 理地 址为: 12340+111+19=1246AH 同样也 可以 跨段 如: MOV DX , ES: [BX][DI]
30
8086 寻址方式
1.7 相对基 址变 址寻址 方式 (relative based indexed addressing) 操作数 的有 效地址 是一 个基 址寄存 器与一个变 址寄 存器的 内容 和指令中指 定的 位移量 之和 。 例: MOV AX , MASK[BX][DI] 也可 写成 MOV AX , MASK[BX+DI] 如果 DS=1234H , BX=111H , DI=19H , MASK=10H 则物 理地 址为: 12340+111+19+10=1247AH 同样也 可以 跨段 如: MOV DX , ES: MASK [BX][DI] 注意: 有关 32 位比例 变址寻 址方 式和前 面公 式类
31
8086 寻址方式
IP
EA
2. 与转移地 址有关的 寻址方式
位移 量
这种寻 址方式 用来 确定转 移指 令及 CALL 指 令的转 向地址 。
2.1 段内直接寻址
转向的 有效地 址是 当前 IP 寄存 器的内 容和 指令中 指定的 8 位或 16 位位移 量之和 。 这时有 效地址 用相 对于当 前 IP 地址 的位移 量来表 示,所 以它 是一种 相对 寻址。 指令 中 的位移 量是转 向的 有效地 址与 当前 IP 值之 差。
32
8086 寻址方式
位移 量 IP
EA
段内直接寻址适 合于条件转 移及无条件 转移指令,但是 对于条件转 移,位移量 只允许为 8 位( 32 位机器允许 8 或 32 位)。 无条件转移指令 ,当位移量 为 8 位时称 为短跳转,当位 移量为 16 位时称 为近跳 转,指令的格式 汇编格式为 : JMP NEAR PTR P01_ABC (位移量为 16 位) JMP SHORT P09_XYZ (位移量为 8 位 )
33
8086 寻址方式
2.2 段内间接寻址
转向的 有效地 址是 一个寄 存器 或一个 存储 单 元的内 容。 这个寄 存器或 存储 单元的 内容 可以用 数据 寻 址方式 中除立 即数 以外的 任何 一种寻 址方 式 取得, 所得到 的转 向的有 效地 址用来 取代 IP 寄存器 的内容 。 这种寻 址方式 以及 以下两 种段 间寻址 方式 都 不能用 于条件 转移 指令。 也就 是说条 件转 移 指令只 能用于 段内 直接寻 址的 8 位位 移量 , 而 JMP 和 CALL 指令 则可用 四种 寻址方 式中 的任意 一种。 34
寄存器 指令 数据 寻址方 式
根据数 据 寻址方 式 或 计算出 EA 值
转向 的有 效地址
转向 的有 效地址
存储单 元 35
8086 寻址方式
段内间 接寻址 转移 指令的 汇编 格式: JMP BX JMP WORD PTR [BP+TABLE] 假设 DS=2000H , BX=1256H , SI=528F , OFFSET=20A1 JMP BX (IP)=1256H JMP TABLE[BX] (IP)= 20000+1256+20A1 = (232F7)=3280H JMP [BX][SI] (IP)= 20000+1256+528F =(264E5)=2450H 36
8086 寻址方式
2.3 段间直接寻址
在指令 中直接 提供 了转向 段地 址和偏 移地 址 取代 CS 及 IP 寄存 器的内 容。 指令的 汇编格 式: JMP FAR PTR NEXTPROC 。 指令 偏移 地址
IP 寄存 器
段地址 CS 寄存器 37
8086 寻址方式
2.4 段间间接寻址 用存储器中两个 相临 WORD 的内容 取 代 CS 及 IP 寄存器的内容。 其中存储单元的 地址由除立 即数和寄 存器方式以外的 任意一种数 据寻址方 式取得。 指令的汇编格式 : JMP DWORD PTR [BX+P_ABC] 。 寻址方 式为直接 变址寻址, DWORD PTR 为双字 操作符,说 明转向地址需 取双字为段简转 移指令
38
存储器中 的 二个相继 字
指令
数据 寻址方 式
根据数据 寻址方式 计算 出 EA 值
转向的偏 移地址
IP
转向 的段 地址
CS
39
程序占有的空间和执行时间
8086 的机器 指令是 可变 长的, 1 条 16 位指 令 的长度 可为 1~7 个字 节, 32 位指令 可达 14 个 字节。 如果计 入前 缀字节 ,长 度还会 增加 。程序 大占的 空间就 越大 。 当程序 在运行 时, 访问存 储器 取得操 作数 或存放 结果需 要时间 ,运 算器执 行指 令也需 要时 间。尽 管 CPU 从 5MHZ 到 2GHZ ,在 体系结 构上 采用 数据预 取、高 速缓 冲、流 水线 等技术 ,但 时间还 是需要 的。 完全同 样功能 的不 同程序 ,可 能在占 有存 储空间 和执行 时间上 会有 很大差 别。 在时间 和空 间要求 高的情 况下, 要仔 细斟酌 程序 的算法 、数据结 构 及指令 与寻址 方式 的选 择。
40
8088/8086 Effective Address (EA) Calculation
Description Clock Cycles Displacement 6 Base or Index (BX,BP,SI,DI) 5 Displacement +(Base or Index) 9 Base+Index (BP+DI,BX+SI) 7 Base+Index (BP+SI,BX+DI) 8 Base+Index+Displacement (BP+DI,BX+SI) 11 Base+Index+Displacement (BP+SI+disp, BX+DI+disp) 12
add 4 cycles for word operands at odd addresses add 2 cycles for segment override 41
80x86 的指令系统 数据传送指令 串处理指令 算术指令 控制转移指令 逻辑指令 处理机控制指令
42
一、数据传送指令
1. 通用数 据传送 指令 MOV ( Move )传送 PUSH ( Push onto the stack )进栈 POP ( Pop from the stack )出栈 XCHG ( Exchange )交换 386+ 通用数 据传送 指令 MOVSx 、 MOVZx 、 PUSHA 、 PUSHAD 、 P OPA 、 POPAD 43
MOV AX, DATA_SEG MOV DS, AX
1. 通用数据传送指令
MOV AL, ‘A’
MOV 指令 格式 为 : MOV DST,SRC 执行 的操 作 :(DST)(SRC)
MOV AX, XYZ[BP][SI] MOV BX, OFFSET TAB
1. MOV mem/reg1, mem/reg2 ( 最少有 一个是寄存器 ,不 允许指 定段寄存器 )
2. MOV reg, data (data 是立即 数 )
3. MOV ac, mem or MOV mem, ac (ac 是累加 器 )
4. MOV segreg, mem/reg (segreg 不能是 CS ,此时不能 响 应中断 )
5. MOV mem/reg, segreg
6. MOV mem/reg, data 44
1. 通用数据传送指令
PUSH 进栈 指令 格式 为 :PUSH SRC 执行 的操 作 :(SP)(SP)-2 ((SP)+1,(SP))(SRC) POP 出栈指令 格式 为 :POP DST 执行 的操 作 :(DST)((SP+1),(SP)) (SP)(SP)+2 LOW SP
SP
PUSH PUSH PUSH PUSH
reg mem data * segreg
POP reg POP mem POP segreg
01 31
LOW
AX=3101H 45
1. 通用数据传送指令
XCHG 交换指令 格式为 :XCHG OPR1,OPR2 执行的 操作 :(OPR1) (OPR2)
可以在 寄存器 与寄存 器或 存储器 之间 交换数 据 不可以 使用段寄存 器。 除立即 数外的任意 寻找方 式 不影响 标志位 XCHG XCHG
BX , [BP+SI] CH , CL 46
2. 累加器专用传送指令
IN(Input) 输入 OUT(Output) 输出 XLAT (Translate) 换码 这组指 令只限 于使 用累加 器 AX 或 AL 传送信 息.
IN 输入指令 长格 式为 : IN AL,PORT( 字节 ) IN AX,PORT( 字 ) 执行 的操 作 : (AL)(PORT)( 字节 ) (AX)(PORT+1,PORT)( 字 ) 短格 式为 : IN AL,DX( 字节 ) IN AX,DX( 字 ) 执行 的操 作 : AL((DX))( 字节 ) AX((DX)+1,DX)( 字 )
47
2. 累加器专用传送指令
OUT 输出指令 长格式 为 : OUT PORT,AL( 字节 ) OUT PORT,AX( 字 ) 执行的 操作 : (PORT)(AL)( 字节 ) (PORT+1,PORT)(AX)( 字) 短格式 为 : OUT DX,AL( 字节 ) OUT DX,AX( 字 ) 执行的 操作 : ((DX))(AL)( 字节 ) ((DX)+1,(DX))AX( 字 )
48
2. 累加器专用传送指令
在 IBM-PC 机里 , 外部设 备最多可有 65536 个 I/O 端口 , 端口 ( 即外设 的端口地址 ) 为 0000~FFFFH. 其中 前 256 个端口 (0~FFH) 可以直 接在指令 中指定 , 这就是 长格式中 的 PORT, 此时 机器指 令用二个字 节表示 , 第二个字节就 是端口号 . 所以用长 格 式时可 以在指定中 直接指定端 口号 , 但只 限于前 256 个端口 . 当 端口号 >=256 时 , 只能使 用短格式 , 此时 , 必须先 把端口号 放到 DX 寄存器 中 ( 端口号 可以从 0000 到 0FFFFH), 然后再用 IN 或 OUT 指令 来传送信息 . 输入、输出指 令不影响标 志位。 .XLAT 换码指 令 格式为 : XLAT OPR 或 : XLAT 执行的 操作 :(AL) ((BX)+(AL))
其中 : BX 是表 的首 地址( OPR ), AL 是 OFFSET ,常 用于 代码 转换 (查表 )。 不影响 标志 位 MOV AL, 1
XYZ_TAB BX
0F 0E 0C 0B 0A 09 … 03 02 01 00
MOV BX , OFFSET XYX_TAB XLAT ( 等价于 XLAT XYX_TAB) 49
在使用 这条 指令之 前, 应先 建立一 个字 节 存储器 表,表 格的 首地址 提前 存入 BX 或者 EBX 寄存器 ,需 要转换 的代 码应 该是相 对于 表 格首地 址的 偏移量 也提 前存 放在 AL 寄存 F0040 器中, 表格 的内容 则是 所需 要转换 的代 码 ( BX ) ,该指 令执 行后就 可在 AL 中得到转 换后 的代码 。 ( AX ) =0F 例: 2C F004F ( BX ) =0040H ( AL ) =0FH ( DS ) =F000H ,把 F0000+0400+0F=F004F 的 内容送 到 AL ,执 行指 令 XLAT 后( AL ) =2CH ,即指 令把 AL 中的代码 0FH 转换 为 2CH 。 注意: AL 寄存器 只有 8 位,所 以表 格的 长度不 能超 过 256 。 50
3. 有效地址送寄存器指令
LEA(Load effective address) 有效地 址送寄 存 器 LDS(Load DS with Pointer) 指针送 寄存器 和 DS LES(Load ES with Pointer) 指针送 寄存器 和 ES
LEA 有效 地址 送寄存 器 格式 为 : LEA REG,SRC LEA BX , [BX+SI+0123H] LEA BX , LIST 执行 的操 作 :(REG) SRC 指令把源 操作 数的有 与 注意 LEA 于 MOV 的差 别 MOV BX, OFFSET LIST段寄存 效地 址送 到指定 的寄 存器中 (REG 不能是 MOV BX , [BX+SI+0123H] 功能相同 , 但后者快 器 ). SRC 可使用除 立即 数和寄 存器外 的任 一种存 储器 寻址 方式。
51
REG 不许 是段 寄存器 ,不 影响 标志寄 存器
3. 有效地址送寄存器指令
LDS 指针送 寄存器 和 DS 指令 格式 为 : LDS REG,SRC 执行 的操 作 :(REG) (SRC) (DS) (SRC+2) 把源 操作 数指定 的 4 个相继 字节送 到由 指令指 定 的寄 存器 及 DS 寄存器 中 . 该指令 常指 定 SI 寄存器 . LES 指针送 寄存 器和 ES 指令 格式 为 : LES REG,SRC 执行 的操 作 : (REG) (SRC) (ES) (SRC+2) 把源 操作 数指定 的 4 个相继 字节送 到由 指令指 定 的寄 存器 及 ES 寄存 器中 . 该指 令常 指定 DI 寄存器 . DS : BX LES DI , [BX]
LOW
34 12 00 30
DI ES 52
4. 标志寄存器传送指令
LAHF(Load AH with flags) 标志送 AH SAHF(store AH into flags)AH 送标志 寄存 器 PUSHF(push the flags) 标志进 栈 POPF(pop the flags) 标志出栈
.LAHF 标志送 AH 格式为 : LAHF 执行的操 作 :(AH) (FLAGS 的低 字节 ) .SAHF AH 送标志 寄存器 格式为 : SAHF 执行的操 作 :(PSW 的低字 节 ) (AH) .PUSHF 标志进 栈 格式为 : PUSHF 执行的操 作 :(SP) (SP)-2 ((SP)+1,(SP)) (PSW) .POPF 标志出 栈 格式为 : POPF 执行的操 作 :(FLAGS) ((SP)+1,(SP)) (SP) (SP+2)
53
二、 算术指令
除 INC 不影响 CF 标志外, 其余都影响 条件 标志 ( CF 、 ZF 、 SF 、 OF )
1. 加法指令 ADD(add) 加法 ADC(add with carry) 带进 位加法 INC(increment) 加 1
.ADD 加法 指令 格式 : ADD DST,SRC 执行的 操作 :(DST) (SRC)+(DST) .ADC 带进位 加法 指令 格式 : ADC DST,SRC 执行的 操作 :(DST) (SRC)+(DST)+CF .INC 加 1 指令 格式 : INC OPR 执行的 操作 :(OPR) (OPR)+1 54
1. 加法指令
溢出 ov nv 方向 dn( 减 ) up( 增 ) 中断 ei( 启用 ) di( 禁用 ) 零 zr nz 正负 ng( 负 ) pl( 正 ) 辅助进位 ac na 奇偶 校验 pe( 偶 ) po( 奇 ) 进位 cy nc
除 INC 不影响 CF 标志外 ,其余都影响 条件 标志 ( CF 、 ZF 、 SF 、 OF ) 1 。都不 溢 出 二进 制加 法
+
无符 号数
+
0000 0100 0000 1011 0000 1111
4 11 15 CF=0
带符 号数
+
+4 +11 +15 OF=0
2 。无符 号数 溢 出
3 。带符 号数溢 出
0000 0111 + 1111 1011 1 0000 0010
+
7 251 258
+
+
CF=1 ,现为 2 , 错
+
+7 -5 +2 OF=0
0000 1001 0111 1100 1000 0101
9 124 133
CF=0
+
+9 +124 +133
OF=1 ,现为 -123 , 错
3 。都 溢出 1000 0111 + 1111 0101 1 0111 1100
+
135 245 380
CF=1 ,现为 124 , 错
+
-121 -11 -132
OF=1 ,现为 124 , 错
55
1. 加法指令
加法指 令例子 DX=4652H ADD DX , 0F0F0H DX=3742H ZF=0 、 SF=0 、 CF=1 、 OF=0 2. DX=0002H 、 AX=0F365H 、 BX=0005H 、 CX=0E024H ADD AX , CX AX=0D389H ZF=0 、 SF=1 、 CF=1 、 OF=0 ADC DX , BX DX=0008H ZF=0 、 SF=0 、 CF=0 、 OF=0 这个 例子 是双精 度加 法
1.
56
2. 减法指令 SUB(subtract) 减法 SBB(subtract with borrow) 带借位减法 DEC(Decrement) 减 1 NEG(Negate) 求补 CMP(Compare) 比较 .SUB 减法指 令 格式 : SUB DST,SRC 执行的操作 :(DST) (DST)-(SRC) .SBB 带借位 减法指令 格式 : SBB DST,SRC 执行的操作 :(DST) (DST)-(SRC)-CF
57
除 DEC 不影 响 CF 标志外,其余 都影响 条件标 志( CF 、 ZF 、 SF 、 OF )
2. 减法指令
.DEC 减 1 指令 格式 : DEC OPR 执行的操作 :(OPR) (OPR)-1 .NEG 求补指 令 格式 : NEG OPR 执行的操作 :(OPR) -(OPR) .CMP 比较指令 格式 : CMP OPR1,OPR2 执行的操作 : (OPR1)-(OPR2) 该指令与 SUB 指令 一样执行减 法操作 , 但不保存结 果 , 只是根据结 果设置条件 标志 .
58
2. 减法指令
标志位说明:
CF 位说明 无符 号数相 减的 溢出, 同时 又是向 高位的 借位值 当无符 号数运 算时 ,如果 减数 > 被减 数,则 有借位 , CF=1 ;否 则, CF=0 OF 位说 明带符 号数 相减的 溢出 。 当有符 号数运 算时 ,如果 两个 数符号 相反 , 而结果 的符号 与减 数相同 ,则 OF=1 ;否 则, OF=0 在 NEG 运算 时,当 操作 数为 0 时, 求补运 算 使得 CF=0 ,其它 CF=1 ;同 样操作 数为 -
59
除 CF 和 OF 以外 的 条件标 志 无定
义
3. 乘法指令
如果乘 积的 高一半 为 0 ,则
CF=OF=0 否则, 则 CF=OF=1
MUL(Unsigned Multiple) 无符号数乘 法 IMUL(Signed Multiple) 带符号数乘 法 MUL 无符号数乘 法指令 格式 : MUL SRC 执行的操作 : 字节操作数 :(AX) (AL)*(SRC) 字操作数 :(DX,AX) (AX)*(SRC) IMUL 带符号数乘 法指令 格式 : IMUL SRC 执行的操作 : 与 MUL 相同 , 但必须是带 符 号数 , 而 MUL 是无符 号数 .
60
在乘法 指令里 ,目 的操作 数必 须累加 器, 字运算 为 AX ,字 节运算 为 AL 。两个 8 位数相 乘得到 的是 16 位乘积 放在 AX 中,两 个 16 位数 相乘 得 到的 32 位乘积 ,存放 在 DX , AX 中。 其中 DX 存放高 位字, AX 存放 低位字 。 指令中 的源操 作数 可以使 用除 立即数 以外 的任何 一种寻 址方式 。 如果乘 积的高 一半 为 0 ,则 CF=OF=0 ,否则 CF=OF=1 。对 于 MUL 可以 用来检 查字 节相乘 的 结果是 字节还 是字 ,或者 可以 检查字 相乘 的结果 是字还 是双字 。对 于 IMUL ,如 果乘积 的高 一半 是低一 半的符 号扩 展,则 CF 和 OF 均为 0 ,否 则就均 为 1 。 61
除法对 条件 标志无定义
4. 除法指令
如果 被除数 的高 8 位 ( 或 16 位 ) 绝对 值 ≥ 除数 的绝 对值,则商 会溢 出。 由系 统直接 转入 0 型中断 。
DIV(Unsigned divide) 无符号 数除法 IDIV(Signed divide) 带符号数除法 DIV 无符号数除法指 令 格式 : DIV SRC 执行的操作 : 字节 操作 :(AL) (AX)/(SRC) 的商 (AH) (AX)/(SRC) 的余 数 字操作 : (AX) (DX,AX)/(SRC) 的商 (DX) (DX,AX)/(SRC) 的 余数
62
IDIV(Signed divide) 带符号数除法 格式 : IDIV SRC 执行的操作 : 与 DIV 相同,但操 作书必须 是带符号数,商 和余数也是 带符号数, 且 余数的符号和被 除数符号相 同。 除法指令的寻址 方式和乘法 指令相同。 其 目的操作数必须 存放在 AX 或 DX , AX 或 EAX , EDX 中;而其源操作 数可以用除 立即数以外的任 一种寻址方 式。 63
5. 类型转换指令:
CBW(Convert byte to word) 字节 转换 为字 CWD(Contert word to double word) 字转换 为双字 CBW 字节 转换 为字 格式: CBW 执行的 操作 : AL 的内容 扩展 AH ,形成 AX 中的字。 即 如果 AL 的最 高有 效位为 0 ,则 ( AH ) =0 ;如果 AL 的最高 有效 位为 1 ,则( AH ) =0FFH 。 CWD 字转换 为双字 格式: CWD 执行的 操作 : AX 的内容 扩展 DX ,形成 DX : AX 中的 双字。 即如 果 AX 的最高 有效位 为 0 ,则( DX ) =0 ; 如果 AX 的最高 有效位为 1 ,则 ( DX ) =0FFH 。
64
6. 十进制调整指令 1. 压缩的 BCD 码调整指令 DAA: 加法的十进制调 整指令 DAS: 减法的十进 制调整指令 2. 非压缩 的 BCD 码调整指令 AAA: 加法的 ASCII 调整指 令 AAS: 减法的 ASCII 调整指令 AAM: 乘法的 ASCII 调整指 令 AAD: 除法的 ASCII 调整指 令
65
BCD 码 ( Binary Coded Decimal )
二进制编码的十 进制数:一 位十进制数 用 4 位二 进制编码来 表示 8086 支持压缩 BCD 码和非压缩 BCD 码的 调整运算 真值 8 64 二进制 编码 压缩 BCD 码 非压缩 BCD 码
08H 40H 08H 64H 08H 0604H
66
压缩 BCD 码加、减调整指 令 使用 DAA 或 DAS 指令前,应先执行 以 AL 为目的操作数的加法或减法指 令。 DAA 和 DAS 指令对 OF 标志无定义 ,按结果影响其他标志,例如 CF 反 映压缩 BCD 码相加或 减的进位或借 位 状态。
67
例:压缩 BCD 加法 mov al,68 ; al =68h ,压缩 BCD 码表示真值 68 mov bl,28 ; bl =28h ,压缩 BCD 码表示真值 28 add al,bl ;二进 制加法: al= 68h+2 8h=90 h daa ;十进制调整: al=9 6h ;实现 压缩 BC D 码加法: 68 + 28 = 96 68
例:压缩 BCD 减法 mov al,68 h ; al =68h ,压缩 BCD 码表示真值 68 mov bl,28 h ; bl =28h ,压缩 BCD 码表示真值 28 sub al,bl ;二进 制减法: al= 68h-2 8h=40 h das ;十进制调整: al=4 0h ;实现 压缩 BC D 码加法: 68 -28 = 40 69
三、逻辑指令 NOT 不允 许 使用 立即 数, 其他 4 条指令 除非 操作 数是 立即 数, 至少 有一 个操 作数 必须 存放 在寄 存器 中, 另一 个操 作数 可以 使用 任意 寻址 方式 。
1. 逻辑运 算指令 AND (and) 逻辑与 OR (or) 逻辑或 NOT (not) 逻辑非 XOR (exclusive or) 异或 TEST (test) 测试 AND 逻辑与指令 格式 : AND DST,SRC 执行的操作 :(DST) (DST)^(SRC)
70
除 NOT 外, CF= OF =0 , AF 无定义, SF , ZF , PF 根据运 算结果 定
1. 逻辑运算指令
OR 逻辑或 指令 格式 : OR DST,SRC 执行的 操作 :(DST) (DST)V(SRC) NOT 逻辑 非指 令 格式 : NOT OPR (不许用 立即 数,不 影响 标志位 ) 执行的 操作 :(OPR) (OPR) XOR 异或指 令 格式 : XOR DST,SRC 执行的 操作 :(DST) (DST)V(SRC) TEST 测试指令 格式 : TEST OPR1,OPR2 执行的 操作 :(DST)^(SRC) 两个操 作数 相与的 结果 不保 存 , 只根据 其特征置条 件码
71
逻辑指令应用 AND 指令 可用 于复位 某些 位(同 0 相与 ),不 影 响其他 位:将 BL 中 D3 和 D0 位清 0 ,其他 位不 变 and bl,11110110B OR 指令可 用于 置位某 些位 (同 1 相或) ,不影 响 其他位 :将 BL 中 D3 和 D0 位置 1 ,其 他位不 变 or bl, 00001001B XOR 指令可 用于 求反某 些位 (同 1 相异或 ),不 影响其 他位: 将 BL 中 D3 和 D0 位求 反,其 他不 变 xor bl, 00001001B TEST 指令通 常用于 检测 一些条 件是 否满足 ,但
72
CF
2. 移位指令 0
逻辑 及算 术左 移
0
CF
逻辑 右移
CF 算术右移
CF SHL (shift logical left) 逻辑左移 循环右移 SAL (shift arithmetic left) 算术左移 SHR (shift logical right) 逻辑右移 SAR (shift arithmetic right) 算术右移 CF ROL (Rotate left) 循环左移 循环左移 ROR (Rotate right) 循环右移 RCL (Rotate left through carry) 带进位循 环左移 RCR (Rotate right through carry) 带进位 循环右移 格式 : SHL OPR,CNT( 其余的类似 ) 其中 OPR 可以是除 立即数以外 的任何寻址方 式。移位次 数由 CNT 决定, CNT 可以是 1 或 CL 。 循环移位指令可 以改变操 作数中所 有位的位置 ; 移位指令 则常 常用来 做乘以 2 除以 2 操作 . 其中 算术移位指 令适用于 带符号数 运算 ,SAL 用来 乘 2,SAR 用来除以 2; 而逻辑 移位指令 则用来无符 号数运 算 ,SHL 用来乘 2,SHR 用来除以 2. CF
CF 带进位循 环左 移
带进位循 环右 移
73
四、串处理指令
REP 重复串 操作直 到 (CX)=0 为止
MOVS
( move string 串传递 )
STOS
( store in to string 串存 入)
LODS
( load from string 从串取 )
REPE/REPZ 当相 等 / 为零时 重复串 操作
REPNE/REPNZ 当不相 等 / 不为零时 重复 串操 作
CMPS
( compare string 串比较 )
SCAS
( scan string 串扫描)
74
1. REP MOVS/STOS/LODS
1. 与 REP 相配 合工作 的 MOVS,STOS 和 LODS 指令 REP 重复串 操作直 到 (CX)=0 止 格式 : REP string primitive 其中 String Primitive 可为 MOVS,LODS 或 STOS 指令 执行的 操作 : 1) 如 (CX)=0 则退出 REP, 否则 往下执 行 . 2) (CX) (CX)-1 3) 执行其中 的串 操作 4) 重复 1)~3)
75
1. REP MOVS/STOS/LODS
MOVS 串传 送指 令
格式 : 可有 三种 MOVS DST,SRC MOVSB( 字节 ) MOVSW( 字 ) 其中第二 、三种格式 明确地注明 是传送字节或 字,第一 种格式 则应在操 作数中表明 是字还是字 节操作,例如 : MOVS ES: BYTE PTR [DI],DS:[SI] 执行的操 作 : 1) ((DI)) ((SI)) 2) 字节操作 : (SI) (SI)+( 或 -)1, (DI) (DI)+( 或 -)1 当方向 标志 DF=0 时用 +, 当方向 标志 DF=1 时用 3) 字操 作 : (SI) (SI)+( 或 -)2, (DI) (DI)+( 或 -)2 当方向 标志 DF=0 时用 +, 当方向 标志 DF=1 时用 该指令不 影响条件码 . 76
1. REP MOVS/STOS/LODS
MOVS 指令可 以把由源变 址寄存器指向 的 数据段中的一个 字(字节) 传送到由目 的 变址寄存器指向 的附加段中 的一个字( 字 节)中去,同时 根据方向标 志及数据格 式 对源变址寄存器 和目的变址 寄存器进行 修 改。当该指令与 前缀 REP 联用时 ,可将数 据段中的整串数 据传送到附 加段中去。 这 里,源串必须在 数据段中, 目的串必须 在 附加段中,但源 串允许用段 跨越前缀来 修 改。在与 REP 联用时 还必须先把 数据串的 长度值送到计数 寄存器中, 即便控制指 令 结束。
77
1. REP MOVS/STOS/LODS
; define data segment datarea segment
mess1 db ‘hello world $' datarea ends ; define extra segment extra segment mess2 db 17 dup (?) extra ends ; define code segment code segment assume cs:code,ds:datarea,es:e xtra ......
;set DS register to current data segment mov ax,datarea mov ds,ax ;set ES register to current extra segment mov ax,extra mov cs,ax ...... lea si,mess1 lea di,mess2 mov cx,10 cld rep movsb ...... code ends 78
1. REP MOVS/STOS/LODS
CLD (Clear direction flag) 该指令 使 DF=0, 在执行 串操作 指令时 可使 地址自 动增 量 ; STD (Set direction flag) 该指令 使 DF=1, 在执行 串操 作 指令时 可使 地址自 动减 量 . STOS 存入串指 令 格式 : STOS DST STOSB( 字节 ) STOSW( 字 ) 执行的 操作 : 字节 操作 : ((DI)) (AL), (DI) (DI)+-1 字操 作 : ((DI)) (AX), (DI) (DI)+-2 该指令 把 AL 或 AX 的内容 存入 由 (DI) 指定 的附 加段的 某 单元中 , 并根据 DF 的值及 数据 类型修 改 DI 的内容 , 当它 与 REP 联用时 , 可把 AL 或 AX 的内 容存 入一个 长度 为 (CX) 的缓冲 区中 . 79
1. REP MOVS/STOS/LODS LODS 从串 取指令 格式 : LODS SRC LODSB LODSW 执行的 操作 : 字节 操作 : (AL) ((SI)), (SI) (SI)+-1 字操 作 : (AX) ((SI)), (SI) (SI)+2 该指令 把由 (SI) 指定的 数据段 中某 单元的 内容 送 到 AL 或 AX 中 , 并根据 方向标 志及 数据类 型修 改 SI 的内 容 . 指令 允许使 用段 跨越前 缀来 指定非 数 据段的 存储区 . 该指令 也不影 响条 件码 . 一般说 来 , 该指令 不和 REP 联用 . 有时缓 冲区中 的一串 字符需 要逐 次取出 来测 试时 , 可使 用本指 80 令.
2. REPE/REPZ 、 REPNZ/REPNE 及 CMPS 、 SCAS 指令
2. 与 REPE/REPZ 和 REPNZ/REPNE 联合 工作 的 CMPS 和 SCAS 指令 REPE/REPZ 当相 等 / 为零时 重复 串操作 格式 : REPE( 或 REPZ) String Primitive 其中 String Primitive 可为 CMPS 或 SCAS 指令 . 执行的 操作 : 1) 如 (CX)=0 或 ZF=0( 即某次比 较的 结果两 个操 作数不 等 ) 时退 出 , 否则往 下执行 2) (CX) (CX)-1 3) 执行其 后的 串指令 4) 重复 1)~3) 81
2. REPE/REPZ 、 REPNZ/REPNE 及 CMPS 、 SCAS 指令
REPNE/REPNZ 当不 相等 / 不为零 时重复串操 作 格式 : REPNE( 或 REPNZ) String Primitive 其中 String Primitive 可为 CMPS 或 SCAS 指令 执行的操作 : 除退出 条件 (CX=0) 或 ZF=1 外 , 其他操 作与 REPE 完全相同 . CMPS 串比较 指令 格式 : CMP SRC, DST CMPSB( 字节 ) CMPSW( 字 ) 执行的操作 : 1) ((SI))-((DI)) 2) 字节操作 : (SI) (SI)+-1, (DI) (DI)+-1 字操 作 : (SI) (SI)+-2, (DI) (DI)+-2 指令把由 (SI) 指向的 数据段中 的一个字 ( 或字节 ) 与由 (DI) 指向的 附加段中的 一个字 ( 或字节 ) 相减 , 但不保存结果 , 只根据结 果设置 条件码 , 指令的其它 特性和 MOVS 指令的 规定相同 . 82
2. REPE/REPZ 、 REPNZ/REPNE 及 CMPS 、 SCAS 指令
SCAS 串扫描 指令 格式: SCAS DST SCASB (字节 ) SCASW (字) 执行的 操作 : 字节操作 : (AL) - ((DI)), (DI) (DI)+-1 字操作 : (AX) - ((DI)),(DI) (DI)+-2 该指令 把 AL( 或 AX) 的内容 与由 (DI) 指定 的在 附加段 中的一 个字 节 ( 或字 ) 进行比 较 , 并不 保 存结果 , 只根 据结果 置条 件码 . 指令的 其他特 性 和 MOVS 的规定 相同 . 83
五、控制转移指令
总的来说,转移 可以分成两 类:段内转 移 和段间转移。段 内转移是指 在同一段的 范 围内进行转移, 此时只需改 变 IP 或 EIP 寄存器的内容, 即用新的转 移目标地址 代 替原有的 IP 或者 EIP 的值就可达 到转移 的目的。段间转 移则是要转 移到另一个 端 去执行程序,此 时不仅要修 改 IP 或者 EIP 寄存器内容,还 需要修改 CS 寄存器的内 容才能达到目的 。因此,此 时的转移目 标 地址应由新的段 地址和偏移 地址两部分 组 成。 84
五、控制转移指令
1. 无条件转 移指令: 指令
JMP(jmp) 跳转
1) 段内直 接短转 移 格式 :JMP SHORT OPR 执行的 操作 :(IP) (IP)+8 位位 移量( 8 位位 移量有 目标地 址 OPR 确定) 2) 段内直 接近转 移 格式 :JMP NEAR PTR OPR 执行的 操作 :(IP) (IP)+16 位位移 量 说明: 都可直 接使 用符号 地址 ,都使 用相 对寻址 ,在机 器执行 时是 当前的 IP 或 EIP 的值 (即 JMP 指令的 下一条 指令 的地址 )与 指令中 的 8 位位移 量之和 。位 移量需 要满 足向前 或向 后转移 85
五、控制转移指令
3) 段内间接转移 格式 :JMP WORD PTR OPR 执行的操作 :(IP) (EA) EA 值由 OPR 的寻址方式 确定,它可 以使 用除立即数以外 的任一种寻 址方式。如 果 指定的是寄存器 ,则把寄存 器的内容送 到 IP 或者 EIP 寄存器中; 如果指定的 是存储 器中的一个字或 者双字,则 把该存储单 元 的内容送到 IP 或者 EIP 寄存器 中。 86
五、控制转移指令
4) 段间直 接 ( 远 ) 转移 格式 :JMP FAR PTR OPR 执行的 操作 :(IP) OPR 的段 内偏移 地址 , (CS)OPR 所在 段的段 地址 使用直 接寻址 方式 ,可使 用符 号地址 。 5) 段间间 接转移 格式 :JMP DWORD PTR OPR 执行的 操作 :(IP) (EA) , (CS) (EA+2) EA 由 OPR 的寻址 方式确 定, 可以使 用除 立即数 及寄存 器以外 的任 何存器 寻址 方式。 根据 寻址方 式求出 EA 后, 把指 定的存 储单 元的字 的内 容送 到 IP 或 EIP ,并 把下一 个字 的内容 送到 CS 寄 存器。
87
2. 条件转移指令
条件转移指令根 据上一条指 令所设置的 条 件码来判别测试 条件,每一 种条件转移 指 令都有他的测试 条件,满足 测试条件则 转 移到由指令指定 的的转向地 址去执行那 里 的程序;如果不 满足则顺序 执行下一条 指 令。因此,当满 足测试条件 时: IP 或者 EIP 与位移量 相加得到 转向地址;不 满足 测试条件时, IP 或 EIP 值不变 。 OPR 应 指定一个目标地 址,在 8086 中只提 供短 转移格式,目标 地址应在本 条转移指令 的 下一条指令的 -128~+127 个字节 的范围 内。
88
2. 条件转移指令
1) 根据单 个条 件标志 的设 置情 况转移 JZ( 或 JE) (Jump if zero, or equal) 结果 为零 ( 或相等 ) 则转移 格式 :JE( 或 JZ) OPR( 不是测试 OPR 是否为 零,而是测 试 ZF 位 ) 测试条件 :ZF=1
JNZ( 或 JNE) (Jump if not zero, or not equal) 结果不 为零 ( 或不 相等 ) 则转移 格式 :JNZ( 或 JNE) OPR 测试条件 :ZF=0 JS (Jump if sign) 结果为负则转 移 格式 : JS OPR 测试条件 :SF=1 JNS (Jump if not sign) 结果为 正则转移 格式 :JNS OPR 测试条件 :SF=0 89
2. 条件转移指令
JO (Jump if overflow) 溢出 则转移 格式 : JO OPR 测试条件 :OF=1
JNO (Jump if not overflow) 不溢出则 转移 格式 : JNO OPR 测试条件 :OF=0
JP ( 或 JPE) (Jump if parity, or parity even) 奇偶位 为 1 则转移 格式 : JP OPR 测试条件 :PF=1
JNP ( 或 JPO) (Jump if not parity, or parity odd) 奇偶位 为 0 则 转移 格式 : JNP( 或 JPO) OPR 测试条件 :PF=0
90
2. 条件转移指令
JB ( 或 JNAE, JC) (Jump if below, or not above or equal, or carry) 低于 , 或者不 高于或等 于 , 或进位 位为 1 则转移 格式 :JB ( 或 JNAE,JC) OPR 测试条件 : CF=1
JNB ( 或 JAE,JNC) (Jump if not below, or above or equal, or not carry) 不低于 , 或者高于 或者等于 , 或进位位为 0 则转移 格式 :JNB ( 或 JAE,JNC) OPR 测试条件 : CF=0
这 10 条指令一般 适用于测试某 一次运算 的结果并根 据其不同 的特 征产生程 序分支作不 同的处理。 91
2. 条件转移指令
例:根据一次加 法运算的结 果实行不同 的 处理,结果为 0 做动作 2 ,否则做动 作 1。 (AX) ←(AX)+(TEMP) 解:┇ ADD AX , TEMP Y ACTION_2 (AX)=0? JZ ACTIO N_2 N ┇ ACTI ON_1 ACTI ON_2: ACTION_1 ┇ ACTI ON_2 92
2. 条件转移指令
2) 比较两 个无 符号数 , 并根据 比较的 结果转 移 JB ( 或 JNAE,JC) 低于, 或者不高 于或等于, 或进位位为 1 则转移 格式和测 试条件 : 同上 JNB ( 或 JAE,JNC) 不低于,或者 高于或等于 ,或进位 位为 0 则转 移 格式和测 试条件 : 同上
JBE ( 或 JNA) (Jump if below or equal,or not above) 低于或 等于 , 或不高 于则转移 格式 :JBE( 或 JNA) OPR 测试条件 :CF V ZF=1 JNBE( 或 JA) (Jump if not below or equal,or above) 不低于 或等 于 , 或者高 于则转移 格式 :JNBE( 或 JA) OPR
仔细体 会测试条件
93
2. 条件转移指令
3) 比较两 个带 符号数 , 并根据 比较的 结果转 移
JL( 或 LNGE) (Jump if less,or not greater or equal) 小于 , 或者 不大于或 者等于则转 移 格式 :JL( 或 JNGE) OPR 测试条件 :SF ∀ OF=1 JNL( 或 JGE) (Jump if not less,or greater or equal) 不小于 , 或者 大于或者 等于则转移 格式 :JNL( 或 JGE) OPR 测试条件 :SF ∀ OF=0 JLE( 或 JNG) (Jump if less or equal,or not greater) 小于或 等于 , 或者不 大于则转 移 格式 :JLE( 或 JNG) OPR 测试条件 :(SF ∀ OF)VZF=1 JNLE( 或 JG) (Jump if not less or equal,or greater) 不小 于或等 于 , 或者大 于则转移 格式 :JNLE( 或 JG) OPR 测试条件 :(SF ∀ OF)VZF=0
仔细体 会测试条件
94
2. 条件转移指令
4) 测试 CX 的值 为 0 则转移 指令 JCXZ (Jump if CX register is zero) CX 寄存 器的内 容为零 则转 移 格式 : JCXZ OPR 测试条 件 : (CX)=0
注 : 条件转移为 8 位短跳 , 不影 响条件码 !
95
3. 循环指令
LOOP 循环指 令 格式 : LOOP OPR 测试条 件 : (CX)<>0 LOOPZ/LOOPE 当为零 或相 等时循 环指 令 格式 : LOOPZ( 或 LOOPE) OPR 测试条 件 :(CX)<>0 且 ZF=1 LOOPNZ/LOOPNE 当不为 零或不 相等 时循环 指 令 格式 : LOOPNZ( 或 LOOPNE) OPR 测试条 件 :(CX)<>0 且 ZF=0
96
3. 循环指令
这三条指令的步 骤是 : 1) (CX) (CX)-1 2) 检查是否满足测 试条件 , 如满 足则 (IP) (IP)+D8 的符号扩充 . 这里使用的是相 对寻址方式 , OPR 必须指 定一个表示转向 地址的符号 标志(符号 地 址),在机器指 令里用 8 位位移量 D8 (范围 -128~127 )来 表示转向地 址与当 前 IP 值得差 。 循环指令不影响 条件码。 97
3. 循环指令
例: MOV CX,10 ┇
AGAIN: ┇ LOOP AGAIN
98
4. 子程序
CALL ( call )调 用指令
RET ( return )返回 指令
99
4. 子程序 1. CALL ( call )调用 指令 ( 1 )段内 直接近 调用 格式: CALL DST 执行的 操作: 当操 作数长 度为 16 位时, PUSH(IP) , (IP)←(IP)+D16 ( 1 )把 子程序 的返 回地址 ( CALL 指令的 下一条 指令的 地址) 存入 堆栈中 ,以 便子程 序返 回主程 序时使 用。 ( 2 )转 移到子 程序 的入口 地址 去执行 。 指令中 DST 给出转 向地址 (子 程序的 入口 地址, 即子程 序的第 一条 指令的 地址 ), D16 为机 器指 令中的 偏移量 ,是 转向地 址和 返回地 址之 间的差 100 值。
4. 子程序
( 2 )段内 间接 近调用 格式: CALL DST 执行的 操作 :当操 作数 长度 为 16 位时, PUSH(IP) , (IP)←(EA),DST 可使用 寄存 器或存 储器 寻址 方 式。 这两种 方式 均为近 调用 ,转 向地址 中只 包含偏 移地 址部分 , 段地址 保持 不变。 ( 3 )段间 直接 远调用 格式: CALL DST 执行的 操作 :当操 作数 长度 为 16 位时, PUSH(CS), PUSH(IP) , (IP) ←DST 指定的 偏移地 址, (CS) ← DST 指 定的段 地址 ( 4 )段间 间接 近调用 格式: CALL DST 执行的 操作 :当操 作数 长度 为 16 位时, PUSH(CS), PUSH(IP) , (IP) ←(EA) , (CS) ← (EA),EA 是由 DST 的寻101
4. 子程序
RET ( return )返回指 令 RET 指令放 在子程 序的 末尾, 使子 程序 在功能 完成 后返 回调用 程序 继续执 行, 而返 回地址 是调 用程序 调用 子程 序是存 放在 堆栈中 的, 因此 RET 指令操作 是返回 地址 出 栈送 IP 和 CS 寄存器 。 ( 1 )段内 近返 回 格式: RET 执行的 操作 :( IP )← POP () ( 2 )段内 带立 即数返 回 格式: RET EXP ( EXP 是一个 表达 式) 执行的 操作 :完成 与( 1 )相 同操 作后修 改堆 栈指针 ( SP ) ← ( SP ) +D16 ( D16 由 EXP 计算) 返回地 址出 栈修改 堆栈 指针 为了将 子程 序所需 要使 用的 参数入 栈, 使用完 后修 改堆 栈指针 使其 指向参 数入 栈以 前的值 。 102
4. 子程序
( 3 )段间 远返回 格式: RET 执行的操作:( IP )← POP () ( 4 )段间 带立即数返 回 格式: RET EXP ( EXP 是一个 表达式) 执行的操作:完 成与( 3 )相同操作 后修 改堆栈指针( SP ) ←( SP ) +D16 ( D16 由 EXP 计算) CALL 和 RET 不影响标志位。 103
5. 中断
INT 指令 格式 : INT TYPE 或 INT 执行的 操作 : (SP) ((SP)+1,(SP)) (SP) ((SP)+1,(SP)) (SP) ((SP)+1,(SP)) (IP) (CS)
(SP)-2 (PSW) (SP)-2 (CS) (SP)-2 (IP) (TYPE*4) (TYPE*4+2)
TYPE 为类 型号 ,可以是 常数或表 达式, 值在 0~255 范围 内。 INT 是一个 字节的中断 指令 ,隐 含的类 型号 为 3 。 104
5. 中断
INTO 若溢 出则 中断 执行的 操作 : 若 OF=1 则 : (SP) ( (SP)+1, (SP) ) (SP) ( (SP)+1, (SP) ) (SP) ( (SP)+1, (SP) ) (IP) (CS)
(SP)-2 (PSW) (SP)-2 (CS) (SP)-2 (IP) (10H) (12H)
INT 和 INTO 不影响除 IF 、TF 和A C以外 的标 志位 。 105
5. 中断
IRET 从中断 返回指 令 格式 : IRET 执行的 操作 : (IP) (SP) (CS) (SP) (PSW) (SP)
( (SP)+1, (SP) ) (SP)+2 ( (SP)+1, (SP) ) (SP)+2 ( (SP)+1, (SP) ) (SP)+2
指令的 标志位 由堆 栈中取 出的 值来设 定。 106
六、处理机控制指令
1. 标志处理 指令
CLC 进位位 置 0 指令 (Clear carry) CF 0 CMC 进位位求 反指 令 (Complement carry) CF CF STC 进位 位置 1 指令 (Set carry) CF 1 CLD 方向标 志置 0 指令 (Clear direction) DF 0 STD 方向 标志置 1 指令 (Set direction) DF 1 107
六、处理机控制指令
2. 其他处 理机控制指 令
NOP (No Operation)
无操作
HLT (Halt)
停机
WAIT (Wait)
等待
ESC (Escape)
换码
LOCK (Lock)
封锁
这些指令可以控 制处理机状 态 . 这们都不 影响条件码 .
108
六、处理机控制指令
NOP 无操 作指 令 该 指令 不执行 任何操 作 , 其机 器码 占有一 个字 节 , 在调试 程序 时往往 用这 条指 令占有 一定 的存储 单元 , 以 便在正 式运 行时用 其他 指令 取代 . HLT 停机 指令 该 指令 可使机 器暂停 工作 , 使处理机 处于 停机状 态 以便等 待一 次外部 中断 到来 , 中断结束 后可 继续执 行下 面的程 序 . WAIT 等待指 令 该 指令 使处理 机处于 空转 状态 , 它也 可以 用来等待 外部中 断的 发生 , 但中 断结 束后仍返 回 WAIT 指令 继续 等待 .
109
六、处理机控制指令
ESC 换码指令 格式 ESC mem 其中 mem 指出 一个 存储单元 ,ESC 指令把该 存储 单元的 内容送 到数 据总线 去 . 当然 ESC 指令不 允许使 用立 即数 和寄存 器寻 址方式 . 这条指 令在使 用协处 理机 (Coprocessor) 执行 某些 操作时 , 可从存储 器指得 指令 或 操作数 . 协处理 机 ( 如 8087) 则是为 了提 高速度 而可以 选配的 硬件 . LOCK 封锁 指令 该 指令 是一种 前缀 , 它可 与其 他指令 联合 , 用来 维 持总线 的锁 存信号 直到 与其 联合的 指令 执行完 为止 . 当 CPU 与其 他处 理机协同 工作时 , 该指令 可避 免破坏 有用
110
PART 3. 汇编语言的指令格式
一、汇编程序功能 翻译 编辑程 序
PROGR.ASM 文件
汇编程序 MASM
PROGR.OBJ 文件
连接 程序 LINK
PROGR.EXE 文件
上图表示了汇编语言程序建立及处理的过程,可归纳 如下四个步骤:
1. 2. 3. 4.
用编辑器建立 ASM 源文件; 用 MASM 程序把 ASM 文件转换成 OBJ 文件; 用 LINK 程序把 OBJ 文件转换成 EXE 文件; 键入文件名执行; 111
一、汇编程序功能
常用的汇编程序:
Microsoft Macro Assembler(MASM); Borland Turbo Assembler(TASM);
汇编程序的主要功能:
1. 检查源程序 2. 检测源程序中的语法错误,并给出错误信 息 3. 产生源程序的目标程序,并给出列表文件 (lst 文件,同时给出汇编语言和机器语言的 文件 ) 4. 展开宏文件 112
二、伪操作
汇编语 言程 序语句 除指 令以 外还可 以由 伪操作 和宏指令 组成。 伪操 作又称 伪指 令, 它不像 机器 指令那 样是 在程 序运行 期间 由计算 机来 执行 的,它 是在 汇编程 序对 源程 序汇编 期间 由汇编 程序 处理 的操作 ,他 们可以 完成 如数 据定义 、分 配存储 区、 指示 程序结 束等 功能。
( 一 ) 、数据定 义及 存储器 分配伪 操作
这一类 伪操 作的格 式是 : [Variable] Mnemonic Operand,...,Operand [;Comments]
其中变 量 (Variable) 字段 是可 有可无 的, 它用符 号地 址 表示, 其作 用与指 令语 句前 的标号 相同 ,但它 的后 面不 跟冒号 。如 果语句 中有 变量 则汇编 程序 使其记 以第 一个 字节的 偏移 地址。 113
( 一 ) 、数据定义及存储器分配伪 操作
注释 (Comments) 字段用 来说明 该伪 操作的 功能 ,它也 是可有 可无 的。 助记符 (Mnemonic) 字段说 明所用 伪操 作的助 记 符,常 用的有 以下 几种:
DB 伪操作用 来定 义字节 ,其 后的每 个操 作数都 占有 一个字 节。 DW 伪操作 用来 定义字 ,其后 的每 个操 作数都 占有 一 个字 ( 低位字节 在第 一个字 节地址 中 , 高位字 节在 第 二个字 节地 址中 ) 。 DD 伪操作 用来 定义双 字, 其后 的每个 操作 数占有 二 个字。 DQ 伪操 作用 来定义 四个 字,其 后的 每个操 作占有 四 个字。 DT 伪操 作用 来定义十 个字 节 ( 五个 字 ) ,其 后的 每个 操作数 占有 十个字 节, 形成 压缩的 BCD 码。 114
( 一 ) 、数据定义及存储器分配伪 操作
D_BYTE D_WORD D_DD
DB 10,’a’,20H;byte data DW 100,100H,-5 0A 61 DD 15*4, 0fffeh
MESSAGE
DB
43 45 4C 4C 4F
41 42
‘HELLO’ DB ‘AB’ DW ‘AB’ 42 41
20 64 00 00 01 FD FF
3C 00 00 00 FE FF 00 00 115
( 一 ) 、数据定义及存储器分配伪 操作 LOW
00 01 02
-
00 01 02
-
操作数 字段还 可以 使用复 制操 作符 (duplication opreator) 来复制 某个操 作数 ,例 : OPER1 DB 2 DUP(0,1,2,?) 操作数 ?可 以保留 空间 ,但 不存入 数据 。
注 1 :使用 PTR 属性操作 符 , 可以 指定操 作数 的 类型属 性,例 :
MOV AX, WORD PTR OPER1 注 2: 使用 LABEL 伪操 作可以 使同 一变量 具有 不 同的类 型属性 ,例 : BYTE_ARRAY LABEL BYTE WORD_ARRAY
DW
ARR DB 100 DUP(1, 2 DUP(2,3), 4, 5)
50 DUP(?) ?
…
116
( 二 ) 、表达式赋值伪操作 EQU
格式 :
变量名 EQU 表达式
例: CONST EQU 256 ; 数赋以符 号名 DATA EQU HEIGHT+12 ; 地址表 达式赋 以符号名 ALPHA EQU 7 BETA EQU ALPHA-2 B EQU [BP+8] ; 变址引 用赋以 符号名 B P8 EQU DS:[BP+8] 在 EQU 表达 式中有变量 或标号, 则应先定义 。另有一个与 EQU 类 似的 = 伪操 作也可以作 为赋值操 作使用。这 们之间的区别 是 EQU 伪操作中 的表达式名 是不允许重复 定义的,而 = 伪操作 则允许重 复 定义。 例: EMP=7
117
( 三 ) 、处理器选择伪操作
由于 80x86 的所 有处理 器都 支持 8086/8088 指 令系统 ,但每 一种 高档的 机型 又都增 加一 些新的 指令, 因此在 编写 程序时 要对 所用的 处理 器有一 个确定 的选择 .8086 / .286 / .286P / .386 / .386P / .486 / .486P / .586 / .586P 其中缺 省为 .8086 ; P 为保护 方式下 的指 令系 统,即 可以使 用特 权指令 ;它 们都支 持相 应的协 处理器 。 这类伪 操作通 常都 放在程 序的 最开头 ,也 可以加 在某特 定的语 句前 。 118
( 四 ) 、段定义伪操作
A. 完整的 段定 义伪操 作 存储器 的物 理地址 是由 段地 址和偏 移地 址组合 而成 的, 汇编程 序在 把源程 序转 换为 目标程 序时 ,必须 确定 标号 和变量 的偏 移地址 ,并 且需 要把有 关信 息通过 目标 模块 传送给 连接 程序, 以便 连接 程序把 不同 的段和 模块 连接 在一起 形成 一个可 执行 程序 。为此 ,需 要用到 段定 义伪 操作, 段定 义伪操 作的 格式 如下 : segment_name SEGMENT ... segment_name ENDS 其中删 节号 部分, 对于 数据 段、附 加段 和堆栈 段来 说, 一般是 存储 单元的 定义 、分 配等伪 操作 ;对于 代码 段则 是指令 及伪 操作。 119
A. 完整的段定义伪操作
此外, 还必须 明确 段和段 寄存 储器的 关系 ,这可 用 ASSUME 伪操 作来实 现, 其格式 为: ASSUME assignment , ... , assignment 其中 assignment 说明分 配情况 ,其 格式为 : segment_register_name: segment_name 其中段 寄存器 名必 须是 CS 、 DS 、 ES 和 SS 中 的一个 ,而段 名必 须是由 SEGMENT 定义 的段 中 的段名 。而 ASSUME NOTHING 则可取 消前 面 由 ASSUME 所指 定的段 寄存 器。 120
A. 完整的段定义伪操作 ;****************************************************** Data_seg1 segment ;define data segment … Data_seg1 ends ;****************************************************** Data_seg2 segment ;define data segment … Data_seg2 ends ;****************************************************** Code_seg segment ;define code segment ASSUME CS: Code_seg, DS: Data_seg1, ES: Data_seg2 START: MOV AX, Data_seg1 MOV DS, AX MOV AX, Data_seg2 MOV ES, AX … … Code_segENDS ;****************************************************** END START
121
A. 完整的段定义伪操作
由于 ASSUME 伪操作只是指 定某个段分 配给哪一 个段寄存器 ,它 并不能把 段地址装入 段寄存器中, 所以在代码 段中,还 必须把段地 址装入相 应的段寄存 器中。 但是,代 码段不需要 这样做,代码 段的这一操 作是在程 序初始化时 完成的。 SEGMENT 伪操作还可 以增加类型 及属性的说 明,格式如 下: segname SEGMENT [align_type] [combine_type] [‘class’] ... segname ENDS 一般情况 下 , 这些说 明可以不用 。但是,如 果需要用连接 程序把本 程序与其 他程序模块 相连接时,就 需要使用这 些说明。 分别叙述如 下: 定位类型 (align_type) 可以是 :
PARA 指定段 的起 始地址 必须 从小段 边界 开始, 即段地 址的 最低的 16 进制 数位 必须为 0 (缺省 )。 BYTE 该段可以 从任 何地址 开始 。 WORD 该段必 须从 字的边 界开 始 , 即段 地址 必须为 偶数 。 ( DWORD 4 ) PAGE 该段必 须从页 的边 界开 始 , 即段 地址的 最低 两个 16 进制数 位
122
A. 完整的段定义伪操作
组合类 型 (combine_type) 说明程 序连接 时的 段合并 方法 ,可以 是 :
PRIVATE 私有段,该段连 接时将不 与其他模 块中有相同名 字的 其他分段合 并。( 缺省 ) PUBLIC 该段连接 时将与有相同 名字的其他 分段连接在 一起 . 其 连接次序由 连接命令指 定 . COMMON 该段在连 接时与其他同 名分段有相 同的起始地 址 , 所 以会产生覆 盖 .COMMON 的连接长 度是各分段中 最大长度 . AT expression 使段的起始 地址是表达 式所计算出 来的 16 位段 地址 . 但它不 能用来指 定代码段 . STACK 指定 该段在运行 时为堆栈 段的一部分 . MEMORY 指定该将分 配在所有其 他连接在一 起的段的前 面 ( 在 高地址上 ) ,如果连接时 有几个指定 MEMORY 的段,则遇到 的 第一个段作 为 MEMORY 段,其他段则 作为 COMMON 段 .
类别 (‘class’) 连接时 用于 组成段 组的 类型 名。相同 名称 并不能 产生 合并, 但在 LOAD 时可 以把 他们的位 置靠在 一起。
123
B. 存储模型与简化段定义伪 操作
较新版 本的汇 编程 序,除 支持 完整的 SEGMENT 段定义 伪操作 外, 还支持 较新 的、简 单的 段定义 方法。 这种方 法虽 然不象 SEGMENT 伪操 作那 样 具有较 完整的 表达 能力, 但确 实简单 易用 。 1. MODEL 伪操作 格式: .MODEL memory_model [, model options ] 它是用 来表示 存储 模型的 (memory_model) ,也 就是在 存储器 中如 何安排 各个 段的。 包括 代码段 的安排 ,寻址 的远 近;数 据段 的安排 ,数 据寻址 的远近 。根据 不同 的组合 ,有 七种存储模 型 124
B. 存储模型与简化段定义伪 操作
(1)Tiny 所有数 据和 代码都 放在一 个段 内, 并且都 是近 访问。 Tiny 程序 可以 写成 .com 文件格 式,程 序从 0100H 的存储 单元 开始, 用于 小程 序。 (2)Small 所有数 据放在 一个 64K 的数据 段内 ,所有 代码 放在一 个 64K 的代码 段内 ,数据 和代 码也 都是近 访问 。 这是一 般程 序最常 用的 格式 。 (3)Medium 代码使 用多个 段, 一般一 个模 块一 个段, 而 数据合 并成 一个 64K 的段组 ,这 样数据 是近访 问, 而代 码是可 以远 访问的 。 (4)Compact 数据使用 多个段 ,而 代码放 在一 个 64K 的 段内, 这样 代码是 近访 问, 而数据 是可 以远访 问的 。 125
B. 存储模型与简化段定义伪 操作 (5)Large 所有数 据和代 码都可 用多 个段, 因此 都可以 是远访 问。 (6)Huge 和 Large 一样,但 允许 数据段 的大小 超过 64K 。 (7)Flat 允许用 户使用 32 位偏 址, 但需要 在保 护模式 下来使 用。 ( MASM 6.0 支持) model options 允许有 三个选项: 高级 语言 接口、 操作 系 统和堆 栈距 离: 被那种 高级 语言调 用: C 、 BASIC 、 FORTRAN 、 PASCAL 运行在 那种 操作系 统之 下: OS_DOS (缺 省) 、 OS_OS2 NEARSTACK ( DS 和 SS 组合 到一 个 DGROUP 段中, DS 、 SS 均指向 DGROUP , TINY 、 SMALL 、 MEDIUM 、 FLAT 是缺 省项 为
126
B. 存储模型与简化段定义伪 操作 例: .MODEL SMALL,C .MODEL LARGE,PASCAL,OS_DOS,FARSTACK 2. 简化的 段定义伪操 作 汇编程 序给 出的标 准段 有以 下几种 : .code 代码段 .initialized data 初始化 数据 段 .uninitialized data 未初始 化数 据段 .far initialized data 远初始 化数 据段 .far uninitialized data 远未初 始化 数据段 .constants 常数段 .stack 堆栈段 作用: ( 1 )把 常数 段和数据 段分开; ( 2 )把初 始化 数据段 和未 初始化 数据 段分 开;( 3 )把远和 近的 数据 段分开 。 为高级 语言 编写一 个汇 编语 言过程 ,可 使用上 述标 准段
127
B. 存储模型与简化段定义伪 操作
简化段 定义伪 操作 :
.CODE [name]
;有多 个代 码段则 要指 ;定每 个段 名
.DATA .DATA ? .FARDATA [name] ; 缺省以 FAR_DATA 命名 .FARDATA ? [name] ;缺省 以 FAR_BSS 命名 .CONST .STACK [size] ;可指 定大 小,缺 省 1K 注意: 在使 用简 化段伪 操作 时,必 须在 这些简 化段位 操作之 前, 即程序 的一 开始 先使用 .MODEL 伪操作 定 义存储 模型 ,然后 再使 用简 化段伪 操作 定义段 。每一 个新段 的开 始就是 上一 个段 的结束 ,不 必用 ENDS 作 为段的 结束 符。
128
B. 存储模型与简化段定义伪 操作
与简化 段定 义有关 的预 定义 符号 1 、 @Model 以数值 表示 当前所 用的 存储 模型: tiny = 1 , small 或 flat = 2 , compact = 3 , medium = 4 , large = 5 , huge = 6 2 、 @code 由 .CODE 伪操作定 义的 段名或 段组 名。 3 、 @codesize 以数值 表示当 前代 码段情 况。 在指定 的存 储模型 中, 只有 一个代 码段 ( tiny , small , compact , flat )时, 此值 为 0 ;其 他有多 个代 码段的 情况 下 , 此值 为 1 。 4 、 @data 由 .DATA 伪操作 定义 的段名 ,或 由 . DATA , .DATA ?, .CONST 和 .STACK 所定义的 段组名 。 5 、 @datasize 以数值 表示 当前数 据段 情况 。 在指定 的存 储模型 中, 只有 一个数 据段 ( tiny , small , medium , flat )时, 此值 为 0 ;有 多个数 据段 的 compact 和 large 时,此 值为 1 ;有 多个 数据段 且由 超过 64KB 的大 数据 段的 huge 时,此值 为 129
B. 存储模型与简化段定义伪 操作
6 、 @fardata 由 .FARDATA 伪操作定 义的 段 名。 7 、 @fardata ? 由 .FARDATA ?伪操 作定 义的段 名。 8 、 @curseg 当前段 名。 9 、 @stack 堆栈段的 段名 或者 段组名 。 10 、 @filecur 当前文件 名( 包括扩 展名 )。 11 、 @filename 当前 文件 名(不 包括 扩展名 ) 。 12 、 @wordsize 表明 段为 16 位还 是 32 位的 数值回 送符 。 16 位则回送 2 ; 32 位则 回送 130
B. 存储模型与简化段定义伪 操作 .MODEL .STACK .DATA ABC .CODE START:
END
SMALL 100H DB …
‘ABC’
MOV AX, @DATA ;给出数据段 的段名 MOV DS, AX MOV AL, ’C’ MOV AH,0EH INT 10H … MOV AX, 4C00H INT 21H START 131
B. 存储模型与简化段定义伪 操作
在使用 MODEL 时 SMALL 模型的段 的默 认情况 (其 它 从略)
伪操作
名字
定位
组合
类
.CODE
_TEXT
Word PUBLIC ‘CODE’
.FARDATA
FAR_DATA
Para
Private ‘FAR_DATA’
.FARDATA?
FAR_BSS
Para
Private ‘FAR_BSS’
.DATA
_DATA
Word PUBLIC ‘DATA’
DGROUP
.CONST
CONST
Word PUBLIC ‘CONST’
DGROUP
.DATA?
_BSS
Word PUBLIC ‘BSS’
DGROUP
.STACK
STACK
Para
DGROUP
STACK ‘STACK’
组
132
B. 存储模型与简化段定义伪 操作 .MODEL .STACK .CONST
SMALL 100H …
.DATA … .CODE START:
END
MOV AX, DGROUP ; 把段组名装入 DS MOV DS, AX 段组名 作为段地址 装入 DS … 寄存器 中,在访问 CONST MOV AX, 4C00H 段和 DATA 段中的 变量 , 都用 DS 作为 段寄存器来 访 INT 21H 问,提 高运行效率 START
133
B. 存储模型与简化段定义伪 操作 .MODEL .STACK 100H .FARDATA
SMALL
… .DATA … .CODE START:
ASSUME END
.FARDATA 和 .FARDATA? 建立的是 独立 的段, 所以 必 须为它们 建立 一个段 寄存 器 ,常用 ES
MOV AX, @DATA MOV DS, AX MOV AX, @FARDATA MOV ES, AX ;指 定独 立段 ES:@FARDATA … START 134
B. 存储模型与简化段定义伪 操作
3.
段组定 义伪 操作 格式: grpname GROUP segname[, segname …]
D_seg1 segment WORD PUBLIC ‘DATA’ … D_seg1 ends D_seg2 segment WORD PUBLIC ‘DATA’ … D_seg2 ends DATAGROUP GROUP D_seg1 , D_seg2 C_seg segment PARA PUBLIC ‘CODE’ ASSUME CS: C_seg, DS: DATAGROUP START: MOV AX, DATAGROUP MOV DS, AX … … C_seg ENDS END START
; 例如:
汇编 程序 能自动 地 把各 数据 段组成 一 个段 组 DGROUP , 以便 使用 一个数 据 段寄 存器 DS 来访 问个 数据 段。 DGROUP 伪操 作允 许用 户自 行指定 段 组, 定义 在不用 段 中的 变量 ,可用 一 个段 寄存 器访问 。 135
( 五 ) 、程序开始和结束伪 操作
在程序的 开始可以用 NAME 或 TITLE 为模块 取名字, NAME 的格 式是 :
NAME module_name
汇编程序 将以给出的 module_name 作为 模块的名字 。如果程 序中没 有 NAME 伪操作,则也 可使用 TITLE 伪操作 ,其格式为 : TITLE text TITLE 伪操作可指定列 表文件每 一页上打 印的标题。 同时,如果程 序中没有 使用 NAME 伪操作,则汇 编程序将用 text 中的前六 个字 符作为模 块名。 text 最多可 以 60 个字符。 如果程序既无 NAME 又 无 TITLE 伪操作,则将 用源程序文 件名作为 模块名。 NAME 和 TITLE 伪操作不是必须 的。 表示源程 序结束的伪 操作的格式为 : END [label] 其中标号 指示程序开 始执行的起始 地址。如果 多个程序 模块相连接
136
( 五 ) 、程序开始和结束伪 操作
MASM 6.0 增加了 程序入口 点和出口点的 伪操作: .STARTUP 用来定 义程序的初 始入口点,并 且产生设置 DS 、 SS 、和 SP 的代码。如果使 用了 .STARTUP 则结束 程序的 END 伪操作中 不必再指定 程序的入口点 标号。 .EXIT 用来产生退 出程序并返回 操作系统 的代码,其 格式为: .EXIT [return_value]; return_value 为返回 给操作系 统的值, 常用 0 .MODEL SMALL .DATA … .CODE .STARTUP … .EXIT 0 137
( 六 ) 、对准伪操作
EVEN 伪操作 使下一个 字节地址成 为偶数。一 个字的地址最 好从偶地址 开始,所 以对于字数组 为保证其从 偶地址开始 ,可以在 它前面用 EVEN 伪操作来 达到这一目的 ,( ALIGN num 是保证 边界以 4 的倍数 为开始 )例如 : DATA SEGMENT ... EVEN WORDAY DW 100 DUP(?) ... DATA ENDS ORG Constant expression 用来设 置当前地址 计数器的值。 如常数表 达式的值为 n ,则 ORG 伪操作可以 使下一个字 节的地址为 常 数表达式 的值 n 。 地址计数 器的值可以用 $ 来表示,汇 编语言允许 用户直接用 $ 来引用地 址计数器 的值,因此 : ORG $+8 :可以表示跳过 8 个字节 的存储区 , 建立了一 个 8 字节的 未初始化的 缓冲区,可 用 label 伪操作 来定义该缓 冲区的变 量名。 JMP $+2 138 可以表示 一条空指令, 该指令只是 延迟处理机 的一些时 间,而无其 他功
( 六 ) 、对准伪操作
例如: BUF DW 1,2,$+1,3 10H ,问 内存 情况如 何? LOW
例如:
么? 例如:
如果 BUF 的偏址 为
01 00 02 00 15 00 03 00
BUF DB 1,2,3,4 ABC EQU $- OFFSET BUF ; 问 ABC 等于什
BUF LABEL BYTE ORG $ + 8 和 BUF DB 8 DUP(?) 有无区别 ? . COM 程序用 ORG 100H JMP BEGIN 139
( 七 ) 、基数控制伪操作
汇编程序 默认的数为 十进制数,因 而除非专门 指定,汇 编程序把程 序中出现 的数均看作 十进制数,为 此,当使用 其他基数 表示的常数 时,需要 专门以标记 如下 :
二进制数 :由一串 0 、 1 组成其后跟以字 母 B ,如 00 101 10 0B
十进制数 :由 0~ 9 的数字组成。 一般情况下 后面不必 加上标记, 在 指定其他 基数的情况 下,后面可跟 字节字母 D ,如 178 D 。
十六进制 数:由 0~9 及 A~F 组成的 数,后面跟字 母 H 。这个 数的第 一个字符 必须是 0~9 ,所以 如果第一个 字符是 A~F 时,应 在其前加 上数字 0 ,如 0FF FF H 。
八进制数 :由数字 0~7 组成的 数,后面 可跟字母 O 或 Q ,如 17 77Q 。
RA DIX 伪操作,可以 把默认的基 数改变为 2~ 16 范围内的 任何基数 ,其格式 如下: .R AD IX e xpr es sio n 其中表达 式用来表示 基数值(用十 进制表示) 。
140
( 七 ) 、基数控制伪操作
例如: MO V BX , OF FH M OV B X , 178 与 .R ADI X 16 M OV B X , 0FF M OV B X , 178 D 是等价 的。 应当注 意, 在用 .RAD IX 16 把基数 定为十 六 进制后 ,十 进制数 后都 应跟 字母 D 。在这 种情况下, 如 果某个 十六 进制数 的末 字符 为 D ,则应在 其后 跟字母 H ,以免 与十 进制数 发生混 淆。 字符串 可以 看成串 常量 ,可 以用单 引号 或双引 号把 字符 串放在 其中 ,得到 的是 字符 串的 AC SII 值,例 如:‘ ABC D’ 。 141
( 八 ) 、过程定义伪操作
格式为 : procedure_name PROC Attribute … procedure_name ENDP
其中过 程名为 标识 符,它 又是 子程序 入口 的符号 地址, 它的写 法与 标号的 写相 同。 属性 (Attribute) 是指 类型属 性, 它可以 是 NEAR 或 FAR 。段 内调 用使用 NEAR 属性, 段间调 用使 用 FAR 属性 。
142
三、汇编语言的程序格式
汇编语 言源程 序中 的每个 语句 由 4 部分组 成 :
[ 名字 项 ]
操作 码
操作数 [ 注释 ]
其中
名字项 :符号 表达
操作码 :操作 码的 助记符 号、 可以是 指令 、伪操 作、宏 指令 。
操作数 :可以 由一 个或多 个表 达式
注释 : 说明 程序或 语句 的功能 。; 为识别 注释的 开始 。
143
三、汇编语言的程序格式
1. 名字项 组成: 字母: A – Z 数字: 0 – 9 ( 不可以开头) 专用字符: ? , . ( 如果使用必须开头) , @ , - , $ 除数字外,所有的字符都可以放在源语句的第 一个位置。名字中如果用到 . 必须是第一个字 符。汇编程序只能识别名字的前 31 个字符。 用途: 标号 或变量 。都表示本语句的符号地址, 都是可有可无的,只有当要用符号地址来访问该 语句时,它才需要出现。
144
三、汇编语言的程序格式
1) 标号 在代 码段中 定义 ,后跟 :, 也可以 用 LABE L 或 EQU 来定 义,也 可以 定义为 过程 名。标 号经常 在转移 指令 或 CALL 指令 的操 作数段 出现 ,用以 表示转 向地 址。
标号的属性:段、偏移及类型。 段属性定义标号的段起始地址,必须在一个段寄 存器中,标号的段则总是在 CS 寄存器中。 偏移属性:标号的偏移地址是从段起始地址到定 义标号的位置之间的字节数。对于 16 位段时 16 位无符号数。 类型属性:用来指出该标号是在本段内引用还是 在其他段内引用,如果是在段内则称 NE AR ,对 于 16 为段,指针长度为 2 字节。段 外则称 FAR ,对于 16 位段指针长度为 4 字节:段地址 2 字节,偏移地址 2 字节。 145
三、汇编语言的程序格式
2) 变量 在数 据段或 附加 数据段 定义 ,不需 要后 跟:, 也可以 用 LABL E 或 EQU 来定 义。 变量经 常在操 作数字 段出 现。
变量的 属性 :段、 偏移 及类 型。 段属性 :定 义变量 的段 起始 地址, 此值 必须在 一个段 寄存器 中。
偏移属 性: 变量的 偏移地址是从段起始地址到定义
变量的位置之间的字节数。
类型属 性: 变量的 类型 属性 定义该 变量 所保留 的字节 数。
在同一 个程序 中, 同样的 标号 或变量 的定 义只 允许出 现一次 ,否 则编译 程序 会指示 错误 。 146
三、汇编语言的程序格式
2. 操作 项
包括: 指令 、伪操 作、 宏定 义。
3. 操作 数项
操作数 项由 一个或 多个 表达 式组成 ,多 个操作 数之 间一般 用逗 号分开 。对 于指 令,操 作数 项一般 给出 操作数 地址 ,对于 伪操 作或 宏指令 ,一 般给出 它们 所要求 的参 数。
操作数 可以 是常数 、寄 存器 、标号 、变 量或 表达式 。 这里我 们将 重点讨 论表 达式 。表达 式是常数、 寄存 器、标 号、 变量与 操作 符相组合的 序列 ,可以 有数 字表达 式和 地址表 达式 两种 。 147
3. 操作数项
1).
算术操 作符
包括: + 、 - 、 * 、 / 、和 MOD 。 算术操 作符 可以用 数字 表达 式或地 址表 达式中 ,需 要注意 的是 在用于 地址 表达 式时, 要有 明确的 物理 意义: 例如 地址相 乘、 不同 段相加 。在 地址表 达式 中可以 使用 + 或 - 但也 要有 意义, 例如 SU M+ 1 匙 SU M 字节单 元的下 一个 字节单 元的 地址 。 例: DA TA DW 1,2,3,4,5,6 D_ LEN DW ? MO V CX , ( D_L EN – DA TA) /2 汇编的 结果 为 MO V CX , 6 148
3. 操作数项
2).
逻辑与 移位操作符
包括: AND 、 OR 、 XOR 、 NOT 、 SHL 、 SHR 等。 他们都 是按位 操作 的,只 能用 于数字 表达 式。 移位操 作符的 格式 为: expr essio n SH L (或 SHR ) num shift ,汇编 程序将 expre ssion 左移或 者右移 numshif t 为, 如果移 位数 大于 15 结果 则为 0 。 例 IN AL , PORT2 OUT PORT 2 AND 0FEH , AL
149
3. 操作数项
3).
关系操 作符
包括: EQ (=) 、 NE( <> ) 、 LT( <) 、 GT (> ) 、 LE (≦ ) 、 GE (≥) 。 需要注 意的 是关系 操作 符的 两个操 作数 必须都 是数 字,或 同一 段内的 两个 存储 器地址 ,计 算的结 果为 逻辑值 ,结 果为真 ,表 示为 0F FF FH ;结果为 假, 表示为 0 。 例 MO V BX , ( (PO RT 2 LT 5) AN D 20 ) O R (( POR T2 GE 5 AN D 3 0 ) 当 PO RT2 < 5 时汇编结 果为 MOV BX , 20 否则, 汇编 结果为 MO V BX , 30
150
3. 操作数项
4) . 数值 回传
包括: TYP E 、 LEN GT H 、 SI ZE 、 OF FSE T 、 SE G 等 。
这些操 作把 一些特 征或 存储 器地址 的一 部分作 为数值 回送。
TY PE :格 式 TY PE ex pr ess ion 或 la bel
如果该 表达 式是变 量, 则回 送该变 量以 字节数 表示的 类型: DB 为 1 , DW 为 2 , DD 为 4 , DF 为 6 , DQ 为 8 , DT 为 10 。如果 该表达 式是 标号, 则回送 代表该 标号 类型的 数值 : NE AR 为 -1 , FAR 为 -2 。 如果表 达式 为常数 ,则 回送 0 。
例:
DA TA DW
1 ,2,3 151
3. 操作数项
LENG TH 格式 为 LENG TH Va riab le 对于变 量中使 用 DUP 的情 况, 汇编程 序将 回送 该变量 的单元 数, 其他情 况回 送 1 。 例 DATA DW 100 DUP ( 0 ) MOV CX , LENGT H DA TA 则,汇 编结果 为 MOV CX , 100 DATA DB ‘123 45’ MOV CX , LENGT H DA TA 则,汇 编结果 为 MOV CX , 1 152
3. 操作数项
SIZE
格式为 SIZE Variab le
汇编程 序应 回送分 配给 该变 量的字 节数 。但实 际上, 是 LE NGT H 和 TY PE 的乘 积。
OFFS ET 格式 为 OFFS ET Va riab le 或 labl e
汇编程 序将 回送变 量或 标号 的偏移 地址 值。
例 MO V
BX , OF FS ET DA TA
实际上 他和
SEG
LE A
BX , DA TA 等价的。
格式为 SEG Var iable
汇编程 序将 回送变 量或 标号 的段地 址值 。例如 MO V BX , SE G DA TA 会把立 即数插 入指 令,在 连接 时完
153
3. 操作数项
5).
MOV MOV MOV MOV
[BX],AX [BX], 4 WORD PTR [BX], 4 BYTE PTR [BX], 4
属性操 作
包括: PTR 、段操作 符、 SH ORT 、 THI S 、 HIG H 、 LO W 、 HIG HW ORD 、 LO W WO RD 等。
PTR :格 式 typ e PTR expr essi on
PT R 用来建 立一个 符号 的地址 ,但 它本 身并不 分配 存储器 ,只 是用来 给已 分配 的存储 地址 赋予另 一种 属性, 使该 地址具 有另 一种 类型。 例 TW O_B YTE DW ? ON E_B YTE EQ U BY TE P TR TWO _B YT E OT HER _BY TE EQ U BY TE P TR (TW O_ BY TE +1) 154
3. 操作数项
FIRST_BYTE EQU THIS BYTE TABLE DW 100 DUP(?) START EQU THIS FAR MOV CX, 100
段操作 符 用来表 示一个 标量 、变量 或地 址表达 式的 段的属 性。 例 MOV AX, ES:[B X+SI] SHOR T 用来修 饰 JMP 指令 中转向 地址 的属性 ,指 出转向 地址是 下一 个地址 的 + -1 27 个字节 范围之 内。 THIS :格式 THIS attrib ute 或 type
它可以 像 PT R 一样建 立一 个指定类型 的或 指定距 离的操作数 。该 操作数 的段 地址和 偏移 地址与 下一 个存储 单元 地址相 同。 155
3. 操作数项
HIGH
和 LOW
括号、 结构、 LENGTH,SIZE, WIDTH, 和 MASK 名:( 段取代)
称为字 节分离操作 , HI GH 表示取 其高字节, LOW 表示 PTR,OFFSET,SEG,TYPE, THIS 及段操作符 取其低 字节。 HIGH , LOW 例: * , / , MOD , SHL , SHR CO NST EQ U 0 ABC DH +, MO V AH , H IGH C ON ST
HIGH WORD
表达式的 级别
和 LOWW ORD
称为字 分离操作, 它接 收一 个数或 地址表达式 , HI GHW OR D 表示取 其高位 字 , LO WW OR D 表示取 其低位 字。( MAS M6 支持)
EQ,NE,LTLE,GT,GE NOT AND OR,XOR SHORT 156
4. 注释项
用来说 明一段 程序 ,一条 或几 条指令 的功 能。 它可有 可无。 但对于 汇编语 言而 言,注 释项 的作用 非常 明显 ,它可 以使得 程序 容易理 解和 被读懂 。 注释应 重点描 写功 能和作 用, 少写动 作。 在读程 序时应 多学 习注释 的写 法。
157
PART4. 循环与分支程序设 计
编制汇编语言程 序的步骤
1. 分析题意 、确 定算法 、给 出适当 的数 据结 构。这 是最关 键的 一步。 2. 根据算法 ,画 出程序 框图 。这一 点对 于初 学者最 重要, 可以 由粗到 细使 算法具 体化 。 3. 根据框图 编程 序。 4. 上机调试 程序 。 (DEBUG)
程序分为: 顺序、循环、 分支 和子程序 。
158
一、 循环程序设计
1. 循环程序 的结构形 式
可分为 DO_WHILE 和 DO_UNTIL 两种 结构 形式
循环初 始状态
循环初 始状态
循环体 循环控 制条件
Y
N DO_WHILE
循环 体
循环控 制条件 Y
N
DO_UNTIL 159
一、 循环程序设计
( 1 )设置 循环的初始 状态。如计数 值 , 初始状态。 ( 2 )循环 体。 ( 3 )循环 控制部分。 一般来说,如果 有循环次数 等于 0 的可能 ,则应该选择 DO_WHILE 结构, 否则, 使用 DO_UNTIL 的结构。
160
一、循环程序设 计
2. 循环程序 设 计方法 例一:把 BX 寄 存器内的二进制 数用 16 进制数 表示出来,并输 出到屏幕。
开始 初始化循环 计数 BX 循环左 移位 (4bit) 把 BX 最右 面的转换为 ASCII 是 A~F ? Y
N
加7 显示一个字符 N
循环结 束? Y 结束 161
loop1:
printit:
mov mov
ch,4 ; number of digs ah,0eh ;int 10 fun-0e
开始 初始化循环 计数
mov rol mov and add cmp jl add
cl,4 ;set counter bx,cl ;left digit to ritht al,bl al,0fh ;mask off leftNM al,30h ;hex to ASCII al,3ah ;is it 〉 9 printit ;<9 jmp al,7 ;digit is A~F
int dec jnz ret
10h ;display ch loop1
BX 循环左 移位 (4bit) 把 BX 最右面 的转换为 ASCII 是 A~F ? Y
N
加7 显示一个字符 N
循环结 束? Y 结束 162
一、 循环 程序设计
例二:在 ADDR 单元存放着数 Y 的地址,把 Y 中 的 1 的个数 存入 COUNT 单元。
开始 初始化 C=0 Y=0 ?
Y
N Y=- ? N
Y YC=C+1
COUNT=C 结束
Y 逻辑左移 1 位 163
dataarea addr number count dataarea
segment dw number dw Y dw ? ends
prog main start:
开始 初始化 C=0 Y=0 ?
Y
loop1:
N Y=- ? N
Y YC=C+1 Y 逻辑左移 1 位
COUNT=C 结束
shift: exit: main Prog
segment proc far assume cs:prog, ds:dataarea push ds ;save old data seg sub ax,ax ;ax=0 push ax ;save it on stack ;=============== mov ax,dataarea ;set dx mov ds,ax ;---------------------------mov cx,0 mov bx,addr mov ax,[bx] ;put Y in ax test jz jns inc
ax,0ffffh ;test Y exit ;if 0,exit shift ; C unchanged cx
shl jmp mov ret endp ends end
ax,1 loop1 count,cx
start
164
二、 分支程序设 计
1.
分支程序的 结构形式
分支程 序可以 有两 种形式 ,他 们相当 于高 级 语言的 IF_THEN_ELSE 语句和 CASE 语句 。 他们的 共同特 点是 运行方 向是 向前的 ,在 某 一种特 定的情 况下 ,只能 执行 多个分 支中 的 一个。 判断条 件
Y
判断条 件
N …
165
二、 分支程序设 计 search
2. 分支程 序设 计方 法 程序的 分支一 般用 条 件转移 指令来 产生 。 例一:在数 据附加 段 有一个 从小到 大排列 的数组 ,首地 址放 在 DI 中,数 组的 第一个 单元放 着数组 的长 度。 AX 存放着 无符号 数。 要求在 数组中 查找 ( AX ), 如果找 到则 使 CF=0 , SI 存放偏 址,否 则 CF=1 。
初始化 low, high low>high
Y no_match
N mid=(low+high)/2 si= 查找元素 的偏 址 N compare ax=mid hicher>
CF=1
=ok
退出 166
dseg low_idx high_idx dseg
segment dw ? dw ? ends
push ds push ax mov ax, dseg mov ds, ax mov es, ax pop ax ;find out if ax lies beyond thebounder cmp ax, es:[di+2] ; <|= 1st el.? ja chk_last ;no,go check last el lea si, es:[di+2] ;fetch addr of 1st el je exit ;=1st el.,set CF stc ;<1st el.,set CF jmp exit chk_last: mov si, es:[di] ;point to last el shl si, 1 add si, di cmp ax, es:[si] ;value>=last el.? jb search ;no go search list je exit ;yes,exit if value=last el stc ;if value>last el,set CF jmp exit
search: mov mov mov mov mid: mov
low_idx, 1 ;fetch index bx, es:[di] high_idx, bx bx, di cx, low_idx
;calculate middle ;point
search mov dx, high_idx cmp cx, dx ja no_match 初始 化 low, high add cx, dx shr cx, 1 mov si, cx Y no_match shl si, 1 ;calculate next low>high search addr compare: N cmp ax, es:[bx+si] ;search value found? je exit mid=(low+high)/2 ;if so exit ja higher ;otherwise,find correct half dec cx ; is lower si= 查找元 素的偏 址 mov high_idx, cx N compare jmp mid CF=1 higher: =ok ax=mid inc cx mov low_idx, cx hicher>
二、 分支程序设 计
3.
跳跃表法
另外一 种实现 CASE 的方法 可以用 跳跃 表 法,可 以使程 序根 据不同 的条 件转移 到多 个分支 上去
例一:根据 AL 的那一个 BIT 为 1 (从低到高)把 程序转移到 8 个不同 的分支中去。
168
.data branch_tab
dw
.code Start:
Loop:
mov mov cmp je mov
shr jnc jmp not_yet: add jmp other : … rout_1:… rout_2:… end Start
rout_1 dw dw dw dw dw dw dw
rout_2 rout_3 rout_4 rout_5 rout_6 rout_7 rout_8
bx, @data ds, bx al, 0 other si, 0 al, 1 not_yet branch_tab[si] si, type branch_tab Loop
;put al last bit to CF ;if CF=0,on bit in al has not yet been found ;if CF=1,then control is transferred. ;if no transfer,then the bit that is on not found ,si add 2 ;jump to loop toshift and reset
169
PART5. 子程序结构
子程序又称为过 过程和函数。 模块化程序设计 实现的不同功能 各个模块在明确 定后,就可以分 再把它们连接在 是一种很好的程 构就是模块化程
程,它相当 于高级语言 的 方法是按照 把程序划分 各自功能和 别编制和调 一起,形成 序设计方法 序设计的基
各部分程序 成多个模块 相互连接的 试程序,最 大的程序。 ,而子程序 础。
所 , 约 后 这 结
170
一、子程序的设计方法
1. 过程定 义伪操 作
过程定 义伪 操作在 过程 (子 程序) 的前 后,使 整个过 程形成 清晰 的、具 有特 定功 能的代 码块 。格式 如下: Procedure_name PROC Attribute … … Procedure_name ENDP 其中过 程名 为标识 符, 它又 是子程 序入 口的符 号地址 。 它的写 法和 标号相 同。 Attribute 是指类 型属性 ,它 可以是 NEAR 和 FAR 。如 果定 义为 FAR 属性, CALL 和 RET 就都是 FAR 属性 ,反 之亦然。 如果 调用 和子 程序在 同的 代码段 ,则 使用 NEAR 属性。如 果调用 和 子程序 在不 同的代 码段 ,则 必须使 用 FAR 属性。 171
一、子程序的设计方法
例 1. 调用 程序和 子程 序在同 一代 码段 MAIN
MAIN SUBR1 SUBR1
PROC FAR … CALL SUBR1 … RET ENDP PROC NEAR … RET ENDP
MAIN
PROC … CALL … RET
FAR
NEAR
SUBR1
PROC … RET ENDP
MAIN
ENDP
SUBR1
SUBR1
172
一、子程序的设计方法
一般来说,主过 程 MAIN 应定义为 FAR 属性,这是由于 我们把程序 的主过程看 作 DOS 调用的一个 子过程,因 而 DOS 对 MAIN 中的 RET 就是 FAR 属性的。当然 CALL 和 RET 的属性是汇编程 序确定的, 用户只需正确选 择 PROC 的属性就 可以了 。 过程定义也可以 嵌套,一个 过程定义中 可 以包含多个过程 定义。 173
一、子程序的设计方法
例 2. 调用 程序和 子程 序不在 同一 代码段 内 SEGX
SEGMENT … SUBT PROC FAR … RET SUBT ENDP … CALL SUBT … SEGX ENDS ------------------------------------SEGY SEGMENT … CALL SUBT … SEGY ENDS
174
一、子程序的设计方法
2. 子程序调 用和返回
过程的 正确执 行是 由子程 序的 正确调 用和 正确 返回保 证的。 CALL 和 RET 就是完 成这些 功能 。 为了保 证其正 确性 ,除 PROC 的属性 要正确 选 择外, 子程序 必须 注意子 程序 运行期 间的 堆栈 状态。 由于 CALL 时已使 用返 回地址 入栈 ,所 以 RET 时应该 使用 返回地 址出 栈,如 果子 程 序中不 能正确 使用 堆栈而 造成 执行 RET 前 SP 并未指 向进入 子程 序时的 返回 地址, 则必 然会 导致运 行出错 ,因 此子程 序中 对堆栈 的使 用应 该特别 小心, 以免 发生错 误。 175
一、子程序的设计方法
3. 保护与 恢复寄 存器
由于调 用程 序和子 程序 是可 能分别 编制 的,所 以他们 所用的 寄存 器可能 会发 生冲 突,应 该把 子程序 所需要 使用的 寄存 器内容 保存 在堆 栈中, 在退 出子程 序前把 寄存器 内容 恢复原SUBT 状。 PROC
SUBT PUSH PUSH … … POP POP RET SUBT
PROC CX SI SI CX ENDP
NEAR PUSH PUSH PUSH PUSH … … POP POP POP POP RET
AX BX CX DX DX CX BX AX
一般来 说,子程 中用到 的寄存器 应该保 存的。但 ,如果 使用的寄 器在主 程序和子 序之间 传送参数 话,这 种寄存器 不一定 需要保存 特别时 用来向主 回送结 果的寄存 ,更不 能因此而
序 是 是 存 程 的 就 , 程 器 被
176
一、子程序的设计方法
4. 子程序的 参数传递
1 )通 过寄存 器传 递参数
是最 常用 ,最方 便的 用法, 但参 数很多 时不能 使用 这种 方法
2 )如 果过程 和调 用程序 在同 一源文 件中 ,则 过程可 直接访 问模 块中的 变量 3 )通 过地址 表传 递参数 地址 4 )通 过堆栈 传递 参数或 参数 地址 5 )多 个模块 之间 的参数 传递 ( PUBLIC 、 EXTRN )
177
4 )采用堆栈传送参数或参数地址
code2_seg
segment assume cs: code2 proadd proc far push bp ;save bp mov bp, sp ;use bp to parameter push ax ;save other registers push cx push si push di mov si, [bp+0ah] ;get addr of ary mov di, [bp+08h] ;get addr of count mov cx, [di] ;cx←(count) mov di, [bp+06h] ;get addr of sum xor ax, ax next: add ax, [si] add si,2 loop next mov [di], ax ;store result pop di ;restore registers pop si pop cx pop ax pop bp ret 6 ;adjust stack ,return proadd endp code2_seg ends
parm_seg ary dw count dw sum dw parm_seg
segment 100 dup(?) 100 ? ends
stack_seg dw tos label stack_seg
segment 100 dup(?) word ends
code1_seg segment main proc far Push Start: mov ax,stack_seg sp-2 (DI) mov ss,ax (SI) src->sp mov sp, offset tos (CX) … mov bx,offset(AX) ary ;push addr of (BP) push bx ;ary(BP) onto stack 原始 mov bx,offset (IP) count 返回地 址 push bx (CS) mov bx,offset sum sum 的地址 push bx 的地址 call count far ptr proadd ary 的地址 … main endp code1_seg ends
178
5 )多个模块之间的参数传递( PUBLIC 、 EXTRN ) extrn var1: word, output:far extrn var2: word public exit Loc_seg segment Vardw 5 Loc_seg ends Main proc far Start: … mov ax,seg var1 mov ds,ax … mov ax,seg var2 mov es,ax … jmp output … exit: mov ax,4c00h int 21h Main ends end start
public var1 ;-----------------------------Ex_seg segment var1 dw 10 Ex_seg ends
public var2 extrn exit: far ;-----------------------------Ex_seg1 segment var2 dw 3 Ex_seg1 ends ;-----------------------------public output Pron … output: Pron
segmeng
jmp ends
exit
179
一、子程序的设计方法
5. 增强功 能的过 程定 义伪操 作
其中 attributes 由以下 几项组 成
从 MASM5.1 提供增强 功能 的过程 定义 伪操作 ,格 式 为: procname PROC [attributes field][USES register] [, parameter field] … … procname ENDP distance
language type
visibility
prologue
distance 为 FAR 或 NEAR 。在 简化 段定义 中 已指定 内存没 此模 型情况 下, 不必再 指定 。如果 程序中 为指定 内存 模型, 则应 有用户 自行 指定类 型属性 ,如果 用户 未指定 ,则 缺省值 为 NEAR 。
180
一、子程序的设计方法
language type 为 PASCAL 、 BASIC 、 FORTRAN 、 C 等; 说明 该子程 序被高 级语 言调用 ,如 果在 .MODEL 中 说明, 这里可 以省 略。必 须注 意,如 果过 程伪操 作中使 用了参 数字 段,但 在 .MODEL 和 language type 中均未指 定一 种语言 类型 的话, 则 MASM 将指 示出 错。为 此, 即使你 的过 程并 不需要 由高级 语言 调用, 也应 该指定 一种 语言类 型。 Visibility 为 Private 或 Public ,缺省 为后者 。 Private :该过 程的可 见性 只能是 当前 的源文 件 。 Public :允 许其他 模块 调用改 过程 。 Prologue 是宏 的名字 ,可 以控制 入口 和出口 的 代码。 181
一、子程序的设计方法 (BP-?) (BP-?)
(BP)
(BP)
局部 变量 区 原始 (BP)
(BP+4)
返回地址
(BP+6)
(BP+8)
par1 par2 par3
C near 调用
(BP+A)
局部 变量 区 原始 (BP)
返回 地址
par1 par2 par3
C far 调用
(BP-?) (BP) (BP+6) (BP+A)
局部 变量 区 原始 (BP)
返回 地址
par3 par2 par1
PASCAL 、 BASIC 、 FORTRAN 调用 182
5. 增强功能的过程定义伪操作 .MODEL medium
.data ary
dw
100 dup(?)
count
dw
100
sum .stack
dw 200h
?
.code
code1
main Start:
proc
far
mov
ax, @data
mov
ds, ax
mov push
bx,offset ary bx
mov
bx,offset count
push mov
bx bx,offset sum
push
bx
call
far ptr proadd
mov
ax,4c00h
. code code2 proadd proc pascal uses ax cx si di , para:word, parc: word, pars:word mov si, para mov di, proc mov cx, [di] mov di, pars xor ax, ax next: add ax, [si] add si,2 loop next Push mov [di], sp-2 (DI)ax ret (SI) src->sp proadd endp (CX) end start (AX)
(BP)
原始 (BP) 注意:可以用 LOCAL (IP) 为局部变量申请空间 返回地 址 LOCAL vardef [,(CS) vardef ] 其中变量定义可以用 sum 的地址 Label count 的地址 Label : type ary 的地址 Label [ count] : type 编译后,实际是用 [BP- ? ]
183
高级汇编语言技术 一、宏汇编 二、重复汇 编 三、条件汇 编
输入输出 BIOS/DOS 中断 磁盘文件存取 图形与 I/O 控制
184
一、宏汇编
使用子程序结构 存储空间及程序 模块化程序设计 及修改等。 使用子程序也有 ,保存及恢复寄 要增加程序的开 间。 因此,有时,特 是需要传送的参
具有很多优 点:可以节 省 设计所花的 时间,可提 供 的条件,便 于程序的调 试 一些缺点: 为转子及返 回 存器以及参 数的传送等 都 销,消耗了 时间和存储 空 别在子程序 本身较短或 者 数较多的情 况下,使用 宏 185
一、宏汇编
宏是源 程序 中一段 有独 立功 能的代 码, 只需要 在源 程序 中定义 一次 ,就可 以多 次调 用它, 调用 时只需 要一 个宏 指令语 句就 可以了 。 宏定义 是用 一组伪 操作来 实现的。 其格式 是: macro_name MACRO [dumny_parameter_list] ... ( 宏定义 体 ) ENDM
其中 MACRO 和 ENDM 是一对伪 操作 。这对 伪操作 之间 是宏定义体 —— 是一 组独立 功能 的程序 代码 。 宏指令 名 (macro_name) 给出该 宏定义 的名 称,调 用时 就使用 宏指 令名来 调用 该宏 定义。 186
一、宏汇编
宏指 令名给出该 宏定义的 名称,调用时 就使用指 令名 来调用该宏 定义。宏 指令的第一个 符号必须 是字 母,其后可 以跟字母 ,数字或下划 线字符, 其中 哑元表 (dumny_parameter_list) 给出了该宏定 义中所用到的形式参数 ( 或称虚参 ) ,每个哑元之间 用逗号隔开。
经宏定 义后 的宏指 令就 可以 在源程 序中 调用。 这种 对宏 指令的 调用 称为宏 调用 ,宏 调用的 格式 是: macro_name [actual_parameter_list]
实元表 (actual_parameter_list) 中的每一 项为 实元, 相 互之间 用逗 号隔开 。 187
一、宏汇编
在源程序被汇编 调用作宏展开。 代源程序中的宏 宏定义中的哑元 是一一对应的。 该和哑元的个数 求他们必须相等 数,则多余的实 小于哑元个数, 理。还应该注意 代哑元后,所得 否则汇编程序将
时,汇编程 宏展开就是 指令名,而 。在取代实 一般来说, 相等,但汇 。若实元个 元不予考虑 则多余的哑 ,宏展开后 到的语句应 会指示出错
序将对每个 用宏定义体 且用实元取 ,实元和哑 实元的个数 编程序并不 数大于哑元 ;若实元个 元作“空” ,即用实元 该是有效的 。
宏 取 代 元 应 要 个 数 处 取 , 188
一、宏汇编
例:用 宏指 令定义 两个 字操 作数相 乘, 得到一 个 16 位 得第三 个操 作数作 为结 果 。
宏定义 :
宏调用 :
MULTIPLY MACRO OPR1,OPR2,RESULT PUSH DX PUSH AX MOV AX,OPR1 IMUL OPR2 MOV RESULT,AX POP AX POP DX ENDM … MULTIPLY CX,VAR,XYZ[BX] …
MULTIPLY 240,BX,SAVE …
189
一、宏汇编
宏展开:
… PUSH PUSH MOV IMUL MOV POP POP … MOV IMUL MOV POP POP …
DX AX AX,CX VAR XYZ[BX],AX AX DX PUSH DX PUSH AX AX,240 BX SAVE,AX AX DX
( 1 )宏指令可以 带哑元,调用时可 以用实元取代,避 免了子程序因参数 传送带来得麻烦, 使宏汇编得使用增 加了灵活性。 ( 2 )实元可以是 常数、寄存器、存 储单元名以及能用 寻址方式找到得地 址或表达式等。实 元还可以是指令的 操作码的一部分等 。 ( 3 )宏调用与子 程序调用的工作方
190
一、宏汇编
子程序 是在 程序 执行期 间由 主程序 调用的 ,它 只占有 它自 身大 小的一 个空 间;而 宏调用 则是 在汇编 期间 展开 的,每 调用 一次就 把宏定 义体 展开一 次, 因而 它占有 的存 储空间 与调用 的次 数有关 ,调 用次 数越多 ,占 有的存 储空间 越大 。 一般来 说, 由于 宏汇编 可能 占有较 大的空 间, 所以代 码较 长的 功能往 往使 用子程 序而不 用宏 汇编; 那些 较短 的且变 元较 多的功 能段使 用宏 汇编就 更为 合理 了。 在程序 中, 宏定 义必须 出现 在宏调 用之前 ,即 191 必须先 定义 后调 用。
一、宏汇编
1. 宏定义 可以无 变元
宏定义 : SAVEREG MACRO PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI ENDM 宏调用 : SAVEREG 宏展 开则 将宏定 义体 的内容 全部 列出。 192
一、宏汇编
2. 变元可 以是操 作码
宏定 义 : FOO MACRO P1,P2,P3 MOV AX,P1 P2 P3 ENDM 宏调 用 : FOO WORD_VAR, INC, AX 宏展 开 : + MOV AX, WORD_VAR + INC AX
193
一、宏汇编
3. 变元可 以是操 作码 的一部 分 , 但在宏 定义体中必 须用 & 作为分 隔符 . 宏定义 : LEAP 宏调用 : 宏展开 : + +
MACRO COND, LAB J&COND LAB ENDM ... LEAP Z,THERE ... LEAP NZ,HERE ... ... JZ THERE ... JNZ HERE ... 194
一、宏汇编
4. & 是一 个操作 符 , 它在 宏定义 体中 可以作 为哑 元的前 缀 , 展开时 可以 把 & 前后 个符号 合并 而形 成一个 符号 , 这个 符号 可以是 操作 码 , 操作 数或 是一个 字符串 。 宏定义 : PO MACRO P1 JMP TA&P1 ENDM 宏调用 : PO WORD_VAR 宏展开 : + JMP TAWORD_VAR 展开时 ,汇编 程序 把 TAP1 看作 是一个 独立 的标 号,并 不把 TAP1 中的 P1 作为 哑元看 待, 这样就195
一、宏汇编 5. 变元是 ASCII 串的情 况 宏定义 : MSGGEN MACRO LAB, NUM, XYZ LAB&NUM DB 'HELLOMR.&XYZ' ENDM 宏调用 : MSGGEN MSG,1,TAYLOR 宏展开 : + MSG1 DB 'HELLO MR.TAYLOR'
196
一、宏汇编
6. 宏指令名 可以与指令助 记符或伪操 作名相同 , 在这种情况 下 , 宏 指令的优 先级最高, 而同名的指令 或伪操作就 失效了 . 伪操作 PURGE 可以用 来在适当的 时候取消宏 定义 , 以便 恢复指令的 原始含 义 .。 格式: PURGE macro_name[, macro_name,…] 宏定义 : ADD MACRO OPR1,OPR2,RESULT ... ENDM 宏调用 : ... ADD XX,YY,ZZ PURGE ADD ... 在宏调用 后 , 用 PURGE 伪操作 取消定义 , 以便恢 复 ADD 指令的原 始含义 , 在 PURGE ADD 后面所 用的 ADD 指令 , 则服 从机器指令 的 定义 . PURGE 伪操作 可同时取消 多个宏操作 , 此时各宏 指令之间用 逗号隔 开。 也可以用来 删除一个不 用的宏定 义,即使该 宏定义成为 空, 程序中如 果出现了一 个已被删除的 宏定义的宏 调用,则 汇编程序不 197
一、宏汇编
7. LOCAL 伪操作 的使用 . 宏定义 体内允 许使 用标号 , 如 : 宏定义 : ABSOL MACRO OPER CMP OPER, O JGE NEXT NEG OPER NEXT: ENDM 如果程 序中多 次调 用该宏 定义 时 , 展开后 会出 现 标号的 多重定 义, 这是不 允许 的。为 此系 统提供 了 LOCAL 伪操作 , 其格 式是 LOCAL list of local labels 198
一、宏汇编
其中局 部标 号表内 的各 标号 之间用 逗号 隔开。 汇编 程序 对 LOCAL 伪操作 的局部 标号 表中的 每一 个局 部标号 建立 唯一的 符号 ( 用 ??0000~??FFFF) 以代 替在 展开中存 在 的每个 局部 标号 . 必须 注意 ,LOCAL 伪操作只 能用在 宏 定义体 内 , 而且 它必 须是 MACRO 伪操作 后的 第一个 语 句 , 在 MACRO 和 LOCAL 伪操作之 间还 不允许 有注释 和 分号标 志 . 本例中 的 ABSOL 宏定 义在 考虑有多 次调 用可 能性的 情况下 , 应定义 为 : ABSOL MACRO OPER LOCAL NEXT CMP OPER,0 JGE NEXT NEG OPER NEXT: ENDM 199
一、宏汇编
宏调用 :
... ABSOL VAR ... ABSOL BX ...
宏展开 :
... + CMP VAR,0 + JGE ??0000 + NEG VAR +??0000: ... + CMP BX,0 + JGE ??0001 + NEG BX +??0001: ...
在以 上了 的例子 中, 宏定 义体 内只 使用了 一个 标号 ,如 宏定 义体内 的标 号数 多于 一个 ,则可 把它 们列 在 LOCAL 伪操作 之后 ,如 : LOCAL NEXT,OUT,EXIT 在宏 展开 使,汇 编程 序对 第一 次宏 调用使 用? ? 0000 取代 NEXT ,用?? 0001 取代 OUT ,用?? 0002 取代 EXIT 。对第 二 次宏 调用 将用? ? 0003 取代 NEXT ,用 ?? 0004 取代 OUT ,用 ?? 0005 200
一、宏汇编 8. 宏定义 中允许 使用 宏调用 , 其限制条 件是 : 必须先定 义后调 用宏 定义 : DIF MACRO X,Y MOV AX,X 宏展开: SUB AX,Y ENDM PUSH DX DIFSQR MACRO OPR1,OPR2,RESULT PUSH AX PUSH DX MOV AX,VAR1 PUSH AX DIF OPR1,OPR2 SUB AX,VAR2 IMUL AX IMUL AX MOV RESULT,AX MOV VAR3,AX POP AX POP AX POP DX POP DX ENDM 宏调用 : DIFSQR VAR1,VAR2,VAR3
201
一、宏汇编
9. 宏定义 体内不 仅可 以使用 宏调 用 , 也可以 包含宏 定义 . 宏定义 : DEFMAC MACRO MACNAM, OPERATOR MACNAM MACRO X, Y, Z PUSH AX MOV AX, X OPERATOR AX,Y MOV Z, AX POP AX ENDM ENDM 其中 MACNAM 是内层的 宏定 义名 , 但又 是外 层宏定义 的哑元 , 所以调 用 DEFMAC 时 , 就形成 一个宏 定义 .
202
一、宏汇编 宏调用 : DEFMAC ADDITION, ADD 宏展开 : + ADDITION MACRO X,Y,Z PUSH AX MOV AX,X ADD AX,Y MOV Z,AX POP AX ENDM 形成加 法宏 定义 ADDITION. 同样 , 宏调用 DEFMAC SUBTRACT, SUB 形成减 法的 宏定义 . 当然在 形成这 些宏定 义后 , 就可以 使用宏 调用 ADDITION VAR1,VAR2,VAR3
203
一、宏汇编
而展开成 : + PUSH AX + MOV AX,VAR1 + ADD AX,VAR2 + MOV VAR3,AX + POP AX
204
一、宏汇编 10. 这里再 介绍 一个宏 定义 的变元 中使 用的伪 操作 %, 它的 格式是 : %expression 汇编程 序把跟 在 % 之后 的表达 式的 值转换 成当 前基数 下的数 , 在展开 期间 , 用这个数 来取 代哑 元. 宏定义 : MSG MACRO COUNT,STRING MSG&COUNT DB STRING ENDM ERRMSG MACRO TEXT CNTR=CNTR+1 MSG %CNTR, TEXT ENDM
205
一、宏汇编
宏调用 : ... CNTR=0 ERRMSG 'SYNTAX ERROR' ... ERRMSG 'INVALID OPERAND' ... 宏展开 : ... + MSG1 DB 'SYNTAX ERROR' ... + MSG2 DB 'INVALID OPERAND'
206
一、宏汇编
一般来 说, 在宏调 用时 实元 和哑元 是一 一对应 的, 但汇 编程序 并不 要求他 们的 个数 必须是 相等 的,只 要保 证宏 展开后 所得 到的语 句是 有效 的就可 以了 。在 MASM6 中 ,可以 使用 : REQ 指定 某个 变元是 必须 有的 。 宏定义 : DIF MACRO A,B DIF1
DIF2
DB B-A ENDM MACRO DB B-A ENDM MACRO DB B-A ENDM
A:REQ,B:REQ
A:REQ,B
207
一、宏汇编
MASM6 还可以用:=操作符为宏变元提供缺省的参 数值。 宏定义: DIF3 MACRO A:=<10>,B:=<12> DB B-A ENDM 宏调用和宏展开: DIF3 5 DIF3 DB 12-5 DB 12-10 DIF3 ,8 DIF3 5,8 DB 8-10 DB 8-5 208
一、宏汇编
11. 列表伪 操作 MASM 提供 .xall, .lall, .sall 用来控 制汇编 清单 中宏展 开的列 出情 况。 .xall ,为 缺省情 况, 指示清 单中 只列出 产生 目 标码的 宏展开 。 .lall ,列 出包括 注释 在内的 宏 .sall ,不 列出任 何宏 的信息 注意在 宏中如 果用 ;; 来注释, 永远 不会在 汇编 清单中 展开, 即使 在 .lall 之下 在清单 中那 个也 不会出 现。 209
二、重复汇编 二、重 复汇 编 有 时汇 编语言 程序需 要连 续地重 复完 全相 同的或 者 几乎完 全相 同的一 组代 码, 这时可 使用 重复汇 编。 1. 重复伪 操作 其格式 为 : REPT expression ... ( 重复 块 ) ENDM 其中表 达式 的值用 来确 定重 复块的 重复 次数 , 表达式 中 如包含 外部 或未定 义的 项则 汇编指 示出 错 . 重复伪 操作 并不一 定要 在宏 定义体 内 , 例如 :
X=0
REPT 10 X=X+1 DB X ENDM
则汇编 后产 生 + DB 1 + DB 2 + DB 3 ... + DB 10 210
二、重复汇编 把字符 A 到 Z 的 ASCII 码填 入数组 TABLE CHAR='A' TABLE LABEL BYTE REPT 26 DB CHAR CHAR=CHAR+1 ENDM 用宏定 义及重 复伪 操作把 TAB,TAB+1,TAB+2,...,TAB+16 的内 容存入 堆 栈. 宏调用 : 宏定义 : I=0 REPT 17 PUSH_TAB MACRO K PUSH_TAB PUSH TAB+K I=I+1 ENDM ENDM
% I
211
二、重复汇编
要求建立一个 100 DW 字的数组 , 其中每 个字的内容是下 一个字的地 址 , 而最后一 个字的内容是第 一个字的地 址 . ARRAY LABEL WORD 则汇 编后 产生 + DW $+2 REPT 99 + DW $+2 DW $+2 + DW $+2 ENDM ... DW ARRAY + DW $+2
212
二、重复汇编 2. 不定重 复伪 操作 (1) IRP 伪操作 格式是 : IRP dummy, <argument list> ... ( 重复块 ) ENDM 汇编程 序把重 复块 的代码 重复 几次 , 每次 重复 把 重复块 中的哑 元用 自变量 表中 的一项 来取 代 , 下 一次取 代下一 项 , 重复 次数由 自变 量表中 的自 变 量个数 来确定 . 自变量 表必须 用尖 括号括 起 , 它 可以是 常数 , 符号 , 字符串 等 .
213
二、重复汇编
例 1: IRP X,<1,2,3,4,5,6,7,8,9,10> DB X ENDM 汇编后得 : + DB 1 + DB 2 ... + DB 10 例 2: IRP REG,
PUSH REG ENDM 汇编后得 : + PUSH AX + PUSH BX + PUSH CX + PUSH DX 214
二、重复汇编
(2) IRPC 伪操 作
格式是 : IRPC dummy, string( 或 <string>) ... ( 重复块 ) ENDM IRPC 和 IRP 类似 , 但自变量表必 须是字符串 . 重复次 数由字符串中 的字符个 数确定 , 每次重复用字 符串中的下 一个字符 取代重复块 中 的哑元 . 例 : 例 1: IRPC X, 0 1 2 3 4 5 6 7 DB X+1 ENDM 汇编后得 : + DB 1 + DB 2 ... + DB 8
215
二、重复汇编
例 2: IRPC K, A B C D PUSH K&X 汇编后展开形成 : + PUSH AX + PUSH BX + PUSH CX + PUSH DX
216
三、条件汇编
汇编程序能根据 条件把一段 源程序包括 在 汇编语言程序内 或者把它排 除在外,这 里 就用到条件伪操 作。条件伪 操作的一般 格 式是 : IFXX argument ... } 自变量满足给定 条件汇编此 块 [ELSE] ... } 自变量不满足给 定条件汇编 此 块 ENDIF 自变量必须在汇 编程序第一 启遍扫视后 就
217
三、条件汇编
条件伪 操作 中的 XX 表示条 件如 下 :
IF expression 汇编程序求 出表达式的值 , 如此值 不为 0 则满 足条件 . IFE expression 如求出表达 式的值为 0 则满足条件 . IFDEF symbol 如符号已在 程序中定义 , 或者已用 EXTRN 伪操 作说明该符 号是在外部 定义的 , 则满足条件 . IFNDEF symbol 如符号 未定义或未 通过 EXTRN 说明为外部符 号则满足条 件 . IFB <argument> 如自 变量为空则 满足条件 IFNB<argument> 如自变 量不为空则 满足条件 IFIDN <arg-1>,<arg-2> 如果字符串 <arg-1> 和字 符串 <arg-2> 相同 , 则满足 条件 . IFDIF <argu-1>,<argu-2> 如果字符串 <arg-1> 和字 符串 <arg-2> 不相同 , 则满足条件 .
条件伪 操作 可以用 在宏 定义 体内 , 也可以 用在宏定义 体 外 , 也允许 嵌套 任意次 .
218
三、条件汇编
例 1: 宏指令 MAX 把三 个变元中的 最大值放 在 AX 中 , 而且使变元 数不同时 产生不同的 程序段 . 宏定 义 : MAX MACRO K, A, B, C LOCAL NEXT, OUT MOV AX, A IF K-1 IF K-2 CMP C, AX JLE NEXT MOV AX, C ENDIF NEXT: CMP B, AX JLE OUT MOV AX, B ENDIF OUT: ENDM
219
三、条件汇编
宏调用 : MAX 1,P MAX 2,P,Q MAX 3,P,Q,R 宏展开 : MAX 1, P + MOV AX,P +??0001: MAX 2, P, Q + MOV AX,P +??0002: CMP Q,AX + JLE ?? 0003 + MOV AX,Q
+??0003: MAX 3, P, Q, R + MOV AX,P + CMP R,AX + JLE ?? 0004 + MOV AX,R +??0004: CMP Q,AX + JLE ?? 0005 + MOV AX,Q +??0005: 220
三、条件汇编
例 2. 宏指 令 GOTO L,X,REL,Y ( 其中 REL 可以是 Z,NZ,L,NL 等 ) 可以 根据不 同情况 产生无 条件 转移指 令或 比较和 条件 转移指 令. 宏定义 : GOTO MACRO L, X, REL, Y IFB JMP L ELSE MOV AX,X CMP AX,Y J&REL L ENDIF 221 ENDM
三、条件汇编
宏调用 : ... GOTO LOOP,SUM,NZ,15 ... GOTO EXIT ... 宏展开 : ... + MOV AX,SUM + CMP AX,15 + JNZ LOOP ... + JMP EXIT 222
三、条件汇编
例 3. 宏定义 可允许 递归 调用, 此时 条件 伪操作 可用 来结 束宏 递归 。 宏指令 POWER 可以用 来实现 X 和 2N 相乘 . 这只 需对 X 左移 N 次可实现 , 可以设 COUNT 为递归 次数的 计数 值 , 当该数 与 N 相等时即 可结束 递归 调用 . 宏定义 : POWER MACRO X, N SAL X, 1 COUTN=COUT+1 IF COUNT-N POWER X,N ENDIF ENDM 宏调用 : COUTN=0 POWER AX,3 宏展开 : + SAL AX,1 + SAL AX,1 + SAL AX,1
223
三、条件汇编
例 4. 宏指令 BRANCH 产生一条转 向 X 的转移指令 。当它相对 于 X 的距离小 于 128 字节时产生 JMP SHORT X; 否则产 生 JMP NEAR PTR X(X 必须 位于该转移 指令之后 ,即低地址 区 ) 。 宏定义 : BRANCH MACRO X IF ($-X) LT 128 JMP SHORT X ELSE JMP NEAR PTR X ENDIF ENDM 宏调用 : BRANCH X 宏展开 : 如 X 与 BRANCH 指令间的距离 小于 128 时产生 + JMP SHORT X 否则产生 : + JMP NEAR PTR X 224
阅读程序练习 ABC
ANEXT:
ABC
PROC PUSH PUSH PUSH MOV MOV MOV ROL MOV AND DAA ADD ADC INT LOOP POP POP POP RET ENDP
FAR CX DX AX DL,AL CX,2 AH,0EH DL,4 AL,DL AL,0FH
HEX_PUT
HEX_NEXT:
AL,0F0H AL,040H 10H ANEXT AX DX CX HEX_PUT
PROC FAR PUSH CX PUSH DX PUSH AX MOV DL,AL MOV CX,2 MOV AH,0EH ROL MOV AND DAA ADD ADC INT LOOP POP POP POP RET ENDP
DL,4 AL,DL AL,0FH AL,0F0H AL,040H 10H HEX_NEXT AX DX CX
225
DOS 功能调用 AH
功能
调用参数
返回参数
00
程序终止 ( 同 INT 20H)
CS= 程序段前缀
01
键盘输入并回显
AL= 输入字符
02
显示输出
DL= 输出字符
03
异步通迅输入
AL= 输入数据
04
异步通迅输出
DL= 输出数据
05
打印机输出
DL= 输出字符
06
直接控制台 I/O
DL=FF( 输入 ) DL= 字符 ( 输出 )
AL= 输入字符
07
键盘输入 ( 无回显 )
AL= 输入字符
08
键盘输入 ( 无回显 ) 检测 Ctrl-Break
AL= 输入字符 226
DOS 功能调用 09
显示字符串
DS:DX= 串地址 '$' 结束字符串
0A
键盘输入到缓冲区
DS:DX= 缓冲区首地址 (DS:DX)= 缓冲区最大字符数
(DS:DX+1)= 实际输入的 字符数
0B
检验键盘状态
AL=00 有输入 AL=FF 无输入
0C
清除输入缓冲区并 请求指定的输入功能
AL= 输入功能号 (1,6,7,8,A)
0D
磁盘复位
清除文件缓冲区
0E
指定当前缺省的磁盘 驱动器
DL= 驱动器号 0=A,1=B,...
AL= 驱动器数
0F
打开文件
DS:DX=FCB 首地址
AL=00 文件找到 AL=FF 文件未找到 227
DOS 功能调用 10
关闭文件
DS:DX=FCB 首地址
AL=00 目录修改成功 AL=FF 目录中未找到文件
11
查找第一个目录项
DS:DX=FCB 首地址
AL=00 找到 AL=FF 未找到
12
查找下一个目录项
DS:DX=FCB 首地址 ( 文件中带有 * 或 ?)
AL=00 找到 AL=FF 未找到
13
删除文件
DS:DX=FCB 首地址
AL=00 删除成功 AL=FF 未找到
14
顺序读
DS:DX=FCB 首地址
AL=00 读成功 =01 文件结束 , 记录中无数 据 =02 DTA 空间不够 =03 文件结束 , 记录不完整 228
DOS 功能调用 15
顺序写
DS:DX=FCB 首地址
AL=00 写成功 =01 盘满 =02 DTA 空间不够
16
建文件
DS:DX=FCB 首地址
AL=00 建立成功 =FF 无磁盘空间
17
文件改名
DS:DX=FCB 首地址 (DS:DX+1)= 旧文件名 (DS:DX+17)= 新文件名
AL=00 成功 AL=FF 未成功
19
取当前缺省磁盘驱动器
AL= 缺省的驱动器号 0=A,1=B,2=C,...
1A
置 DTA 地址
DS:DX=DTA 地址
1B
取缺省驱动器 FAT 信息
AL= 每簇的扇区数 DS:BX=FAT 标识字节 CX= 物理扇区大小 DX= 缺省驱动器的簇数
DL= 驱动器号
同上
1C
取任一驱动器 FAT 信息
229
DOS 功能调用 21
22
随机读
随机写
DS:DX=FCB 首地址
AL=00 =01 =02 =03
读成功 文件结束 缓冲区溢出 缓冲区不满
DS:DX=FCB 首地址
AL=00 写成功 =01 盘满 =02 缓冲区溢出
23
测定文件大小
DS:DX=FCB 首地址
AL=00 成功 ( 文件长度填 入 FCB) AL=FF 未找到
24
设置随机记录号
DS:DX=FCB 首地址
25
设置中断向量
DS:DX= 中断向量 AL= 中断类型号
26
建立程序段前缀
DX= 新的程序段前缀
230
DOS 功能调用 DS:DX=FCB 首地址 CX= 记录数
AL=00 =01 =02 =03
随机分块写
DS:DX=FCB 首地址 CX= 记录数
AL=00 写成功 =01 盘满 =02 缓冲区溢出
29
分析文件名
ES:DI=FCB 首地址 DS:SI=ASCIIZ 串 AL= 控制分析标志
AL=00 标准文件 =01 多义文件 =02 非法盘符
2A
取日期
CX= 年 DH:DL= 月 : 日 ( 二进制 )
2B
设置日期
CX:DH:DL= 年 : 月 : 日
AL=00 成功 =FF 无效
27
28
随机分块读
读成功 文件结束 缓冲区太小 , 传输结束 缓冲区不满
231
DOS 功能调用 2C
取时间
CH:CL= 时 : 分 DH:DL= 秒 :1/100 秒
2D
设置时间
CH:CL= 时 : 分 DH:DL= 秒 :1/100 秒
AL=00 成功 =FF 无效
2E
置磁盘自动读写标志
AL=00 关闭标志 AL=01 打开标志
2F
取磁盘缓冲区的首址
ES:BX= 缓冲区首址
30
取 DOS 版本号
AH= 发行号 ,AL= 版本
31
结束并驻留
AL= 返回码 DX= 驻留区大小
33
Ctrl-Break 检测
AL=00 =01 DL=00 =01
DL=00 关闭 Ctrl-Break 检测 =01 打开 Ctrl-Break 检测
取状态 置状态 (DL) 关闭检测 打开检测
232
DOS 功能调用 35
取中断向量
AL= 中断类型
36
取空闲磁盘空间
DL= 驱动器号 0= 缺省 ,1=A,2=B,...
ES:BX= 中断向量 成功 :AX= 每簇扇区数 BX= 有效簇数 CX= 每扇区字节数 DX= 总簇数 失败 :AX=FFFF
38
置 / 取国家信息
DS:DX= 信息区首地址
BX= 国家码 ( 国际电话前 缀码 ) AX= 错误码
39
建立子目录 (MKDIR)
DS:DX=ASCIIZ 串地址
AX= 错误码
3A
删除子目录( RMDIR ) DS:DX=ASCIIZ 串地址
AX= 错误码
3B
改变当前目录 (CHDIR)
DS:DX=ASCIIZ 串地址
AX= 错误码
3C
建立文件
DS:DX=ASCIIZ 串地址 CX= 文件属性
成功 :AX= 文件代号 错误 :AX= 错误码 233
DOS 功能调用 DS:DX=ASCIIZ 串地址 AL=0 读 =1 写 =3 读 / 写
成功 :AX= 文件代号 错误 :AX= 错误码
关闭文件
BX= 文件代号
失败 :AX= 错误码
读文件或设备
DS:DX= 数据缓冲区地址 BX= 文件代号 CX= 读取的字节数
读成功 : AX= 实际读入的字节数 AX=0 已到文件尾 读出错 :AX= 错误码 写成功 : AX= 实际写入的字节数 写出错 :AX= 错误码 成功 :AX=00 出错 :AX= 错误码 (2,5)
3D
打开文件
3E 3F
40
写文件或设备
DS:DX= 数据缓冲区地址 BX= 文件代号 CX= 写入的字节数
41
删除文件
DS:DX=ASCIIZ 串地址
234
DOS 功能调用 42
移动文件指针
43
置 / 取文件属性
44
设备文件 I/O 控制
BX= 文件代号 成功 :DX:AX= 新文件指 CX:DX= 位移量 针位置 AL= 移动方式 (0: 从文件头绝对 出错 :AX= 错误码 位移 ,1: 从当前位置相对移动 ,2: 从文件尾绝对位移 ) DS:DX=ASCIIZ 串地址 AL=0 取文件属性 AL=1 置文件属性 CX= 文件属性 BX= 文件代号 AL=0 取状态 =1 置状态 DX =2 读数据 =3 写数据 =6 取输入状态 =7 取输出状态
成功 :CX= 文件属性 失败 :CX= 错误码
DX= 设备信息
235
DOS 功能调用 45
复制文件代号
BX= 文件代号 1
成功 :AX= 文件代号 2 失败 :AX= 错误码
46
人工复制文件代号
BX= 文件代号 1 CX= 文件代号 2
失败 :AX= 错误码
47
取当前目录路径名
DL= 驱动器号 DS:SI=ASCIIZ 串地址
(DS:SI)=ASCIIZ 串 失败 :AX= 出错码
48
分配内存空间
BX= 申请内存容量
成功 :AX= 分配内存首地 失败 :BX= 最大可用内存
49
释放内容空间
ES= 内存起始段地址
失败 :AX= 错误码
4A
调整已分配的存储块
ES= 原内存起始地址 BX= 再申请的容量
失败 :BX= 最大可用空间 AX= 错误码 236
DOS 功能调用 4B
装配 / 执行程序
4C
带返回码结束
DS:DX=ASCIIZ 串地址 ES:BX= 参数区首地址 AL=0 装入执行 AL=3 装入不执行
失败 :AX= 错误码
AL= 返回码
4D 取返回代码
AX= 返回代码
4E
查找第一个匹配文件
DS:DX=ASCIIZ 串地址 CX= 属性
AX= 出错代码 (02,18)
4F
查找下一个匹配文件
DS:DX=ASCIIZ 串地址 ( 文件名中带有 ? 或 *)
AX= 出错代码 (18)
54
取盘自动读写标志
AL= 当前标志值 237
DOS 功能调用 文件改名
DS:DX=ASCIIZ 串 ( 旧 ) ES:DI=ASCIIZ 串 ( 新 )
AX= 出错码 (03,05,17)
57
置 / 取文件日期和时间
BX= 文件代号 AL=0 读取 AL=1 设置 (DX:CX)
DX:CX= 日期和时间 失败 :AX= 错误码
58
取 / 置分配策略码
AL=0 取码 AL=1 置码 (BX)
成功 :AX= 策略码 失败 :AX= 错误码
59
取扩充错误码
AX= 扩充错误码 BH= 错误类型 BL= 建议的操作 CH= 错误场所
56
238
DOS 功能调用 5A
建立临时文件
CX= 文件属性 DS:DX=ASCIIZ 串地址
成功 :AX= 文件代号 失败 :AX= 错误码
5B
建立新文件
CX= 文件属性 DS:DX=ASCIIZ 串地址
成功 :AX= 文件代号 失败 :AX= 错误码
5C
控制文件存取
62
取程序段前缀
AL=00 封锁 =01 开启 BX= 文件代号 CX:DX= 文件位移 SI:DI= 文件长度
失败 :AX= 错误码
BX=PSP 地址 239
BIOS 中断 INT
10
AH
0
功能
调用参数
返回参数
设置显示 方式
AL=02 80×25 黑白方式 AL=03 80×25 彩色方式 AL=04 320×200 彩色图形方式 AL=05 320×200 黑白图形方式 AL=06 320×200 黑白图形方式 AL=07 80×25 单色文本方式 AL=08 160×200 16 色图形 (PCjr) AL=09 320×200 16 色图形 (PCjr) AL=0A 640×200 16 色图形 (PCjr) AL=0B 保留 (EGA) AL=0C 保留 (EGA) AL=0D 320×200 彩色图形 (EGA) AL=0E 640×200 彩色图形 (EGA) AL=0F 640×350 黑白图形 (EGA) AL=10 640×350 彩色图形 (EGA) AL=11 640×480 单色图形 (EGA) AL=12 640×480 16 色图形 (EGA) AL=13 320×200 256 色图形 (EGA) AL=40 80×30 彩色文本 (CGE400) AL=41 80×50 彩色文本 (CGE400) AL=42 640×400 彩色图形 (CGE400)
240
BIOS 中断 10 1
置光标类型
(CH)0-3= 光标起始行 (CL)0-3= 光标结束行
10 2
置光标位置
BH= 页号 DH,DL= 行 , 列
10 3
读光标位置
BH= 页号
CH= 光标起始行 DH,DL= 行 , 列
10 4
读光笔位置
AH=0 光笔未触发 =1 光笔触发 CH= 象素行 BX= 象素列 DH= 字符行 DL= 字符列
241
BIOS 中断 10 5
置显示页
10 6
屏幕初始化或上卷
10 7
屏幕初始化或下卷
AL= 页号
AL= 上卷行数 AL=0 整个窗口空白 BH= 卷入行属性 CH= 左上角行号 CL= 左上角列号 DH= 右下角行号 DL= 右下角列号
AL= 下卷行数 AL=0 整个窗口空白 BH= 卷入行属性 CH= 左上角行号 CL= 左上角列号 DH= 右下角行号 DL= 右下角列号
242
BIOS 中断 10 8
读光标位置的字符和属 性
10 9
在光标位置显示字符及 属性
10 A 在光标位置显示字符
10 B
BH= 显示页
AH= 属性 AL= 字符
BH= 显示页 AL= 字符 BL= 属性 CX= 字符重复次数
BH= 显示页 AL= 字符 CX= 字符重复次数
置彩色调板 (320×200 图 BH= 彩色调板 ID 形) BL= 和 ID 配套使用的颜色
10 C 写象素
DX= 行 (0-199) CX= 列 (0-639) AL= 象素值
243
BIOS 中断 10 D
读象素
DX= 行 (0-199) CX= 列 (0-639)
AL= 象素值
10 E
显示字符 ( 光标前移 )
AL= 字符 BL= 前景色
10 F
取当前显示方式
AH= 字符列数 AL= 显示方式
显示字符串 ( 适用 AT)
ES:BP= 串地址 CX= 串长度 DH,DL= 起始行 , 列 BH= 页号 AL=0,BL= 属性 串 :char,char,... AL=1,BL= 属性 串 :char,char,... AL=2 串 :char,attr,char,attr,... AL=3 串 :char,attr,char,attr,...
光标返回起始位置 光标跟随移动 光标返回起始位置 光标跟随移动
10 13
244
BIOS 中断
11 设备检验
AX= 返回值 bit0=1, 配有磁盘 bit1=1,80287 协处理器 bit4,5=01,40×25BW( 彩色板 ) =10,80×25BW( 彩色板 ) =11,80×25BW( 黑白板 ) bit6,7= 罗盘驱动器 bit9,10,11=RS-232 板号 bit12= 游戏适配器 bit13= 串行打印机 bit14,15= 打印机号
12 测定存储器容量
AX= 字节数 (KB) 245
BIOS 中断 13 0
软盘系统复位
13 1
读软盘状态
AL= 状态字节
AL= 扇区数 CH,CL= 磁盘号 , 扇区号 DH,DL= 磁头号 , 驱动器 号 ES:BX= 数据缓冲区地址
读成功 :AH=0 AL= 读取的扇区数 读失败 :AH= 出错代码
同上
写成功 :AH=0 AL= 写入的扇区数 写失败 :AH= 出错代码
13 2
13 3
读磁盘
写磁盘
13 4
检验磁盘扇区
同上 (ES:BX 不设置 )
成功 :AH=0 AL= 检验的扇区数 失败 :AH= 出错代码
13 5
格式化盘磁道
ES:BX= 磁道地址
成功 :AH=0 失败 :AH= 出错代码 246
BIOS 中断 14 0
初始化串行通讯口
14 1
向串行通讯口写字符
AL= 初始化参数 DX= 通讯口号 (0,1)
AH= 通读口状态 AL= 调制解调器状态
AL= 字符 DX= 通讯口号 (0,1)
写成功 :(AH)7=0 写失败 :(AH)7=1 (AH)0-6= 通讯口状态
14 2
从串行通讯口读字符
DX= 通讯口号 (0,1)
14 3
取通讯口状态
DX= 通讯口号 (0,1)
读成功 :(AH)7=0 (AL)= 字符 写失败 :(AH)7=1 (AH)0-6= 通讯口状态 AH= 通讯口状态 AL= 调制解调器状态 247
BIOS 中断 15 0
启动盒式磁带马达
15 1
停止盒式磁带马达
15 2
磁带分块读
ES:BX= 数据传输区地址 CX= 字节数
15 3
磁带分块写
DS:BX= 数据传输区地址 CX= 字节数
AH= 状态字节 AH=00 读成功 =01 冗余检验错 =02 无数据传输 =04 无引导
同上 248
BIOS 中断 16 0
从键盘读字符
AL= 字符码 AH= 扫描码
16 1
读键盘缓冲区字符
ZF=0 AL= 字符码 AH= 扫描码 ZF=1 缓冲区空
16 2
读键盘状态字节
AL= 键盘状态字节
17 0
打印字符 回送状态字节
AL= 字符 DX= 打印机号
AH= 打印机状态字节
17 1
初始化打印机 回送状态字节
DX= 打印机号
AH= 打印机状态字节
17 2
取状态字节
DX= 打印机号
AH= 打印机状态字节 249
BIOS 中断 1 A
0
读时钟
CH:CL= 时 : 分 DH:DL= 秒 :1/100 秒
1 A
1
置时钟
CH:CL= 时 : 分 DH:DL= 秒 :1/100 秒
1 A
2
读实时钟
CH:CL= 时 : 分 (BCD) DH:DL= 秒 :1/100 秒 (BCD)
1 A
6
置报警时间
CH:CL= 时 : 分 (BCD) DH:DL= 秒 :1/100 秒 (BCD)
1 A
7
清除报警
250
8086 寻址方式
1.1 立即寻 址方式 (immediate addressing) MOV AX, 1000H ;AX=1000H 1.2 寄存器 寻址方式 (register addressing) MOV AX, BX 1.3 直接寻 址方式 (direct addressing) MOV AX, VALUE 或 MOV AX, [VALUE] 1.4 寄存器 间接寻址 方式 MOV AX, DS:[BX] 或 MOV AX, ES:[BX] 1.5 寄存器 相对寻址 方式 MOV AX, TABLE[SI] 或 MOV AX, ES:[TABLE+SI] 1.6 基址变 址寻址方 式 MOV AX, [BX][DI] 或 MOV AX, ES:[BX+DI] 1.7 相对基 址变址寻 址方式 MOV AX , MASK[BX][DI] 或 MOV AX , ES:MASK[BX+DI] 251
8086 寻址方式
位移 量 IP
EA
2. 与转移 地址有 关的 寻址方 式 2.1 段内直 接寻 址 JMP NEAR PTR P01_ABC JMP SHORT P09_XYZ 2.2 段内间 接寻 址 JMP BX JMP WORD PTR [BP+TABLE] 2.3 段间直 接寻 址 JMP FAR PTR NEXTPROC JMP DWORD PTR [BX+P_ABC] 252