assembly - 带段寄存器的 x86-64 MOV 指令上的 REX.W 前缀

标签 assembly x86-64 instructions machine-code

我正在阅读 x86/x64 developer's manual试图理解指令编码并被来自段寄存器的 mov 混淆,即 this page 上的第 12 和第 13 种形式.具体有两个问题:

(1) 两者都标有 REX.W 前缀,但据我了解,此标志仅在操作数大小为 64 位时使用。我明白为什么它应该与 r64 一起使用,但除此之外,为什么这两个指令标有 REX.W 前缀?

(2) 两条指令中都有一个m16 destination,是不是重复了?为什么这两条指令首先要分开?

我能想到的 (2) 的一个原因是,在第一种形式中,可以选择带有 66H 前缀的 r16/r32,而当 REX.W 存在时(对于 r64),66H 将被忽略。但是 66H 似乎也不适用于 m16,为什么它包含在第二种形式 (r64/m16) 中?

最佳答案

我认为这是一个编辑错误。我认为第 12 行应该省略 REX 前缀,以与第 11 行的 16 位形式和第 13 行的 64 位形式形成对比(就像有 16-32-和 64-位形式一样对于其他变体)。

(也许有人试图将这三种形式组合成一行。该条目的“描述”列显示“将零扩展 16 位段寄存器移动到 r16/r32/r64/m16”,所以这与有人开始合并行然后意识到 r64 行应该分开,但忘记从 16 中删除 REX.W 是一致的/32 位行。)

我认为 m16 出现在所有三种形式中的原因是从段寄存器到内存的移动总是 16 位,无论操作数大小如何。 SR 中的 mov 是一条奇怪的指令。


没有理由使用 64 位形式:所有支持 64 位模式的 CPU 都零扩展到没有前缀的完整寄存器大小。

The upper bits of the destination register are zero for ... and all Intel 64 processors.

异常(exception)情况是早于 Pentium Pro 的 32 位 CPU,以及 Quark (based on P5)这也是仅 32 位的。

我没有检查 AMD 手册,看看是否有任何 AMD64 CPU 可能会为 8c d8 (mov eax,ds 没有前缀)。但是 Intel 的手册明确指出,所有 Intel64 CPU 都将零扩展到 32 位(因此在写入 32 位寄存器时会像往常一样隐式扩展到 64 位)。


66h 操作数大小前缀可用于编码 66 8c d8 (mov ax,ds),留下 RAX 的高位字节未修改(就像写入 16 位寄存器时一样)。

通常您不会想要这个,但是操作数大小前缀确实影响mov reg, SR,这与 REX.W 不同。

关于assembly - 带段寄存器的 x86-64 MOV 指令上的 REX.W 前缀,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55527352/

相关文章:

c - C中的函数调用需要多少条机器指令?

c# - CIL 指令 : Check if a getter method is called?

assembly - gcc 内联汇编中的 ljmp 语法

c++ - 如何指示编译器为 __m128 生成未对齐的加载

c - 当堆栈增长时,谁负责向操作系统请求页面?

linux - Lisp 工具包 (ltk) : Cannot get SCALE :variable value

assembly - x86_64 - cmpxchg。返回值

c - 如何获取线程的CPU指令数?

assembly - 尝试分配变量时,MIPS程序集解析错误

c - x86 汇编例程无缘无故卡住