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
Related videos on Youtube
Linkas
Updated on October 20, 2020Comments
-
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 over 11 yearsThere's no difference. The assembler just accepts two different dialects.
-
Mr Lister over 11 years+1 for a question on x86 assembly. And @AkiSuihkonen, that looks like an answer rather than a remark.
-
osgx over 11 yearsLinkas, 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 over 7 yearsAlthough 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 over 11 yearsNasm will barf on
PTR
. Masm/Tasm will barf without it. -
Michael Petch over 7 yearsIn GNU assembler the identifier BYTE, WORD, DWORD are also like defines 1,2,4
movb BYTE [ecx], 0
is actually the same asmovb 1[ecx], 0
which ismov BYTE PTR [ecx+1], 0
.movb WORD [ecx], 0
is same asmovb 2[ecx], 0
ormov BYTE PTR [ecx+2], 0
.mov eax, WORD
is the same asmov eax,2
.mov eax, BYTE
is the same asmov eax,1
etc. -
Orion Lawlor over 7 yearsInteresting, thank you! "mov ecx,BYTE" is a syntax error in NASM, MASM, and TASM, but not gas.
-
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 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 almost 7 yearsI 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 theadd r/m32, imm32
encoding, but that's when you use it on the non-memory operand) -
metablaster over 2 yearsThank you for the awesome book from India!