0%

汇编语言

名词解释

1、指令系统:CPU能识别的所有指令的集合。
2、机器语言:指令代码语言。
3、机器语言程序:用机器语言编写的程序。
4、汇编语言:符号化语言。
5、汇编语言(源)程序:用汇编语言编写的程序。
6、汇编:将汇编语言源程序翻译成机器语言的过程。
7、反汇编:将机器语言程序翻译成汇编语言程序。

1
2
3
4
5
6
MOV AL,12H  //BO 12
ADD AL,21H //04 21
PUSH AX //50
MOV BL,FFH //B3 FF
AND BL,AL //20 C3
POP AX //58

//后为汇编后的结果。
文件名.ASM->文件名.OBJ(目标码文件)。
连接 Link.exe程序生成.exe文件

8086汇编语言程序中语句的种类

1、指令语句:CPU能执行的语句。汇编后能翻译成二进制指令代码的语句。
2、伪指令语句:CPU不能执行的语句。汇编后不能翻译成二进制指令代码的语句。如DB、DW。
3、宏指令语句:本身是8086指令系统没有的指令。是用户用宏定义伪指令定义的一条新语句。

汇编语言中语句的组成

名称、助记符、操作数、注释
注意:凡是数字,必须以0~9开头,凡是名称,必须以字母开头。
如:DB,means data byte,所定义的数据类型为一个字节宽度。
DW,means data word,所定义的数据类型为两个字节。
DD,means data double word,所定义的数据类型为四个字节。
变量名
标号名—next:(冒号不能少)

汇编语言程序设计中用到的常数及表达式

1、二进制常数以大写B结尾。
2、十进制常数D缺省。
3、十六进制常数以大写H结尾。

1
2
3
4
5
6
7
MOV DL,'A'//A的阿思科码常数
STRING DB 'an apple'//字符串常数

/*表达式*/
MOV AL,5+2*3//汇编时会先计算表达式的值
AND AL,21H AND 0FH
MOV AX,5 LT 3//LT为<,为真取全一,为假取全零

标号、变量及伪指令

标号

1
2
NEXT:.......
JZ NEXT

1、标号一旦定义了,就具有三个属性:NEXT所在存储单元的段地址属性(SEG);段内偏移地址属性(OFFSET)较常用;类型(TYPE)分为NEAR和FAR两种类型。
NEAR—近程— -1(在同一个代码段内跳转)
FAR—远程— -2(不在同一个代码段内跳转)

变量

1、DB:定义字节型变量1
2、DW:定义字型变量2
3、DD:定义双字型变量4
例:在DS段有以下变量定义:

1
DAT1 DB 12,12H,-12,'1'

变量一旦定义了,就具有了五个属性:
1、段地址属性;SEG
2、段内偏移地址(有效地址)属性;OFFSET
3、类型的属性;(值为变量所占的字节数)TYPE
4、长度属性;LENGTH
5、大小属性。SIZE

获取DAT1的类型
如:MOV AL,TYPE DAT1
等效于:MOV AL,1

获取DAT1的段内偏移
MOV BX,OFFSET DAT1
BX是地址寄存器,才有进一步寻址的意义,否则给AX寄存器语法无误,但是没有现实意义。

一个逻辑段的地址,没有特别说明,段内偏移地址为0。

1
DAT2 DW $+2,56ACH,78H

在MASM.exe中有一个$位,叫做位置计数器(16位),表示汇编程序汇编到的位置。

1
2
3
4
5
6
7
8
9
DAT3 DB 'THIS'
DAT4 DW 'AB','C'//小端存储
//以DB或是DW定义的字符串,一个单引号里面最多只能有两个字符串,如果只放一个,则DB不能超过64k,否则逻辑段放不下。(段内编译为16位,最大为64KB)
DAT5 DD 9CH//4个字节
DAT6 DW DAT3//DAT6位置存放的是DAT3的字型属性--段内偏移
DAT7 DD DAT3//四个字节存放的是DAT3的双字属性--段地址属性,存放的是1500:000A,因此四个字节依次存放的是0A,00,00,15。
DAT8 DB 4 DUP(?)//DUP重复操作符
DAT9 DW 3 DUP(?)
buf2 DB 7 DUP(5 DUP(55H),10 DUP(240))

长度:在变量名定义语句中,所定义的变量的个数。有DUP语句时,数字参数就是变量数,没有DUP的语句就是定义了一个变量。

