【发布时间】: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 段的位移?这是指令的默认值,还是在某个地方也进行了编码?段覆盖字节是否与此有关?
正如你们当中精通的人现在可能已经注意到的那样,我在这个领域几乎是个新手,我不得不真正考虑在这里发帖,因为有些人会变得有点专横或光顾一个“无聊”的问题,但我真的可以在这里使用一些帮助。
如果我对事物的理解有误,请纠正我,如果有人愿意大致解释编码的工作原理,我将不胜感激。
提前致谢!
【问题讨论】: