29

我正在阅读一些关于汇编指令的英特尔操作码的材料,但我不明白操作码字节后面的含义是什么。例如:cw, cd, /2, cp, /3.

请给我一个提示这是什么意思或我在哪里可以找到完整的参考?

E8 cw CALL rel16 调用近、相对、相对于下一条指令的位移
E8 cd CALL rel32 调用近、相对、相对于下一条指令的位移
FF /2 CALL r/m16 近调用,绝对间接,在 r/m16 中给出的地址
FF /2 CALL r/m32 近调用,绝对间接,在 r/m32 中给出的地址
9A cd CALL ptr16:16 调用远、绝对、在操作数中给出的地址
9A cp CALL ptr16:32 调用远、绝对、操作数中给出的地址
FF /3 CALL m16:16 呼叫远,绝对间接,在 m16:16 中给出地址
FF /3 CALL m16:32 呼叫远,绝对间接,在 m16:32 中给出地址
4

3 回答 3

33
于 2017-01-12T15:14:24.723 回答
21

我最喜欢的来源是英特尔本身:英特尔® 64 和 IA-32 架构软件开发人员手册。与过去的版本不同,所有卷现在都很好地包装在一个(3044 页)PDF 中。

看起来对您最有帮助的部分是第 2 卷第 3 章中的 3.1.1.1(截至我撰写本文时最新 PDF 的第 432 页)。

于 2013-02-22T05:48:07.660 回答
10

许多用于立即版本指令的操作码,包括使用ModR/M 字节中83的 3 位/r字段作为 3 个额外的操作码位。英特尔的第 2 卷手册记录了这一点,我认为附录中的操作码表包括它。

这就是为什么大多数原始 8086 立即数指令and r/m, imm仍然只允许 2 个操作数,不像shrd eax, edx, 4imul edx, [rdi], 12345其中两个 ModRM 字段都用于编码 dst/src 操作数,以及暗示立即操作数的操作码。

SHRD/SHLD 并添加了 386,并且 imul-immediate 添加了 186 。不幸的是,copy-and-AND ( and eax, edx, 0xf) 不可编码,但至少 x86 可以使用 LEA 进行非常常见的复制和添加或子操作。

但是,如果每个立即数和单操作数指令(如pushor not)都需要一个完整的操作码,那么 8086 就会用完 1 字节的操作码。(特别是因为设计者选择在 AL 和 AX 没有 modrm 字节的短格式上花费大量编码空间,比如cmp ax, 12345在 16 位模式下只有 3 个字节而不是 4 个字节,或者在 32cmp eax, imm32中只有 5 个字节而不是 6 个字节cmp r/m32, imm32-bit 模式。对于单字节 xchg-with-ax 和单字节 inc/dec 寄存器。)


示例:解码48 83 C4 38 (从一个操作码字节如何根据“寄存器/操作码”字段解码为不同的指令?那是什么?,这个Q的副本)

48是一个 REX.W 前缀(REX 只设置了 W 位,因此它表示 64 位操作数大小,但没有高位寄存器)。

Opcode83说它可以是 7 条不同的指令,具体取决于称为“寄存器/操作码字段”的字段

每条指令都有自己的文档,例如add(vol2 手册的 html 摘录)
REX.W + 83 /0 ib ,显示了 for之类的编码ADD r/m64, imm8,这就是您所拥有的。

来自 wiki.osdev.org 的 ModRM 位域图

  7                           0
+---+---+---+---+---+---+---+---+
|  mod  |    reg    |     rm    |
+---+---+---+---+---+---+---+---+

0xc4 = 0b11000100,所以 reg 字段 = 0。因此我们的操作码是83 /0,在 Intel 的表示法中。

其余的 ModRM 字段是:

  • mode = 0b11,因此 rm 字段编码一个寄存器操作数,而不是寻址模式的基址寄存器。
  • rm = 0b100。reg #4 = SPL/SP/ESP/RSP。(在这种情况下,RSP 因为它是 64 位操作数大小)。请参阅英特尔的手册,或https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers获取表格。

所以指令是add rsp, 0x38

ndisasm -b64同意:

$ cat > foo.asm
db 0x48, 0x83, 0xC4, 0x38
$ nasm foo.asm     # create a flat binary with those bytes, not an object file
$ ndisasm -b64 foo
00000000  4883C438          add rsp,byte +0x38
于 2018-12-30T08:37:23.430 回答