x86指令格式

来源:互联网 发布:pyqt4 linux 安装 编辑:程序博客网 时间:2024/05/21 14:47

当计算机处理器芯片运行时,它读取存储在内存中的指令码。每个指令码集合可能包含一个或多个字节的信息,这些信息指示处理器完成特定的任务。每条指令码都是从内存中读取的,指令码所需的数据也是存储在内存中并从内存中读取。包含指令码的内存字节和包含处理器使用的数据的字节没有区别。


    为了区分数据和指令码,要使用专门的指针(pointer)帮助处理器跟踪数据和指令码存储在内存中的位置。


    指令指针(instruction pointer) 用于帮助处理器了解哪些指令码已经处理过了,以及接下来要处理的是哪条指令码。有些专门的指令能够改变指令指针的位置,比如跳转到程序的特定位置。


    数据指针(data pointer) 用于帮助处理器了解内存中数据区域的起始位置。这个区域称为 堆栈(stack),当新的数据元素被放入到堆栈中时,指针在内存中“向下”移动。当数据被读取出堆栈时,指针在内存中“向上”移动。

每条指令都必须至少包含1个字节的操作码(operation code,简写为 opcode)。操作码定义处理器应该完成什么操作。每个处理器系列都具有其自己的预定义好的操作码,它们定义所有可用的功能。


指令码格式:

IA-32指令码格式由四个主要部分构成:,


    a) 可选的指令前缀;

            指令前缀可以包含1个到4个修改操作码行为的 1 字节前缀。安装前缀的功能,这些前缀被分为 4 个组。修改操作码时,每个组的前缀一次只能使用一个(因此最多有4 个前缀字节)。这 4 个前缀组如下:

                @a1@ 锁定前缀和重复前缀

                        锁定前缀表示指令将独占的使用共享内存区域。这对于多处理器和超级线程系统非常重要。

                        重复前缀用于表示重复的功能(常常在处理字符串时使用)。

                @a2@段覆盖前缀和分支提示前缀

                        段覆盖前缀定义可以覆盖定义了的段寄存器的指令。

                        分支提示前缀尝试向处理器提供程序在条件跳转语句中最可能的路径的线索(这同预报分支的硬件一起使用)。

                @a3@操作数长度覆盖前缀

                        操作数长度覆盖前缀通知处理器,程序将在这个操作码之内切换 16 位 和 32 位的操作数长度。这使程序可以再使用大长度的操作码时警告处理器,帮助加快对寄存器的数据赋值。

                @a4@地址长度覆盖前缀

                        地址长度覆盖前缀通知处理器,程序将切换 16 位 和 32 位的内存地址。这两种长度都可以被声明为程序的默认长度,这个前缀通知处理器程序将切换到另一个长度          

    b) 操作码(opcode)

            IA-32指令码格式中唯一必须的不是就是操作码。每个指令码都必须包含操作码,它定义了处理器执行的基本功能或任务。

            操作码的长度在 1 到 3 字节之间,它唯一地定义要执行的功能。

            例如:2字节的操作码 OF A2定义了IA-32 CPUID指令。当处理器执行这个指令码时,它返回不同寄存器中关于微处理器的特定信息。

            注:寄存器是处理器芯片之内的组件,用于临时存储处理器正在处理的数据。

    c) 可选的修饰符

            一些操作码需要另外的修饰符来定义执行的功能中涉及到什么寄存器和内存位置。修饰符包含在 3 个单独的值中:

                @a1@ 寻址方式说明符(ModR/W)字节

                        ModR/W字节由 3 个字段的信息构成,如下:

                        mod 字段 和 r/m 字段一起使用,用于定义指令中使用的寄存器或者寻址模式。在指令中,可能的寻址模式有 24个,加上 8 个可以使用的通用寄存器,所以又32个可能值。


                        reg/opcode 字段用于运行使用更多的 3 位 进一步定义操作码功能(比如操作码子功能),或者可以用于定义寄存器。


                        r/m 字段用于定义用作该功能的操作数的另一个寄存器,或者可以把它和 mod 字段组合在一起定义指令的寻址模式。

                @a2@ 比例-索引-基址(SIB)字节

                        SIB字节也由 3 个字段的信息构成,如下:

                        比例 字段指定操作的比例因子。

                        索引 字段指定内存访问中用作索引寄存器的寄存器。

                        基址 字段指定用作内存访问的基址寄存器的寄存器。


                        ModR/M 和 SIB 字节的组合创建一个表,它可以定义用于访问数据的众多可能的寄存器组合和内存模式。


                @a3@ 1,2或4个的地址移位字节

                        地址移位 字节用来指定对于 ModR/W 和 SIB 字节中定义的内存位置的偏移量。可以使用它作为基本内存位置的索引,用于存储或者访问内存的数据。            


    d) 可选的数据元素

            指令码的最后一部分是该功能使用的数据元素。

            一些指令码从内存位置或者处理器寄存器读取数据,而一些指令码在其本身之内包含数据。这个值经常被用于表示静态数字值(比如要加的数字)或者内存位置。根据数据长度,这个值可以包含 1,2,或者 4 字节的信息。



例子:

指令码:C7 45 FC 01 00 00 00

    它定义操作码 C7,这个操作码是把值传送到内存位置的指令。

    修饰符 45 FC 定义了内存位置(它定义从 ESP 寄存器中的值(值 45)指向的内存位置开始的 4 个字节(值FC))。

    最后 4 个字节定义放到这个内存位置的整数值(在当前例子中这个值是 1)。


注:从这个例子可以看出,值 1 被写为 4 个字节的 十六进制值 01 00 00 00。数据流中的字节的顺序取决于是用的处理器的类型。

      IA-32平台处理器使用“小端(little-endian)”表示法。其中低值的字节首先出现(当从左到有读取)。

      其他处理器使用“大端(bit-endian)”表示法,其中高值字节首先出现。

      在汇编语言程序中指定数据和内存位置值时,这一概念非常重要。