x86,BYTE和BYTE PTR之间的区别

时间:2012-12-09 18:06:22

标签: assembly x86

这两条线有什么区别? PTR在这里改变了什么?

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

3 个答案:

答案 0 :(得分:14)

摘要:

  • 当操作数大小未被另一个操作数暗示时,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 / other asm),使用“byte ptr”更加便携。

另请参阅“汇编语言编程的艺术”中的book from India8.12.3部分(以及8.11.3“类型冲突”)中的4.2.16部分。

更新:感谢Frank Kotler,似乎NASM“使用了英特尔汇编语法的变体”(wiki),其中不包括PTR操作。

UPDATE1:英特尔有原始"ASM86 LANGUAGE REFERENCE MANUAL",1981-1983,第4-15页定义了PTR运营商:

  

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
  

此表单还可用于覆盖变量或标签的type属性。例如,如果您希望将已定义的单词变量作为两个字节访问,则可以编写以下代码:

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:感谢斯图加特的Uni of the bitaver!微软有original MACRO-86 manual(1981)。第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是强制性的。根据MACRO-86手册,mov BYTE [ecx], 0的使用不正确。

答案 1 :(得分:6)

你正在使用一个宽松的汇编程序,看来,我的C编译器对内联汇编的支持肯定不满意。正确的语法是BYTE PTR告诉汇编器ECX寄存器中的值应该被视为指针。 PTR。但是那个超过指定的语法,它已经可以告诉你,你想把它作为一个指针,你把[括号]放在寄存器名称周围。使用[ecx]已经明确表示您打算将零存储到ECX寄存器提供的地址中。

所以它知道如何使用ECX寄存器,唯一不知道的其他事情是需要将多少字节设置为零。选择是1,2或4.你说清楚了,1。BYTE。

答案 2 :(得分:0)

在MASM中,BYTE PTR [ecx]访问地址ecx处的内存。 BYTE [ecx]是一个语法错误(&#34;第一个操作数中的内联汇编语法错误&#39 ;;找到&#39; [&#39;&#34;)。

在NASM或YASM中,BYTE [ecx]访问地址ecx处的内存。 BYTE PTR [ecx]是语法错误(&#34;错误:逗号,冒号或行尾预期&#34;在NASM中,&#34;未定义符号`PTR&#39;&#34;在YASM中)。< / p>

在TASM中,BYTE PTR [ecx]和BYTE [ecx]是等效的 - 都是地址ecx的访问存储器。

然而,在Gnu汇编程序气体中,当使用英特尔语法时,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