大小:在变量名定义语句中,所定义的所有变量所占的总的字节数叫做该变量的大小。DAT9占了6个字节,则其大小为6个字节。

1
2
3
4
5
MOV AL,DAT1+2//
MOV AX,DAT1//语法错误,无法汇编,需要强制类型转换
MOV AX,WORD PTR DAT1//AX = 120CH//DAT1仍然是字节变量,属性临时修改操作符
MOV [BX],10H//语法错误
MOV BYTE PTR[BX],10H//bingo

指令的分类

1、数据传送类指令。MOV。
2、算术运算类。加减乘除
3、逻辑运算指令。与、或、抑或、非
4、移位类
5、标志位操作指令
6、转移类指令。条件转移指令、无条件转移指令、子程序调用指令。
7、循环控制指令。LOOP
8、子程序调用与返回指令。call
9、中断调用返回指令。
10、字符串操作类指令。
11、输入输出指令。
12、其他指令。
13、宏指令。

目的操作数DST
操作数OPR

数据与转移地址的寻址方式

寻址方式

寻址方式就是求操作数所在地或者算在存储器单元地址的方式。

求得的操作数OPR可以作为操作或运算的数据用,或者用作实现转移的转移地址用。(段内转移求偏移地址给IP,段间转移还要求得目的地的段地址给CS)。

关于寻找数据的寻址方式

1、立即数寻址。要寻找的操作数指令中给出了,如

1
MOV AX,1234H//目的操作数,源操作数(立即数寻址)

说明立即数只能做源操作数。

2、寄存器寻址。要寻找的操作数在某寄存器中。如

1
2
MOV AX,BX//源操作数的寻址方式是寄存器寻址
MOV AX,CL//源和目的的操作类型不一致

当源操作数和目的操作数都是寄存器寻址时,要注意类型要一致。

1
2
MOV [0200H],56H//[]里是个地址,DS:0200H,立即数没有类型,该指令语法错误
MOV WORD PTR[0200H],56H

在书写指令时,要注意类型要明确。源和目的操作数只要有一方明确,则类型明确。

1
2
3
MOV DS,1500H//error!
MOV AX,1500H
MOV DS,AX

在给段地址寄存器(DS\ES\SS)赋值时,需要通过中间的通用寄存器。
当DS、ES、SS做目的操作数时,源操作数不能为立即数或立即数寻址。

1
MOV CX,AX

CX\IP不能做目的操作数。只能通过执行转移指令操作数改变CX和IP内的值。(IP指令指针寄存器)。
堆栈必须按照字操作。

3、存储器寻址。要寻找的操作数OPR在存储器某单元中。存储操作数的单元的EA(段内偏移地址)可以由以下五种寻址方式求得:
(一)直接寻址。在指令中直接写出操作数所在单元的地址。
(二)寄存器间接寻址。寄存器有基址寄存器BX、源变址寄存器SI、目的变址寄存器DI,形式如[SI]。
(三)寄存器相对寻址。基址寄存器BX、基址指针寄存器BP、源变址寄存器SI、目的变址寄存器DI,这四者之一加上一个8/16位的disp(相对位移量),两部分之和就是操作数所在存储单元的地址。
(四)基址、变址寻址。基址[BX],[BP]。变址寄存器[SI],[DI]。
(五)基址、变址且相对寻址。基址寄存器+变址寄存器+相对位移量。

直接寻址

操作数所在单元的有效地址指令中直接给出了。如:

1
MOV AL [2000H]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//DS段
data1 DB 12H
data2 DB 34H
//CS段
MOV AL ,data1//目的操作数寄存器寻址,源操作数是直接寻址
//(AL)= 12H;

MOV data2,data1;//error!
//上面error语句可以修改为
MOV AL,data1
MOV data2,AL

MOV data1,AX//error!类型不一致
MOV WORD PTR data1,AX//只是在本行语句种起作用,对data1的类型进行临时修改,在之后的编程中,data1的类型依然为字节型。

两存储器单元之间不能直接操作。

寄存器间接寻址

段内偏移只可能存储在寄存器[BX],[SI],[DI]中。段地址位于[DS]中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data1 DB 12H
data2 DB 34H

//把data1对应数据移动到AL
MOV BX,offset data1
//源操作数为立即数寻址,变量一旦定义了,就具有了五个属性,属性是一个常数。
MOV AL,[BX]
//源操作数采用的是寄存器间接寻址

