x86/x64 添加置换寻址

Posted

技术标签:

【中文标题】x86/x64 添加置换寻址【英文标题】:x86/x64 Add Displacement addressing 【发布时间】:2012-11-11 08:17:36 【问题描述】:

我正在为 x86/x64 CPU 指令编写编译器,但我似乎无法弄清楚人们所说的“位移”地址是什么意思。例如,此处详细说明了添加指令: http://www.c-jump.com/CIS77/CPU/x86/X77_0150_encoding_add_edx_displacement.htm

我只是试图实现将寄存器添加到正常内存地址的添加指令。问题是,该地址是一个“位移地址”。这是否意味着地址是一个有符号值,它是指令位置的偏移量?

【问题讨论】:

你在生成汇编代码吗?你不能生成 C 代码,或者使用 LLVM 吗?或者使用code.google.com/p/asmjit 或其他库发出机器代码?你了解 x86/64 指令集吗?你学习了吗intel.com/content/www/us/en/processors/… 【参考方案1】:

x86 中有几种不同形式的间接操作数:

    [注册] [reg + 位移] [位移] [reg * 常量 + reg] [reg * 常量 + reg + 位移]

“位移”只是添加到地址其余部分的常量。如果地址中除了常量之外没有任何分量,它仍然被称为“位移​​”。这主要是为了与其他寻址形式保持一致。

另一种看待它的方式是所有地址都具有以下形式

[reg * 常数 + reg + 位移]

每个组件都允许值为 0。

[位移]形式只是位移以外的所有分量都为零的编码。

作为编译器编写者,最后两种形式特别有趣。它们使在单个指令中对 pArray[index]->field + 1 之类的内容进行编码变得容易。

【讨论】:

好的,那么 [reg * constant + reg +displacement] 如何编码成机器指令呢?假设我在内存位置 0x00000001 有一个数组,我想访问它的索引,即 AL。我想我想使用移动指令并执行 MOV AH 0x00000001[AL]。我认为这只是 [reg+displacement]。本页的第 6 节显示了对 R/M 字节的编码,但它确实令人困惑:c-jump.com/CIS77/CPU/x86/lecture.html 看看英特尔手册的第 2 卷。每条指令都指定了它的编码形式。列出 r/m 操作数的编码形式接受 mod/rm 字节中的寄存器或内存操作数。 看看英特尔手册的第 2 卷。每条指令都指定了它的编码形式。列出 r/m 操作数的编码形式接受 mod/rm 字节中的寄存器或内存操作数。在第 2 卷的第 2 章第 2.1 节中,有一个表格显示了 mod r/m 字节的含义。列有 [--][--] 的形式表示使用 SIB 字节的编码。 SIB 寻址的形式为 regconstant + reg。某些形式的 mod/rm 字节表明 SIB 字节后跟一个位移。那些给出了 regconstant + reg + constant 形式。还有一张表格解释了 SIB。 哦,好的,谢谢!我还在阅读,在 64 位处理器上,位移地址仍然是 32 位?所以在任何更大的东西上,你必须将它加载到一个寄存器中才能读取它? @Scott,可以将寄存器用作位移吗?组装时lea %rax(%r12), %r14 gcc 吐了Error: junk (%r12) after register【参考方案2】:

该页面不准确。它所说的“进行位移的添加”是指add r[16|32], r/m[16|32]add edx, [0xdisp] 的形式,您可能会在反汇编程序的输出中看到它。假设它正在讨论操作码为0x03 的 ADD 指令,

edx 寄存器目标进行编码并在 ModR/M 字节中指定一个 32 位位移作为有效地址,将使其值为 0x15(请参阅英特尔® 64 和 IA-32 架构软件开发人员手册第 1 卷)。 2,第 41 页,表 2-2)。 该指令的作用是将内存地址disp处的dword添加到edx的内容中。 因此,指令的实际编码为:\x03\x15\x00\x00\x00\x01,用于 1 个字节的位移。

【讨论】:

【参考方案3】:

没有“需要位移的特殊添加”,该页面不必要地混淆 - 这只是正常内存操作数编码的一部分。

add 是一个相当标准的指令,其编码方式与所有 alu-ops 的编码方式相同:有一种特殊情况是使用 al 作为目标并立即作为源 (04 ib),使用ax/eax/rax 作为目标和直接作为源 (+ 05 imm),add r/m, imm 的三个版本(一个用于 8 位目标,一个用于更广泛的目标和一个符号扩展的 8 位源,一个用于更广泛的目标和一个宽源),当然还有add r, r/madd r/m, r

这只是add r, r/m 的一个特例,其中r/m 采用位移的形式:参见ModRM encoding 的注释#1。

所以他们只是指add edx, [sdword]。 (但他们错误编码了 reg 字段,edx 对应于010,而不是011

【讨论】:

所以要将 AL(8 位寄存器 0)添加到内存位置 0x00000000,CPU 将接受(十六进制)00 05 00000000?

以上是关于x86/x64 添加置换寻址的主要内容,如果未能解决你的问题,请参考以下文章

在 x86/x86_64 处理器上使用 LFENCE 指令是不是有意义?

x86 32位操作码,x86-x64不同或完全删除

C# 中的 x86/x64 CPUID

Intel x86_64 Architecture Background 1

Linux Kernel Documentation: x86_64 Support

Linux Kernel Documentation: x86_64 Support