汇编指令解析

主要说明功能及其例子

一些概念的普及

一定要注意大小端的问题,大小端和得出来的值是不一样的。
在这里插入图片描述
总结:

大端是高字节存放到内存的低地址

小端是高字节存放到内存的高地址

寄存器

寄存器就是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。实际上寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。
寄存器功能:可将寄存器内的数据执行算术及逻辑运算,存于寄存器内的地址可用来指向内存的某个位置,即寻址;可以用来读写数据到电脑的周边设备。

存储器

存储器是计算机系统中的记忆设备,用来存放程序和数据。既然都是用来存放数据的东西。
存储器功能:存放指令和数据,并能由中央处理器(CPU)直接随机存取。

标志寄存器:

CPU内部的寄存器,(对于不同的处理机,个数和结构都可能不同)具有三种作用:
用来存储相关指令的某些执行结果;
用来为CPU执行相关指令提供行为依据;
用来控制CPU的相关工作方式。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据传送指令

MOV:传送字或字节。

    MOV目的(除CS、IP以外的寄存器或存储器) 源(寄存器、存储器、立即数)
    ex:
    MOV  ECX ,EDX ;   EDX->ECX
    ECX =00000034H		EDX =00000052H
    指令执行结果: ECX = 00000052H, EDX不变,标志寄存器也不变

MOVSX:先符号扩展,再传送。

MOVSX的操作数B所占空间必须小于操作数A. 
按符号扩展传送数据指令,将源操作数的内容---传送-->目标操作数。目的操作数左边空缺的为用源操作数的符号进行填充。可对有符号的数进行扩展,以便运算。
ex:
	MOV    BL, 80H; 80H->BL
	MOVSX AX,   BL  ; 80H用符号扩展为FF0H->AX
	80h = 1000 0000 最高位为符号位, 即符号位为1
	则MOVSX AX, BL后, AX = 1111 1111 1000 0000 = FF80h
ex:
   movsx   edx, eax //设eax  == 61h
   执行后的结果应为:
   edx == 00000061h
   61h = 0110 0001 最高位为符号位, 即符号位为0
   则EDX = 0000 0000 0000 0000 0000 0000 0110 0001 = 00000061h
ex:
	movsx eax,bx
	bx是16位,eax是32位,传值过程:
	先用bx的符号位把eax高16填满,
	bx传值到eax的低16位
	我们观察EAX的值,和EBX的值,bx现在是A123,符号位是1(用计算器将其转为二进制,最高位就是符号位)则 eax = FFFA123

MOVZX:先零扩展,再传送。

MOVZX的操作数B所占空间必须小于操作数A.MOVZX不用像MOVSX哪样,先判断符号,再填充,MOVZX直接用0来填充
按零扩展传送数据指令,将源操作数的内容---传送-->目标操作数。目的操作数左边空缺用0填充。可对无符号的数进行扩展,以便运算。

ex:
MOVZX 操作数A ,操作数B 	//B的空间小于A
movzx eax,bx (bx现在是A123)
bx现在是A123
执行完,EAX为0000A123

PUSH : POP

push功能:将源操作数推入堆栈	源操作数可以是16位通用寄存器、段寄存器或存储器中的数据字,但不能是立即数。堆栈是以“先进后出”的方式工作的一个存储区,栈区的段地址由SS寄存器的内容确定。堆栈的最大容量可为64K,即一个段的最大容量。堆栈指针SP始终指向栈顶,其值可以从FFFEH(偶地址)开始,向低地址方向发展,最小为0。
pop功能:把当前SP所指向的堆栈顶部的一个字送到指定的目的操作数中,目的操作数可以是16位通用寄存器、段寄存器或存储单元,但CS不能作目的的操作数。每执行一次出栈操作,SP←SP+2,即SP向高地址方向移动,指向新的栈顶。
在psuh和pop的功能中还有一个ss:sp的指针其值在堆栈.
如果将10000~1000F作为栈的空间:初始转态的栈是空的,此时:
ss=1000
sp=0010(F的高一位地址 )
栈空间大小为16个字节,栈最底部的字节单元地址为 1000:000E
任意时刻 SS:SP指向栈顶,当栈中只有一个元素的时候:
**SS=1000,SP=000E**
栈为空,就相当于栈中唯一的元素被pop,出栈后,SP=SP+2,SP原来为000E,加2后SP=10
所以当栈为空的时候,SS=1000,SP=10

PUSHA/PUSHAD

当操作数的大小是32位时:
	这两个指令的作用是把通用寄存器压栈。寄存器的入栈顺序依次是:EAX,ECX,EDX,EBX,ESP(初始值),EBP,ESI,EDI.
当操作数的大小是16位时:
	这两个指令的作用是把通用寄存器压栈。寄存器的入栈顺序依次是:AX,CX,DX,BX,SP(初始值),BP,SI,DI.