MOV [BX],56H
//源操作数为立即数寻址,目的操作数为寄存器间接寻址,error,立即数没有类型,故而整个指令类型不确定。

MOV BX,offset data1
MOV SI,offset data2
MOV [BX],[SI]
//error!两存储器单元之间不能直接传输数据。需要使用一个通用寄存器过渡。
//修改为
MOV AL,[SI]
MOV [BX],AL

寄存器相对寻址

操作数所在存储单元的段内十六位偏移地址是由两部分相加。第一部分为[BX],[BP],[SI],[DI],第二部分为一个相对位移量disp。

当使用[BX],[SI],[DI]这三个寄存器中的任意一个时,段地址默认为DS寄存器。
当使用[BP]寄存器时,段地址默认为SS段。只有在寄存器相对寻址中才出现了BP,在寄存器间接寻址中没有BP参与。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
MOV [BP],AL;
//把AL寄存器中的内容写入到一个字节单元中,SS:(BP)+0<-(AL),这样只能是寄存器相对寻址,不能是寄存器间接寻址。

MOV BX,offset data1;
//把data1单元的偏移地址放到BX寄存器中,以便于下一步讲AL中数据存入到data1下两个存储单元中。
//方法一:
MOV data1+3,AL
//目的操作数采用直接寻址
//方法二
MOV [BX]+3,AL
MOV [BX+3],AL
MOV 3+[BX],AL//+可以缺省
//目的操作数寄存器相对寻址,三种方法等效

MOV BX,0
MOV AL,00H
MOV data1[BX],AL
//目的操作数为寄存器相对寻址,偏移量disp不是一个常量,而是一个变量,当相对量是一个变量的时候,取变量的十六位offset,相当于缺省+的那种情况。此时十六位有效地址为offset data1+(BX)<-(AL)
此时段地址不能看寄存器了,要看变量,变量在哪里定义的,段地址就在相应的寄存器中。

例:8086型号的CPU执行以下程序:

1
2
3
4
5
6
7
8
PUSH AX
PUSH BX
PUSH CX

//目的是DX<-(AX),但不能破坏SP指针
//意味着不能执行pop操作。充分利用BP相对寻址段地址在ss寄存器的基本原理
MOV BP,SP//破坏了BP,如果不能破坏BP,需要在前一步增加一条PUSH BP。
MOV DX,[BP+4]//如果源操作数是立即数,则要注意类型要明确

基址变址寻址

操作数所在存储单元的段内十六位有效地址由两部分组成。第一部分是在[BX],[BP]基址寄存器中。另一部分在[SI],[DI]变址寄存器中。
段内地址所在寄存器以基址寄存器为准,若基址寄存器使用[BX],则段地址在DS中;若基址寄存器使用[BP],则段地址在SS中。

1
2
3
4
5
6
7
8
9
10
data1 DB 12H
data2 DB 34H

MOV BX,offset data1
MOV SI,0
MOV AL,0
MOV CX,10
NEXT:MOV [BX][SI],AL//将data1所在单元清零,循环将data1及以后的是个单元清零
INC SI
LOOP NEXT

基址变址且相对寻址

操作数所在单元的有效地址由三部分组成。第一部分位于基址寄存器中。第二部分位于变址寄存器中。第三部分为8位/16位的相对位移量。
段地址所在寄存器:若偏移量是常数,则以以基址寄存器为准,若基址寄存器使用[BX],则段地址在DS中;若基址寄存器使用[BP],则段地址在SS中。若偏移量是变量,段地址所在寄存器需要根据变量的定义位置来确定。

1
2
3
4
5
6
7
8
9
10
data1 DB 12H
data2 DB 34H

MOV BX,0
MOV SI,0
MOV AL,0
MOV CX,10
NEXT:MOV data1[BX][SI],AL//将data1所在单元清零,循环将data1及以后的是个单元清零
INC SI
LOOP NEXT

隐含寻址

1
2
3
4
5
6
7
8
9
PUSH AX
//只指明了源操作数,但是CPU知道目的操作数在哪里,目的操作数为隐含寻址
//具体步骤

SP<-(SP)-2
(SS:(SP))<-(AX)

MOV AL,data1+2//直接寻址
MOV AL,data1+data2//error!变量不能在指令语句中运算

