64 位下 jmp 指令 Intel 与 AMD 的实现
今天我注意到了在 64 位模式下 far jmp 指令的 Intel 和 AMD 实现的一些差别,源于下面的指令:
jmp far [compatibility_pointer] compatibility_pointer: |
在某种情况下,上面的指令在 AMD processor 下是正确的,但是在 Intel 下台是不正确的。
这个某种情况是:当指令的 operand size 是 64 位时:
- 在 Intel processor 下,far pointer 是 80 位的(16 位的 selector + 64 位的 offset 值)
- 在 AMD porocessor 下,far pointer 是 48 位的(16 位的 selector + 32 位的 offset 值)
这种情况发生在 64 位模式下,使用 REX.W prefix 来指定 operand size 是 64 位时。
1. AMD processor 下
对于 far jmp 的描述为:
Mnemonic Opcode Descripton JMP FAR mem16:32 FF /5 Far jump indrect,with the target specified by a far pointer in memory |
AMD Manual 上说: If the operand-size is 32 or 64 bits, the operand is a 16-bit selector followed by a 32-bit offset.
当 operand size 为 64 位时,这个 far pointer 还是 48 位的,
因此,AMD 并没有实现 80 位的 far pointer
2. Intel processor 下
对于 far jmp 的描述为:
Opcode Instruction Op/En 64-Bit Compatibility/Legacy Mode Descriptor REX.W + FF/5 Jmp m16:64 A Valid N.E. Jmp far, absolute indirect address given in m16:64 |
Intel 实现在 64 位 operand size 下 far pointer 是 80 位(selector16 : offset64),它使用 REX.W 指定 operand size 为 64 位
因此,上面的代码改为:
jmp far [compatibility_pointer] compatibility_pointer: |
当将 offset 定义为 64 位时,上面的代码在 Intel 平台下才是正确的。
3. Intel/AMD 的差异
造成 Intel 与 AMD 的差异是:
- Intel 下:32-bit, 48-bit, or 80-bit pointer, depending on operand-size attribute.
- AMD 下:A 32-bit or 48-bit far pointer, depending on the effective operand size
我坦诚,我之前对 Intel 的实现关注少,绝大部分时间都是以 AMD 的实现为标准,现在恐怕要改变过来。