8086指令系统概述
8086指令系统概述
Intel 8086指令系统共有117条基本指令,可分成6个功能组
① 数据传送类指令 :数据从哪里到哪里
② 算术运算类指令
③ 位操作类指令
④ 串操作类指令
⑤ 控制转移类指令
⑥ 处理机控制类指令
数据传送类指令
一丶通用数据传送指令
1.MOV传送指令
mov 指令传送功能图
请注意,立即数不能直接给段寄存器,都是通过中转的
mov 注意事项
1.两个操作数的类型不一致
例如源操作数是字节,目的操作数是字,或者是相反
1
|
mov al,050AH //错误 al是八位寄存器,只能接受八位,而这里是16位了 |
对于存储器,和立即数同时都作为操作数的情况下,必须显示的指明是什么类型
1
|
mov [2000h],12h //错误,应该写成 mov byte ptr(或者word ptr)[2000h],12h |
如果只是12h,则用byte ptr,当然你也可以写成word ptr,但是修改内存的值修改后则是修改的两个字节的长度
2.两个操作数不能是存储器
例如 mov [2000h],[2200h] 因为内存只是存储的,传送的结果要保存在寄存器当中,显然内存没有内置CPU,所以通过寄存器中转,所以不能直接这样
3.小心段操作寄存器
1.立即数不能直接给段寄存器
mov ds,100
2.不能直接改变cs段寄存器的值
mov cs,[si] 这条指令是可以编译通过,但是运行的时候,因为你把代码段的值改了,然后CS:IP确定的下一跳指令就会出错,比如你的这条指令下面还有个mov ax,0 当你上面改了,那么mov ax,0 永远不会执行,而你熟悉的改了cs的值可以,如果不熟悉那么代码段就被破坏,程序就会执行崩溃.
3.段寄存器和段寄存器不能直接数据传送
mov ds,es
2.xchg交换指令
xchg reg/mem/accum , reg/mem/accum (accum指的是AL/AX/EAX)
其实就是寄存器的值交换,那么此时ax的值就是1,bx就是0
ax = 0 bx = 1 xchg ax,bx
有人说mov 指令也可以,确实是可以,但是指令周期不一样,这个比mov指令快一个指令周期,而且还不浪费寄存器(否则需要三个寄存器完成交换)
寄存器和存储器交换
xchg ax,[2000h] 字交换,ax正好可以放下16位,等价于 xchg [2000h],ax 这里会有人说为什么不用 word ptr说明一下,因为后面跟着的是16位寄存器,它默认就是 word ptr了xchg al,[2000h] 字节交换 ,等同于 xchg [2000h],al 同上为什么不用byte ptr
3.xlat 换码指令(查表指令)
将BX指定的缓冲区中,al执行的位移处的一个字节数据取出赋值给al,后面没有操作数,默认操作数就是 BX和AL,直接 一个 xlat即可.,相当于数组寻址,bx放在数组首地址,al放下标。给设备做了一个表
改设备表,就相当于改了代码
ary[]={0,0,0...96}//把65的ascii换为65 ary[65]
转变成mov 相当于
mov al,ds:[bx+al]//注意这里是bx我草!!!!
就是dx数据里面有一块完整的内存(比如是ASCII码 a b c d),al 就给定一个下标,然后调用xlat指令,就可以根据al的下标获取出来 abcd其中的一个ASCII码重新放到al中,相当于数组寻址
第一步,使用e命令给400偏移处写入 abcdefg的字符
第二步 使用 d命令查看
第三步开始汇编,先给bx赋值偏移量为400,则 DS:[DX]可以取得61(也就是a)的编码,但是怎么取出来,要根据al给定的下标,比如al给了3,那么就是 DS:[DX+AL] 也就是取出63的编码,赋值给al,我这里给的是0,所以下标取内容是61
4.PUSH,POP堆栈指令
SS代表栈的段地址,SP代表是栈顶 BP代表是栈底,堆栈的操作指令有两种,第一种是PUSH压栈,第二种是POP出栈
PUSH r16/m16/seg ;SP←SP-2 //第一步寄存器sp指针-2 ;SS:[SP]←r16/m16/seg //第二部把寄存器或主存或段寄存器压入到栈
POP r16/m16/seg ;r16/m16/seg←SS:[SP] //第一步从栈中取出数据赋值给寄存器或主存或段寄存器 ;SP←SP+2 //第二部把寄存器sp指针+2
注意:栈结构是从高地址向低地址去使用
mov指令模拟push指令
第一步,要压栈之前,sp需要-2,留出一个字的空间,这样才可以把字压入栈中
mov sp,bp 栈底和栈顶一样 sup sp,2 栈顶-2留出两个字节空间让数据压栈 mov bp sp, 让新的栈顶指针位置赋值给栈底 mov word ptr [bp],1 栈底位置处压入1
mov模拟pop出栈指令
mov bp,sp 首先栈顶栈底一样 mov ax,[bp] 栈底的数据给ax add sp,2 栈顶指针移动 mov bp,sp 栈底位置和栈顶位置一样
x86提供了指令,push 和pop,
push ax 把 ax压栈,pop ax 出栈的值放到ax中
push的指令:push r16/m16/seg (可以是16位寄存器,2个字节的内存,或者段寄存器)
pop 一样
注意:需要自己控制堆栈的平衡,操作单位是字
5 标志寄存器传送指令
作用:
add ax ,1 add ax,1 //这种情况标志寄存器的值还没有保存
有两对4条指令(分别对应8位寄存器,和16位寄存器)
低八位传送 LAHF 和 SAHF
16位传送 PUSHF 和 POPF
LAHF 代表 的意思 第一个字母 L代表load(加载的意思) AH八位寄存器AH,F是标志位
表示把 Flag标志寄存器里面的低八位标志,传送到 AH中
LAHF ;AH←FLAGS的低字节 LAHF指令将标志寄存器的低字节送寄存器AH SF/ZF/AF/PF/CF状态标志位分别送入AH的第7/6/4/2/0位,而AH的第5/3/1位任意
SAHF S可以理解为设置,或者保存的意思 ,就是 AH的高八位当做标志位给Flag寄存器的标志位赋值
表示我们通过AH的值,设置flag标志寄存器
SAHF ;FLAGS的低字节←AH SAHF将AH寄存器内容送FLAGS的低字节 用AH的第7/6/4/2/0位相应设置SF/ZF/AF/ PF/CF标志
标志位都清零
xor ah,ah (为什么用这个,因为这个CPU寻址的时候指令执行周期短,如果 写成 mov ah,0那么带有立即数所以比较慢) SAHF //清零标志位
PUSHF 和 POPF
pushf 的功能是将标志寄存器的值压栈
SP←SP-2 ;SS:[SP]←FLAGS PUSHF指令将标志寄存器的内容压入堆栈,同时栈顶指针SP减2
popf 是从栈中探出数据,输入标志寄存器。
;FLAGS←SS:[SP] ;SP←SP+2 POPF指令将栈顶字单元内容送标志寄存器,同时栈顶指针SP加2
pushf 和 popf,为直接访问寄存器提供了方法。
格式
pushf//这两条指令后面都不加东西,默认的操作对象是:所有的标志寄存器。 popf
标志位都清零
pushf 获取标志位到ax中,但是需要pop获取 pop ax xor ax,ax 获取到了设置为0 push ax 重新压栈 popf 设置标志寄存器,一般来说不用设置标志寄存器的高八位
单独修改标志寄存器某一位
pushf 保存全部标志到堆栈 pop ax 从堆栈中取出全部标志 or ax,0100h 设置D8=TF=1,这个地方就是对某一位设置 ax其他位不变 push ax 将ax压入堆栈 popf FLAGS←AX//设置所有标志寄存器
6 地址传送指令
lea 和mov 区别
lea简单的说,lea指令可以用来将一个内存地址直接赋给目的操作数,例如:
lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。
而mov指令则恰恰相反,例如:
mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。
LEA 有效地址传送指令 例如 LEA AX,[bp] 这样
LEA r16,mem (具体查询 inter手册) lea ax,[BX+SI+8]//精简写法,很快,两个加法比一个lea慢
上面这样写只是求出内存地址,假设bp的值是2000,则给ax是2000,而不是2000里面的内容,这样写比add快,但是真正用法不是这样的,真正用法就是求内存地址而已(注意不是求出内存单元的值,如果写成 add ax,[bp],如果是这样,那么ax的值就不是2000了,就是2000地址里面的内容了)
LDS LES 指针传送指令 :程序一大,数据段就应该有很多,LDS和LES指令可以使用两个段寄存器来回切换
LDS r16,mem ;r16←mem, ;DS←mem+2 LDS指令将主存中mem指定的字送至r16,并将mem的下一字送DS寄存器
LES r16,mem ;r16←mem, ;ES←mem+2 LES指令将主存中mem指定的字送至r16,并将mem的下一字送ES寄存器
例如:
切换段寄存器
mov word ptr [3060h],0100h mov word ptr [3062h],1450h les di,[3060h] //es=1450h,di=0100h lds si,[3060h] //ds=1450h,si=0100h
7 输入输出指令
汇编语言中,CPU对外设的操作通过专门的端口读写指令来完成;
读端口用IN读指令,写端口用OUT写指令。
在往键盘写数据里的时候,需要更改标志位.才能out
IN AL,21H;表示从21H端口读取一字节数据到AL IN AX,21H;表示从端口地址21H读取1字节数据到AL,从端口地址22H读取1字节到AH MOV DX,379H IN AL,DX ;从端口379H读取1字节到AL OUT 21H,AL;将AL的值写入21H端口 OUT 21H,AX;将AX的值写入端口地址21H开始的连续两个字节。(port[21H]=AL,port[22h]=AH) MOV DX,378H OUT DX,AX ;将AH和AL分别写入端口379H和378H
算术运算类指令
加法指令
ADD reg,imm/reg/mem == reg←reg+imm/reg/mem ADD mem,imm/reg == mem←mem+imm/reg
ADC带进位的加法:两数结果加上标志位,这个指令做16位寄存器模拟32位加法运算
mov ax,4652h ;ax=4652h add ax,0f0f0h ;ax=3742h,CF=1 mov dx,0234h ;dx=0234h adc dx,0f0f0h ;dx=f325h,CF=0 //低位先做sdd运算,高位在做sdc运算 DX.AX=0234 4652H +F0F0 F0F0H ------------------ =F325 3742H
ADC reg,imm/reg/mem == reg←reg+imm/reg/mem+CF ADC mem,imm/reg == mem←mem+imm/reg+CF
增量INC,INC指令不影响进位CF标志,按定义设置其他状态标志
INC reg/mem //很简单,寄存器,或者内存自增1,C语言中相当于i++, ++i
例:
INC bx //bx自增1 INC byte ptr[bx] //地址自增
减法指令
SUB reg,imm/reg/mem == reg←reg-imm/reg/mem SUB mem,imm/reg == mem←mem-imm/reg
SBB带借位的减法:十六位寄存器模拟三十二位寄存器减法
mov ax,4652h ;ax=4652h sub ax,f0f0h ;ax=5562h,CF=1 mov dx,0234h ;dx=0234h sbb dx,f0f0h ;dx=1143h,CF=1 //低位先做sub运算,高位在做sbb运算 ;DX.AX=0234 4652H -F0F0 F0F0H =1143 5562H
0000 = fff16 //这里0000不够减,所以要向前借位,最后借到为fff16,cf=1 - - ffff ffff =0001 =0001
SBB reg,imm/reg/mem == reg←(reg-(imm/reg/mem)-CF) SBB mem,imm/reg == mem←mem-imm/reg-CF
自减 DEC,不能进行大数运算,因为没有影响借位寄存器
DEC reg/mem == reg/mem←reg/mem-1
INC(自增)指令和DEC(自减)指令都是单操作数指令,主要用于对计数器和地址指针的调整
NEG求补指令,影响cf进位标志位
NEG reg/mem == reg/mem←0-reg/mem
请注意,CPU并不会执行补码,而是写成
SUB 0,1 //用0减去操作数1,然后结果返回操作数
求补运算也可以表达成,将操作数按位取反后加1,
NEG指令对标志的影响与用零作减法的SUB指令一样
CMP 比较指令,不影响操作数,只影响标志寄存器
1.CMP指令是将目的操作数减去源操作数,按照定义相应的设置状态标志
2.CMP指令执行的功能与SUB指令(相减指令)一样,但是不同的是CMP指令之根据结果设置标志位
而不修改值
机器码是39代表的是CMP指令
CMP reg,imm/reg/mem CMP mem,imm/reg
例子:
cmp al,100 jz below //jz :al == 100则 zf==1 会跳转到below执行,相当于c语言的goto指令 below: ...
乘法指令
MUL (无符号字节乘法)
注意:8位寄存器相乘要放到16位寄存器,16位寄存器相乘要放到32位寄存器,必须放到al,ax
指令格式: ax = al * r8/m8 ax(16位寄存器)存放 al * r8(八位寄存器)或者 m8(内存中八位的值)
mov al,0b4h ;al=b4h=180 mov bl,11h ;bl=11h=17 mul bl ;ax=Obf4h=3060 ;OF=CF=1,AX高8位不为0
IMUL有符号的字节乘法
IMUL r8/m8 ax = al * r8/m8 和上面一样,结果放到ax中,al可以×八位的寄存器,或者内存取出的数值的8位数值
mov al,b4h ;al=b4h=-76 mov bl,11h ;bl=11h=17 imul bl ;ax=faf4h=-1292 ;OF=CF=1,AX高8位含有效数字
除法指令
DIV
DIV r8/m8 ;无符号字节除法: AL←AX÷r8/m8的商,Ah←AX÷r8/m8的余数
mov ax,0400h ;ax=400h=1024 mov bl,0b4h ;bl=b4h=180 div bl ;商al=05h=5 ;余数ah=7ch=124
IDIV
IDIV r8/m8 ;有符号字节除法: AL←AX÷r8/m8的商,Ah←AX÷r8/m8的余数
mov ax,0400h ;ax=400h=1024 mov bl,0b4h ;bl=b4h=-76 idiv bl ;商al=f3h=-13 ;余数ah=24h=36
SHR 右移一定程度可以替代除法但是不能求余数 ,只能求2的倍数,
注意:有符号数不能右移,因为会丢失精度,计算机的除法是没有小数位的,无符号除法则可以右移,不会影响结果
比如-3/2就错了,用右移动就错了
用法:
Usage: SHR dest,count //后面跟操作数和位移量
fd 1111 1101 -》 1111 1110 结果为-2了,因为丢失了精度
and ax,1 求除2的余数 ,如果结果为1则除2余1,如果结果为0则整除2,如果要判断除4的余数,则
and ax,11 这样就求出除4的余数了。
5除2 求余数 0101 & 1 -------- 1 //结果为1,则5除2有余数为1 9除4 求余数 1001 & 11 ---------- 1 //结果为1,则9除4有余数为1
shr 和 and ax ,1 配合,可以替代除法运算
符号扩展指令,不影响标志位
CBW 8位拓展为16为,符号位填充高位字节
CBW ;AL的符号扩展至AH ;如AL的最高有效位是0,则AH=00 ;AL的最高有效位为1,则AH=FFH。AL不变
例子:
mov al,80h ;al=80h cbw ;ax=ff80h mov al 7fh ;al =7fh cbw ;ax=007fh
CWD 16位拓展到32位,用dx来保存拓展位,符号位填充高位字节
CWD ;AX的符号扩展至DX ;如AX的最高有效位是0,则DX=00 ;AX的最高有效位为1,则DX=FFFFH。AX不变
十进制调整指令(不常用)
十进制数调整指令对二进制运算的结果进行十进制调整,以得到十进制的运算结果
分成压缩BCD码和非压缩BCD码调整
BCD压缩码就是通常的8421码;它用4个二进制位表示一个十进制位,一个字节可以表示两个十进制位,即00~99
36 表示十进制的三十六,不是十六进制的36
原理:如果al大于9就+6,不大于就不加6,
---------------------------------------------------------------------------------------------------------------------------
BCD非压缩码用8个二进制位表示一个十进制位,只用低4个二进制位表示一个十进制位0~9,高4位任意,通常默认为0
0306 表示十进制的36,不是十六进制的36
BCD压缩码的加法和减法
DAA:BCD压缩吗的加法
(ADD AL,i8/r8/m8)//可以add指令,也可以adc指令 (ADC AL,i8/r8/m8) DAA ;AL←将AL的加和调整为压缩BCD码
例子
39+1如果变为4a就是十六进制运算 使用DAA则结果为40,符合十进制运算结果
DAS:BCD压缩吗的减法
(SUB AL,i8/r8/m8)//可以sub指令,也可以sbb指令 (SBB AL,i8/r8/m8) DAS ;AL←将AL的减差调整为压缩BCD码
12 -3 如果变为0f就错了,运算结果为16进制的结果 使用DAS则结果为9,符合十进制运算结果
注意:使用DAA或DAS指令前,应先执行以AL为目的操作数的加法或减法指令
BCD非压缩码的加法和减法
AAA和AAS指令在调整中产生了进位或借位,则AH要加上进位或减去借位,同时CF=AF(低4位进位检测)=1,否则CF=AF=0;它们对其他标志无定义
AAA :BCD非压缩码的加法
(ADD AL,i8/r8/m8) (ADC AL,i8/r8/m8) AAA ;AL←将AL的加和调整为非压缩BCD码 ;AH←AH+调整的进位
例子:
mov ax,0608h ;ax=0608h,非压缩BCD码表示真值68 mov bl,09h ;bl=09h,非压缩BCD码表示真值9 add al,bl aaa ;十进制调整:ax=0707h,实现非压缩BCD码加法:68+9=77
AAS :BCD非压缩码的减法,注意:AAS只负责al,ah他不负责
(SUB AL,i8/r8/m8) (SBB AL,i8/r8/m8) AAS ;AL←将AL的减差调整为非压缩BCD码 ;AH←AH-调整的借位
例子:
mov ax,0608h ;ax=0608h,非压缩BCD码表示真值68 mov bl,09h ;bl=09h,非压缩BCD码表示真值9 sub al,bl aas ;十进制调整:ax=0509h, 实现非压缩BCD码减法:68-9=59
BCD非压缩码的乘法和除法:AAM和AAD指令根据结果设置SF、ZF和PF,但对OF、CF和AF无定义
AAM:BCD非压缩乘法,AAM指令跟在字节乘MUL之后,将乘积调整为非压缩BCD码
(MUL r8/m8) AAM ;AX←将AX的乘积调整为非压缩BCD码
例子:
mov al,08h //ax=08h,非压缩BCD码表示真值68 mov bl,09h //bl=09h,非压缩BCD码表示真值9 mul bl aam 十进制调整:ax=0702h,实现非压缩BCD码乘法:8×9=72
AAD:BCD非压缩除法,AAD指令跟在字节除DIV之前,先将非压缩BCD码的被除数调整为二进制数
(DIV r8/m8) AAD ;AX←将AX中非压缩BCD码扩展成二进制数
例子:
mov ax,0608h //ax=0608h,非压缩BCD码表示真值68 mov bl,09h //bl=09h,非压缩BCD码表示真值9 aad div bl ;除法运算:商al=07h,余数ah=05h,实现非压缩BCD码除法:68÷9=7(余5)
位操作指令
AND:
格式: AND OPRD1,OPRD2
功能: 对两个操作数实现按位逻辑与运算,结果送至目的操作数.本指令可以进行字节或字的‘与’运算,OPRD1<--OPRD1 and OPRD2.
AND reg,imm/reg/mem AND mem,imm/reg
作用:
1 判断一个数某位是0还是1
1001 & 1000 //判断最高位是否为1 ------------ 1000 //得到最高位为1
2 给数字的某一位置为0
1111 & 1000 ------ 1000 //后三位被置为了0
注意:AND指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
and ax,not 1(1取反)
逻辑或运算
OR
作用:置数字的某位数为1
OR reg,imm/reg/mem OR mem,imm/reg
注意:OR指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
逻辑异或指令
XOR
作用:对某个数子的某些位数取反
例子:最高位4位取反
1010 1010 xor 1111 0000 -------------- 0101 1010
注意:XOR指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
逻辑非指令
NOT
NOT reg/mem
注意:NOT指令是一个单操作数指令,NOT指令不影响标志位
测试指令
TEST
作用:Test命令将两个操作数进行逻辑与运算,并根据运算结果设置相关的标志位。但是,Test命令的两个操作数不会被改变。运算结果在设置过相关标记位后会被丢弃
TEST reg,imm/reg/mem TEST mem,imm/reg
注意:AND指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
例子:
test al,01h ;测试AL的最低位D0 jnz there ;标志ZF=0,即D0=1 ;则程序转移到there ... ;否则ZF=1,即D0=0,顺序执行 there: ...
移位指令
SHL reg/mem,1/CL //逻辑左移 SHR reg/mem,1/CL //逻辑右移 SAL reg/mem,1/CL //算数左移 SAR reg/mem,1/CL //算数右移
移位指令的第一个操作数是指定的被移位的操作数,可以是寄存器或存储单元,后一个操作数表示移位位数,该操作数为1,表示移动一位;当移位位数大于1时,则用CL寄存器值表示,该操作数表达为CL
移位指令对标志的影响
按照移入的位设置进位标志CF
根据移位后的结果影响SF、ZF、PF
对AF没有定义
如果进行一位移动,则按照操作数的最高符号位是否改变,相应设置溢出标志OF:如果移位前的操作数最高位与移位后操作数的最高位不同(有变化),则OF = 1;否则OF = 0。当移位次数大于1时,OF不确定
----------------------------------------------------------------------------------------------------------------------------
逻辑左移
shl :各二进制位全部左移若干位,高位丢弃,低位补0
每移动一次写一行代码是赚的,连续唯一是效率低的 注意最高位去cl位了,没有丢弃,最高位会一直覆盖最高位 shl 取代乘2的乘法
逻辑右移
shr :各二进位全部右移若干位,低位丢弃,高位补0或者补符号位
每移动一次写一行代码是赚的,高位补0 shr 取代除2的除法,注意是整除的情况下才可以
算数左移
sal
sal和shl 一样的,反汇编不会翻译sal,debug没有sal 指令
算数右移 :
sar
注意:高位补符号位
循环移位:
ROL reg/mem,1/CL ;不带进位循环左移 ROR reg/mem,1/CL ;不带进位循环右移 RCL reg/mem,1/CL ;带进位循环左移 ,进位保存在cf,下次循环+cf的进位值 RCR reg/mem,1/CL ;带进位循环右移 , 进位保存在cf,下次循环+cf的进位值
作用:
高4位和低4位互换,应用在加密算法 比如一个8位的数,判断有多少个1,这个数字移动8次就能数出有多少个1,并且不改变源数
带进位循环示意图
循环移位指令对标志的影响
按照指令功能设置进位标志CF
不影响SF、ZF、PF、AF
如果进行一位移动,则按照操作数的最高符号位是否改变,相应设置溢出标志OF:如果移位前的操作数最高位与移位后操作数的最高位不同(有变化),则OF = 1;否则OF = 0。当移位次数大于1时,OF不确定
串操作指令
串操作指令是8086指令系统中比较独特的一类指令,采用比较特殊的数据串寻址方式,在操作主存连续区域的数据时,特别好用、因而常用
重点掌握: MOVS STOS LODS CMPS SCAS REP 一般了解: REPZ/REPE REPNZ/REPNE
串寻址方式
源操作数用寄存器SI寻址,默认在数据段DS中,但允许段超越:DS:[SI] 目的操作数用寄存器DI寻址,默认在附加段ES中,不允许段超越:ES:[DI] 每执行一次串操作指令,SI和DI将自动修改: ±1(对于字节串)或±2(对于字串) 执行指令CLD指令后,DF = 0,地址指针增1或2 执行指令STD指令后,DF = 1,地址指针减1或2
MOVS串传送 memcpy
作用:把字节或字操作数从主存的源地址传送至目的地址
MOVSB
MOVSB ;字节串传送:ES:[DI]←DS:[SI] //段寄存器ds:si的位置传送到段寄存器es:di的位置 ;SI←SI±1,DI←DI±1 //si di自动加1
例子:
mov si,offset source //源偏移地址 mov di,offset destination//目的偏移地址 movsb //传送一个字节
MOVSW
MOVSW ;字串传送:ES:[DI]←DS:[SI] ;SI←SI±2,DI←DI±2 //si di自动加2
MOVSB:传送一个字节,之后SI和DI(或者ESI和EDI)加/减1
MOVSW:传送一个字 =2字节,之后SI和DI(或者ESI和EDI)加/减2
MOVSD:传送一个双字 =4字节,之后SI和DI(或者ESI和EDI)加/减4
STOS串存储 memset
作用:把AL或AX数据传送至目的地址
STOSB ;字节串存储:ES:[DI]←AL ;DI←DI±1
STOSW ;字串存储:ES:[DI]←AX ;DI←DI±2
例子:
CLD //置标志为DF=0 MOV AL,3 //赋值al寄存器为3 LEA DI,[EA] //赋值目的地址指针 STOSW //执行指令使al中的内容拷贝到di目的地址
LODS串读取
相当于memchr :在内存中搜索二进制数据
作用:把指定主存单元的数据传送给AL或AX
LODSB ;字节串读取:AL←DS:[SI] ;SI←SI±1
LODSW ;字串读取:AX←DS:[SI] ;SI←SI±2
例子:
CLD //置标志为DF=0 MOV SI,[EA] //初始si指针的偏移位置 LODSW //执行指令赋值一个子数据到AX
CMPS串比较
将主存中的源操作数减去至目的操作数,以便设置标志,进而比较两操作数之间的关系
简而言之:
意思就是 源内存中的数(可以理解为数,也可能是字符串的ASCII码) 减去 目的内存中的数,根据结果设置标志位
比如 源内存 的数字是 1 目的内存中 也是1 那么 1 -1 就为0,0是结果,根据结果设置一下标志位 则ZF = 1,也就是源和目的相等,相当于memcmp
CMPSB ;字节串比较:DS:[SI]-ES:[DI] ,SI←SI±1,DI←DI±1
CMPSW ;字串比较:DS:[SI]-ES:[DI],SI←SI±2,DI←DI±2
SCAS串扫描
将AL/AX减去至目的操作数,以便设置标志,进而比较AL/AX与操作数之间的关系
简而言之:
就是你要搜索的字节,放到AL,或者AX中,然后会和DI去比较,然后根据结果设置标志,在C语言中,这个相当于 memchr命令:
从buff所指内存区域的前count个字节查找字符ch。 void *memchr( const void *buf, int c, size_t count );
SCASB ;字节串扫描:AL-ES:[DI] ,DI←DI±1
SCASW ;字串扫描:AX-ES:[DI], DI←DI±2
REPEAT重复前缀指令
简单理解为就是为串操作单独提供的循环指令,比如我们上面要用MOVS串操作指令的时候,把源寄存器中的值,拷贝到目的寄存器中,假设我们有个HELLO 我们要使用五次 MOVSB命令才能拷贝过去
现在提供了一个为串操作的循环
重复前缀分为两类,3条指令
1.配合使用,MOVS,STOS,LODS 的时候,使用指令REP前缀,不影响标志
2.配合使用 CMPS,SCAS,指令,使用REPZ和REPNZ前缀
然后重复次数放到cx寄存器中
mov cx,3 rep movsb
REP前缀可以理解为:当数据串没有结束(CX≠0),则继续传送
REPZ,和REPNZ解析
REPZ: 1.每次执行串指令,则CX-1 2.判断零标志位(ZF)是否为零 3.如果CX == 0,或者 ZF == 0 则重复执行结束 注意可以简单理解为,cx !=0 && zf == 1 的时候继续循环 ----------------------------------------------------- REPNZ: 1.每次执行串指令,则CX-1 2.判断零标志位(ZF)是否为1 3.如果CX == 0,或者 ZF ==1 则重复执行结束 REPNZ/REPNE的前缀,可以简单理解为 cx != 0 && zf ==0 的时候继续.
机器代码F3,表示指令重复执行
注意:带循环的指令用 -T 进去看
repz,默认z可以不写:重复执行命令
补充:
ptr 指令相当于c语言的强转
mov ax,word ptr [bx]; 是把内存地址等于“BX寄存器的值”的地方所存放的数据,赋予ax。由于只是给出一个内存地址,不知道希望赋予ax的,是byte还是word,所以可以用word明确指出;如果不用,既(mov ax, [bx]; )则在8086中是默认传递一个字,既两个字节给ax
or 是或运算,A OR B的结果:当A、B中只要有一个或者两个都为1时,结果为1,否则为0;
xor 是异或运算,A XOR B的结果:当A、B两个不同时结果为1,否则为0。
键盘两个寄存器:1 一个存按了什么 2 一个存标志位
-r ip 修改下一条指令
int 21 是指令执行功能调用,相当于已经封装好的类
》0《0??标志位判断
ffff -1为-2的补码
1000 0010 //-2的源码 1111 1101 //取反 1111 1110 //取反加1 =FE
一个int最大为 42亿
对标志没有定义:指令执行后这些标志是任意的、不可预测(就是谁也不知道是0还是1)
对标志没有影响:指令执行不改变标志状态
ax,0fffh 加0代表十六进制
公交和广告牌,空调都用bcd码,常用在单片机上
NUM 1 dw 2,dup(2) 作用为定义两个dw类型的2
c语言位移根据类型判断
--------------------------------------------------------------------------------------------------------------
1 、OFFSET是将数值回送变量或标号的偏移地址值. ,一般用于全局变量
2. LEA是将数值回送变量或标号的有效地址值.