关于转移地址的寻址方式

1、段内转移——只有IP发生了改变
1)直接寻址(相对寻址,会加上一个相对位移量)。转移指令中直接给出了转移目的地的地址。以标号的形式。

1
2
L1:...
JMP L1

指令结构:操作码(一个字节)+ 当前IP位置(下一条指令起始地址)的相对位移量。如果相对位移量在[-128,0]范围内(负向转移),则使用一个字节记录相对位移量。如果相对位移量在[0,32767]范围内(正相转移),则使用两个字节记录相对位移量。因为此时转移位置还没有经过编译,不知道具体的相对位移量是多少,只能全部按照两字节相对位移量处理。当负向转移的相对位移量较大时,也可以考虑使用两个字节来存储相对位移量。
当确定正向转移的偏移量不超过127时,为了节省空间,可以使用下面指令

1
2
JMP SHORT L1
//适用于转移偏移量位于[-128,127]的转移指令

转移到目的地的IP = 当前IP(待执行的下一条指令的首地址)+disp(相对位移量)
8086指令系统中所有的条件转移指令,只能在段内转移。且转移范围为[-128,127]字节之间。如果转移地址偏移量超过了这个范围,则需要使用无条件转移指令实现二级跳。
8086指令系统中所有的条件转移指令,它的寻址方式是段内相对寻址。
例:8086CPU执行JZ L1指令时,IP = 0100H,disp = FDH,这条指令执行以后IP的值为多少呢?
当前IP = 0102H,再加上FDH(补码表示的位移量),得出的结果为00FFH。
2)段内间接寻址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
;DS段
TABLE DW L2//L2是一个标号,即将L2的段内偏移地址存放在TABLE单元,L2为转移目的地址的段内偏移量
;CS段
MOV BX,offset L2
JMP BX;IP<-(BX)
L2:

//直接寻址指令为
JMP TABLE
//IP<-(TABLE),TABLE变量为直接寻址

//间接寻址指令为
MOV BX,offset TABLE
JMP WORD PTR [BX]
//以BX寄存器做间接寻址方式的段内间接寻址

//基址变址寻址指令为
MOV SI,0
MOV BX,offset TABLE
JMP WORD PTR [BX][SI]
//基址变址寻址方式的段内间接寻址

例:若(AL) = 1,则转到L1;若(AL) = 2,则转到L2;若(AL) = 3,则跳转到L3。转移相对位移量小于127字节。
通过观察发现三条跳转指令顺序排列,首地址与AL内数字n的关系为

1
2
3
4
5
6
7
8
9
10
11
12
MOV BX,offset TAB
DEC AL//AL内容减一
ADD AL,AL
MOV AH,0;
ADD BX,AX
JMP BX//段内间接寻址
TAB:JMP SHORT L1//段内直接寻址
JMP SHORT L2
JMP SHORT L3
L1:
L2:
L3:

数据传送指令

除SAHF、POPF(标志寄存器内指令出栈)指令外,其余传送类指令CPU执行后对6个状态标志均无影响
语法规则如下:
1、立即数只能做源操作数。
2、类型要一致。
3、类型要明确。
4、当DS、ES、SS这三个段寄存器做目的时,源操作数不能为立即数。
CS、IP不能做目的。
5、两存储单元不能直接操作。
6、在指令语句中,不允许两个变量参加运算。

通用数据数据传送指令

1
2
//把源操作数以某种方式指明的内容传送到目的地去
MOV DST SRC

‘通用’的是指一定能用到。

取有效地址指令LEA

1
2
3
LEA REG(16bit),MEM
//MEM为由五种存储器寻址方式之一指明的一个存储单元
//最好把有效地址放到BX、BP、SI、DI中。

例子:

1
2
3
4
5
6
MOV BX,offset data1
LEA BX,data1
//把data1单元的有效地址给BX,上述两条指令功能相同

MOV BX,PTR data1
//把data1看成一个字单元的内容传输给BX

取地址指针指令LDS、LES

1
2
3
LDS REG(16bit),SRC
//把取回来的地址放到DS
//SRC为使用五种寻址方式指明的一个存储单元,从SRC获得的是一个双字单元,小地址单元(第一个字,存偏移量)给REG,大地址单元(第二个字,存段地址)给DS寄存器。

例:某数X(字)所在存储单元的地址指针已经在POINT双字单元中,将DX<-X。

