汇编复习

考试范围

1、题型:简答(6 个,24 分);计算写出 OF SF ZF CF 值;指令执行题;内存绘制题;编程题;论述题

2、第一、二、三章(汇编语言的组合;计算机中数和符号的表示;补码的加减运算;逻辑运算规则;汇编程序的优势;寄存器的作用和组成;8086 结构特征;段;有效地址、物理地址;外设和接口;32 位 CPU 工作模式;汇编编程所需文件;上机步骤)

第四章(寻址方式)

第五章(指令系统)

第六章(伪指令,变量属性,赋值伪指令,过程定义伪指令,数值回送伪指令)

第七章(分支,循环)

第一章 基础

1.1 简介

1.1.1 机器语言与汇编语言

三类计算机程序设计语言:

  1. 机器语言
  2. 汇编语言
  3. 高级语言

汇编指令也称为符号指令。汇编语言也称为符号语言。符号也称为助记符。

汇编程序 是把汇编语言源程序翻译成机器码的程序。这个过程称为 汇编

1.1.2 汇编语言的组成

  1. 汇编指令:机器码助记符,是汇编语言的核心
  2. 伪指令:没有对应机器码,计算机不执行
  3. 其他符号:如 +、-、*、/ 编译器识别,没有对应机器码

1.1.3 学习意义

  1. 对于计算机应用开发有重要作用
  2. 是从根本上认识和理解计算机工作过程的最好办法

1.2 数据表示

1.2.1 进制转换

  1. B 二进制
  2. D 十进制
  3. H 十六进制

101101(B)=45(D)=101101B=45D=1011012=4510

1.2.2 二进制和十六进制的运算

1.2.3 带符号数的补码

补码符号位数据位
正数0
000
负数1其正数数据位反码再把最低位加一

性质:补码的补码是原码。

1.2.4 补码加减法

[ X + Y ] = [ X ] +[ Y ]

[ X – Y ] = [ X ] +[ – Y ]

不必考虑数字的正负,符号位直接参与运算。最高位的进位丢弃。

1.2.7 逻辑运算

  1. 与 AND
  2. 或 OR
  3. 非 NOT
  4. 异或 XOR异或就是异,不一样则 true。

小结

  1. 汇编语言的优势?因为用汇编语言设计的程序最终被转换成机器指令,故能够保持机器语言的一致性,直接、简捷,并能像机器指令一样访问、控制计算机的各种硬件设备,如磁盘、存储器、CPU、I/O 端口等。使用汇编语言,可以访问所有能够被访问的软、硬件资源。目标代码简短,占用内存少,执行速度快,是高效的程序设计语言,经常与高级语言配合使用,以改善程序的执行速度和效率,弥补高级语言在硬件控制方面的不足,应用十分广泛。

第二章 计算机基本原理

2.1 计算机系统组成

基本工作原理

  1. 存储程序
  2. 程序控制

这种原理称为冯诺依曼原理,这样的计算机称为冯诺依曼计算机,这种计算机的体系结构称为冯诺依曼结构。

典型冯诺依曼结构如图所示。

主要部分:

  1. 中央处理器
  2. 存储器
  3. 输入/输出子系统

三部分由系统总线连在一起。

2.2 存储器

2.2.2 存储器

  1. 基本存储单元
    • 最小单位:一个二进制位 bit
    • 一个字节:八位二进制 Byte
    • 一字 (Word):2 字节 Word
    • 双字:2 字 32 位
    80×86 微机内存储器以字节为基本单位。即读写至少是一个字节。(隐藏知识点,地址按照字节编码)
  2. 字的存储一字 16 位,高八位为高位字节,低八位为低位字节。规定高位字节在高地址单元,低位字节在低地址单元。

2.2.3 存储器分段

  1. 分段概念8086 系统有 20 根地址线,可以寻址 1MB。但 8086 系统是 16 位机,16 位结构解决 20 位地址,采用分段法。段的划分并不是在内存,是来自 CPU。计算物理地址 段地址 * 16 + 偏移地址 = 物理地址。 (注意,* 16 是左移 4 位,不是左移 16 位!)每个段 64KB,因为偏移地址 16 位。意义:使得程序设计时,程序保持相对的完整性。
  2. 段的类型存储器逻辑分段类型:
    • 代码段 存放指令,段基址存放在段寄存器 CS(Code Segment)
    • 数据段 存放数据,段基址存放在段寄存器 DS(Data Segment)
    • 附加段 辅助存放数据,段基址存放在段寄存器 ES(Extra Segment)
    • 堆栈段 重要的数据结构,可用来保存数据、地址和系统参数,段基址存放在段寄存器 SS(Stack Segment)
    编写汇编时必须有代码段,而数据段、堆栈段、附加段可以根据需要选择。

2.2.4 逻辑地址

用户编程时使用的地址。

段地址和偏移地址都是 16 位二进制数。

有可能多个逻辑地址组织对应到同一个物理单元上。因此逻辑地址不是唯一的。

CPU 要想读写数据,需要进行下面三类交互:

  1. 存储单元地址
  2. 器件选择,读/写命令
  3. 读/写数据

