我正在阅读一些关于英特尔操作码汇编指令的资料,但我无法理解它遵循操作码字节是什么意思。例如:“cw”,“cd”,“/ 2”,“cp”,“/ 3”。 请给我一个提示是什么意思或在哪里可以找到完整的参考?提前谢谢!
E8 cw CALL rel16相对于下一条指令调用近,相对位移
E8 cd CALL rel32相对于下一条指令调用near,relative,displacement
FF / 2 CALL r / m16呼叫接近,绝对间接,r / m16中给出的地址
FF / 2 CALL r / m32呼叫接近,绝对间接,r / m32中给出的地址
9A cd CALL ptr16:16调用操作数中给出的far,absolute,address
9A cp CALL ptr16:32调用操作数中给出的far,absolute,address
FF / 3 CALL m16:16调用远,绝对间接,m16:16中给出的地址
FF / 3 CALL m16:32调用远,绝对间接,m16:32中给出的地址
答案 0 :(得分:11)
我最喜欢的来源是英特尔本身:Intel® 64 and IA-32 Architectures Software Developer Manuals。与过去的版本不同,所有卷现在都很好地包含在一个(3044页)PDF中。
看起来最有帮助的部分是第2卷第3章中的3.1.1.1(截至我写这篇文章的最新PDF版本的第432页)。
答案 1 :(得分:2)
许多用于指令即时版本的操作码,包括83
,使用ModR / M字节中的3位/r
字段作为3个额外的操作码位。英特尔的第2卷手册对此进行了说明,我认为附录中的操作码表中包括了它。
这就是为什么大多数原始8086立即指令(如and r/m, imm
仍只允许2个操作数,而与shrd eax, edx, 4
或imul edx, [rdi], 12345
不同的是,两个ModRM字段均用于编码dst / src操作数,以及表示立即操作数的操作码。
SHRD / SHLD并添加了386,imul-immediate添加了286。不幸的是,复制与(and eax, edx, 0xf
)无法编码,但是至少x86可以将LEA用于非常常见的复制和添加或子操作。
但是,如果每条立即数和单操作数指令(如push
或not
)本身都需要完整的操作码,则8086将用1字节的操作码。 (特别是因为设计人员选择在简短形式上花费大量编码空间,而AL和AX没有现代字节,例如cmp ax, 12345
仅是3个字节,而不是16位模式下的4个字节,或者cmp eax, imm32
在32位模式下cmp r/m32, imm32
只有5个字节,而不是6个字节。对于单字节xchg-with-ax和一个字节的inc / dec寄存器。)
示例:解码48 83 C4 38
。(摘自How does one opcode byte decode to different instructions depending on the "register/opcode" field? What is that?,此Q的副本)
48
是REX.W前缀(REX仅设置了W位,因此它指示64位操作数的大小,但没有高位寄存器)。
操作码83
表示它可以是7种不同的指令,具体取决于称为“寄存器/操作码字段”的字段
每条指令的文档,例如add
(html extract of the vol2 manual),显示类似
的编码
REX.W + 83 /0 ib
代表ADD r/m64, imm8
,这就是您所拥有的。
diagram of the ModRM bit fields from wiki.osdev.org
7 0 +---+---+---+---+---+---+---+---+ | mod | reg | rm | +---+---+---+---+---+---+---+---+
0xc4 = 0b11000100,因此reg字段=0。因此,我们的操作码为83 /0
,以Intel的符号表示。
其余的ModRM字段为:
所以指令是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