当前位置:首页 > NASM网际编译器手册
2.1.11 -a参数:根本不进行预处理
如果NASM被做为一个编译器的后端使用,为了节约时间和提高速度,它可能假设编译器已经进行了预处理,而完全不需要预处理。-a参数不需要参数,NASM将肢用一个什么都不做的stub预处理来替换这个参数。
2.1.12 -w参数:允许/禁止汇编警告
NASM在汇编码方案的过程中将检测很多条件,来提醒用户,但是一个错误不致于生成一个文件是这些条件做为链接错误来报错并且在消息的前面有?warning?这个词,Warning 不会阻止NASM生成文件并返回给系统一个成功的状态。有些情况可以忽略:它们只是想提醒用户。因而NASM允许用户用-w命令行参数来允许可禁止指定类别的警告。警告类别可以用名字来描述,例如:orphan-labels,你可以用-w+orphan-labels来允许这个级别的警告用-w-orphan-labels来禁止它.可用的警告信息有:macro-params 包含所有错误号参数执行的多行宏警告信息.这个警告类别默认是允许的;关于如何禁止它的例子见第4.2.1节.orphan-labels 包含警告哪些没有指令但用冒号定义的标号的源码行.NASM默认情况下没有对这种条件进行规定;如果你想进一步了解它见第3.1节的例子.number-overflow 包含不适用于32位的数字信息(例如:打入太多个f而产生0x7ffffffff的错误)这个警告默认情况是允许的.
2.1.13 NASM的环境变量
如果你定义了一个叫NASM的环境变量,程序将会把它解释为为一个外部命令行参数,在真正的命令行以前进行处理.你可以用这个来为头文件定义标准的搜索路径.通过在NASM变量中用-i操作.这个变量的值用空格分开,以致于-s -ic:\\\\nasmlib 将做为2个单独的操作.然而,这意味着变量-dNAME=\不会做你想要做的事.因为它将在空格处分开并且NASM命令行处理器将会得到两个无意义的字 -dNAME=\为了可以这样做,NASM提供了一个操作,如果你在变量的前面字符加一个不为负号的字符,NASM将会这个符号做为分隔符,所以设置变量 !-s!-ic:\\\\nasmlib 等价于-s-ic:\\\\nasmlib,但!-dNAME=\将会工作。
2.2 MASM用户快速入门
如果你用MASM写过程序或用与MASM相兼容的TASM或a86,这节试着说明MASM与NASM在语法上的主要区别.
如果你没有用过MASM,哪么请跳过这一节.
2.2.1 NASM是大小写区分的
一个简单的区别是NASM是区分大小写的,你调用标号foo,Foo或FOO是不一样的。如果你编译过DOS或OS/2的.OBJ文件,你可以执行UPERCASE 指令(文档见第6.2节)来保证向其它模块输出的所有符号都为大写。但在这里NASM只在标号间对它们进行区分。
2.2.2 NASM 需要用方括号引用内存
NASM在语法上被设计为尽量简单。一个实用的设计目标为用户看一行NASM代码时就告诉它产生的操作码是什么。你不能在MASM中这样做:如果你定义如下符号 foo equ 1
bar dw 2
那么下面两行代码 mov ax,foo
5
mov ax,bar
将产生完全不同的操作码,尽管他们有相同的语法。NASM避免这种由有相同语法而产生不同情况的内存引用。这个规则不难实现:对于任何访问内存内容的地方用方括号,而任何访问变量地址的则不用。所以一条指令:mov ax,foo将会总是参考编译时的内容,无论它是一个EQU还是一个变量的地址;访问一个变量的内容时,你必须用mov ax,[bar]这也意味着NASM不需要MASM的OFFSET关键字,所以MASM的mov ax,offset bar与NASM的mov ax,bar意义相同。如果你试着在NASM得到大量的MASM代码,你将会用%idefine offset来生成物大量的OFFSET预处理关键字做为无意义的工作。这会在a86中产生一些迷惑,用一个冒号结束一个标号的定义和一个变量区分引起a86采用NASM形式的语义。所以在a86中,mov ax,var有另外的意义决定于var是否被定义成变量;dw 0(一个标号)或者 var dw 0(一个WORD尺寸的变量)。NASM比较起来是很简单的:任何符号都是一个标号。NASM在简单性方面很出色,也不支持象MASM复杂的语法格式和它的拷贝,如:mov ax,[table+bx],同样的mov ax,es:[di]是错的而mov ax,[es:di]是对的。
2.2.3 NASM不存储变量类型
NASM在设计时,就选择了不记忆你定义的变量类型。然而看到var dw 0 MASM将记下你定义了一个字长的变量,然后在指令mov var,2前 向这个尺寸填入一个值,而NASM则故意不记这个符号除非它开始时,所以你必须用这样的指令:mov word [var],2.由于这个原因,NASM不支持LODS,MOVS,STOS,SCAS,CMPS,INS或OUTS指令,但支持表格处理如:LODSB,MOVSW和SCASD,这些指令明确指定了处理字串的单位。
2.2.4 NASM不用ASSUME.
做为NASM简单性的一部分,它不支持ASSUME关键字,NASM不保留你将什么值放入段寄存器的动作.并且也永远不会自动生成一个段重载前缀。
2.2.5 NASM不支持内存模型
NASM不支持任何提供16位内存模型的操作符。程序员必须保留哪个函数为远调用哪个函数为近调用。对于放入RET指令的正确表格也是负责的。(RETN或RETF;NASM接受RET做为RETN表格的一个替换);另外,程序员也必须自己处理CALL FAR指令对于当外部调用函数时,并且也必须保留外部变量是far 还是near的信息。
2.2.6 浮点数的区别
NASM 用不同的名字引用浮点寄存器;MASM叫它们为ST(0),ST(1),a86叫它们0,1;NASM叫它们st0,st1;
2.2.7 其它区别
由于历史原因,NASM用关键字TWORD,而MASM和其它编译器用TBYTE。NASM同MASM一样不定义未初始化的内存;为了读一个64字节的保留内容。MASM程序员用stack db 64 dup(?),NASM则用stack resb 64,为了有限的兼容,NASM对待问号做为一个有效字符,你可以用? equ 0然后写dw ?将会有效。然而DUP是不被支持的。除了以上说明这些,宏和定向符完全和MASM不同,详细信息请见第四章和第五章。
6
第三章 NASM语言
3.1 NASM源码行的分布
象许多编译器一样,每个NASM的源码行(除非它是一个宏,一个预处理符或一个汇编定向符请见第四章和第五章)都包含4个域:
标号: 指令 操作符 ;注释
通常,这些域的一些为可选的:一个标号,一个指令和一个注释是可选的,当然,在指令域不存在时,操作符域是必需的.NASM在一行中是不限制空格的个数的:标号前可以有空格,指令前可以没有空格,标号后的冒号是可选的.(注意,这意味着如果你愿意用一行来写lodsb,然后用lodab,那么这行只定义了一个标号而且是一个什么也不做的有效代码行.运行用命令行-w+orphan-labels运行NASM,编译器将会提示你:一个没有冒号的标号行被定义.)标号里的有效字符为:字符,数字,_,$,#,@,~,.和?.定义标号的第一个字符必须为字母.,_和?,(详细信息见第3.8节).一个标号如果带前缀$时,表示它将做为一个标号来处理而是一个保留字;因此,如果你用一个叫做eax的符号来链接其它的模块,你应该在NASM的代码中用$eax来区别其它寄存器.这个指令域可以包含什么机器指令:Pentium和P6的指令集,FPU指令,MMX指令和其它未公开的指令.这个指令集通常也可以用前缀:LOCK,REP,REPE/REPZ或REPNE/REPNZ.编译器用前缀A16,A32,O16和O32来表示显式的地址尺寸和操作符尺寸,其中第9章有关于这方面的一个例子.你也可以用段寄存器的名字做为一条指令的前缀:coding es mov [bx],ax等价于指令:mov [es:bx],ax。我们推荐后一种方法,因为它包含了这种编译器的其它一些语法特性, 而对于指令:LODSB则不需要操作数但也可以加一个段寄存器的名字,这对于从es lodsb的形式是一种不清楚的语法。
对于一些不需要前缀的指令如:CS,A32,LOCK,REPE自己可以单独做为一行,则NASM为他们产生前缀字节。除了现存的一些机器指令外,NASM也支持一定数量的伪操作符,详细信息见第3.2节。指令可以操作一些表格:它们可以是用寄存器名字命名的寄存器(如ax,bp,ebx,cr0:NASM不用gas-style语法,这种语法中的寄存器名字前必须加a %sign),或有效地址(见第3.3节),常量(见3.4节)或表达式(见3.5节)。
对于浮点数指令,NASM则有一个范围很广的语法:你可以象MASM一样用两个操作符形式,你也可以用NASM本身的许多单操作符指令。所有支持的指令格式见附见A,例如你可以写:
fadd st1 ;this sets st0:=st0+st1 fadd st0,st1 ;so does this
fadd st1,st0 ;this sets st1:=st1+st0 fadd to st1 ;so does this
所有对内存引用的浮点数指令必须用前缀:DWORD,QWORD或TWORD来表示它所引用内存的尺寸。
3.2 伪操作符
伪操作符的意思是:它们不是真正的x86机器指令,但由于它们易于理解,所以经常在指令域中使用。当前的伪操作符指令有:DB,DW,DD,DQ和DT,与其它指令一起用闹噶钣校篟ESB,RESW,RESD,RESQ和REST,INCBIN命令,EQU命令,TIMES前缀。 3.2.1 DB和有关指令:定义初始化数据
DB,DW,DD,DQ和DT在MASM中用的很多,它们是用来定义输出文件的初始化数据了解的,它们使用的方式很
7
多:
db 0x55 ;只定义一个字节0x55
db 0x55,0x56,0x57 ;成功定义三个字节 db \\'a\\',0x55 ;定义字符常量
db \\'hello\\',13,10,\\'$\\' ;这是字串常量 dw 0x1234 ;0x34 0x12
dw \\'a\\' ;0x41 0x00(它只是一个数字) dw \\'ab\\' ;0x41 0x42(字符常量)
dw \\'abc\\' ;0x41 0x42 0x43 0x00(字串) dd 0x12345678 ;0x78 0x56 0x34 0x12 dd 1.234567e20 ;浮点数常量 dq 1.234567e20 ;双精度浮点数
dt 1.234567e20 ;扩展的双精度浮点数
DQ和DT不能接受数字常量和字符串常量做为操作数。
3.2.2 RESB及相关符号:定义未初始化的数据
RESB,RESW,RESD,RESQ和REST被用在一个模块的BSS段:它们定义未初始化的存储空间。这些操作符中的每一个都可以带一个操作数,这个操作数可以是一些字节,字,或双字来保存空间。这些在第2.2.7节中描述。NASM不支持MASM/TASM用DW来定义未初始化的空间或类似的语法:RESB伪操作数是一个临界的表达式。见第3.7节说明。例如: buffer: resb 64 ;保留64个字节 wordvar: resw 1 ;保留一个字 realarry resq 10 ;10个实数列表
3.2.3 INCBIN:包含外部的二进制文件
INCBIN是从旧的Amiga汇编器DevPac引用来的:它包含一个二进制文件verbatim到一个输出文件。这点对于将一图象与声音数据直接加到一个关于游戏的程序是十分方便的。它可以有以下三种表示方式: incbin \包含整个文件
incbin \跳过前1024个字节
incbin \跳过前1024个字节,并且最多只包含512个字节
3.2.4 EQU:定义常量
EQU字义一个给定的符号为常数:当EQU被用时,源码行必须包含一个标号。EQU的用法是给一个数定义一个标号名字。这个定义是固定的,不能在以后的代码改变它。例如: message db \\'hello,world\\'
msglen equ $-message
定义msglen为常数12.msglen不能在以后重新定义。这也不是一个预处理定义:msglen是当时就被赋值的,用$符号(见第三3.5节关于$的说明)定义时,意思是说它的值为后面字串的长度。要注意的是EQU也是一个临界表达式。(说明见3.7)。
8
共分享92篇相关文档