POPA/POPAD

当操作数的大小是32位时:
	出栈顺序依次是:EDI,ESI,EBP,EBX,EDX,ECX,EAX;
当操作数的大小是16位时:
	出栈顺序依次是:DI,SI,BP,BX,DX,CX,AX;

BSWAP: 交换32位寄存器里字节的顺序。

以字节为单位,把32/64位寄存器的值按照低和高的字节交换
此指令默认的operand size是32bit,如果要使用64位寄存器,那么需要使用REX.W前缀;如果需要使用寄存器R8-R15,那么需要使用REX.R前缀。
指令作用是:32位寄存器内的字节次序变反。(8位)
比如:(EAX)=9668 8368H (96 68 83 68),执行指令:(68 83 68 96) 
BSWAP EAX ,则(EAX)=6883 6896H。

XCHG: 交换字或字节。( 至少有一个操作数为寄存器,段寄存器不可作为操作数)

XCHG指令,双操作数指令,用于交换src和dest操作数的内容。其中,src和dest可以是两个通用寄存器,也可以是一个寄存器和一个memory位置。在XCHG执行期间,memory操作数被引用时,处理器自动实现locking protocol,不依赖LOCK prefix或IOPL字段(I/O privilege level field,EFR寄存器中的IOPL字段)的值。
ex: xchg DEST, SRC
	==>
	temp = DEST;
	DEST = SRC;
	SRC = temp

CMPXCHG: 比较并交换操作数。(第二个操作数必须为累加器AL/AX/EAX)

CMPXCHG CX,DX
首操作数: CX
第2操作数:DX
(AX) = 2300H
(CX) = 2300H
(DX) = 2400H
则指令执行后, 因(CX)= (AX), 故
第2操作数(DX)直装载到首操作数(CX),ZF置1。
(CX)=2400H,ZF=1

(AX) = 2500H
(CX) = 2300H
(DX) = 2400H
则指令执行后因首操作数(CX)不等于(AX), 即(CX)!=(AX) 。
寄存器( al\ax\eax\rax )中的值与首操作数(CX)不等, 那么首操作数的值 (CX)直接装载到al\ax\eax\rax中,即(AX)= (CX 的值2300H),并将zf清0。

XADD: 先交换再累加。( 结果在第一个操作数里 )

xadd eax,ecx
此时eax=2,ecx=3,执行完:eax=5,ecx=2

XLAT: 字节查表转换── BX 指向一张 256 字节的表的起点,AL 为表的索引值(0-255,即0-FFH); 返回 AL 为查表结果 ( [BX+AL]->AL)
输入输出端口传送指令

查表指令XLAT–主要用于字节查表转换,如:把一种代码转化为另一种代码,数字0~9转化为7段显示器件所需要的驱动代码等。

指令的汇编格式:XLAT opr 或 XLAT,一般写作XLAT,而XLAT opr 的写作方式只是为了程序的易读性
指令的特殊要求:所建字节表格的长度不能超过256字节,因为存放位移量的是8位寄存器AL
X DW 1122H,3344H,5566H,7788H;假设X变量就是一个用于转换的表
LEA BX,X;这是个地址传送指令,一般执行XLAT之前必对BX和AL进行传送数值,形式可能各种各样
MOV AL,03H;将表在这里插入代码片格的第4个字节即第4个数值的序号或第四个值在表格中的偏移地址传送给AL
XLAT;操作数隐含的隐式指令,(AL)<-((DS)*16+(BX)+(AL))
;XLAT执行过程为取指令--取	DS  BX AL中的值给地址加法器,将最终地址通过地址总线传送给主存,然后控制总线传送读命令,读取一个字节数据后通过数据总线传送给AL寄存器,一共访存2次

结果AL为33H。
XLAT作用:将((BX)+(AL))送给(AL)----简单:将BX为首地址的,偏移地址为AL的内容送给AL。
在运行XLAT之前,AL=3 BX=(X的首地址)。
这时BX+AL就是33…为什么?注意高地址放在下面。
也就是。
22------BX指向这里。
11
44。
33-----偏移地址AL为3的位置就是这里。
XLAT X。
在执行XLAT之前,先将X的地址送给BX,偏移次数送给AL。
XLAT即为查找指令 (一个字节)。

数据段中存放有一张ASCII码转换表,设首地址为2000H,现欲查出表中第12个代码的ASCII码。
可用如下指令实现
MOV BX,2000H ;BX←表首地址
MOV AL,0BH ;AL←序号
XLAT;查表转换
执行后:AL = 42H
还可用其他方法实现,如:
MOV BX,0BH
MOV AL,[BX+2000H]

