这两条线有什么区别?这里 PTR 有什么变化?
;first
mov BYTE [ecx], 0
;second
mov BYTE PTR [ecx], 0
概括:
word [ecx]
当操作数大小不被其他操作数暗示时。(否则[ecx]
没问题)。word ptr [ecx]
当操作数大小不被其他操作数暗示时。(否则[ecx]
没问题)。他们每个人都对对方的语法感到窒息。
警告:这是一个非常奇怪的领域,没有任何 ISO 标准或易于找到的 BNF 表;而且我不是走专有 MASM 语法雷区的专家。
您的情况可能没有区别,但 PTR 运算符在其他情况下可能意味着:
http://www.c-jump.com/CIS77/ASM/Instructions/I77_0250_ptr_pointer.htm
通常,PTR 运算符强制将表达式视为指定类型的指针:
.DATA
num DWORD 0
.CODE
mov ax, WORD PTR [num] ; Load a word-size value from a DWORD
我认为,还有汇编程序的特定要求(nasm/tasm/其他 asm),并且使用“byte ptr”更便携。
另请查看India 书中的第 4.2.16节和“汇编语言编程的艺术”中的第8.12.3节(和 8.11.3 “类型冲突”)。
更新:感谢 Frank Kotler,NASM 似乎“使用了英特尔汇编语法的变体”(wiki),其中不包括 PTR 操作。
UPDATE1:有来自英特尔的原始“ ASM86 LANGUAGE REFERENCE MANUAL ”,1981-1983,PTR 运算符在第 4-15 页定义:
PTR 操作员
语法:输入 PTR 名称
说明:PTR 运算符用于定义具有某种类型的内存引用。汇编器根据指令操作数的类型确定要汇编的正确指令。在某些情况下,您可以指定没有类型的操作数。这些情况涉及使用数字或寄存器表达式。这里 PTR 运算符用于指定操作数的类型。以下示例说明了这种用法:
MOV WORD PTR [BX], 5 ;set word pointed to by BX = 5
INC DS:BYTE PTR 10 ;increment byte at offset 10
;from DS
这种形式也可以用来覆盖变量或标签的类型属性。例如,如果您希望以两个字节访问已定义的字变量,则可以编写以下代码:
MOV CL, BYTE PTR AWORD ;get first byte
MOV CL, BYTE PTR AWORD + 1 ;get second byte
字段值:
type 此字段可以具有以下值之一:BYTE、WORD、DWORD、QWORD、TBYTE、NEAR、FAR
name 该字段可以是: 1. 变量名。2. 标签名称。3. 地址或寄存器表达式。4. 表示偏移量的整数。
UPDATE2:感谢斯图加特大学的比特保护者!Microsoft (1981)有原始的 MACRO-86 手册。第 3-7 页:
在使用前向引用时,可以使用 PTR 运算符另一种方式来为自己节省一个字节。如果您将 FOO 定义为前向常量,您可以输入以下语句:
MOV [BX],FOO
您可能希望将 FOO 称为立即字节。在这种情况下,您可以输入任一语句(它们是等效的):
MOV BYTE PTR [BX],FOO
MOV [BX],BYTE PTR FOO
这些语句告诉 MACRO-86 FOO 是一个字节立即数。生成更小的指令。
第 3-16 页:
覆盖运算符
这些运算符用于覆盖变量和标签的段、偏移量、类型或距离。
指针 (PTR)
<attribute> PTR <expression>
PTR 运算符覆盖操作数的类型(BYTE、WORD、DWORD)或距离(NEAR、FAR)。
<attribute>
是新属性;新类型或新距离。
<expression>
是要覆盖其属性的操作数。PTR 最重要和最常见的用途是确保 MACRO-86 理解表达式应该具有的属性。对于 type 属性尤其如此。每当您在程序中放置前向引用时,PTR 都会明确表达式的距离或类型。这样可以避免相位错误。
PTR 的第二个用途是按类型访问数据,而不是变量定义中的类型。这通常发生在结构中。如果结构定义为 WORD 但您想以字节的形式访问项目,则 PTR 是此操作符。但是,更简单的方法是输入第二条语句,该语句也以字节为单位定义结构。这消除了对结构的每个引用都使用 PTR 的需要。请参阅第 4.2.1 节,内存指令中的 LABEL 指令。
例子:
CALL WORD PTR [BX][SI]
MOV BYTE PTR ARRAY, (something)
ADD BYTE PTR FOO,9
在阅读本文并从这些文档中查看一些语法定义后,我认为编写 PTR 是强制性的。mov BYTE [ecx], 0
根据 MACRO-86 手册,使用不正确。
您使用的是许可汇编程序,看来我的 C 编译器对内联汇编的支持肯定不满意。正确的语法是 BYTE PTR 告诉汇编器 ECX 寄存器中的值应该被当作一个指针来对待。PTR。但这是过度指定的语法,它已经可以通过将 [brackets] 放在寄存器名称周围来表明您打算将其用作指针。使用 [ecx] 已经清楚地表明您的意思是将零存储到 ECX 寄存器提供的地址中。
所以它知道如何使用 ECX 寄存器,它唯一不知道的另一件事是需要将多少字节设置为零。选项是 1、2 或 4。你说得很清楚,1. BYTE。
在 MASM 中,BYTE PTR [ecx] 访问地址为 ecx 的内存。BYTE [ecx] 是语法错误(“'第一个操作数'中的内联汇编器语法错误;找到'['”)。
在 NASM 或 YASM 中,BYTE [ecx] 访问地址为 ecx 的内存。BYTE PTR [ecx] 是一个语法错误(NASM 中的“错误:预期的逗号、冒号或行尾”,YASM 中的“未定义符号 `PTR'”)。
在 TASM 中,BYTE PTR [ecx] 和 BYTE [ecx] 是等价的——都访问地址为 ecx 的内存。
但是,在 Gnu 汇编器 gas 中,当使用 intel 语法 BYTE PTR [ecx] 访问 ecx 处的内存时,BYTE [ecx] 实际上访问的是地址 ecx+1 处的内存。也就是说,BYTE [ecx] 等同于 BYTE PTR [ecx+1],它看起来既不健全,也不记录在案。
Gnu 汇编器版本 2.18、2.24 或 2.26.1:
cat > foo.S << EOF
.intel_syntax noprefix
movb BYTE [ecx], 0
movb BYTE PTR [ecx], 0
.att_syntax prefix
EOF
as foo.S
objdump -dM intel a.out
0: 67 c6 41 01 00 mov BYTE PTR [ecx+0x1],0x0
5: 67 c6 01 00 mov BYTE PTR [ecx],0x0