地址、数据、控制信息传送是通过 总线 的。总线有三类:

  1. 地址总线
  2. 控制总线
  3. 数据总线

2.3 寄存器

2.3.1 寄存器介绍

典型 CPU 由 运算器、控制器、寄存器 等器件构成。

8086 CPU 有 14 个寄存器。

按使用类别划分,寄存器分三类:

  1. 通用寄存器
  2. 段寄存器
  3. 专用寄存器

寄存器组如下:

  1. 通用数据寄存器
    • AX Accumulator,累加器,运算时较多使用
    • BX Base,基址寄存器,除了存储数据,一般存放一段内存的起始偏移地址
    • CX Count,计数寄存器,除了存储数据,一般存放重复操作的次数
    • DX Data,数据寄存器,除了存储数据,有时存放 32 位数据的高 16 位
    这四个寄存器可以分成两个独立的 8 位寄存器来使用,AX 的高八位寄存器为 AH(Accumulator High),低八位为 AL(Accumulator Low)。其它寄存器同理。
  2. 地址寄存器
    • SP Stack Pointer,堆栈指针寄存器,存放堆栈栈顶偏移地址
    • BP Base Pointer,基址指针寄存器,存放内存中数据的偏移地址
    • SI Source Index,源变址寄存器,经常用来存放内存中源数据区的偏移地址。变址寄存器指的是,在某些指令作用下它可以自动递增或递减其中的值。
    • DI Destination Index,目的变址寄存器,经常用来存放内存中目的数据区的偏移地址,在某些指令作用下它可以自动递增或递减其中的值。
    这四个寄存器不能拆分使用。
  3. 段寄存器
    • CS Code Segment,代码段寄存器,存放当前正在执行的程序段的地址。
    • SS Stack Segment,堆栈段寄存器,存放堆栈段的段基址。
    • DS Data Segment,数据段寄存器,用来存放数据段的段基址。
    • ES Extra Segment,附加段寄存器,用来存放另一个数据段的段基址。 32 位 8086 处理器增加了两个段寄存器 FS、GS,功能类似 ES(EFG 可还行)。
    32 位的 8086 处理器仍然使用 16 位的段寄存器,但是存储内容变化了。
  4. 指令指针寄存器
    • IP Instruction Pointer,指令指针寄存器,存放即将执行指令的偏移地址。
  5. 标志寄存器
    • FLAGS 存放 CPU 的两类标志:
      • 状态标志反映处理器当前的状态(溢出,进位等)。六个状态标志:
        • CF Carry Flag 进位/借位标志,表示加法有进位或者减法有借位。
        • PF Parity Flag 奇偶标志,1 表示运算结果低八位有偶数个“1”。
        • AF Assistent carry Flag 辅助进位标志。
        • ZF Zero Flag 零标志,1 则运算结果为 0。
        • SF Sort Flag 符号标志,是运算结果最高位(符号位),如果未溢出,1 为负数,0 为非负数。如果溢出了,结果就因错误而无意义,但符号标志仍然可以标志正负,溢出后,1 为正,0 为负(与正常结果相反)。
        • OF Overflow Flag 溢出标志,1 则结果错误。无符号数也有这个标志但可以不处理。
      • 控制标志控制 CPU 的工作方式,如 是否响应可屏蔽中断。三个控制标志:
        • TF
        • IF Interrupt Flag 中断允许,1 表示允许处理器响应可屏蔽中断请求信号,称为开中断。反之则关中断。
        • DF Direction Flags 方向标志,0 时用增加的方式修改源或目的地址。见 SI/DI 寄存器
      标志名标志为 1标志为 0OF 溢出 是/否OVNVDF 方向 减/增DNUPIF 中断 允许/不允许EIDISF 符号 负/正NGPLZF 零 是/否ZRNZAF 辅助进位 有/无ACNAPF 奇偶 偶/奇PEPOCF 进位 有/无CYNC状态标志每次运算后自动产生,控制标志的值由指令设定。

2.3.2 CS 和 IP

CS 是 Code Segment 代码段寄存器,IP 是 Instruction Pointer 指令指针寄存器。

提供了 CPU 要执行的指令的地址。因此如果内存中的一段信息被 CPU 执行过,就一定被 CS:IP 指向过。

2.3.3 堆栈

数据存入 堆栈 是以 的方式存入(16 位),后存入的数据,物理地址小/低。栈指针 SP 指向栈顶,压栈则 -2。

常常用于保存调用的程序的返回地址和现场参数,也可以作为一种临时的数据存储区。

2.4 外设和接口

外设(外部设备)也称为 输入/输出设备,通过 输入/输出接口 与主机连接。

接口一方面连接外设,一方面通过总线与主机相连。接口内有若干寄存器,用于在 CPU 与外部设备之间传递信息。系统对外设接口中的寄存器进行统一编号,称为端口号。CPU 可以通过端口地址来区分和访问不同的外设。

端口/寄存器分为以下3类

  1. 数据端口 用来存放需要传递的数据。起数据缓冲作用。方向可以是输入/输出。
  2. 控制端口 传递 CPU 对外部设备的控制信号。例如启动磁盘工作。方向总是输出。
  3. 状态端口 协调外设与主机的同步。反映外设工作状态。例如某设备还未准备好接收数据,则不能向它发送数据。状态端口的传送方向对于 CPU 而言总是输入。