IN: I/O端口输入。( 语法:IN 累加器,{端口号│DX} )
OUT: I/O端口输出. (语法:OUT {端口号│DX},累加器)输入输出端口
由立即方式指定时,其范围是 0-255;由寄存器DX 指定时,其范围是 0-65535。

这个指令很强大,可以直接通过端口操作硬件
比如键盘的端口是 64
我们可以利用IN从键盘中读取数据
OUT往键盘的缓冲区写入数据
当然怎么写还有看键盘的规范,寄存器呀,参数呀等等.
这个功能和驱动过保护有关,以前都说驱动过保护,就是就是玩着两个指令,
IN ax,64(端口号)
输出(伪代码,没有看硬盘厂家的标准)
OUT ax,64
IN AL,i8
;字节输入:AL←I/O端口(i8直接寻址)
IN AL,DX
;字节输入:AL←I/O端口(DX间接寻址)
IN AX,i8
;字输入:AX←I/O端口(i8直接寻址)
IN AX,DX
;字输入:AX←I/O端口(DX间接寻址)
将数据传送给外设(伪代码)

OUT i8,AL
;字节输出:I/O端口←AL(i8直接寻址)
OUT DX,AL
;字节输出:I/O端口←AL(DX间接寻址)
OUT i8,AX
;字输出:I/O端口←AX(i8直接寻址)
OUT DX,AX
;字输出:I/O端口←AX(DX间接寻址)

目的地址传送指令

这五个都是一样的原理和解析只是存放的地址名称不一致
LEA: 装入有效地址。例:LEA DX,string;把偏移地址存到DX。

load effective address, 加载有效地址,可以将有效地址传送到指定的的寄存器。指令形式是从存储器读数据到寄存器, 效果是将存储器的有效地址写入到目的操作数, 简单说, 就是C语言中的”&”.

LDS: 传送目标指针,把指针内容装入DS。例: LDS SI,string;把段地址:偏移地址存到DS:SI。

LDS指令 (指针送寄存器和DS)(Load Pointer Using DS)
指令格式:LDS reg16 ,存储器寻址方式
语法格式:LDS reg16 ,reg16/mem/lable
指令功能:从src指定的存储单元开始,由4个连续存储单元中取出前2字节送到reg,取出后2字节送到DS中
ex:LDS AX,(SI +20 ) (20050H)=1234H,(20052H)=5678H,AX=0000H,DS=2000H,SI=0030H,
执行的结果为:AX=???,DS=???
src存储单元地址=DS*10H + SI + 20H =20000+0030+0020=20050;
AX=(20050)=1234H;
DS=(20050+2)=5678H;
ex:
已知指令执行前(22000H~22005H)=12H、34H,56H、78H,9AH、BCH,AX=0000H,DS=2000H,BX=2000H,MEEM=22002H,执行指令LDS AX,MEEM和执行指令LDS AX,(BX)
执行 LDS AX, (BX) 后:
source = 2000H * 10H + 2000H = 22000H
AX = 取地址前16位 (12H, 34H) 得值= 3412H
DS = 取地址后16位 = 22000H + 2 = 22002H (56H. 78H) 得值 = 7856H

LES: 传送目标指针,把指针内容装入ES。例: LES DI,string;把段地址:偏移地址存到ES:DI。

指令格式:LES reg16 ,存储器寻址方式
语法格式: LES reg16 ,reg16/mem/lable ;
指令功能:从src指定的存储单元开始,由4个连续存储单元中取出前2字节送到reg,取出后2字节送到ES中
ex:
LES AX,20(SI)或 LES AX,(SI +20 ) 假设执行前为(20050H)=1234H,(20052H)=5678H,AX=0000H,DS=2000H,SI=0030H
执行的结果为:AX=???,ES=???
物理地址=20020+0030H=20050H = DS * 10 + 20 +SI
AX=(20050H)=1234H
ES=(20050+2H)=5678H

LFS: 传送目标指针,把指针内容装入FS。例: LFS DI,string;把段地址:偏移地址存到FS:DI。
LGS: 传送目标指针,把指针内容装入GS。例: LGS DI,string;把段地址:偏移地址存到GS:DI。
LSS: 传送目标指针,把指针内容装入SS。例: LSS DI,string;把段地址:偏移地址存到SS:DI。

LDS,LES,LFS,LGS,LSS其指令格式都是
    LDS reg16,mem32
其意义是同时给一个段寄存器和一个16位通用寄存器同时赋值
具体如下:reg16=mem32的低字,DS=mem32的高字
例如、
地址 100h    101h    102h   103h
内容   00h      41h        02h     03h
如果指令 LDS AX,[100h]
则结果为 AX=4100h    DS=0302h

标志传送指令

LAHF:标志寄存器传送,把标志装入AH。

