为什么操作数必须在一行中有大小而在 x86 汇编中不能在另一行中

Why operand must have size in one line but not the other in x86 assembly

看图片,在第 34 行我必须写 word ptr 才能工作,而在第 44 行我没有。
这是为什么?

编译器不能像 0FF20h 一样知道 0020h 是一个字吗?
将 0 添加到 0020h 使其成为 00020h 或类似的东西也不起作用。

我在 80x86 上使用 MASM。 emu8086,也尝试过 dosbox v0.74

不同之处在于,您的 assembler 奇怪而危险地接受 0FF20h 作为暗示 word 操作数大小。但即使对于您的 assembler,前导零并不意味着操作数大小,只是实际值;大概它会检查最高有效位的位置。

对于像 NASM 这样设计良好且一致的 assembler 语法,情况并非如此:如果我尝试 assemble 在 16 位模式下使用 nasm -fbin foo.asm

mov [es: si], 2
mov [es: si], 0ff20H

我收到这些错误:

foo.asm:1: error: operation size not specified
foo.asm:2: error: operation size not specified

只有一个寄存器可以表示整个指令的操作数大小,而不是常数的宽度。 (mov [si], ax 没有歧义:不存在目标宽度与源宽度不同的 mov 形式,并且 ax 绝对是 word 大小。)

GAS(GNU assembler)同样适用于 AT&T 和 Intel 语法模式。 (其 Intel 语法模式与 MASM 非常相似。)

没有 mov r/m16, sign_extended_imm8 编码,但有 add 和大多数 ALU 操作,因此 assembler 没有理由假设 xyz [mem], 0 表示字节操作数大小。更有可能是程序员忘记了指定,所以它把它当作一个错误,而不是默默地接受一些模棱两可的东西。

mov word [mem], 0 是将内存中的单词归零的完全正常的方法。


除此之外,x86 在 16 位代码中支持 32 位操作数大小,使用 66h 操作数大小前缀 。这与地址大小无关。

mov dword ptr es:[si], 0FF20h 也是可编码的,如果您省略 size ptr 说明符,则与 mov word ptr es:[si], 0FF20h 完全不明确。

正如 Jester 评论的那样,如果将前导零算作常量宽度的一部分,则 0FF20h 很容易被视为暗示 dword.

Note that you had to write 0FF20H with a leading zero too so if the assembler really relied on the length of the literal, it could have thought that was a dword ... similarly for 0FFH. It would be a dangerous game. Note sensible assemblers don't even allow your second form without explicit size. That's just a bug waiting to happen.

(明智的 assemblers 包括 NASM 和 GAS,就像我上面显示的那样)。

如果我是你,我会很不高兴我的 assembler 毫无怨言地接受了 mov es:[si], 0FF20h。我认为 emu8086 甚至比 MASM 更糟糕,并且通常接受像 mov [si], 2 这样带有一些默认操作数大小的东西,而不是警告。

我也不喜欢 MASM 如何从 symbol db 1, 2, 3 中神奇地推断出操作数大小,但这并不含糊,它只是意味着您必须查看符号的声明方式才能知道操作数是什么- 它将暗示大小。