• 转载的指令仅用于自己学习 指令集合


    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)加/减
    MOVSW:传送一个字 =2字节,之后SI和DI(或者ESI和EDI)加/减
    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是将数值回送变量或标号的有效地址值.
  • 相关阅读:
    configure: error: Unable to use libevent (libevent check failed)
    ZABBIX修改用户名密码
    《平凡的世界》
    Directory "/usr/share/zabbix/assets" must be writable.
    《人生第一次》纪录片
    前端语言开发模板
    cometd源码阅读SecurityPolicy授权模块(十二)
    设计思路已读未读设计
    cometd源码阅读Extension扩展(十)
    计算2个时间相差多少天多少分钟多少秒
  • 原文地址:https://www.cnblogs.com/nanfengnan/p/13882236.html
Copyright © 2020-2023  润新知