zoukankan      html  css  js  c++  java
  • 汇编学习

    参考:http://www.luocong.com/learningopcode.htm

    再来看一个例子:

        8B 03    MOV EAX, [DWORD DS:EBX]
    65  8B 03    MOV EAX, [DWORD GS:EBX]
    

    65就是一个Segment override prefix,用来改变默认的段,从上表中我们可以看出:65代表的是段GS。注意!这里也是用默认的概念。

    读者在这里也许会存在一个疑问:默认?我怎么知道当前默认的是哪个段呢?以及为什么要用默认的概念呢?

    答案是这样的:在使用内存中的数据时,处理器必须首先知道它的段地址(Segment)和偏移量(Offset),但是如果在每个地方都要显式地直接指出段地址,那么在OpCode格式中就必须增加一个新的域,这将会比现有的OpCode体系多占用大量的字节,而且处理器也必须多花费额外的时钟周期来进行解码——无论在空间还是时间上,都不值得!

    因此,为了解决这个问题,一个方案诞生了:

    指令由不同的定义被划分为不同的组,每个组各自有一个默认的段:

    CS: for EIP pointer
    ES: 目的操作数是内存单元的串指令(movs, cmps等),在这里源操作数是储存在段DS里面。
    SS: 堆栈操作(push, pop等)
    DS: 剩下的数据操作指令。

    有了这个规则,处理器识别当前应该用哪个段将会变得非常简单而直接:

    1. 如果有“Segment override prefix”,那么就使用这个prefix所指定的段。
    2. 否则就使用默认的段。

    呵呵不要紧,让我们来举个例子看看ModR/M到底是怎么来看的:

    mov edi, ecx	8B F9
    sub edi, ecx	2B F9
    

    注意这两个OpCode的第二个字节——都是F9,再来看看OpCode的格式:

    Prefixes  Code  ModR/M  SIB  Displacement  Immediate
    

    我们在前面说过,在OpCode的格式中,只有Code是必须有的,别的都是可选的。所以,在8B F9和2B F9这两组OpCode中,8B和2B就是Code,(这里没有Prefixes,因为Prefixes只有在前面的章节中所介绍过的那几个:66、67、F2、F3、2E、36、3E、26、64、65、F0)。

    紧接着在Code后面的就是ModR/M了,所以在这两组OpCode中的F9就是ModR/M。(在这里也没有SIBDisplacementImmediate

    F9的4:4格式的二进制是1111 1001,我们把它分解成2:3:3的二进制看看:

    16进制      2进制的2:3:3格式
    F9          11 111 001
    

    也就是:

           Mod: 11
    Reg/Opcode: 111
           R/M: 001
    32bitmodrm

    假设是在32位模式下。从上面的第二个图中可以看到,Mod总共分为00、01、10、11四种情况,每种情况又分别有8种情况。现在Mod是11,所以我们应该看Mod为11的那一栏。

    OK,现在来讨论第二个:Reg/Opcode

    Reg/Opcode中间的那个“/”表示“或”,意思就是,这个地方可以表示为Reg或者Opcode——至于到底什么时候表示Reg,什么时候表示Opcode,这就要由Code来决定了。目前我们不必去深究它,后面会讲明白的,我们只要知道,如果它是表示Opcode,则这个指令必定是2个字节的。

    Reg由3个bit的二进制组成,因此,它可以表示:

    2 ^ 3 = 8
    

    一共8种可能的值。我们知道,常用的通用寄存器恰好也有8个,因此,根据组合数学的常识,可以得到:

    REG && Register

    REG
    Register

    000
    EAX

    001
    ECX

    010
    EDX

    011
    EBX

    100
    ESP

    101
    EBP

    110
    ESI

    111
    EDI

    这是在32位的模式下得到的。

    在16位的模式下,Reg则是表示另外一种“局部”的格式,它的低4位表示寄存器的低地址,高4位表示寄存器的高地址,如下表:

    REG && Register

    REG
    Register

    000
    AL

    001
    CL

    010
    DL

    011
    BL

    100
    AH

    101
    CH

    110
    DH

    111
    BH

    好了,把目光返回到上面的32位ModR/M图,看看最上面,在r32(/r)那一栏中,REG=111表示的就是寄存器EDI

    到目前为止,最后剩下还没讨论的就是R/M。这一栏要与Mod结合起来。我们来看Mod为11的那一栏——R/M为001对应的寄存器是ECX

    好了!大功告成!整理如下:

           Mod: 11  表示应该查看Mod为11的那一栏
    Reg/Opcode: 111 表示的是寄存器EDI
           R/M: 001 表示的是ECX
    

    因此,通过OpCode:

    8B F9
    2B F9
    

    不难得到:

    mov edi, ecx	8B F9
    sub edi, ecx	2B F9
    

    (注:8B是助记符“MOV”的Code,2B是助记符“SUB”的Code

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    悄摸直播(一)—— 推流器的实现(获取笔记本摄像头画面,转流推流到rtmp服务器)
    MySQL知识-MySQL同版本多实例的配置
    Jumpserver-跳板机的搭建
    搭建本地的yum仓库-较简单
    监控-zabbix
    Git-Jenkins-代码的上线
    ELK-日志管理平台
    简单的认识Linux
    工作碰上的技术问题及处理经验(三)
    oracle数据库应用开发经验
  • 原文地址:https://www.cnblogs.com/yuliyang/p/3449159.html
Copyright © 2011-2022 走看看