【发布时间】:2013-03-04 19:55:40
【问题描述】:
我有 32 位操作码:FF 35 0E 20 40 00。有没有人知道一个很好的操作码表来回答这个问题? (我知道我可以使用反汇编程序,但我想知道如何使用操作码表来确定这一点)。我找到了this 网页,但FF 有7 种不同的解决方案。没听懂。
【问题讨论】:
我有 32 位操作码:FF 35 0E 20 40 00。有没有人知道一个很好的操作码表来回答这个问题? (我知道我可以使用反汇编程序,但我想知道如何使用操作码表来确定这一点)。我找到了this 网页,但FF 有7 种不同的解决方案。没听懂。
【问题讨论】:
你找错地方了。您应该在 Intel 或 AMD 的官方文档中查看此内容。
Vol 2B 的Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 3A and 3B 的Appendix A Opcode Map 表示FF 是INC/DEC Grp51A。
Table A-6 Opcode Extensions for One- and Two-byte Opcodes by Group Number of Vol 2B 表示 FF/Group 5 INC、DEC、CALLN、CALLF、JMPN、@987654336、@、@7 中的任何一个ModR/M 字节的第 5 位到第 3 位,即后面的字节。 (0x35>>3)&7=6 或二进制的 110。所以,这是PUSH Ev。
Vol 2A 中的Chapter 2 Instruction Format 解释了一条指令由哪些部分组成,包括那些ModR/M 字节和其他部分。
Vol 2B 的Appendix A Using Opcode Tables 告诉你E:
ModR/M 字节跟在操作码后面并指定操作数。操作数要么是通用寄存器,要么是内存地址。如果是内存地址,则地址是根据段寄存器和以下任何值计算得出的:基址寄存器、索引寄存器、比例因子、位移。
它还告诉你v:
字、双字或四字(在 64 位模式下),取决于操作数大小属性。
所以,您知道Ev 表示寄存器或内存操作数,由于这是用于 32 位代码并且没有指令前缀,因此操作数大小为 32 位。所以,Ev 一个 32 位寄存器或内存中的一个 32 位变量。
现在你需要找出从 ModR/M 到结尾的其余字节。
查看Figure 2-1. Intel 64 and IA-32 Architectures Instruction Format 的Vol 2A。它告诉你在ModR/M=0x35:
Mod = 00(二进制)Reg = 110(二进制;我们之前已提取这 3 位)R/M = 101(二进制)
Vol 2A 的Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte 告诉你Mod = 00 和R/M = 101 表示disp32,IOW,指令中有一个由32 位位移组成的内存操作数。
ModR/M 字节的Reg 字段已用于选择七条指令之一,因此该字段不编码寄存器操作数。
所以,你的指令是PUSH DWORD [0x0040200E]。
这与我的反汇编输出一致。
【讨论】:
让我们尝试一次一个字节地遍历这个字节序列。
FF。在 Intel Instruction Set Reference 中的 Opcode Map 中查找它告诉我们这是一条 INC 或 DEC 指令,以及神秘的“Grp 5 - 1A”。 1A 表示“ModR/M 字节的第 5、4 和 3 位用作操作码扩展”。 ModR/M 字节是对用于该指令的操作数的源和地址进行编码的字节。在这种情况下,这三位用于扩展操作码。35。这是 ModR/M 字节,通常出现在操作码本身之后,在使用它的指令中。 35(十六进制)是二进制的 00110101,所以位 5、4 和 3 是 110。在操作码扩展表(表 A-6)中查找它,我们可以看到这意味着这是一条 PUSH d64 Ev 指令。 d64 脚注表示“在 64 位模式下,指令默认为 64 位操作数大小,无法编码 32 位操作数大小。”。这是PUSH 指令所期望的。 Ev 是一个指定操作数编码的符号 - 最重要的是,它表明 ModR/M 字节跟在操作码本身之后。另一方面,v 表示操作数的大小取决于操作数大小属性。我们已经有了 ModR/M 字节,所以我们来解码它(表 2-2,假设这段代码运行在 32 位模式下):有效地址由 disp32 指定,这意味着 32 位位移应遵循 ModR/M 字节。指定寄存器的部分说应该使用ESI,但在这种情况下,该字段用于操作码扩展,因此不用于表示寄存器源操作数。0E 20 40 00,当解码为小端时,表示0x40200e。这是将用于该指令的操作数的地址。总结一下,我们得到FF 35 0E 20 40 00 是PUSH DWORD [0x40200e],即它将从地址0x40200e 读取的32 位值压入堆栈。
【讨论】: