一、汇编语言概述
①运行汇编语言程序的步骤:
编辑程序-> 汇编语言源程序(用汇编语言写的程序)
->汇编程序(将源程序翻译成二进制代码)->浮动目标文件.boj文件
->连接程序->可执行文件.exe文件
②汇编语言语句格式
[名字] 操作符 操作数 [;注释]
1.一条汇编语言语句唯一不可缺少的是操作符,其余皆可没有
如:XLAT(它的操作数隐含了,是固定的)
2.操作符与操作数之间以空格隔开,不同操作数之间以逗号隔开
3.名字:
(1)标号:指令符号地址 标号与操作符以冒号隔开
(2)变量名:数据符号地址 变量名与操作符之间以空格隔开
4.操作数
(1)立即数,指令中直接含有指令需要的操作数,是指令的一部分
(2)寄存器数,操作数在寄存器中
(3)存储器数,操作数在存储器中
例如:
L:MOV AX,[2000H];将存储单元位置为DX:2000H的一个字取出放入AX
DATA1 DB 12H,?,2+6
XLAT;换码
二、汇编语言指令中操作数的寻址方式(指令的寻址方式)
[名字] 操作符 操作数 [;注释]
①段寄存器和存储器操作数不能同时作为目的操作数和源操作数
②CS不能作为目的操作数
一、寻址方式的不同种类
①立即寻址
②寄存器寻址
③存储器寻址:
(1)直接寻址
(2)寄存器间接寻址
(3)寄存器相对寻址
(4)基址变址寻址 (基址寄存器:BX,BP 变址寄存器: DI,SI)
(5)相对基址变址寻址
二、三种不同的寻址方式
①立即数寻址:操作数是指令的一部分。
1°汇编语言语句规定:
(1)立即数如果表示成 以字母开头的十六进制数,则应当以数字0做前缀
如 :MOV BX,0AB12H ;立即数AB12H在汇编语句中应以数字0做前缀,标明其为一个数字
(2)数制用后缀表示,缺省时表示十进制数
如:MOV AL,12;立即数12D,十进制的12
MOV AH,12H;十六进制的12H,0012H
MOV AL,10;立即数10D,十进制的10
MOV AL,10B;立即数10B 实际上是00000010B 与AL大小相同
底层的二进制代码不同进制的立即数都会汇编成同样的二进制数
2°立即数的位数与目的操作数的位数相同,即立即数的位数不需要指定,且立即数不能作为目的操作数
如:
MOV AL,12H;这里的立即数是8位的,12H
MOV AX,12H;这里的立即数是16位的,0012H
②寄存器寻址:操作数在CPU的某个寄存器中,指令指定寄存器号
1°不同的寄存器号
(1)8位:AH,AL,BH,BL,CH,CL,DH,DL
(2)16位:AX,BX,CX,DX,SI,DI,BP,SP//不可拆分的十六位
(3)段寄存器:
1.CS不能当作目的操作数
2.两个段寄存器不能同时作为目的操作数和源操作数
3.立即数不能直接送给段寄存器
如:MOV DS,AX;段寄存器DS作为目的操作数
③存储器寻址:操作数在存储器中,汇编语言语句需要给出有效地址(段内偏移),以及在不确定存储器操作数大小的情况下需要用PTR语句指出
注意:两个存储器操作数不能同时作为目的操作数和源操作数
在汇编语言中,用 [有效地址] 表示存储器寻址
1°8086下(有效地址为16位)
EA(有效地址)=
其中:
BX(基址寄存器)
BP(栈基址寄存器)
————————————
SI(源变址寄存器)
DI(目的变址寄存器)
————————————
偏移量可以是寄存器AL,AX 如[BX+AL]
2°默认段约定
BP(栈基址寄存器)、SP(栈顶指针寄存器):SS (SP隐含于PUSH和POP操作)
IP(指令指针):CS// 用于取指
其他情况:DS
3°段超越
若不想使用默认段,可以指明所用段
MOV AL, DS:[BP];BP的默认段是SS,利用DS:[]说明段超越
4°寻址方式
(1)直接寻址:直接用立即数当做段内偏移
MOV BX,[10H];用0010H当作十六位有效地址,默认段DS
(2)寄存器间接寻址:直接用寄存器号当作偏移地址 //基址、变址寄存器均可
MOV BX,[BX]
MOV BX,[DI];默认段DS
(3)寄存器相对寻址:用寄存器操作数+立即数作为偏移地址
MOV BX,[BX+10H]
MOV BX,[DI+10H]
(4)基址变址寻址:用基址寄存器 + 变址寄存器 作偏移地址
MOV BX,[BX+SI]
MOV BX,[BP+DI];默认段为SS
(5)相对基址变址寻址:用基址寄存器 + 变址寄存器+立即数 作偏移地址
MOV BX,[BX+SI+27];27D
三、转移地址的寻址方式(跳转指令的不同跳转方式)
①段内相对寻址:IP+=偏移量,IP直接由标号位置赋值 (仅此可实现条件跳转)
②段内间接寻址:IP+=存储器操作数/寄存器操作数
③段间直接寻址:CS:IP直接由标号位置赋值
④段间间接寻址:CS:IP,存储器双字 操作数低16位送IP,高16位送CS
①段内相对寻址:<标号>
汇编语言语句用标号表示,而机器指令用的是位移量,即标号的有效地址与当前IP之差
短跳转:SHORT//8位
近跳转(近类型):NEAR PTR//16位
JMP NEAR PTR A1
JMP SHORT A1
虽然表示的是跳转到A1去,但是实际上机器指令中有一个对应的偏移量
②段内间接寻址:<16位寄存器操作数 或 16位存储器操作数 替换IP的值>
JMP BX
JMP WORD PTR [BX+2];DS:BX+2D
③段间直接寻址:<标号>
远跳转(远类型):FAR PTR
JMP FAR PTR A1
标号的符号地址 包含一个段地址和段内偏移 直接给CS和IP
④段间间接寻址:<32位存储器操作数 分别替换CS 和 IP,IP都用低地址数>
JMP DWORD PTR [SI];寄存器间接寻址
四、指令系统(指令的集合)
注意:
1.CS不能当作目的操作数
2.两个段寄存器不能同时作为目的操作数和源操作数
3.立即数不能直接送给段寄存器
4.存储器操作数不能同时作为目的操作数和源操作数
5.XCHG不允许使用段寄存器
6.
隐含默认操作数的指令:
PUSH、POP:SS:SP
PUSHF、POPF:标志寄存器,SS:SP
LDS(指针送寄存器和段寄存器指令):DS
XLAT(换码):AL 和 BX XLAT ; 相当于MOV AL,[BX+AL]
IN/OUT :AL、(DX) IN AL,n
ADC(带进位加法):CF
SBB(带接位减法):CF
MUL(无符号数乘法):AL(字节乘)、AX(字乘) MUL SRC;AX<-AL*SRC
DAA(BCD码):AL、
JMP:IP / CS
一、数据传送指令
①MOV
MOV DS,AX //MOV中数据段可以作为目的操作数,可以用立即数传给寄存器,寄存器传给段寄存器实现 立即数传给段寄存器
MOV WORD PTR [BX],AX
②PUSH
PUSH AX
PUSH WROD PTR [BX]
③POP
POP AX
POP DWORD PTR[DI]
④PUSHF/POPF
弹栈和压栈的操作数均变成了标志寄存器低16位(Pentium下的低16位,8086就是标志寄存器)
⑤XCHG(交换) eXCHanGe
XCHG WORD PTR [BX],AX //不能同时存储器操作数喔
XCHG AX,BX
————————————————————————————————————————
⑥LEA(存储器寻址的有效地址EA送寄存器) Load Effective Address
LEA CX,[BX+102H] //这里目的操作数不能是段寄存器
//CX的值等于
ADD BX,102H
MOV CX,BX+102H
//当然LEA没有改变 BX的值,这里改变了
⑦LDS(指针(存储器操作数) 送 寄存器和段寄存器指令 ) 隐含段为DS
LDS DI,[BX]
DS:[BX]16位 赋值给 DI //具体赋值多少位给目的操作数 要看目的操作数的位数
DS:[BX+2]存储器单元16位 赋值给DS
—————————————————————————(源操作数只能是存储器操作数)
⑧XLAT(换码) transLATe //可以实现非压缩BCD码 到 ASCII码的转换 AL、BX
XLAT (操作数隐含)
相当于执行 MOV AL,[BX+AL] //而且这里的寄存器是固定不变的,寻址->基址寄存器BX
⑨IN/OUT I/O端口输入/输出 AL、DX
IN AL,n //n<=256时 端口地址 直接用立即数表示 00H~FFH
IN AL,DX //若要表示更大的端口地址,则需要用到数据寄存器DX作为端口地址的存放位
OUT n,AL
二、算术运算指令(会影响标志寄存器中的状态标志)
①加减法: 操作符 目的操作数,源操作数;目的操作数=目的操作数@源操作数(有符号补码)
//按定义影响标志寄存器标志位
ADD(加法):ADD DST,SRC
SUB(减法):SUB DST,SRC
ADC(带进位加法):ADC DST,SRC //DST<-DST+SRC+CF
SBB(带借位减法):SBB DST,SRC //DST<-DST-SRC-CF
ADD DWORD PTR [BX],02ABC4EFH
②加1、减1指令:(有符号补码)
//仅对CF标志位没有影响,假设16位,因为INC加法进位只可能是FFFFH进位,则执行INC之后,结果为0,ZF=1,取代了CF的作用
INC(加一,increase):INC OPR
DEC(减一,decline):DEC OPR
INC DWORD PTR[BX] //必须指明存储器操作数的类型
INC AX
INC BYTE PTR[BX+DI+10]
③CMP 比较指令
//按定义影响标志位(减法定义)
CMP OPR1,OPR2
执行OPR1-OPR2 不存数据,只影响标志位,用来判断大小
目的操作数不能是立即数,两操作数不能同时是存储器操作数。(这个①②③都满足)
④MUL 无符号乘法
//只影响CF和OF,非定义影响:如果乘积的高半部分为0则CF=0,OF=0,否则均为1
被乘数默认为 AL,AX之一,并且存入AX,DX:AX
MUL BYTE [BX]; (AX)<—(AL)*[BX]//乘数和被乘数等长
MUL WORD [BX[;(DX:AX)<—(AX)*[BX]
MUL AH; (AX)<—(AL)*(AH)
三、BCD码调整指令(会影响标志寄存器中的状态标志)
DAA( 压缩BCD码加法调整指令 bcD Add Ajustment)
//只对AL调整,并且仅OF无定义
1)如果AL的低4位大于9或AF=1,则ADD AL,6 并且AF<-1 //AF是辅助进位,最低四位
2)如果AL的高4位大于9或CF=1,则ADD AL,60H并且CF<-1 //CF是进位
十六进制逢十六进一,可以将加法调整为十进制加法
如:
MOV AL,54H
MOV BL,37H
ADD AL,BL
DAA;DAA只调整AL,所以要将压缩BCD码(8位)放入AL
四、逻辑运算指令(会影响标志寄存器中的状态标志)
①AND,OR,XOR,TEST 按位与,或,异或,按位比较
//CF和OF置0(不产生进位和溢出),AF辅助进位无定义,按定义影响其他
AND DST,SRC
OR DST,SRC
XOR DST,SRC
TEST OPR1,OPR2//只进行 OPR1∧OPR2,不存结果 和CMP一样
②NOT 按位取反指令
//不影响标志位
五、移位循环指令
六、控制转移指令
①无条件转移
(1)段内相对:
JMP SHORT A1
JMP NEAR PTR A1
(2)段内间接:
JMP OPR //寄存器或存储器操作数
(3)段间直接:
JMP FAR PTR A1(4)段间间接:
JMP DWORD PTR [OPR]
②条件转移
条件相对转移只能是段内短转移 或 段内近转移,8086微处理器只提供短转移方式。
③LOOP 循环控制相对转移
//用于已知循环的次数,次数存于计数器CX中
LOOP OPR //相对转移 IP+=8位带符号数,OPR是目标地址
CX<—CX-1 直到CX=0
④子程序(过程/函数)的调用 和 返回
//根据子程序的类型确定 段内或 段间,
NEAR 为段内
FAR 为段间
(1)段内相对调用
CALL DST
(2)段内间接调用
CALL DST
(3)段间直接调用
CALL DST
(4)段间间接调用
CALL DST
段内相对和段间直接都是直接给出 子程序名,底层实现是偏移量
而段内间接可以给存储器或寄存器操作数,段间间接只能给存储器操作数
与JMP类似,
与JMP不同的是,它需要将当前IP存入堆栈中,以便返回主程序
(SP<-SP-2 [SP]<-CS)(段间需要)
SP<-SP-2 [SP]<-IP
⑤子程序 返回
//将堆栈中的IP值存回IP中,如果是段间需要返回CS,具体是段间还是段内 跟调用该指令的子程序类型有关。
RET (直接返回)
RET N(带参返回,先返回IP(和CS),再返回参数的N个字节)
⑥中断指令
(1)INT中断指令
INT n ;n为中断类型码
(2)IRET中断返回
(3)INT 21H 系统功能调用