LAHF(加载状态标志位到 AH)指令将 EFLAGS 寄存器的低字节复制到 AH。被复制的标志位包括:符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位。使用这条指令,可以方便地把标志位副本保管在变量中:
1 .data
2 saveflags BYTE ?
3 .code
4 lahf                      ;将标志位加载到 AH
5 mov saveflags, ah         ;用变量保存这些标志位

SAHF: 标志寄存器传送,把AH内容装入标志寄存器。

SAHF(保存 AH 内容到状态标志位)指令将 AH 内容复制到 EFLAGS(或 RFLAGS)寄存器低字节。例如,可以检索之前保存到变量中的标志位数值:
1 mov ah, saveflags  ;加载被保存标志位到 AH
2 sahf                        ;复制到 FLAGS 寄存器

PUSHF: 标志入栈。

SDM指令功能描述(PUSHF/PUSHFD/PUSHFQ)
总体描述:
根据操作数宽度的不同:
32:
栈指针递减4,然后压入eflags寄存器的值
16:
栈指针递减2,然后压入eflags的低16位
64:
栈指针递减8,然后压入rflags寄存器的值
当把eflags复制到栈顶的时候,VM(bit16)和RF(bit17)位不会被复制,而 会用 0填充

POPF: 标志出栈。

从栈中弹出数据,送入标志寄存器中。

PUSHD: 32位标志入栈。

POPD: 32位标志出栈。

算术运算指令

ADD: 加法。

格式:add 参数1, 参数2
功能:参数1和参数2相加,将结果赋值给参数1,即 :参数1=参数1+参数2

ADC: 带进位加法。

ADC在功能上和ADD类似,只是有一点区别,即执行ADC指令时,将进位标志CF的值加进和中。
ADC DST,SRC         ;DST<--(DST)+(SRC)+CF
ADC指令多用于多字节相加运算,如进行两个8字节(64位)数据相加,应先用ADD指令将低32位相加,再用ADC指令将高32位相加,此时会把低位字节产生的进位传递到高位字节运算中。ADC影响OF,SF,ZF,AF,PF,CF.标志位

INC: 加 1。

inc a 相当于 add a,1 //i++

AAA: 加法的ASCII码调整。

1. ah = 0,al = 06h,bl = 09h,执行指令add al,bl得ah = 01h,al = 05h,aaa的作用就是将相加后al中的结果15拆分成两部分
(将0fh十进制为15的数字拆分成一个1和一个5,1放在ax的高位ah中,5放在ax的低位al中)
mov		ah,0				;ax = 0038h
mov   	al,'8'				;'8'的ascii码值十进制为56,十六进制为0038h,所以ax = 0038h
add		al,'2'				;'2'的ascii码值十进制为50,十六进制为0032h,所以ax = 0032h,相加后结果为006Ah
aaa							;执行aaa指令后ax = 0100h,本质上是将al低位的a进行化简,a的值为10,转化为BCD码值为01 00h
or			ax,3030h        ;相当于or		ah,30h与or	al,30h操作
将高位的ah与低位的al分别进行ascii码值的转换
最终输出的值为"10",相当于将’8’与’2’进行加法运算,‘8’+‘2’ = “10”
具体算法
(1)如果al的低4位是在0到9之间,保留低4位,清除高4位,如果al的低4位在10到15之间,则通过加6,来使得低4位在0到9之间,然后再对高4位清零。
(2)如果al的低4位是在0到9之间,ah值不变,CF和AF标志清零,否则,ah=ah+1,并设置CF和AF标志。

DAA: 加法的十进制调整。

格式:DAA
功能:将AL的内容调整为两位组合型的二进制数。调整方法与AAA指令类似,不同的是DAA指令要分别考虑AL的高4位和低4位。
如果AL的低4位大于9或AF=1,则AL的内容加06H,并将AF置1;
如果AL的高4位大于9或CF=1,则AL的内容加60H,且将CF置1。

SUB: 减法。

执行减法并将结果存储到目标操作数中。语法示例:sub r1, r2, #5,将寄存器r2的值减去5,结果存储到寄存器r1中。

SBB: 带借位减法。

sbb是带借位减法指令,它利用了CF位上记录的借位值。
指令格式:sbb 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF

DEC: 减 1。

dec a 相当于 sub a,1 

NEG: 取补。

执行的操作:(OPR)<-- —(OPR)
亦即把操作数按位求反后末位加1,因而执行的操作也可表示为:
(OPR)<-- 0FFFFH — (OPR) + 1
NEG指令对标志的影响与用零作减法的SUB指令一样。

CMP: 比较。(两操作数作减法,仅修改标志位,不回送结果)

)指令执行从目的操作数中减去源操作数的隐含减法操作,并且不修改任何操作数。
指令格式:
CMP 目的操作数, 源操作数
CMP结果	ZF	CF
目的操作数 < 源操作数	0	1
目的操作数 > 源操作数	0	0
目的操作数 = 源操作数	1	0
CMP结果	标志位
目的操作数 < 源操作数	SF ≠ OF
目的操作数 > 源操作数	SF = OF
目的操作数 = 源操作数	ZF = 1