1
2
3
4
5
6
7
8
9
LDS BX,POINT
//POINT是一个双字变量,第一个字偏移地址给BX,第二个字给DX,则当前地址指针指向X
MOV DX,[BX]
//使得(DX) = X

//若使用LES指令
LES BX,POINT
MOV DX,ES:[BX]
//注意需要增加段前缀

标志传送指令

LAHF-将标志寄存器flag(PSW)低八位的内容传入AH寄存器。
SAHF-将AH寄存器的内容写入标志寄存器的低八位位置。修改了标志寄存器的内容。
在8086指令系统中没有专门的使标志寄存器清零或置一的指令,但可以使用堆栈操作改变标志寄存器内容,注意不能使用标志传送指令修改TF寄存器的内容,这是因为TF寄存器位于标志寄存器第八位,属于高八位的范围,而该方式只对低八位有效,所以无法改变。
关于标志寄存器的内容,点击这里

数据交换指令XCHG

XCHG OST,SRC
1、其中OST、SRC均不能为立即数
2、所有段寄存器均不能参加交换
3、上文中提到的六点语法规则

1
2
3
4
5
6
7
8
XCHG AX,BX
XCHG AL,[SI+3]
//SI相对寻址
XCHG DH,DL
XCHG AX,ES
//error,段寄存器不能参与交换
XCHG AX,BL
//error 类型不一致

字节转换指令XLAT

格式:XLAT(查表)
无操作数,源和目的都是隐含寻址
功能:AL<-(DS:(BX)+(AL))

例:将0-9及A-FH数字->对应

1
2
3
4
5
6
7
8
9
//在DS段
TABLE DB 30H,31H,...,39H,41H,...46H

//在CS段
MOV AL,4
LEA BX,TABLE
//将TABLE的偏移地址给BX
XLAT
//此时AL的值为34H,将4数字转换为对应的字符

堆栈操作指令

1、PUSH SRC
要注意SRC不能为立即数
2、PUSH DST
3、PUSHF
4、POPF
以上堆栈操作指令都必修按字操作同时遵守上述六个规格。

1
2
3
4
5
6
POP CS
//error!CS不能做目的操作数
PUSH CL
//error!必须按字操作
PUSH 1234H
//error!必须按字操作

算术运算类指令

1、CPU只要执行运算类指令,执行结果就会影响状态标志。
2、段寄存器不能参加运算。

加法指令

1、不带进位位加法
ADD DST SRC
目的操作数DST<-(DST)+SRC,同时根据和设置六个状态标志。ZF、PF、SF、CF、OF、AF。
2、带进位位的加法
ADC DST SRC
目的操作数DST<-(DST)+SRC+CF,同时根据和设置六个状态标志。
3、增一指令
INC DST
目的操作数DST<-(DST)+1,同时根据结果设置除CF以外的五个状态标志。对CF无影响。
例:两个字型变量相加代码
两字型变量相加

1
2
3
4
5
6
7
LEA SI,DVAR
MOV AX,[SI]
ADD AX,[SI]+4
MOV WORD PTR DVARC,AX
MOV AX,[SI]+2
ADC AX,[SI]+6
MOV WORD PTR DVARC+2,AX

减法指令

1、不带借位位减法
SUB DST,SRC
DST<-(DST)-(SRC),并根据结果设置六个状态标志。
2、带借位位的减法
SBB DST,SRC
DST<-(DST)-(SRC)-CF,CF为借位标志,并根据结果设置六个状态标志。
只要有一方类型明确了,双方就都明确了。
3、减一指令
DEC DST
DST<-(DST)-1,并根据结果设置除CF以外的状态标志,对CF没影响。
例:若(AL) = FFH,CF = 0,则CPU执行:

1
INC AL

指令后,(AL) = ?,CF = ?
(AL) = 00H,CF = 0。

4、比较指令
CMP DST,SRC
(DST)-(SRC),结果不存储,只是根据结果设置六个状态标志。分别为CF、SF、ZF、PF、OF。
产生条件,使用比较指令来产生条件。
测试条件满足吗?如果满足则转到代码一,如果不满足则转到代码二。

1
2
MOV AL,α
CMP AL,β

