NASM 和8位内存偏移混淆

NASM and 8-bit memory offset confusion

从英特尔软件开发人员手册(在此 post 中称为 ISDM)和 x86 Instruction Set Reference(我假设它只是前者的副本),我们知道mov 指令可以将数据从 eax/ax/al 移动到内存偏移量,反之亦然。

例如,mov moffs8, alal寄存器的内容移动到某个8位内存偏移量moffs8.

现在,moffs8 是什么?引用 ISDM (3.1.1.3):

moffs8, moffs16, moffs32, moffs64 — A simple memory variable (memory offset) of type byte, word, or doubleword used by some variants of the MOV instruction. The actual address is given by a simple offset relative to the segment base. No ModR/M byte is used in the instruction. The number shown with moffs indicates its size, which is determined by the address-size attribute of the instruction.

我强调了 moffs8 类型为 byte 且大小为 8 位的句子。

我是汇编的初学者,所以,在读完这篇文章后,我立即开始使用 NASM 来尝试 mov moffs8, al 指令。这是我写的代码:

; File name: mov_8_bit_al.s
USE32

section .text
    mov BYTE [data], al

section .bss
    data resb 2

这是 nasm -f bin mov_8_bit_al.s 产生的(十六进制):

A2 08 00 00 00

以下是我的理解:

貌似08 00 00 00是内存偏移量,但在本例中是moffs32,而不是moffs8!因此,CPU 在执行 A2 时将只读取一个字节,并将 00 视为 ADD 指令或其他内容,这不是预期的。

目前,在我看来 NASM 在这里生成了无效的字节码,但我想是我误解了什么……也许 NASM 没有遵循 IDSM?如果是这样,它的代码将无法在 Intel CPUs 上正确执行,所以它应该遵循它!

你能解释一下我哪里错了吗?

moffs后面的大小后缀其实是指操作数的大小,而不是地址本身的大小。这反映了 r/m.

后尺寸后缀的含义

手册实际上在注释中是这样说的:

NOTES:
* The moffs8, moffs16, moffs32 and moffs64 operands specify a simple offset relative to the segment base, where 8, 16, 32 and 64 refer to the size of the data. The address-size attribute of the instruction determines the size of the offset, either 16, 32 or 64 bits.