AAS: 减法的ASCII码调整。

若AL寄存器的低4位>9或AF=1,则:
(1)AL=AL-6,AF置1;
(2)将AL寄存器高4位清零;
(3)AH=AH-1,CF置1。
否则,不需要调整。
如下面的汇编指令
.data
val1 BYTE ‘8’
val2 BYTE ‘9’
.code
mov ah, 0
mov al,val1 ; AX = 0038h
sub al,val2 ; AX = 00FFh
aas ; AX = FF09h
pushf ; 保存进位标志位
or al,30h ; AX = FF39h
popf ; 恢复进位标志位
算出ax = 00ffh之后,看末尾的f,
f超过值9,将f-6后值为09放入末尾的al之中
因为f减去了值6,所以打头的00需要减1
00-1=ffh,最终结果为ax = ff09h

DAS: 减法的十进制调整。

格式:DAS
功能:
如果AL低四位>9或AF=1 ,则AL的值减06h,并置AF=1
如果AL高四位>9或CF=1 ,则AL的值减60h ,且置CF=1

MUL: 无符号乘法。结果回送AH和AL(字节运算),或DX和AX(字运算)

32 位模式下,MUL(无符号数乘法)指令有三种类型:
执行 8 位操作数与 AL 寄存器的乘法;
执行 16 位操作数与 AX 寄存器的乘法;
执行 32 位操作数与 EAX 寄存器的乘法。
MUL 指令中的单操作数是乘数。下表按照乘数的大小,列出了默认的被乘数和乘积。由于目的操作数是被乘数和乘数大小的两倍,因此不会发生溢岀,换句话说,两个8位二进制数的乘积不会超过16位。

被乘数	乘数	乘积存放位置	备注
AL	reg8/mem8	AX	MUL操作数是8位寄存器,自动将AL当作被乘数。结果存放AX。
AX	reg16/mem16	DX:AX	MUL操作数是16位寄存器,自动将AX当作被乘数。结果的低位放在AX,高位在DX。
EAX	reg16/mem32	EDX:EAX	MUL操作数是32位寄存器,自动将EAX当作被乘数。结果的低位在EAX,高位在EDX。
当被乘数和乘数都是8位时:
MOV AL,66 ;AL存放被乘数,66是16进制数
MOV BL,9 ;BL存放乘数,9是16进制数
MUL BL ;因为被乘数默认放在AL,所以只需要一个操作数来告诉CPU乘数是多少
 最后,结果存放在AX中
 当被乘数和乘数都是16位时:
 MOV AX,120 ;AX存放被乘数,120是16进制数,超过了8位的范围
 MOV BX,120 ;BX存放乘数,120是十六进制数,超过了8位的范围
 MUL BX ;因为被乘数默认放在AX,所以只需要一个操作数来告诉CPU乘数是多少
 最后,结果保存在AX和DX中,DX保存结果的高16位,AX保存结果的低16位
BA  =	10111010
c	=		1100
值	100010111000
		00000000
   	   00000000
      10111010
     10111010
    100010111000

IMUL: 整数乘法,有符号数乘法。结果回送AH和AL(字节运算),或DX和AX(字运算)

40 =	00101000
4  = *		0100
AH =	00000000
AL = +	10100000
值 = 	10100000

-4 = 	11111100
4  = 	00000100
AH = 	11111111
AL = 	11110000
值 =    111101111 = -16

mov al, -4
mov bl, 4
imul bl             ; AX = FFF0h, OF = 0

mov eax, +4823424
mov ebx, -423
imul ebx         ; EDX:EAX = FFFFFFFF86635D80h, OF = 0

AAM: 乘法的ASCII码调整。

该指令是用于调整寄存器AL之值,该值是由二个单BCD码字节用无符号乘指令MUL所得的积。其调整规则如下:
AH←AL/10(商),AL←AL%10(余数)
指令的格式:AAM
受影响的标志位:PF、SF和ZF(AF、CF和OF等都是无定义)
例如:
MOV AL, 9
MOV BL, 8
MUL BL      ;AL=72D
AAM          ;AH=7, AL=2
ASCII码除调整指令AAD(Ascii Adjust After Division)
该指令是在作除法前用于调整寄存器AH和AL之值,它是把二个寄存器中单BCD码组成一个十进制数值,为下面的除法作准备的。其调整规则如下:
AL←AH*10+AL,AH←0
指令的格式:AAD
受影响的标志位:PF、SF和ZF(AF、CF和OF等都是无定义)
例如:
MOV AX, 0502H
MOV BL, 10D
AAD     ;AH=0, AL=52D
DIV BL  ;AH=2(余数), AL=5(商)