根据单个条件:
CF-JC(有借位则转移)+标号—段内直接寻址、JNC(没有解位则转移)
SF-JS(结果为负则转移)+标号、JNS(结果不为负则转移)
ZF-JZ/JE(结果为0则转移)+标号、JNZ/JNE(结果不为零则转移)
PF-JP(结果低八位1的个数为偶数则转移)+标号、JNP(结果低八位1的个数不为偶数则转移)
OF-JO(结果溢出则转移)+标号、JNO(结果未溢出则转移)

若α、β为无符号数,则不存在大小的关系,只存在高低的关系。(相等、高、低)。CF
高 JA/JNBE
低 JB/JNAE(不高于也不等于)
相等JE
不相等JNE
小于等于 JBE/JNA
大于等于 JAE/JNB

若α、β为有符号数,则存在大小的关系。(相等、大、小)。SF XOR OF = 1,目的小于源
大:JG/JNLE
小:JL/JNGE
小于等于:JLE/JNG
大于等于:JGE/JNL

所以,在编写程序时首先要明确参与运算的数据是有符号的还是无符号的。

5、求负指令
NEG DST
DST<-0-(DST),并根据结果设置六个状态标志。
例子:在存储器BUFFER单元有一个16位的带符号数,求该数的绝对值,并把结果放回原数。
1、分析题目-提出解决问题的算法。
当x≥0时,它的绝对值是它本身。
当x<0时,它的绝对值是它的相反数。
2、画出程序流程。
开始框和结束框必须用椭圆框。矩形框是处理框。
两数比较(x和0比较),使用SF条件,如果SF = 1,则x小于零,对x求负,结果存入BUFFER单元;如果SF!=1,则x不为负,可以直接结束程序。
3、编写程序。

1
2
3
4
5
6
7
8
9
10
//定义DS段,data word,DW类型为字型变量
BUFFER DW ?

//定义代码段
START:MOV AX,BUFFER
CMP AX,0
JNF EXIT
NEG AX
MOV BUFFER,AX
EXIT:...

乘法指令

加减运算是有符号还是无符号,由程序员来确定。例如,参与运算的是无符号的,则使用JB、JA指令;参与运算的是带符号的,则使用JL、JG指令。但是在乘除法中,有符号数和无符号数有各自的乘除法指令。
1、无符号乘法
MUL SRC
2、有符号数乘法
IMUL SRC
3、上述指令目的操作数为隐含寻址。隐含的操作数为被乘数,指令中给出的源操作数为乘数。SRC不能为立即数寻址。
4、乘法指令为字节型乘法还是字型的乘法,由源操作数来决定。
字节乘法:(DST)被乘数隐含在AL中,AX(AH:AL)<-(AL)SRC。八位乘八位,得到的结果为十六位。
字乘法:(DST)被乘数隐含在AX中,DX:AX<-(AX)
SRC。十六位乘上十六位,结果表示为32位。
5、无符号乘法积的结果:不管是字乘还是字节乘,指令执行后只影响CF、OF两个标志。其余的状态标志没定义。
若OF = 0,CF = 0,说明高八位积无效。
若OF = 1,CF = 1,说明高八位有有效积。
6、有符号数乘法积的结果:
字节乘法:字节乘法:(DST)被乘数隐含在AL中,AX(AH:AL)<-(AL)SRC。指令执行后只影响CF、OF两个标志。
若OF = 0,CF = 0,说明AH中的积无效。AH中所存数据为AL中数据的符号的扩展。
字乘法:(DST)被乘数隐含在AX中,DX:AX<-(AX)
SRC。
若OF = 0,CF = 0,说明DX中的积无效。AH中所存数据为AX中数据的符号的扩展。
若OF = 1,CF = 1,说明DX中有有效积。

除法指令

1、无符号数除法:DIV SRC
2、有符号数除法:IDIV SRC
3、SRC不能为立即数寻址。
4、乘法指令为字节型乘法还是字型的乘法,由源操作数来决定。
5、无符号字节型除法:(DST)被除数隐含在AX中,(AX)/(SRC)后,商放在AL,余数放在AH。
无符号字型除法:(DST)被除数隐含在DX:AX中,(DX:AX)/SRC,商放在了AX中,余数放在了DX中。
6、在有符号除法中,被除数为正,除数为正,则商为正,余数为正。若被除数为正,除数为负,则商为负,余数为正。若被除数为负,除数为正,则商为负,余数为负。若被除数为负,余数为负,则商为正,余数为负。
7、除法指令执行之后,对六个状态标志均无定义。

