x86 在执行指令和 reading/writing 数据时如何处理字节寻址与字寻址?

How does x86 handle byte vs word addressing when executing instructions and reading/writing data?

所以我正在学习 x86 的工作原理,并且遇到过有人说它是字节可寻址的,但可以读取字、双字等。 处理器如何决定使用哪种方法以及何时使用? 例如。为了访问下一条指令以及当用户想要 read/write 到内存时,使用哪种寻址模式?

每个内存访问都有一个由机器代码指令指定的操作数大小。(寻址模式不是正确的术语:不同的寻址模式是指定内存的不同方式要访问的内存块的最低地址,如 [rdi][rdi + rdx*8][RIP + rel32])

编码不同的操作数大小是通过前缀(整数指令的 16 位、32 位和 64 位)或相同助记符(8 位整数)的不同操作码完成的。 或者使用 VEX 或 EVEX 前缀中的位,用于 AVX/AVX512 指令,可以使用 xmm、ymm 或 zmm 寄存器。

解码还取决于当前模式,即默认操作数大小:32 位和 64 位模式为 32,16 位模式为 16。 66 操作数大小前缀表示相反的大小。

在 64 位模式下,REX 前缀中的 .W(宽度)位将操作数大小设置为 64 位。 (有些指令如 push/pop 默认为 64 位操作数大小,不需要前缀,但大多数指令如 add/sub/mov仍默认为 32 位)

还有一个 0x67 地址大小前缀,可将寻址模式转换为其他大小。 (16 对 32 或 64 位模式 64 -> 32。)


例如,mov [rdi], eax 是一个双字存储,机器代码编码将通过在 16/32/64 位操作数大小的操作码上不使用特殊前缀来指定。 (有关可用编码,请参阅 https://www.felixcloutier.com/x86/mov。但请注意,英特尔的手册 没有 在每个条目中提及 66 操作数大小前缀:它有 2 个相同的编码不同的尺寸。你必须根据当前模式的默认值知道哪个需要 66 前缀。)

16 位操作数大小如 mov [rdi], ax 将具有与 66 操作数大小前缀相同的机器代码。

8 位操作数大小 (mov [rdi], al) 有自己的操作码,不需要前缀。

movzx / movsx 是有趣的情况:内存访问大小与目标寄存器不同。内存访问大小(字节或字)由操作码指定。操作数大小前缀只影响目标大小。 x86-64 63 /r movsxd(双字->qword 符号扩展)除外,其中 66 操作数大小前缀 缩小内存访问缩小到 m16 以匹配目的地。

SIMD 指令类似;指令编码唯一地确定内存访问大小,以及读取或写入的寄存器。