DIV: 无符号除法:商回送AL,余数回送AH,(字节运算);或商回送AX,余数回送DX(字运算)

div是除法指令,使用div做除法的时候应注意一下问题:
1)除数:有8位和16位两种,在一个reg(寄存器)或内存单元中。
2)被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,默认存放在 AX中存放;如果除数为16位,被除数则为32位,在DX和AX中存放, DX存放高16位, AX存放低16位。
3)结果:如果除数为8位,则AL存储除法操作的商, AH存储除法操作的余数;如果除数为16位,则 AX存储除法操作的商,DX存储除法操作的余数
div reg
div 内存单元
div byte ptr ds:[0]

含义:(al)= (ax) / ((ds) * 16 + 0)的商
  (ah) = (ax) / ((ds) * 16 + 0)的余数
div word ptr es:[0]
含义: (ax) = [(dx * 10000H) + (ax)] / ((es) * 16 + 0) 的商
  (dx) = [(dx * 10000H) + (ax)] / ((es) * 16 + 0) 的余数
div byte ptr [bx + si + 8]
含义: (al) = (ax) / [(ds) * 16 + (bx) + (si) + 8] 的商
(ah)= (ax) / [(ds) * 16 + (bx) + (si) + 8] 的余数
div word ptr [bx + si + 8]
含义:  (ax) = [(dx) * 10000H + (ax)] / [(ds) * 16 + bx + si + 8] 的商
 (dx) = [(dx) * 10000H + (ax)] / [(ds) * 16 + bx + si + 8] 的余数 

编程:利用除法指令计算100001/100
1)被除数100001大于65535,不能用ax寄存器存放,只能用dx 和 ax联合存放,即16位除法。
2)除数100小于255,可以用一个8位寄存器存放,但是,因为被除数是32位的,除数应为16位,所以要用一个16位寄存器来存放除数100。
3)100001表示为16进制为186A1H,因为要分为高位和低位存放。
实现:
mov dx, 1     //或 10000H
mov ax, 86A1H    //(dx) * 10000H + ax = 100001  
mov bx, 100
div bx
编程:利用除法指令计算1001/100
1)1001可以用ax存放,100可以用8位寄存器存放,所以进行8位除法。
实现:
mov ax, 1001
mov bl, 100
div bl

IDIV: 整数除法:商回送AL,余数回送AH,(字节运算);或商回送AX,余数回送DX(字运算)

idiv bh
idiv byte [0x2002]        ; AX中的内容除以该地址处的一个字节,商在AL中,余数在AH中
idiv bx        ; 被除数由DX和AX组成32位被除数,
idiv word [0x2002]        ; word 说明操作数是16位的
idiv ebx
idiv word [0x2002]
如果被除数和除数的符号相同,商为正数,否则商为负数。
余数的符号始终和被除数相同。
mov ax, 0x0400		; 1024
mov bl, 0xf0		; -16
idiv bl			; AL = 0XC0 
times 510-($-$$) db 0
db 0x55, 0xaa

AAD: 除法的ASCII码调整。

 AAD
	AAD指令也是一个隐含了寄存器操作数AL和AH的指令。它是对非压缩型BCD码进行调整,其操作为:
  (AL)←(AH) ′0AH+(AL)
  (AH)←0
即将AH寄存器的内容乘以10并加上AL寄存器的内容,结果送回AL,同时将零送AH。以上操作实质上是将AX寄存器中非压缩型BCD码转换成为真正的二进制数,并存放在AL寄存器中。
执行AAD指令以后,将根据AL中的结果影响状态标志位SF、ZF和PF,但其余几个状态标志位如AF、CF和OF的值则不确定。
AAD指令的用法与其它非压缩型BCD码调整指令(如AAA、AAS、AAM)有所不同。AAD指令不是在除法之后,而是在除法之前进行调整,然后用DIV指令进行除法,所得之商还需用AAM指令进行调整,方可得到正确的非压缩型BCD码的结果。
例如想要进行以下十进制除法运算:73÷2=?可先将被除数和除数以非压缩型BCD码的形式分别存放在AX和BL寄存器中,被除数的十位在AH,个位在AL,除数在BL。先用AAD指令对AX中的被除数进行调整,之后进行除法运算,并对商进行再调整。可编程序段如下:
    MOV  AX,0703H ;(AH)=07H,(AL)=03H
    MOV  BL,02H     ;(BL)=02H
    AAD                ;(AL)=49H(即十进制数73)
    DIV   BL           ;(AL)=24H(商),(AH)=01H(余数)
    AAM               ;(AH)=03H,(AL)=06H