例:将存储器BUFFER1中的字节型无符号二进制数转换为十进制数。并将转换后的结果以分离BCD数形式存入BUFFER2以下单元。(个位数存在低地址单元)
思想:除十取余

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在DS段定义
BUFFER1 DB ?
BUFFER2 DB 3 dup(?)

在CS段编程序
MOV AL,BUFFER1
MOV AH,0
//当除数为八位时,被除数必须十六位,因此AX寄存器高位一定要清零。
MOC CL,10
//注意源操作数不能是立即数
DIV CL
//商在AL,余数在AH
MOV BUFFER2,AH
MOV AH,0
//得到新的被除数
DIV CL
MOV BUFFER2+1,AH
MOV BUFFER2+2,AL

符号扩展指令

1、CBW
无操作数,隐含地将AL中的八位二进制数扩展到AX中(十六位AH:AL)。AH中的内容是AL符号位的扩展。
2、CWD
无操作数,隐含地将AX中的十六位数扩展成32位,存储在DX:AX中。其中DX中的内容为AX中符号位的扩展。
3、这些指令的存在是为了在某些算术运算中类型要保持一致。
例:求Y = ab+c-18。其中a、b、c三个变量都是字节型的。
1、注意y显然是十六位的,把a
b的结果存放在datay单元。
2、首先在ds段定义这些变量。然后在cs段编写程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//ds
data DB ?
datb DB ?
datc DB ?
daty DW ?

//cs
MOV AL,data
IMUL datb
//使用带符号数乘法,积在AX中,十六位,在下一步加c时,要对c进行符号位扩展
MOV BX,AX
MOV AL,datc
CBW
ADD AX,BX
SUB AX,18
MOV daty,AX

注意,可以使用EQU语句定义符号常量,如上述程序中的18,可以定义为cc。

1
cc EQU 18

BCD数调整指令

+:分离BCD数、组合BCD数
-:分离BCD数、组合BCD数
:分离BCD数
/:分离BCD数,且是先调整后运算
+-
先运算再调整

1、加法BCD数调整指令
组合BCD:DAA
分离BCD:AAA
都隐含的是对AL中的内容的调整,执行结果会正常设置六个状态标志。
例子:组合BDC数运算56+73

1
2
3
4
MOV AL,56H
ADD AL,73H
DAA
//高四位超过九需要修正,低四位没有超过九且没有向高位的进位所以不需要修正

例子:分离BCD数运算4+8

1
2
3
4
MOV AL,04H
ADD AL,08H
AAA
//低四位超过九需要加六修正,因为是分离BCD数,所以指令还会使高四位自动清零,并将AF标志传送给CF和AH,AH= 01H,最后的结果(AX) = 0102H。

这是因为分离BCD数相加结果十位最大为1,所以可以直接根据AF标志位来确定AH的内容。
大部分场合使用的是组合BCD数的运算。
分离BDC数加法参与运算的不论是数字还是字符‘1’,运算得到的结果都相同。所以该指令又称为阿思科码加法调整指令。
2、减法BCD数调整指令
组合BCD数:DAS 减六修正原则,超过九则减六
分离BCD数:AAS
例:组合BCD数31-87

1
2
3
4
5
MOV AL,31H
SUB AL,87H
//有一位借位,存在CF中,最终输出结果要考虑CF寄存器内容
DAS
//AL = 44H,CF = 1,相当于借位了100,所以此时结果为44-100 = -56

3、乘法BCD数调整指令
分离BCD数:AAM
例:分离BCD数7*8

1
2
3
4
5
6
7
MOV AL,07H
MOV BL,08H
MUL BL;
//AX<-(AL)*(BL) == 0038H
AAM
//对AX中得到的积做除十运算,商放在AH中,余数放在AL中
最终(AX) = 0506H

积的调整指令会调整SF、ZF标志。

4、除法BCD数的调整
AAD
1、只能是分离BCD数运算
2、先调整,再运算。
例:27/4BCD数除法运算

1
2
3
4
5
MOV AX,0207H
MOV BL,04H
AAD
//隐含地对AX中的分离BCD数AX<-(AH)*10+(AL)
DIV BL

AAD指令执行会影响PF,ZF,SF三个标志,剩余的三个标志没定义。

逻辑运算类指令-五条

1、段寄存器不能参加运算。

