学习笔记分享之汇编---2. 汇编指令&语法

前言:
  此文章收录在本人的《学习笔记分享》分类中,此分类记录本人的学习心得体会,现全部分享出来希望和大家共同交流学习成长。附上分类链接:
  https://www.cnblogs.com/tibbors/category/1729804.html

学习内容:汇编指令&语法:

  1. 拷贝源操作数到目标操作数:

    mov 目标操作数,源操作数

    • 源操作数可以是任意单元(r/m/sr/imm) (sr:Segment Register)

    • 目标操作数可以是除了立即数之外的任意单元(r/m/sr)

    • 操作数的宽度必须前后一致

    • 源操作数和目标操作数不能同时为内存单元

  2. 加/减/与/或/异或:

    🞕 add/sub/and/or/xor 目标操作数,源操作数

    • 源操作数可以是r/m/imm

    • 目标操作数可以是r/m

    • 操作数的宽度除了源操作数是立即数的情况之外(即:立即数可以是任意位)必须前后一致

    🞕 非:

    • not r/m8   not r/m16   not r/m32
  3. 从指定内存中写入/读取数据:

    mov dword ptr ds:[m],imm   //写

    mov r,dword ptr ds:[r]      //读

    ptr: Point 代表后面是一个指针 (指针即里面存的不是普通的值,而是个地址)
    
    在8086中设置4个16位的段寄存器,用于管理4种段:
    ①数据段---ds(Data Segment):数据段寄存器
    ②代码段---cs(Code Segment):代码段寄存器
    ③堆栈段---ss(Stack Segment):堆栈段寄存器
    ④附加段---es(Extra Segment):附加段寄存器
    
    BYTE 字节 = 8(BIT)
    
    WORD 字  =  16(BIT)
    
    DWORD 双字 =  32(BIT)
    
    1KB = 1024 BYTE
    
  4. 寻址公式

    (LEA与MOV的区别在于MOV是取地址中的值,而LEA是取地址)

    ①[imm]形式

    读取内存的值 向内存中写数据 读取内存编号
    mov r,dword ptr ds:[m] mov dword ptr ds:[m],r/imm lea r,dword ptr ds:[m]

    ②[r]形式

    读取内存的值 向内存中写数据 读取内存编号
    mov r',imm
    mov r'',dword ptr ds:[r']
    mov r,imm
    mov dword ptr ds:[r],imm
    lea r',dword ptr ds:[r'']
    mov r',dword ptr ds:[r'']

    ③[r+imm]形式

    读取内存的值 向内存中写数据 读取内存编号
    mov r',imm 
    mov r'',dword ptr ds:[r'+imm]
    mov r,imm 
    mov dword ptr ds:[r+imm],imm
    lea r,dword ptr ds:[r+imm] 
    mov r,dword ptr ds:[r+imm]

    ④[r+r*(1/2/4/8)]形式

    读取内存的值 向内存中写数据 读取内存编号
    mov r',imm
    mov r'',imm 
    mov r''',dword ptr ds:[r'+r''*4]
    mov r',imm
    mov r'',imm
    mov dword ptr ds:[r'+r''*4],imm
    lea r',dword ptr ds:[r'+r''*4]

    ⑤[r+r*(1/2/4/8)+imm]

    读取内存的值 向内存中写数据 读取内存编号
    mov r',imm
    mov r'',imm
    mov r''',dword ptr ds:[r'+r''*4+8]
    mov r',imm
    mov r'',imm
    mov dword ptr ds:[r'+r''*4+8],imm
    lea r',dword ptr ds:[r'+r''*4+8]
  5. 压栈与出栈
    PUSH与POP的语法:

    PUSH:

    • PUSH r16/32
    • PUSH m16/32
    • PUSH imm8/16/32

    POP:

    • POP r16/32
    • POP m16/32

    🞕 注意:
      PUSH/POP加减2/4是看它PUSH/POP的是16/32位的单元

    🞕 附:
    PUSHAD可将八个通用寄存器中的数据写入内存中,然后即可对八个通用寄存器中的数据进行随意更改
      而更改完之后需要恢复现场,就可以用POPAD再将刚刚PUSHAD出去的八个通用寄存器中的值原封不动的还原回去

  6. 带进/借位加/减法
    ADC/SBB:带 进位/借位 加/减法

    格式:
      ADC/SBB r/m , r/m/imm    两边不能同时为内存,宽度要一样
    计算过程:
      当使用ADC/SBB指令后,在执行加/减法时会先看C位寄存器的值:
      ①C位寄存器值为1----执行加/减法时自动多加/减1
      ②C位寄存器值位0----正常执行加/减法

    e.g.
    ①C位寄存器值为1

    MOV EAX,3
    MOV ECX,1

    将C位寄存器值置为1
    ADC EAX,ECX
    ADC-C位为1

    将C位寄存器值置为1
    SBB EAX,ECX
    SBB-C位为1

    ②C位寄存器值为0

    MOV EAX,3
    MOV ECX,1

    将C位寄存器值置为0
    ADC EAX,ECX
    ADC-C位为0

    将C位寄存器值置为0
    SBB EAX,ECX
    SBB-C位为0

  7. 交换数据:
    XCHG:
      格式:
     XCHG r/m , r/m    两边都必须为容器且不能同时为内存,宽度要一样

    e.g.
    XCHG AL,CL
    XCHG DWORD PTR DS:[12FFC4],EAX
    XCHG BYTE PTR DS:[12FFC4],AL

  8. 移动数据:
    MOVS:
    即:把一块内存中的数据移动到另一块内存中
    内存--内存(注意宽度) (唯一可以两边同时为内存单元的指令)
     此指令默认操作[EDI]和[ESI]寄存器
    格式:
     MOVSB == MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
     MOVSW == MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
     MOVSD == MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
    // 注意:[EDI]搭配的是PTR ES,而不是PTR DS
    计算过程:
      ①将[ESI]中存储的地址 对应的 内存中的值 赋给[EDI] 指定的内存
      ②[ESI]和[EDI]中存储的地址同时 加/减 1/2/4
    注意:
      [ESI]和[EDI]中存储地址 加/减 取决于D位寄存器的值为 0/1

  9. 串存储指令
    STOS(Store inTO String):
     功能:
    将[EAX/AX/AL]中的值存入[EDI]指定的内存单元(注意:不是存入[EDI]) 中 (存入的值的位数由BYTE/WORD/DWORD决定,存入后[EDI]的值加/减 由 D位寄存器的值是0/1 决定)
     格式:
     STOSB == STOS BYTE PTR ES:[EDI]
     STOSW == STOS WORD PTR ES:[EDI]
     STOSD == STOS DWORD PTR ES:[EDI]

  10. 重复指令
    REP:
     功能:
    按计数寄存器(ECX)中指定的次数重复执行字符串指令
    每执行一次,就根据D位寄存器中的值(0/1)把内存地址加/减1/2/4

    MOV ECX,10
       //注意,ECX,10 中的10为十六进制,即十进制的16
    REP MOVSD
    REP STOSD
    
  11. 修改[EIP]寄存器
    补充[关于[EIP]]:
    [EIP]中存储的是一个地址,这个地址就是CPU下一步要去的地方,即决定了CPU即将要执行的代码是什么
    想要修改CPU的行为就要修改[EIP]的值


    🞕 JMP:
     功能:
    只修改[EIP]的值,相当于专用于[EIP]的MOV指令
     格式:
    JMP r/imm
    注: JMP只影响[EIP]。
    完整操作简述为:
    MOV EIP,r/imm


    🞕 CALL:
     功能:
    修改[EIP]的值,和JMP一样,但是CALL会修改[ESP]的值,会把下一行指令的地址压栈,而下一行指令的地址的计算是根据CALL这一行存储的字节数相加得到的,然后[ESP]中的值移动到[ESP-4]的内存地址中,相当于把CALL的下一个地址进行一个PUSH。
     格式:
    CALL r/addr
    注:函数的返回地址就是此处CALL压入栈中的地址值
    完整操作简述为:
    PUSH [CALL的地址+CALL行存储的字节数]
    MOV EIP,m/addr


    🞕 RET:
     功能:
    回到刚刚CALL的位置,出栈,相当于一个POP,然后把CALL的下一个地址写入[EIP]。
     格式:
    RET
    完整操作简述为:

    • LEA ESP,[ESP+4]
    • MOV EIP,[ESP-4]
      (=POP EIP)
  12. 比较指令:
    🞕 CMP:
     功能:
    该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。即:在不改变任何数据的情况下,比较两个操作数的大小,比较结果可以通过Z位、S位寄存器得到。

    • Z = 0 : 操作数1 ≠ 操作数2
    • Z = 1 : 操作数1 = 操作数2
    • S = 0 : 操作数1 > 操作数2
    • S = 1 : 操作数1 < 操作数2
       0001 0000            0010 0000
      -0010 0000           -0001 0000
      =1111 0000           =0001 0000
      
      S=1                  S=0
      

     格式:
    CMP r/m,r/m/imm

    🞕 TEST:
     功能:
    两个数值进行与操作,该指令在一定程序上和CMP指令类似,结果不保存,但是会改变相应标志位。
     格式:
    TEST r/m,r/m/imm
     常见用法:
    用TEST指令判断某个单元是否为0,通过Z位寄存器即可得到结果。
    TEST EAX,EAX

    • Z = 1 : 空
    • Z = 0 :非空

    e.g.
    标准用法

    MOV EAX,3
    TEST EAX,3
    TEST标准用法
    常见用法
    MOV EAX,3
    TEST EAX,EAX
    TEST常见用法(非空)
    MOV EAX,0
    TEST EAX,EAX
    TEST常见用法(空)

posted @ 2020-04-18 17:18  Tibbors  阅读(549)  评论(0编辑  收藏  举报