CPU与I/O接口中的端口的信息传输是通过数据总线进行的。

2.5 32 位 8086CPU 的工作模式

  1. 实模式 兼容 16 位机的特点,内存寻址范围 0 ~ 0FFFFFH 的 1MB 空间,地址线低 20 位有效。可以使用 32 位寄存器和 32 位操作数,MS DOS 只能在实模式下运行。
  2. 保护模式 是 32 位 8086CPU 的主要工作模式,特点是 全部地址线参与寻址 ,程序使用 逻辑地址,或者称为虚拟地址。虚拟地址的段选择符存放在寄存器中,应用程序不能更改,操作系统决定。 物理地址 是 16 位段选择符对应的 32 位段基址 和 32 位偏移地址组成。32 位即 4GB 大小。 采用虚拟地址使得各程序之间有严格的内存保护和隔离。
  3. 虚拟 8086 模式 就是生成多个虚拟的 8086CPU,以便运行实模式下的 8086 程序。 支持内存保护和隔离,可以同时运行多个程序。 Windows 下在 DOS 窗口运行一个 DOS 应用程序,则该程序运行在虚拟 8086 模式下。

小结

  1. 8086 结构特征
    1. 数据总线为 16 位;
    2. 运算器一次最多可以处理 16 位的数据;
    3. 寄存器的最大宽度为 16 位;
    4. 寄存器和运算器之间的通路为 16 位

第三章 汇编语言程序实例及上机操作

3.1 汇编语言的工作环境

3.1.1 汇编语言的系统工作文件

代码到程序三步骤

  1. 编辑
  2. 汇编
  3. 连接

编辑形成 .ASM 文件(代码文件),汇编成为 .OBJ 文件,连接形成 .EXE 文件。

因此需要有四种程序:

  1. 编辑程序如记事本,EDIT.COM。
  2. 汇编程序如 MASM.EXE。
  3. 连接程序如 LINK.EXE
  4. 调试程序如 DEBUG.EXE

3.2 实例

 code    segment         ;
 assume cs:code ; 说明语句,指定CODE段与CS寄存器关联。
 start: mov ah,1 ; START:是一个标号,MOV AH,1指令表示把1送AH寄存器,这是因为DOS系统功能的1号功能是键盘输入,所以要把功能号1送AH。
  int 21h ; INT 21H 指令即调用DOS系统功能,其1号功能被执行,程序等待键盘输入,从键盘输入一个字符后,程序才继续执行。注意,这个从键盘输入的字符到哪里去了呢?它被放到寄存器AL中,是该字符的ASCII码。如果是字符“A”,则AL中就为41H。
  mov dl,al ; 把AL送DL寄存器。
  add dl,1 ; DL内容加1。为后面的2号功能调用准备输出的字符。
  mov ah,2 ; 调用DOS系统功能的2号功能,显示DL中的字符。
  int 21h ; 执行
  mov ah,4ch ; 调用DOS系统功能的4CH号功能,4CH号功能是程序结束并返回到操作系统。
  int 21h ; 执行
 code ends ;
         end start ; 说明语句,告诉汇编程序,汇编到此结束,程序的启动地址为标号为START的那条指令(第3行)。

解析:

CODE 是段名,SEGMENTENDS 是关键字。

第 1 行 CODE SEGMENT 和第 11 行 CODE ENDS 这 一对说明语句,定义了代码。

第四章 操作数的寻址方式

  1. 立即寻址方式 MOV AL,6H 指令 目的 数字 源操作数是数字。直接把数字复制进入目的操作数。 只适用于源操作数,类型要和目的操作数相同(同样是字/字节)
  2. 寄存器寻址 MOV AX,BX 源操作数是寄存器。读出寄存器的值,写入目的操作数。
  3. 直接寻址方式 MOV AX,DS:[4050H] MOV AX,[4050] 源操作数是逻辑地址。读出地址的存储单元的值,写入目的操作数。
  4. 寄存器间接寻址方法 MOV AX,[BX] 操作数的地址 EA 在寄存器中。 读入 BX 的值,计算物理地址,再读物理地址的值,写入目的操作数。这里与直接寻址方式的区别在于读了两次,且第一次是寄存器,第二次也是寄存器。 注意,寄存器间接寻址中只允许
    1. BX(DS) Base 基址寄存器,Data Segment 数据段
    2. BP(SS) Base Pointer 基址指针寄存器,Stack Segment 堆栈段
    3. SI(DS) Source Index 源变址寄存器,Data Segment 数据段
    4. DI(DS) Destination Index 目的变址寄存器,Data Segment 数据段
    以上使用逻辑地址的计算方法即段地址 * 16 + 偏移地址 = 物理地址段地址就是括号内的地址,偏移地址就是括号外的寄存器的值。
  5. 寄存器相对寻址方法 MOV AX,TOP[SI] MOV [BX+2623H],AX 以上第一句,源操作数 有效地址 为 EA = SI + TOP(TOP 取其偏移地址若是寄存器或常量,多是 16 位,与 16 位寄存器匹配) 物理地址 为 DS * 10H + EA 然后读取这个物理地址的存储单元的值 这种方式常用于查表。适合访问一维数组。 注意:默认搭配 DS 段寄存器和 BX、SI、DI。SS 段寄存器和 BP
  6. 基址变址寻址方式 MOV AX,[BX+DI] 源操作数物理地址为 DS * 10H + BX +DI 取出该地址的存储单元的值。 允许使用的基址寄存器为
    1. BX(DS) Base 基址寄存器
    2. BP(SS) Base Pointer 基址指针寄存器
    变址寄存器为
    1. SI Source Index 源变址寄存器
    2. DI Destination Index,目的变址寄存器
  7. 相对基址变址寻址方式 MOV AX,[BX+DI+MASK] 物理地址为 DS * 10H + BX + DI + MASK 注意:默认 DS 为数据端 允许使用的基址寄存器为
    1. BX(DS) Base 基址寄存器
    2. BP(SS) Base Pointer 基址指针寄存器
    变址寄存器为
    1. SI Source Index 源变址寄存器
    2. DI Destination Index,目的变址寄存器
    可用于二维数组的处理。