与:AND DST,SRC;(DST)按位与(SRC),CF、OF标志自动清零。AF没定义。正常设置剩余的SF、ZF、PF标志。
或:OR DST,SRC;(DST)按位或(SRC),对标志位的设置与AND指令相同。
异或:XOR DST SRC;(DST)按位异或(SRC)。对标志位的设置与AND指令相同。
测试指令:TEST DST SRC;(DST)位对位与(SRC),根据与的结果甚至标志,并不存放结果,对标志位的设置与AND指令相同。
非:NOT DST;(DST)<-(DST)按位取反。对六个状态标志均无影响。
例:测BX中存储的十六位位数(从右向左编号)的位一和位二,当这两位同时为0时,AL内容置一。
与运算 0000 0000 0000 0110
若BX中的数据与该数与的结果为0,则ZF = 1。
同时应该注意到,题目要求在测试完BX中的数据后BX中的数据应该保持不变,应考虑使用TEST指令。

1
2
3
4
5
6
7
TEST BX,0006H
JZ L1
MOV AL 0000H
JMP L2
L1:MOV AL 0FFFFH
L2:...
//字母开头的数值应该加一个0

例:测BX中存储的十六位位数(从右向左编号)的位一和位二,当这两位只有一位为0时,AL内容置一。
与的结果有两种可能
1、0000 0000 0000 0100
2、0000 0000 0000 0010
测量结果的PF标志位,PF = 1,1的个数为偶数,PF = 0,1的个数为奇数。

1
2
3
4
5
6
7
TEST BX,0006H
JNP L1
MOV AL 0000H
JMP L2
L1:MOV AL 0FFFFH
L2:...
//字母开头的数值应该加一个0

例:将DX寄存器中的数据低七位取反,使用异或运算,低七位异或1,高九位异或0。

例:将CX寄存器中的数据高八位和低八位交换。

1
XCHG CH,CL

移位类指令(八条)

移位指令(四条)

把被移位的操作数看成无符号数,称为逻辑移位,把被移位的操作数看成有符号数,称为算数移位。

逻辑移位

左移:SHL DST,CNT
DST为目的操作数,CNT为移位次数。
移位也是一种运算,段寄存器先然不能参加计算,作为目的操作数来使用。
当CNT = 1时,源操作数部分可以直接写出。当CNT大于1时,移位次数要用CL给出,事先要把移位次数MOV到CL中。这一规则适用于所有八条移位类指令。
移出的最高位到了CF中,最低位自动补零。
在执行完移位指令之后,CPU根据执行结果设置除了AF以外的状态标志。
移位次数超过一位之后,OF标志就没有意义了。
右移:SHR DST,CNT
DST可以是字节型数据,也可以是字型数据。

算数移位

左移:SAL DST,CNT
算数左移和逻辑左移是一回事。
右移:SAR DST,CNT
带符号数最高位为符号位,右移过程中保持最高位不变。最低位移出去移到CF中。
例:5*12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
方法一
MOV AL,5
MOV BL 12
MUL BL
//但是时间花费比较大

方法二
5*12 = 5*(4+8) = 5*4+5*8
MOV AL,5
MOV CL 2
SHL AL,CL
//(AL) = 5*4
MOV BL,AL
SHL AL,1
ADD AL,BL
//(AL) = 5*12

循环移位(四条)

操作数可以是字节型的,也可以是字型的,最高位移入CF中,同时最高位移入最低位中。也可以最高位移入CF中,CF中原来的内容移入最低位中。

不带CF的循环移位

左移:ROL DST,CNT
右移:ROR DST,CNT

带CF的循环移位

左移:RCL DST,CNT
指令中的C指的是带CF
右移:RCR DST,CNT
CPU执行后,只影响CF和OF状态标志,对其余状态表示没定义。

例:若(BX) = 1011 0110B,CF = 1,(CL) = 3,则CPU执行RCR BX,CL指令后,(BX) = _H。
0000 0000 1011 0110
移位后为A016H。注意BX是十六位寄存器,虽然在本题中BX只给了8bit数据。

例:在DX:AX中存放了一个32bit数据m,求m*16
DX中有16bit数据,AX中有16bit数据。

1
2
3
4
5
MOV CL,4
L1:SHL AX,1
//将AX的最高位移入CF中,接下来通过循环移位指令将CF中的数据移入DX最低位中
RCL DX,1
LOOP L1

目前更新进度42P