【问题标题】:i386 Assembler Instruction Encodingi386 汇编指令编码
【发布时间】:2014-05-28 04:21:35
【问题描述】:

我试图了解为 i386/x86 编译的程序中的指令是如何编码的(我使用 http://ref.x86asm.net/coder32.html 作为参考),但我似乎无法掌握这个问题,尽管文档非常好。如果有人可以向我解释这一点,我会非常高兴。

到目前为止,我已经收集到一条指令的编码如下:

Prefix (1 byte) [optional]
Opcode (1 or 2 byte, depending on prefix)
ModR/M (1 byte) [optional]
SIB (1 byte) [optional]
Displacement (1-4 bytes) [optional]
Immediate Value (1-4 bytes) [optional]

可选参数取决于要执行的实际操作,分别。操作码。

假设我有以下简单明了的说明:

6A 4D     push   4Dh

这对我来说没关系,我明白这一点。 6A是操作码,8字节中间值为4Dh。

让我们走得更远:

51     push    ecx

同样的处理,只是 ECX 寄存器的操作码为 50 + 1 作为 r32 操作数。

但是这个呢?

FF 15 F8 2A 42 00     call   DWORD PTR ds:0x422AF8

我知道第一个字节是 CALL 的操作码,第二个是 ModR/M,mod == 00, reg == 010 和 r/m == 101,它指定了一个位移,即F8 2A 42 00 的最后四个字节。

我不明白的是两件事:

首先,根据我上面提到的链接中的表格,FF 操作码可以有多种用途,例如 PUSH、CALL 或 JMP 的变体。唯一的区别似乎是所谓的“操作码扩展”,对于此处的示例来说,它是“2”。这是在哪里编码的?我的反汇编程序如何知道它是 CALL 的 FF,而不是 JMP 的 FF?

其次,为什么这个操作数是 DS 段的位移?这是指令的默认值,还是在某个地方也进行了编码?段覆盖字节是否与此有关?

正如你们当中精通的人现在可能已经注意到的那样,我在这个领域几乎是个新手,我不得不真正考虑在这里发帖,因为有些人会变得有点专横或光顾一个“无聊”的问题,但我真的可以在这里使用一些帮助。

如果我对事物的理解有误,请纠正我,如果有人愿意大致解释编码的工作原理,我将不胜感激。

提前致谢!

【问题讨论】:

    标签: assembly opcode i386


    【解决方案1】:

    您应该阅读官方英特尔指令集参考,而不是那些简洁的在线材料,其中详细解释了所有这些。让我引用相关段落:

    /digit -- 0 到 7 之间的数字表示 ModR/M 字节 该指令仅使用 r/m(寄存器或内存)操作数。这 reg 字段包含提供扩展名的数字 指令的操作码。

    请注意,在您的情况下,modr/m 字节是您解析错误的 0x15。它是二进制的0001 0101,表示 mod=00、reg=010 和 r/m=101。如您所见,reg 字段确实为 2,编码了正确的操作码扩展名。

    至于段问题:是的,访问内存的指令有一个与之关联的默认段,可以用前缀覆盖。反汇编程序可能显示也可能不显示默认段。如果存在实际覆盖,我个人更喜欢它只显示片段。

    【讨论】:

    • 哦,这只是一个错字,抱歉 - 我在帖子中更正了。感谢您的解释,现在它更有意义了。所以 /digit 可以被认为是操作码的“后缀”,以进一步确定它的行为,我明白了。
    【解决方案2】:

    扩展的操作码内容,在手册中写为 /digit,被编码在 ModRM 字节的 R 字段中。在示例中 ModRM 字节为 15,因此 00 010 101 并且您可以看到 R 字段为 2(如预期的那样)。

    ds 是默认值,因此未编码。段覆盖与它有关,但在这种情况下不需要覆盖。

    注意你可以有多个前缀,例如一个段覆盖,一个操作数大小覆盖,一个地址大小覆盖和一个锁前缀(4字节的前缀),你甚至可以有冗余前缀,基本上放尽可能多的前缀你想要,只要你不让整个指令长于 15 个字节(在非常旧的处理器上限制较低)。

    另外,一些新指令有 3 个操作码字节,请参见 0F 38 XX0F 3A XX 组。

    【讨论】:

    • 感谢您的澄清 - 连同 Jester 的回答,这对我来说终于有意义了 :)
    【解决方案3】:

    我喜欢使用英特尔手册中的这些旧表:

    Instruction Prefix                0 oder 1 Byte
    Address-Size Prefix               0 oder 1 Byte
    Operand-Size Prefix               0 oder 1 Byte
    Segment Prefix                    0 oder 1 Byte
    Opcode                            1 oder 2 Byte
    Mod R/M                           0 oder 1 Byte
    SIB, Scale Index Base (386+)      0 oder 1 Byte
    Displacement                      0, 1, 2 oder 4 Byte (4 nur 386+)
    Immediate                         0, 1, 2 oder 4 Byte (4 nur 386+)
    
    Format of Postbyte(Mod R/M aus Intel-Doku)
    ------------------------------------------
    MM RRR MMM
    
    MM  - Memeory addressing mode
    RRR - Register operand address
    MMM - Memoy operand address
    
    RRR Register Names
    Filds  8bit  16bit  32bit
    000    AL     AX     EAX
    001    CL     CX     ECX
    010    DL     DX     EDX
    011    Bl     BX     EBX
    100    AH     SP     ESP
    101    CH     BP     EBP
    110    DH     SI     ESI
    111    BH     DI     EDI
    
    16bit memory (No 32 bit memory address prefix)
    MMM   Default MM Field
    Field Sreg     00        01          10             11=MMM is reg
    000   DS       [BX+SI]   [BX+SI+o8]  [BX+SI+o16]
    001   DS       [BX+DI]   [BX+DI+o8]  [BX+DI+o16]
    010   SS       [BP+SI]   [BP+SI+o8]  [BP+SI+o16]
    011   SS       [BP+DI]   [BP+DI+o8]  [BP+DI+o16]
    100   DS       [SI]      [SI+o8]     [SI+o16]
    101   DS       [DI]      [DI+o8]     [SI+o16]
    110   SS       [o16]     [BP+o8]     [BP+o16]
    111   DS       [BX]      [BX+o8]     [BX+o16]
    Note: MMM=110,MM=0 Default Sreg is DS !!!!
    
    32bit memory (Has 67h 32 bit memory address prefix)
    MMM   Default MM Field
    Field Sreg     00        01          10             11=MMM is reg
    000   DS       [EAX]     [EAX+o8]    [EAX+o32]
    001   DS       [ECX]     [ECX+o8]    [ECX+o32]
    010   DS       [EDX]     [EDX+o8]    [EDX+o32]
    011   DS       [EBX]     [EBX+o8]    [EBX+o32]
    100   SIB      [SIB]     [SIB+o8]    [SIB+o32]
    101   SS       [o32]     [EBP+o8]    [EBP+o32]
    110   DS       [ESI]     [ESI+o8]    [ESI+o32]
    111   DS       [EDI]     [EDI+o8]    [EDI+o32]
    Note: MMM=110,MM=0 Default Sreg is DS !!!!
    
    SIB is (Scale/Base/Index)
    SS BBB III
    Note: SIB address calculated as:
    <sib address>=<Base>+<Index>*(2^(Scale))
    
    Fild   Default Base
    BBB    Sreg    Register   Note
    000    DS      EAX
    001    DS      ECX
    010    DS      EDX
    011    DS      EBX
    100    SS      ESP
    101    DS      o32        if MM=00 (Postbyte)
           SS      EBP        if MM<>00 (Postbyte)
    110    SS      ESI
    111    DS      EDI
    
    Fild  Index
    III   register   Note
    000   EAX
    001   ECX
    010   EDX
    011   EBX
    100              never Index SS can be 00
    101   EBP
    110   ESI
    111   EDI
    
    Fild Scale coefficient
    SS   =2^(SS)
    00   1
    01   2
    10   4
    11   8
    

    【讨论】:

    猜你喜欢
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 2012-02-27
    • 2011-11-22
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多