小结

  1. 选择寻址方式的两个原则
    1. 实用
    2. 有效
  2. 双操作数指令的提示
    1. 双操作数的两个操作数长度需要匹配。
    2. 两个操作数不能同时是内存单元。 因为一条指令需要使用地址线传输地址,如果都是地址,那么一条指令就需要传输两个地址,所以是不现实的。

第五章 常用指令系统

汇编语言的一般格式为:

[ 标号 : ] 指令助记符 [ 操作数 ] [ ; 注释 ]

例如:

 START: MOV AX,DATA ; DATA 送AX

上述一般格式内的方括号为可选内容,由此可知,一条指令中只有 指令助记符 是必不可少的。

意义说明:

  1. 标号 标号是一个符号地址,用来表示指令在内存中的位置。 令使用标号时,应加冒号 :
  2. 指令助记符 指令助记符表示指令名称,是指令功能的英文缩写。
  3. 操作数 操作数表示指令要操作的数据或数据所在的地址。 可以是 寄存器、常量、变量,也可以由表达式构成。 80×86 指令一般带有 0 个、1 个或 2 个操作数。 双操作数指令的 第一个 操作数称为 目的操作数 DST,存放操作结果。第二个 称为 源操作数 SRC。操作数之间用 , 分开。
  4. 注释 注释由分号 ; 开始。 注释超过一行则在每行都必须以分号开头。

5.1 数据传送指令

5.1.1 通用数据传送指令

  1. MOV(move) 传送 格式:MOV DST,SRC 操作:(DST)←(SRC),将源操作数传送到目的操作数。 注意:
    1. DSTSRC 长度必须明确且一致
    2. DSTSRC 不能同为存储器,不允许在两个存储单元之间直接传送数据。这是因为一条指令最多发送一个地址。
    3. DST 不能为 CSIP ,因为 CS:IP 指向的是当前要执行的指令。
    4. DST 不允许是立即数。
    更多信息见 P62
  2. PUSH(push onto the stack) 进栈 格式:PUSH SRC 操作:(SP)←(SP)-2 ((SP)+1,(SP))←(SRC) 表示将源操作数压入堆栈(目的操作数),目的操作数地址由SS:SP指定,指令中无需给出。 SP总是指向栈顶,堆栈操作以 字(16 位) 为单位进行操作。
  3. POP(pop from the stack) 出栈 格式:POP DST 操作:(DST)←((SP)+1,(SP))(SP)←(SP)+2 其中DST表示目的操作数。将堆栈中源操作数弹出到目的操作数,堆栈中源操作数地址由 SS:SP 指定,指令中无需给出。 源操作数弹出后,SP加 2,下移一个字,指向新的栈顶。
  4. XCHG(exchange) 交换 格式:XCHG OPR1,OPR2 操作:(OPR1)← →(OPR2) 其中OPR1OPR2为操作数。把 2 个操作数互换位置。 XCHG为双操作数指令,两个操作数均是目的操作数,除了遵循双 操作数指令的规定,也不能用立即数寻址。

5.1.2 累加器专用传送指令

  1. IN(input)输入 把端口号 PORT 或由 DX 指向的端口的数据输入到累加器,根据端 口号的长度,有长格式和短格式两种形式。
    1. 长格式:IN AL,PORT(字节) IN AX,PORT(字) 操作:AL ←(PORT)AX ←(PORT) PORT 为端口号,端口号范围为 00~FFH 时,可以使用长格式指令 长格式指令,是指其机器指令长度为 2 个字节(端口号占 1 个字节)
    2. 短格式:IN AL,DX(字节) IN AX,DX(字) 操作:AL ←((DX))AX ←((DX)) 端口号范围为 0100H~0FFFFH 时,必须使用短格式指令。 短格式指令长度为 1 个字节,因为端口号存放在 DX 寄存 器中。
  2. OUT(output)输出 把累加器的数据输出到端口 PORT 或由 DX 指向的端口。与输入指 令相同,根据端口号的长度,分为长格式和短格式两种形式。
    1. 长格式:OUT PORT,AL(字节) OUT PORT,AX(字节) 操作:PORT ← AL PORT ← AX
    2. 短格式:OUT DX,AL(字节) OUT DX,AX(字节) 操作:(DX)← AL(DX)← AX
  3. XLAT(translate)换码 格式:XLAT 操作:AL ←(BX+AL) 把 BX+AL 的值作为有效地址,取出其中的一个字节送 AL。

