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

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    5-python基础—获取某个目录下的文件列表(适用于任何系统)
    Automated, Self-Service Provisioning of VMs Using HyperForm (Part 1) (使用HyperForm自动配置虚拟机(第1部分)
    CloudStack Support in Apache libcloud(Apache libcloud中对CloudStack支持)
    Deploying MicroProfile-Based Java Apps to Bluemix(将基于MicroProfile的Java应用程序部署到Bluemix)
    Adding Persistent Storage to Red Hat CDK Kit 3.0 (在Red Hat CDK Kit 3.0添加永久性存储)
    Carve Your Laptop Into VMs Using Vagrant(使用Vagran把您笔记本电脑刻录成虚拟机)
    使用Python生成一张用于登陆验证的字符图片
    Jupyter notebook的安装方法
    Ubuntu16.04使用Anaconda5搭建TensorFlow使用环境 图文详细教程
    不同时区的换算
  • 原文地址:https://www.cnblogs.com/yuliyang/p/3449159.html
Copyright © 2011-2022 走看看