文章目录
数据传输类指令
1. 通用数据传输指令
1.1 MOV指令
形式是 : MOV 目标操作数 ,源操作数
把
源操作数的内容
给目标操作数
下面重点看看 MOV 指令对操作数的要求:
- 目标操作数和源操作数的字长必须相同
- 两个操作数不能同时为段寄存器
- 两个操作数不能同时为存储器操作数(也就是说,如果我们想把内存单元的某一个数赋值到内存的另外一个单元,是不能一步到位的,必须借助中间媒介)
- 目标操作数不能为立即数
- 立即数不能直接传输给段寄存器
- CS,IP 不作为目标操作数
辨析下面指令:
【1】MOV DS, 1000H (×):立即数不能够直接赋值给段寄存器
【2】MOV CS, AX (×):代码段寄存器不能作为目标操作数
【3】MOV VALUE1, CX (×):这里的 VALUE1 是一个定义了的变量,那么它就是一个立即数,立即数不能够作为目标操作数
【4】MOV [BX], [SI] (×):这里用方括号表示存储器寻址,那么 [SI] 就代表存储器里面的一个数,MOV 指令中两个操作数不能够同时为存储器操作数
【5】MOV DS, ES (×):两个操作数不能同时为段寄存器
【6】MOV AH, BX (×):两个操作数字长不一致,AH 是8位的,BX 是16位的
【7】迷惑题:MOV DX , 09H (√):看起来这两个操作数字长不等,但是别忘了,09H 是0开头的,既然是0开头,前面有几个0都可以,那么09H 可以写成 0009H,这样就 OK 了
1.2 堆栈操作指令 PUSH , POP
对于 PUSH 操作,我们首先先将栈顶指针 SP : SP − 2 → SP ,然后把数据压入(16位的!)
对于 POP 操作,取完数后,再将栈顶指针做: SP + 2 → SP (+代表往下,地址增大)
堆栈操作指令例子
1.3 交换指令 XCHG
格式: XCHG 操作数1, 操作数2
这个指令的作用就是将两个操作数的内容互换
但是对操作数有以下要求:
- 任何一个操作数都不能为立即数。因为这两个操作数既是源操作数,又是目标操作数。既然是目标操作数就不能是立即数。
- 两个操作数中必须得保证有一个是寄存器操作数,例如 BX, AX之类的
- 两个操作数不能够同时为存储器操作数。(也就是存储器寻址方式)
- 同样不允许有段寄存器作为操作数
例如: XCHG BX , [BP + SI]
假设
- BX寄存器内存放的内容是 BX = 6F30H
- [ BP + SI ] 是基址+变址寻址方式,由于没有段超越,所以BP默认的段寄存器是 SS,假设:SS = 2F00H, BP = 0200H,SI = 0046H 那么 [ [BP+SI] 表示的偏移地址是:0246H,对应的物理地址就是:2F000H+0246H = 2F246H。
- 那么也就是把 内存地址为 2F246H 的数和寄存器 BX 内的数交换
1.4 查表指令 XLAT
这个适用于查找一维数组中的元素。使用 XLAT 的时候不用写操作数,直接 XLAT 就OK。
但是,有几点说明:
- XLAT 规定:需要使用 BX 存放表头地址,AL 用于存放一维数组中元素距表头的距离。因此,需要查找的元素地址就是 BX+AL
- 那么 XLAT 的工作是
将地址 BX+AL 所指向的数组元素赋值给 AL
2. 地址传输类指令
2.1 LEA (近地址)
LEA 指令是取近地址的
,也就是说,LEA 工作的区域就是在同一个段里面,因此不用考虑段基址
LEA REG, MEM。LEA指令的功能是将变量的 16 位的偏移地址
写入到目标寄存器
。
注意:LEA 指令的源操作数一定要是存储器操作数
!!
LEA 的目标操作数一定不能是段寄存器,而一定是通用寄存器!!,通常是间址寄存器
2.2 LDS & LES (远地址)
LDS
指令功能:从src指定的存储单元
开始,由4个连续存储单元中取出前2字节送到偏移地址,取出后2字节送到DS
中 。
LES
跟上面的一样,只是后2字节送到ES
中 。
例: LDS AX,(SI +20 )
假设执行前为
(20050H)=1234H,(20052H)=5678H,
AX=0000H,DS=2000H,SI=0030H,则物理地址=2000H×16+20+0030H=20050H。
执行的结果为:AX=1234H(偏移地址!),DS=5678H (地址中的数据)(注意取数据的顺序!)
3. 输入输出指令
这一类指令很重要,我们首先需要明确几个定义:1. 什么是接口?2. 什么是端口?
所谓接口
,比如说,我们电脑上有一个用来插 U 盘的东西,我们称之为 “USB接口”,这类和外部设备连接的 “口”,我们就叫做接口。一个计算机里面可以有好多接口。
而端口
是什么呢?比如说,你电脑通过接口连接了某一个设备,而这个设备里面又会有许许多多的寄存器,我们电脑的 CPU 可以直接访问这些寄存器。因此,在外设里面,能够被 CPU 直接访问的寄存器就是端口。
既然有那么多端口,如果要想实现对端口数据的读或写,那么势必需要对这些端口进行地址编码,这样才能准确低找到所需要控制的端口。因此,也就引申出了下面端口的寻址方式:
根据端口地址码的长度,指令具有两种不同的端口地址表现形式:
- 假设我们的端口数目不多,小于256个,那么我们可以使用8位二进制来进行地址编码。那么这个8位的地址我们可以在指令里面直接给出来。(也就是可以寻址的端口数为: 2^8=256 )
- 如果端口很多,端口地址是 16位时,我们在指令里面的端口地址必须要由 DX 指定!这叫间接寻址。所能够寻址的端口数是 216=64K)
另外,端口的编码也分为了两种方式:
- 独立编码的方式:端口地址的编码和存储空间的编码是两个不同的独立地址空间。
- 统一编址方式:对内存单元和端口进行统一的编址
下面我们来看看这两个指令:
【1】IN acc , PORT
acc 表示累加器,PORT 顾名思义就是端口的意思。
IN 操作的功能是把 PORT 所指向的端口的内容 读入 acc里面 (注意:acc 只能是 AX 或 AL)
【2】 OUT PORT , acc
就是把 acc里面的内容 写进 PORT 所指向的端口 里面
4.字位扩展指令
- 仅用于有符号数扩展字长;对无符号数,直接在高位补0
- 符号扩展仅增长数据位数,并不改变数据大小。方便计算
5. 标志位传输指令
这里我们将要了解 4 个指令: LAHF, SAHF, PUSHF, POPF
首先是:
LAHF 和 SAHF,它们的默认操作数是 FALGS 和 AH。
LAHF (Load AH from flags)
. 也就是说,它的功能是将 FLAGS 寄存器的低八位 赋值给 AH。
SAHF (Store AH into flags)
. 意思是将 AH 里面的数 存入 FLAGS 的低八位
PUSHF
和 POPF
很简单,就是将FLAGS 的内容压入堆栈或者说弹出堆栈