5.1.3 地址传送指令

  1. LEA(Load Effective Address)有效地址送寄存器 格式:LEA REG,SRC 操作:REG ← SRC 把源操作数的有效地址 EA 送到指定的寄存器。
  2. LDS(Load DS with Pointer)指针送寄存器和 DS 格式:LDS REG,SRC 操作:REG ←(SRC)DS ←(SRC+2) 把源操作数 SRC 所指向的内存单元中 2 个字送到指定的寄存器 REG 和 DS。
  3. LES(Load ES with Pointer)指针送寄存器和 ES 格式:LDS REG,SRC 操作:REG ←(SRC)ES ←(SRC+2) 把源操作数 SRC 所指向的内存单元中 2 个字送到指定的寄存器 REG 和 ES。

5.1.4 标志寄存器传送指令

  1. LAHF(Load AH with Flags)标志送 AH 寄存器
  2. SAHF(Store AH into Flags)AH 送标志寄存器
  3. PUSHF(Push Flags)标志入栈
  4. POPF(Pop Flags)标志出栈

以上 4 条指令的格式相同,只有操作码部分,操作数为固定默认值。

5.2 算术运算指令

5.2.1 类型扩展指令

  1. CBW 字节扩展成字:convert byte to word
  2. CWD 字扩展成双字:convert word to double word

这两条指令的格式相同,只有操作码部分,无操作数部分。

操作数默认为累加器,无需在指令中给出。

当执行 CBW 时,默认将 AL 寄存器的内容扩展到 AX 寄存器中,扩展方法为符号扩展。

即如果 AL 的最高位为 1(负数),则 CBW 指令扩展时使 AH=FFH,如果 AL 的最高位为 0(正数),则 CBW 指令扩展时使 AH=00H。

当执行 CWD 时,默认将 AX 寄存器的内容扩展到(DX,AX)中,其中 DX 存放双字中的高位,AX 存放双字中的低位。

如果 AX 的最高位为 1(负数),则 CWD 指令扩展时使 DX=FFFFH,如果 AX 的最高位为 0(正数),则 CWD 指令扩展时使 DX=0000H。

5.2.2 加法指令

  1. ADD(add)加法 格式:ADD DST,SRC 操作:(DST)←(DST)+(SRC) ADD 指令将源操作数与目的操作数相加,结果存入目的操作数中。 特别需要注意,加法指令执行后会影响标志寄存器中的 CF 和 OF 标志位。
  2. ADC(add with carry)带进位加法 格式:ADD DST,SRC 操作:(DST)←(DST)+(SRC)+CF 其中上式中的 CF 为运算前 CF 标志位的值。
  3. INC(increment)加 1 格式:INC OPR 操作:(OPR)←(OPR)+1 该指令不影响 CF 标志位。

5.2.3 减法指令

  1. SUB(subtract)减法 格式:SUB DST,SRC 操作:(DST)←(DST)-(SRC)
  2. SBB(subtract with borrow)带借位减法 格式:SBB DST,SRC 操作:(DST)←(DST)-(SRC)-CF
  3. DEC(decrement)减 1 格式:DEC OPR 操作:(OPR)←(OPR)-1 该指令不影响 CF 标志位。
  4. NEG(negate)求补 格式:NEG OPR 操作:(OPR)←(OPR)
  5. CMP(compare)比较 格式:CMP OPR1,OPR2 操作:(OPR1)-(OPR2)

5.2.4 乘法指令

  1. MUL(unsigned mulutiple)无符号数乘法 格式:MUL SRC 操作:当操作数为字节时,(AX)←(AL)×(SRC) 当操作数为字时,(DX,AX)←(AX)×(SRC)
  2. IMUL(signed mulutiple)有符号数乘法 格式和操作与 MUL 相同,用来作有符号数乘法。

乘法指令中,目的操作数默认为累加器 AX,不必在指令中写出。

两个相乘的数必须长度相同,根据 SRC 的长度,默认参与运算的是 AL 寄存器的值(即为 AX 寄存器的第八位)或者是 AX 寄存器的值。

SRC 可以是寄存器或变量,但不能是立即数,因为立即数的长度是不明确的。

5.2.5 除法指令

  1. DIV(unsigned divide)无符号数除法 格式:DIV SRC 操作: SRC 为字节时,(AL)←(AX)/(SRC)的商,(AH)←(AX)/(SRC)的余数。 SRC 为字时,(AX)←(DX,AX)/(SRC)的商,(DX)←(DX,AX)/(SRC)的余数。该指令将参与运算的数据默认为无符号数,则商和余数都是无符号数。
  2. IDIV(signeddivide)有符号数除法 指令格式和操作与无符号数除法相同,用来作有符号数除法。 最终商的符号应是两个操作数符号的异或,而余数的符号和被除数符号一致。

