x86, difference between BYTE and BYTE PTR

45,475

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
Share:
45,475

Related videos on Youtube

Linkas
Author by

Linkas

Updated on October 20, 2020

Comments

  • Linkas
    Linkas over 3 years

    What is the difference between these two lines? What PTR changes here?

    ;first
    mov BYTE [ecx], 0  
    ;second
    mov BYTE PTR [ecx], 0
    
    • Aki Suihkonen
      Aki Suihkonen over 11 years
      There's no difference. The assembler just accepts two different dialects.
    • Mr Lister
      Mr Lister over 11 years
      +1 for a question on x86 assembly. And @AkiSuihkonen, that looks like an answer rather than a remark.
    • osgx
      osgx over 11 years
      Linkas, and there is very important detail missing in the question: What assembler program is used: MASM/TASM/NASM/YAMS or something else. And how it is used (there are dialect options in some of them).
    • Michael Petch
      Michael Petch over 7 years
      Although an old question (now resurrected), was this question about GNU Assembler (as) using Intel syntax without prefixes? If not what assembler was being asked about?
  • Frank Kotler
    Frank Kotler over 11 years
    Nasm will barf on PTR. Masm/Tasm will barf without it.
  • Michael Petch
    Michael Petch over 7 years
    In GNU assembler the identifier BYTE, WORD, DWORD are also like defines 1,2,4 movb BYTE [ecx], 0 is actually the same as movb 1[ecx], 0 which is mov BYTE PTR [ecx+1], 0 . movb WORD [ecx], 0 is same as movb 2[ecx], 0 or mov BYTE PTR [ecx+2], 0. mov eax, WORD is the same as mov eax,2 . mov eax, BYTE is the same as mov eax,1 etc.
  • Orion Lawlor
    Orion Lawlor over 7 years
    Interesting, thank you! "mov ecx,BYTE" is a syntax error in NASM, MASM, and TASM, but not gas.
  • Cody Gray
    Cody Gray almost 7 years
    @Frank's comment should really be the answer here, rather than this well-intentioned mess… ;-) If you wouldn't mind, this is a pretty commonly-asked question, so it might be worth it to go back and rewrite/reformat large portions of this answer (and include a TL;DR for maximum clarity).
  • osgx
    osgx almost 7 years
    @Cody, Hi, actually I can understand anything of this answer now (it was more just like my personal notebook to record some URL to some interesting ancient/museum manuals). Can you help with editing it by rewriting it (probably with conversion to wiki)?
  • Peter Cordes
    Peter Cordes almost 7 years
    I basically wrote a new answer at the top of yours that tries to keep it short and simple. I don't know about any subtleties of using it in MASM, other than to specify the operand size when it's ambiguous. It's not complicated in NASM, though; that's all it does when used on a memory operand. (There's stuff like add edx, strict dword 1 to force the add r/m32, imm32 encoding, but that's when you use it on the non-memory operand)
  • metablaster
    metablaster over 2 years
    Thank you for the awesome book from India!