x86, difference between BYTE and BYTE PTR

Solution 1:

Summary:

  • NASM/YASM requires word [ecx] when the operand-size isn't implied by the other operand. (Otherwise [ecx] is ok).
  • MASM/TASM requires word ptr [ecx] when the operand-size isn't implied by the other operand. (Otherwise [ecx] is ok).

They each choke on the other's syntax.


WARNING: This is very strange area without any ISO standards or easy-to-find BNF tables; and I'm not an expert of walking through minefields of proprietary MASM syntax.

It your case there is may be no difference, but PTR operator can mean in other cases:

http://www.c-jump.com/CIS77/ASM/Instructions/I77_0250_ptr_pointer.htm

In general, PTR operator forces expression to be treated as a pointer of specified type:

 .DATA
 num  DWORD   0

 .CODE
 mov     ax, WORD PTR [num] ; Load a word-size value from a DWORD

I think, there are also assembler specific requirements (nasm/tasm/ other asm) and using of "byte ptr" is more portable.

Also check the section 4.2.16 in book from India and sections 8.12.3 (and 8.11.3 "Type Conflicts") in the "The Art of Assembly Language Programming".

UPDATE: thanks to Frank Kotler, seems that NASM "uses a variation of Intel assembly syntax" (wiki), which doesn't include PTR operation.

UPDATE1: There is original "ASM86 LANGUAGE REFERENCE MANUAL" from Intel, 1981-1983, PTR Operator is defined on page 4-15:

PTR Operator

Syntax: type PTR name

Description: The PTR operator is used to define a memory reference with a certain type. The assembler determines the correct instruction to assemble based on the type of the operands to the instruction. There are certain instances where you may specify an operand that has no type. These cases involve the use of numeric or register expressions. Here the PTR operator is used to specify the type of the operand. The following examples illustrate this use:

MOV  WORD  PTR  [BX], 5        ;set word pointed to by BX = 5
INC  DS:BYTE  PTR  10          ;increment byte at offset 10
                               ;from DS

This form can also be used to override the type attribute of a variable or label. If, for example, you wished to access an already defined word variable as two bytes, you could code the following:

MOV  CL, BYTE  PTR AWORD       ;get first byte
MOV  CL, BYTE  PTR AWORD + 1   ;get second byte

Field Values:

type This field can have one of the following values: BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR

name This field can be: 1. A variable name. 2. A label name. 3. An address or register expression. 4. An integer that represents an offset.

UPDATE2: Thanks to Uni of Stuttgart's bitsaver! There is original MACRO-86 manual from Microsoft (1981). Page 3-7:

The PTR operator can be used another way to save yourself a byte when using forward references. If you defined FOO as a forward constant, you might enter the statement:

MOV [BX],FOO

You may want to refer to FOO as a byte immediate. In this case, you could enter either of the statements (they are equivalent):

MOV BYTE PTR [BX],FOO

MOV [BX],BYTE PTR FOO

These statements tell MACRO-86 that FOO is a byte immediate. A smaller instruction is generated.

And page 3-16:

Override operators

These operators are used to override the segment, offset, type, or distance of variables and labels.

Pointer (PTR)

<attribute>  PTR  <expression>

The PTR operator overrides the type (BYTE, WORD, DWORD) or the distance (NEAR, FAR) of an operand.

<attribute> is the new attribute; the new type or new distance.

<expression> is the operand whose attribute is to be overridden.

The most important and frequent use for PTR is to assure that MACRO-86 understands what attribute the expression is supposed to have. This is especially true for the type attribute. Whenever you place forward references in your program, PTR will make clear the distance or type of the expression. This way you can avoid phase errors.

The second use of PTR is to access data by type other than the type in the variable definition. Most often this occurs in structures. If the structure is defined as WORD but you want to access an item as a byte, PTR is the operator for this. However, a much easier method is to enter a second statement that defines the structure in bytes, too. This eliminates the need to use PTR for every reference to the structure. Refer to the LABEL directive in Section 4.2.1, Memory Directives.

Examples:

 CALL WORD PTR [BX][SI]
 MOV BYTE PTR ARRAY, (something)

 ADD BYTE PTR FOO,9

After reading this and looking to some syntax definitions from these documents I think that writing PTR is mandatory. Usage of mov BYTE [ecx], 0 is incorrect according to MACRO-86 manual.

Solution 2:

You are using a permissive assembler, it seems, my C compiler's support for in-line assembly sure isn't happy with it. The proper syntax is BYTE PTR to tell the assembler that the value in the ECX register should be treated like a pointer. PTR. But that's syntax that's over specified, it could already tell that you meant to use it as a pointer by you putting [brackets] around the register name. Using [ecx] already made it clear that you meant to store zero into the address provided by the ECX register.

So it knows how to use the ECX register, the only other thing it doesn't know is how many bytes need to be set to zero. Choices are 1, 2 or 4. You made it clear, 1. BYTE.

Solution 3:

In MASM, BYTE PTR [ecx] accesses memory at address ecx. BYTE [ecx] is a syntax error ("inline assembler syntax error in 'first operand'; found '['").

In NASM or YASM, BYTE [ecx] accesses memory at address ecx. BYTE PTR [ecx] is a syntax error ("error: comma, colon or end of line expected" in NASM, "undefined symbol `PTR'" in YASM).

In TASM, BYTE PTR [ecx] and BYTE [ecx] are equivalent--both access memory at address ecx.

However, in the Gnu assembler gas, when using the intel syntax BYTE PTR [ecx] accesses memory at ecx, but BYTE [ecx] actually accesses memory at address ecx+1. That is, BYTE [ecx] is equivalent to BYTE PTR [ecx+1], which does not appear to be either sane or documented.

Gnu assembler version 2.18, 2.24, or 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