26

这两条线有什么区别?这里 PTR 有什么变化?

;first
mov BYTE [ecx], 0  
;second
mov BYTE PTR [ecx], 0
4

3 回答 3

25

概括:

  • NASM/YASM 要求word [ecx]当操作数大小不被其他操作数暗示时。(否则[ecx]没问题)。
  • MASM/TASM 要求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根据 MA​​CRO-86 手册,使用不正确。

于 2012-12-09T19:38:47.273 回答
6

您使用的是许可汇编程序,看来我的 C 编译器对内联汇编的支持肯定不满意。正确的语法是 BYTE PTR 告诉汇编器 ECX 寄存器中的值应该被当作一个指针来对待。PTR。但这是过度指定的语法,它已经可以通过将 [brackets] 放在寄存器名称周围来表明您打算将其用作指针。使用 [ecx] 已经清楚地表明您的意思是将零存储到 ECX 寄存器提供的地址中。

所以它知道如何使用 ECX 寄存器,它唯一不知道的另一件事是需要将多少字节设置为零。选项是 1、2 或 4。你说得很清楚,1. BYTE。

于 2012-12-10T00:54:13.670 回答
1

在 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
于 2016-10-04T02:27:02.457 回答