在除法指令里,目的操作数必须是累加器 AX 和 DX,不必在指令中写出。

被除数长度应为除数长度的两倍,余数放在目的操作数的高位,商放在目的操作数的低位。其中 SRC 不能是立即数。

另外,和作乘法时相同,作除法时需考虑是无符号数还是有符号数,从而选择不同的指令。

由于除法指令的字节操作要求被除数为 16 位,字操作要求被除数为 32 位,因此往往需要用符号扩展指令使得被除数长度比除数长度扩大一倍。

需要注意的是,在进行乘法运算时,不会发生溢出问题,但在使用除法指令时,会产生溢出现象。

当除数是字节类型时,除法指令要求商为 8 位。此时如果被除数的高 8 位绝对值≥除数的绝对值,则商会产生溢出。

当除数是字类型时,除法指令要求商为 16 位。此时如果被除数的高 16 位绝对值≥除数的绝对值,则商会产生溢出。

商出现溢出时,系统转 0 号类型中断处理,提示“divide overflow”,并退出程序,返回到操作系统,程序已经崩溃了。

要想避免出现这种情况,必须在作除法前对溢出作出预判。

5.2.6 BCD 码的十进制调整指令

BCD 码是二进制转十进制比较简单的编码,4 位二进制表示 1 位十进制,其转换表如下。

  1. DAA(Decimal Adjust for Addition)加法的十进制调整指令 格式:DAA 操作:加法指令中,以 AL 为目的操作数,当加法运算结束后,使用本指令可以把 AL 中的和调整为正确的 BCD 码格式。 即:
    1. 如果 AL 低 4 位 > 9,或 AF=1,则 AL = AL + 6;
    2. 如果 AL 高 4 位 > 9,或 CF=1,则 AL = AL + 60H, CF = 1。
  2. DAS(Decimal Adjust for Subtraction)减法的十进制调整指令 格式:DAS 操作:减法指令中,以 AL 为目的操作数,当减法运算结束后,使用本指令可以把差调整为 BCD 码格式。 即:
    1. 如果 AL 低 4 位 > 9,或 AF = 1,则 AL = AL – 6,AF = 1;
    2. 如果 AL 高 4 位 > 9,或 CF = 1,则 AL = AL – 60H, CF = 1。

5.3 逻辑与移位指令

5.3.1 逻辑指令

  1. AND(and)与 格式:AND DST,SRC 操作:(DST)←(DST)∧(SRC)
  2. OR(or)或 格式:OR DST,SRC 操作:(DST)←(DST)∨(SRC)
  3. NOT(not)非 格式:NOT OPR 操作:(OPR)←(OPR)
  4. XOR(exclusive or)异或 格式:XOR DST,SRC 操作:(DST)←(DST)∀(SRC)
  5. TEST(test)测试 格式:TEST OPR1,OPR2 操作:(OPR1)∧(OPR2) 说明:TEST 指令的两个操作数相与的结果不保存,只根据结果置标志位。

逻辑运算指令只会对部分标志位产生影响,其中 NOT 指令不影响任何标志位,其他指令将使 CF 位和 OF 位为 0,AF 位无定义,其他位则根据运算结果设置。

逻辑指令除了常规的逻辑运算功能外,通常还可以用来对操作数的某些位进行处理,例如屏蔽某些位(将这些位置 O),或使某些位置 1,或测试某些位等。

  1. SHL(Shift Logical Left)逻辑左移
  2. SAL(Shift Arithmetic Left)算术左移
  3. SHR(Shift Logical Right)逻辑右移
  4. SAR(Shift Arithmetic Right)算术右移
  5. ROL(Rotat Left)循环左移
  6. ROR(Rotat Right)循环右移
  7. RCL(Rotat Left with Carry)带进位循环左移
  8. RCR(Rotat Right with Carry)带进位循环右移

移位指令均是双操作数指令,指令的格式相同,以 SHL 为例,

则:

格式:

  1. SHL OPR,1
  2. SHL OPR,CL,其中 CL 寄存器的值大于 1。

其中 OPR 为寄存器或内存单元,移位次数可以是 1 或 CL 寄存器,如需移位的次数大于 1,则可以在该移位指令前把移位次数先送 CL 寄存器中。

当执行逻辑或算术左移时,操作结果相同,均是最低位补 0,移出的最高位送 CF 标志位;

当执行逻辑右移时,最高位补 0,移出的最低位送 CF 标志位;

当执行算术右移时,OPR 被认为是有符号数,则最高位补符号位自身,移出的最低位送 CF 标志位;

当执行循环左移时,OPR 整体向左移一位,最高位移出,同时送 CF 标志位和最低位;

当执行循环右移时,OPR 整体向右移一位,最低位移出,同时送 CF 标志位和最高位;

当执行带进位循环左移时,OPR 整体向左移一位,此时最高位移出送 CF 标志位,而 CF 标志位原始的数值送 OPR 最低位;

当执行带进位循环右移时,OPR 整体向右移一位,此时最低位移出送 CF 标志位,而 CF 标志位原始的数值送 OPR 最高位。

