序 言

序 言


上一页 返回目录 下一页

C 的经典入门例子:

int main()
{
    printf("Hello, World\n");

    return 0;
}

那么,我们来看看 x86 体系下的两个指令 encode 例子:

1. 在当前 32 位系统下,有下面汇编语句(Intel 格式):

mov word ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678

从这条语句,我们可以得出以下信息:

  • 这是一条 mov 指令
  • first operand(目标操作数)是 memory
  • second operand(源操作数)是 immediate

对于 memory 操作数,我们还了解到:

  • operand size(操作数大小)是 word
  • address size(地址大小)是 32 位
  • memmory 寻址是 [base + index * 8 + displacement32]

对于 immediate 操作数,我们了解到:

  • operand size 是 double word

显然:

first operand(目标操作数)的 operand size 大小是 word(2个字节),而 second operand(源操作数)却是一个 double word 大小的 0x12345678,在这条指令中存在 operand size 不兼容的情况。

那么:对于这条汇编语句,编译器应该如何处理呢?

  • 应该怎样处理 immediate 部分
  • 应该选择哪条 mov 指令
  • 指令最终的 operand size 是多少
  • 在 32 位环境下,如何生成 16 位 operand 或 address 的代码
  • 寻址模式是什么

这些问题是我们最终需要掌握的知识,这是本栏目的最终目的。

实际上,它最终形成的机器编码是:26 66 c7 84 c8 44 33 22 11 78 56

  1. double word 大小的源操作数,会被编译器截断为 word 大小
  2. 选择 MOV Ev, Iz 指令,它的 opcode 是 C7
  3. 最终指令的 operand size 是 word 大小,取决于 first operand 的 size
  4. 在 32 位下,通过使用 operand size override 可以造型为 16 位 operands size,使用 address size override 可以造型为 16 位 address size
  5. 它的寻址模式是:基址+变址寻址,它需要提供 SIB 字节

下面的图直观的分解这条指令的组成部分:

mov word ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678
    -------- --- ---   ---  --   -----------  ----------
       |      |   |     |    |        |            |
       +------|---|-----|----|--------|------------|---------------> operand-size override
              |   |     |    |        |            |
              +---|-----|----|--------|------------|---------------> segment override
                  |     |    |        |            |
                  +-----|----|--------|------------|---------------> base
                        |    |        |            |
                        +----|--------|------------|---------------> index
                             |        |            |
                             +--------|------------|---------------> scale
                                      |            |
                                      +------------|---------------> displacement
                                                   |
                                                   +---------------> immediate


operand-size override: 66H -- prefix
segment override:       26H -- prefix
base:                   SIB.base = 000
index:                  SIB.index = 001
scale:                  SIB.scale = 11
displacement:           44 33 22 11
immediate:              78 56 34 12

这条指令的 encodes 各个部分的意义是:

  • 26:指令的 prefix 部分,它是 semgent overrride prefix ,作用是调整内存操作数的段选择子
  • 66:指令的 prefix 部分,它是 operand size override prefix ,作用是调整操作数的缺省大小
  • C7:指令的 Opcode 部分,是 mov 指令是操作码
  • 84:指令的 ModRM 部分,定义操作数的属性
  • C8:指令的 SIB 部分,定义内存操作数的属性
  • 44332211:指令的 displacement 值
  • 7856:指令的 immediate 值

2. 随便找一个机器码如:FF 15 D4 81 DF 00

那么它的汇编语句是什么呢?

解码器会依次读入第 1 个字节,第 2 个字节等 ... 进行判断:

  1. 第 1 个字节是什么? prefix 还是 opcode
  2. 同样再判断第 2 个字节是不是 prefix,如果不是 prefix ,那么它就是 opcode 码
  3. 如果第 2 个字节是 opcode 码,再判这个 opcode 需不需 ModRM 字节,如果需要,第 3 个字节就是 ModRM 字节
  4. 根据 ModRM 字节判断需不需要 SIB 字节,第 4 个字节如果需它就是 SIB 字节
  5. 判断 ModRM 字节是否需要 displacment 字节和 immediate 字节

根据上面的逻辑,得出:

  1. FF:这个字节是个具有 Group 属性的 Opcode 码,它进行什么操作需要依赖于 ModRM 字节的 Reg 域 换句话来说,FF 并不是完整独立的 Opcode 码,它要联合 ModRM 才能确定具体的操作。
  2. 15:这个是 ModRM 字节(mod-reg-r/m): ModRM.mod = 00,ModRM.reg = 010,ModRM.r/m = 101。 其中 ModRM.reg 域被 FF(opcode) 作为确定具体操作码的参考。
  3. Opcode + ModRm.regFF /010 最终确定为:Call 指令。
  4. ModRM.mod = 00:表示操作数是 memory
  5. ModRM.r/m = 101:memory 操作数是一个 32 位的 displacement 值

所以,这个机器码最终被解码为: call dword ptr [00DF81D4]

下面的直观的图表

FF  15  D4 81 DF 00
--  --  -----------
|   |       |
+---|-------|----------------> opcode: FF (Opcode Group)
    |       |
    +-------|----------------> ModRM:  00-010-101
            |
            +----------------> displacement: d4 81 df 00


opcode:  FF + ModRM.reg = FF /010 ===> call Ev
ModRM:   ModRM.mod + ModRM.r/m    ===> [disp32]

这 2 个例子,作为对学习 x86/x64 指令编码的一个感性认识。接下来的章节逐一剖析 x86/x64 指令编码的来龙去脉。

 

上一页 返回目录 下一页


版权所有 mik  2008 - 2011

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值