1

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

4

1 回答 1

1

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

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

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

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

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


例如,mov [rdi], eax是 dword 存储,机器码编码将通过在操作码上不使用特殊前缀来指定 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(dword->qword 符号扩展),其中66操作数大小前缀确实将内存访问大小缩小到m16与目标匹配。

对于 SIMD 指令也是如此;指令编码唯一地确定内存访问大小,以及读取或写入的寄存器。

于 2019-10-30T15:14:31.533 回答