5.4 串操作(我赌一波,不考)

  1. MOVS(Move String)串传送
    1. MOVSB:以字节为单位传送; 操作: (ES:DI)←(DS:SI),DI±1,SI±1
    2. MOVSW:以字为单位传送; 操作: (ES:DI)←(DS:SI),DI±2,SI±2
    3. MOVS DST,SRC:将源串 SRC 传送到目的串 DST 中。
    MOVS指令的寻址方式是固定的,目的串地址为ES:[DI],源串地址为DS:[SI],因此前两种格式都将操作数直接省略了。若采用第三种格式指令,则以字节为单位传送时,可以表示为:MOVS ES:BYTE PTR[DI],DS:[SI] 目的操作数指出了是字节的传送,如果源串不在数据段,也可加前缀,如ES:[SI]。上述操作中,当方向标志 DF=0 时 SI、DI 用+;DF=1 时 SI、DI 用-。方向标志 DF 的设置有两条指令:
    1. CLD(clear direction flag)设置正向(向前,使 DF=0,SI 或 DI 自动加)
    2. STD(set direction flag)设置反向(向后,使 DF=1,SI 或 DI 自动减)
  2. CMPS(Compare String)串比较
    1. CMPSB(字节) 操作: (ES:DI)-(DS:SI),DI±1,SI±1
    2. CMPSW(字) 操作: (ES:DI)-(DS:SI),DI±2,SI±2
    3. CMPS DST,SRC。
    本条串操作指令把两个串的对应位置的字节或字相减,不保存结果,只是根据结果设置标志位。该指令与前缀 REPE 联用时,可比较两个串是否相等。在每次比较过程中,一旦发现不相等,ZF=0,则终止重复执行,而不必等到整个串全部比较结束,此时 CX≠0,ZF=0。该指令终止执行后,可根据标志 ZF 判断两个串是否相等。其他指令格式与串传送指令相同。
  3. SCAS(Scan String)串扫描
    1. SCASB(字节) 操作: AL-(ES:DI),DI±1
    2. SCASW(字) 操作: AX-(ES:DI),DI±2
    3. SCAS DST。
    串扫描指令是把AL/AX寄存器中的内容与附加段中的由目的变址寄存器DI所指向的内存单元内容相比较,与CMPS比较指令相似,并不保存结果,只是根据结果设置标志位。该指令与前缀 REPNE 联用时,可在目的串中查找有无和 AL/AX 寄存器中的内容相同的字节或字。在每次执行串扫描指令过程中,一旦发现相等,即 ZF=1,则终止执行,此时 CX≠0,ZF=1,说明已找到相同的内容,而不必等到整个串全部扫描结束。该指令终止执行后,可根据标志位 ZF 判断是否找到。指令相关格式要求同串传送指令。
  4. STOS(Store in to String)存入串
    1. STOSB(字节) 操作: (ES:DI)←AL,DI±1
    2. STOSW(字) 操作: (ES:DI)←AX,DI±2
    3. STOS DST
    该指令把AL/AX寄存器的内容存入由目的变址寄存器指向的附加段的某单元中,并根据DF的值及数据类型修改目的变址寄存器的内容。当它与 REP 联用时,可把累加器的内容存入一个连续的内存缓冲区,该缓冲区长度由 CX 指定,因此 STOS 串指令可用于初始化某一块内存区。上述有关串处理指令的特性也适合本指令。
  5. LODS(Load from String)从串取
    1. LODSB(字节) 操作: AL←(DS:SI),SI±1
    2. LODSW(字) 操作: AX←(DS:SI),SI±2
    3. LODS SRC。
    该指令意义不大,一般不和 REP 联用,因为重复执行多次的结果也 只是使累加器为最后一次的值。该指令可以由 MOV 指令代替。

串操作指令用以处理内存中的数据串,但该操作每一次执行处理的只是单个字节或字,因此对于数据串来说,需要重复执行串操作指令才能处理完整个串。

串操作指令的重复有特定的前缀指令配合,下面先介绍前缀指令:

  1. REP(repeat)重复 前缀 REP 的作用是重复执行串操作指令,直到寄存器 CX=0 为止,而每执行一次串操作指令,会使 CX 的内容自动减 1,因此总的重复次数等于 CX 寄存器的初始值。
  2. REPE/REPZ(repeat while equal/zero)相等/为零则重复 前缀 REPE 也叫 REPZ,只有当 CX 寄存器的值≠0 并且标志位 ZF=1 时,重复执行串操作指令。 若用以比较两个字符串是否相等,每次的串操作指令把源串中的一个字节和目的串中的一个字节进行比较,如果相等(即 ZF=1),则还需继续执行串操作指令,若不相等或者比较全部串的数据(CX=0),则停止。
  3. REPNE/REPNZ(repeat while not equal/not zero)不相等/不为零则重复 前缀 REPNE 也叫 REPNZ,只有当 CX 寄存器的值≠0 并且标志位 ZF=0 时,重复执行串操作指令。 若在一个字符串中查找是否存在某一个字符,串操作指令把字符串中的一个字节和要找的这个字符进行比较,如果不相等(即 ZF=0),则还需继续执行串操作指令,直到找到(ZF=1)或者查找完整个串的数据(CX=0),才停止。

串处理指令的特性及用法