CBW: 字节转换为字。(把AL中字节的符号扩展到AH中去)
CWD: 字转换为双字。(把AX中的字的符号扩展到DX中去)
CWDE: 字转换为双字。 (把AX中的字符号扩展到EAX中去)
CDQ: 双字扩展。(把EAX中的字的符号扩展到EDX中去)

逻辑运算类指令

AND: 与运算。

0&0=0;0&1=0;1&0=0;1&1=1

or: 或运算。

0|0=0;  0|1=1;  1|0=1;   1|1=1;

XOR: 异或运算。

0^0=0;  0^1=1;  1^0=1;   1^1=0;

NOT: 取反。

NOT 运算符仅影响紧跟其后的表达式,除非用括号括起更复杂的逻辑表达式。
您可以将 NOT 替换为逻辑运算符 ~ 或 ¬。
NOT 可用于检查数字变量是否具有值 0 , 1 或任何其他值。 例如,所有临时变量都初始化为 0。 因此,当为 #ID 指定了除 0 以外的值时, NOT (#ID) 将返回 false 或 missing。

TEST: 测试。(两操作数作与运算,仅修改标志位,不回送结果)

Test对两个参数(目标,源)执行AND逻辑操作,并根据结果设置标志寄存器,结果本身不会保存。
TEST AX,BX 与 AND AX,BX 命令有相同效果,只是Test指令不改变AX和BX的内容,而AND指令会把结果保存到AX中。

1.Test用来测试一个位,例如寄存器:
test eax,100b;b后缀意为二进制
jnz ******;如果eax右数第三个位为1,jnz将会跳转
我是这样想的,jnz跳转的条件是ZF=0,ZF=0意味着ZF(零标志)没被置位,即逻辑与结果为1。
2.Test的一个非常普遍的用法是用来测试一方寄存器是否为空:
test ecx, ecx
jz somewhere
如果ecx为零,设置ZF零标志为1,jz跳转。

移位指令

SHL: 逻辑左移。

x:=x shl n 二进制数向左移n位,尾部补n个零,相当于x:=x*2^n;

SAL: 算术左移。(=SHL)

SHR: 逻辑右移。(每位右移,低位进 CF,高位补 0)

x:=x shr n 二进制数向右移n位,首部补n个零,相当于x:=x div (2^n);

SAR: 算术右移。(每位右移, 低位进 CF,高位不变)

;SHL、SAL: 每位左移, 低位补 0,  高位进 CF
;SHR     : 每位右移, 低位进 CF, 高位补 0
;SAR     : 每位右移, 低位进 CF, 高位不变

ROL: 循环左移。
ROR: 循环右移。

循环左移/右移指令只是移位方向不同,它们移出的位不仅要进入CF,而且还要填补空出的位。
  例如:
         MOV AL,82H
         ROL AL,1
  首先把82H转换成二进制数10000010B
  循环左移1位后变成:00000101B,换算成十六进制数便是05H
  循环右移1位后变成:01000001B,换算成十六进制数便是41H

RCL: 通过进位的循环左移。

从进位标志位恢复位

RCL 可以恢复之前移入进位标志位的位。下面的例子把 testval 的最低位移入进位标志位,并对其进行检查。如果 testval 的最低位为 1,则程序跳转;如果最低位为 0,则用 RCL 将该数恢复为初始值:

.data
testval BYTE 01101010b
.code
shr testval, 1          ; 将lsb移入进位标志位
jc exit                     ; 如果该标志位置 1,则退出
rcl testval, 1           ; 否则恢复该数原值

RCR: 通过进位的循环右移。

RCR 指令
RCR(带进位循环右移)指令把每一位都向右移,进位标志位复制到 MSB,而 LSB 复制到进位标志位:
从上图来看,RCL 指令将该整数转化成了一个 9 位值,进位标志位位于 LSB 的右边。下面的示例代码用 STC 将进位标志位置 1,然后,对 AH 寄存器执行一次带进位循环右移操作:
stc                            ; CF = 1
mov ah, 10h             ; AH, CF = 00010000 1
rcr ah, 1                    ; AH, CF = 10001000 0
有符号数溢出
如果有符号数循环移动一位生成的结果超过了目的操作数的有符号数范围,则溢出标志位置 1。换句话说,即该数的符号位取反。下例中,8 位寄存器中的正数(+127)循环左移后变为负数(-2):
mov al, +127          ; AL = 01111111b
rol al, 1                   ; OF = 1, AL = 11111110b
同样,-128 向右移动一位,溢出标志位置 1。AL 中的结果(+64)符号位与原数相反:
mov al, -128           ; AL = 10000000b
shr al, 1                  ; OF = 1, AL = 01000000b
如果循环移动次数大于 1,则溢出标志位无定义。

串操作指令

PTR

ptr的作用就是临时指定类型。8086CPU的指令,可以处理两种尺寸的数据,byte和word。所以在机器指令中要指明,指令进行的是字操作还是字节操作