5.5 程序转移指令

5.5.1 无条件转移指令与程序的可重新定位

JMP(jmp):该指令无条件转移到指令指定的地址去执行程序。

  1. 段内直接转移 格式:JMP NEAR PTR OPR 操作:IP←IP+16 位位移量
  2. 段内间接转移 格式:JMP WORD PTR OPR 操作:IP←(EA) 有效地址 EA 值由 OPR 的寻址方式确定。它可以使用除立即数 方式以外的任何一种寻址方式。
  3. 段间直接转移 格式:JMP FAR PTR OPR 操作:IP←OPR 的偏移地址 CS←OPR 所在段的段地址
  4. 段间间接转移 格式:JMP DWORD PTR OPR 操作:IP←(EA) CS←(EA+2)

待续,敢考就敢寄。

第六章 伪指令与源程序格式

6.1 伪指令

6.1.1 处理机选择

随着处理器的升级,增加了新的指令。

处理机选择伪指令有以下几种:

  1. ·8086 选择 8086 指令系统
  2. ·286 选择 80286 指令系统
  3. ·286P 选择保护方式下的 80286 指令系统
  4. ·386 选择 80386 指令系统
  5. ·386P 选择保护方式下的 80386 指令系统
  6. ·486 选择 80486 指令系统
  7. ·486P 选择保护方式下的 80486 指令系统
  8. ·586 选择 Pentium 指令系统
  9. ·586P 选择保护方式下的 Pentium 指令系统

指令中的点 · 是需要的。这类伪指令一般放在代码段中的第一条指令前即可。如不给出,则汇编程序认为其默认选择是 8086 指令系统。

6.1.2 段定义伪指令

  1. 段定义伪指令汇编程序在把源程序转换为目标程序时,只能自动确定标号和变量(代码段和数据段的符号地址)的偏移地址,程序中对于段地址也要作出说明,段地址一旦说明,该段内的指令、标号和变量都属于这个段。段定义伪指令格式:  segment_name  SEGMENT
     ​
     segment_name  ENDSsegment_name由用户确定,大写的为关键字。段定义伪指令两句成对出现,两句之间为其他指令。
  2. 为了确定用户定义的段和哪个段寄存器相关联,用 ASSUME 伪指令 来实现。 ASSUME 伪指令格式: ASSUME register_name: segment_name …,
      register_name: segment_name register_name 为段寄存器名,必须是 CS,DS,ES 和 SS。而 segment_name 则必须是由段定义伪指令定义的段中的段名。ASSUME 伪指令只是指定把某个段分配给哪一个段寄存器,它并不能把段地址装入段寄存器中,所以在代码段中,还必须把段地址装入相应的段寄存器中。还需要用两条 MOV 指令完成这一操作。但是,代码段不需要这样做,代码段的这一操作是在程序初始化时完成的。

6.1.3 程序开始和结束伪指令

源程序结束的伪操作的格式为:

 END [label]

汇编程序将在遇到 END 时结束汇编。其中标号 label 指示程序开始执行的起始地址。

如果是多个程序模块相连接,则只有主程序需要使 用标号,其他子程序模块则只用 END 而不能指定标号。

6.1.4 数据定义与存储器单元分配伪指令

伪指令的一般格式是:

[变量] 操作码 N个操作数 [; 注释]

操作码字段说明所用伪操作的助记符,即伪操作,说明所定义的数据类型。常用的有以下几种。

  1. DB:伪操作用来定义字节,其后的每个操作数都占有一个字节(8 位)。
  2. DW:伪操作用来定义字,其后的每个操作数占有一个字(16 位,其低位字节在第一个字节地址中,高位字节在第二个字节地址中,即数据低位在低地址,数据高位在高地址)。
  3. DD:伪操作用来定义双字,其后的每个操作数占有两个字(32 位)。
  4. DF:伪操作用来定义 6 个字节的字,其后的每个操作数占有 48 位。
  5. DQ:伪操作用来定义 4 个字,其后的每个操作数占有 4 个字(64 位),可用来存放双精度浮点数。
  6. DT:伪操作用来定义 10 个字节,其后的每个操作数占有 10 个字节,为压缩的 BCD 码。

这些伪操作可以把其后跟着的数据存入指定的存储单元,形成初始化数据;或者只分配存储空间而并不确定数值。

6.1.5 类型属性操作符

  1. WORD PTR ; 字类型
  2. BYTE PTR ; 字节类型

就是按照某种类型读取,但不会改变变量本身的类型。

对一个 8 位(或 16 位)的变量可以用 16 位(或 8 位)方式访问。

6.1.6 THIS 操作符和 LABEL 伪操作

通过 THIS 操作符或 LABEL 伪操作,将变量定义为不同的访问类型。

  1. 使用 THIS 操作符: 格式:THIS type
  2. 使用 LABEL 伪操作: 格式:name LABEL type

type在这里是BYTE或者WORD

6.1.7 表达式赋值伪指令“EQU”和“=”

可以用赋值伪操作给表达式赋予一个常量或名字。其格式如下:

 Expression_name EQU Expression
 Expression_name=Expression

后略

第七章 分支与循环程序设计

18 级试卷