DS:SI ——源串段寄存器:源串变址。

例1:SI
MOV SI,0 ;初始化偏移地址为 0
MOV AX,[SI] ;将段地址为 DS 偏移地址为 SI 的内存单元中的值移入 AX 中
MOV AX,DS:[SI] ;将段地址为 DS 偏移地址为 SI 的内存单元中的值移入 AX 中
MOV AX,SS:[SI] ;将段地址为 SS 偏移地址为 SI 的内存单元中的值移入 AX 中

例2:DI
MOV DI,0 ;初始化偏移地址为 0
MOV AX,[DI] ;将段地址为 DS 偏移地址为 DI 的内存单元中的值移入 AX 中
MOV AX,DS:[DI] ;将段地址为 DS 偏移地址为 DI 的内存单元中的值移入 AX 中
MOV AX,SS:[DI] ;将段地址为 SS 偏移地址为 DI 的内存单元中的值移入 AX 中

ES:DI ——目标串段寄存器:目标串变址。

源操作数用寄存器SI寻址,默认在数据段DS中,但是允许段超越:DS:[SI]
目的操作数用寄存器DI寻址,默认在附加段ES中,不允许段超越:ES:[DI]

CX: 重复次数计数器。

    mov cx,循环次数
s:
 循环执行的程序段
	loop s

AL/AX: 扫描值。
D标志: 0表示重复操作中SI和DI应自动增量;1表示应自动减量。
Z标志: 用来控制扫描或比较操作的结束。
MOVS: 串传送。(MOVSB 传送字符, MOVSW 传送字, MOVSD 传送双字)
CMPS: 串比较。(CMPSB 比较字符, CMPSW 比较字)
SCAS: 串扫描。把AL或AX的内容与目标串作比较,比较结果反映在标志位。
LODS: 装入串。把源串中的元素(字或字节)逐一装入AL或AX中。(LODSB 传送字符, LODSW 传送字,LODSD 传送双字)
STOS: 保存串。是LODS的逆过程。
REP: 当CX/ECX<>0时重复。
REPE/REPZ: 当ZF=1或比较结果相等,且CX/ECX<>0时重复。
REPNE/REPNZ: 当ZF=0或比较结果不相等,且CX/ECX<>0时重复。
REPC: 当CF=1且CX/ECX<>0时重复。
REPNC: 当CF=0且CX/ECX<>0时重复。

无条件转移指令

(长转移)
JMP: 无条件转移指令。
CALL: 过程调用。
RET/RETF: 过程返回。

条件转移指令

(短转移,-128到+127的距离内;当且仅当(SF、XOR、OF)=1时,OP1<OP2 )
JA/JNBE: 大于转移。
JAE/JNB: 大于或等于转移。
JB/JNAE: 小于转移。
JBE/JNA: 小于或等于转移。
以上四条,测试无符号整数运算的结果(标志C和Z)
JG/JNLE: 大于转移。
JGE/JNL: 大于或等于转移。
JL/JNGE: 小于转移。
JLE/JNG: 小于或等于转移。
以上四条,测试带符号整数运算的结果(标志S,O和Z)
JE/JZ: 等于转移。
JNE/JNZ: 不等于时转移。
JC: 有进位时转移。
JNC: 无进位时转移。
JNO: 不溢出时转移。
JNP/JPO: 奇偶性为奇数时转移。
JNS: 符号位为 “0” 时转移。
JO: 溢出转移。
JP/JPE: 奇偶性为偶数时转移。
JS: 符号位为 “1” 时转移。

循环控制指令

(短转移)
LOOP: CX不为零时循环。
LOOPE/LOOPZ: CX不为零且标志Z=1时循环。
LOOPNE/LOOPNZ: CX不为零且标志Z=0时循环。
JCXZ: CX为零时转移。
JECXZ: ECX为零时转移。

中断指令

INT: 中断指令。
INTO: 溢出中断。
IRET: 中断返回。

伪指令

DB: 定义字节(1字节)
DW: 定义字(2字节)
DD: 定义双字(4字节)
PROC: 定义过程。
ENDP: 过程结束。
SEGMENT: 定义段。
ASSUME: 建立段寄存器寻址。
ENDS: 段结束。
END: 程序结束。

处理机控制指令

即标志处理指令,处理机控制指令完成简单的控制功能。
CLC: (进位位置0指令)
CMC: (进位位求反指令)
CLC: (进位位置为0指令)
STC: (进位位置为1指令)
CLD: (方向标志位置0指令)
STD: (方向标志位置1指令)
CLI: (中断标志置0指令)
STI: (中断标志置1指令)
NOP: (无操作)
HLT: (停机)
WAIT: (等待)
ESC: (换码)
LOCK: (封锁)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值