NASM doc翻译 by chio.yang@gmail.com

第一章       介绍

1.1 什么是NASM

Netwide Assembler, NASM, 是为可移植性和模块化所设计的80x86汇编器。它支持一系列目标文件,包括Linux/NetBSD/FreeBSD a.out, ELF, COFF, Microsoft 16-bit OBJWin32。它也可以输出普通二进制文件(Plain Binary files)。它的语法被设计成简单并且易于理解,和Intel的语法相似但没那么复杂。它支持PentiumP6 MMX, 3DNow!,SSESSE2操作码,并且带有宏功能。

1.1.1 为什么再发明一个汇编器?

 

1.1.2 Licence情况

  

1.2 联系信息

 

 

第二章       运行NASM

2.1 NASM命令行语法

为了汇编一个文件,你可以发出如下命令:

$ nasm –f <format> <filename> [-o <output>]

例如:

$ nasm –f elf myfile.asm

将汇编myfile.asm到一个ELF对象文件myfile.o

$ nasm –f bin myfile.com –o myfile.com

将汇编myfile.asm到一个raw binary文件myfile.com

要得到可取得的使用指令,输入得到使用帮助

$ nasm –h

Linux下输入file nasm 可以查看你的系统是a.outELF,:

$ File nasm

ELF:

$ Nasm: ELF 32-bit LSB executable i386(386 and up) Version 1

a.out:

$ nasm: Linux/386 demand-page executable(QMAGIC)

2.1.1 –o选项:指定输出文件名

正常情况下,NASM会为你的输出文件选择文件名;这主要依靠对象文件格式。对于Microsoft对象文件格式(obj win32), 它将去掉.asm(.s)扩展名,并替代为.obj.对于Unix对象文件格式(aout, coff, elfas86),它将替代为.o。对于rdf, 它将使用.rdf, 对于bin格式,它仅仅简单地去掉扩展名,因此myfile.asm将产生输出文件myfile.

如果输出文件已经存在,NASM将覆盖它,除非它和输入文件同名,这种情况它给出一个警告并使用nasm,out作为输出文件。

对于上述行为不可接受时,NASM提供了-o命令行选项来允许你指定你期望的文件名。如 :

$ nasm –f bin program.asm –o program.com

$ nasm –f bin driver.asm –o driver.sys

2.1.2 –f选项:指定输出文件格式

如果你不提供-f选项给NASM,它将自动为你选择一个输出文件格式。在NASM的发行版中,缺省的总是bin; 如果你编译你自己的NASM副本,你可以在编译时重定义OF_DEFAULT并选在你想要的缺省输出文件格式。

-o一样,-f和输出文件格式之间的空白是可选的,因此-f elf –felf都是合法的。

一个完全的有效输出文件格式可以获得,你可以打:

$ nasm –hf

2.1.3 –l选项:生成一个列表文件

2.2快速开始:MASM用户

2.2.1 NASM是大小写敏感的

2.2.2 NASM对内存引用要求方括号[]

NASM本质上是为了语法简化而设计。

Foo equ 1

Bar dw 2

MASM中:

mov ax, foo

mov ax, bar

可能让人产生疑惑

但是在NASM中:

Foo总是编译期常量,要访问变量bar的内容,你必须使用:

mov ax, [bar]

因此MASM中的关键字OFFSETNASM中完全不存在,因为不需要。

MASM: mov ax, offset bar

NASM: mov ax, bar

两者完全相同,都表示将bar变量的地址移到ax

 

另外,NASM中一个非常大的简化:一切都是标签label

同样,NASM也不支持混合语法:

MASM: mov ax, table[bx]

NASM: mov ax, [table+bx]

MASM: mov ax, es:[di]

NASM: mov ax, [es:di]

 

2.2.3 NASM不保存变量类型

NASM设计中,选择了不记忆你声明的变量的类型。而MASM可以记住,

var dw 0

mov var, 2

MASM中能填充var开始的两个字节地址的值为2

NASM除了知道var的开始地址,关于它的大小根本不知道,因此你必须显式的写出:

Mov word [var], 2

因此NASM不支持LODS, MOVS, STOS, SCAS, CMPS, INS, OUTS指令

仅仅支持形如LODSB, MOVSW, SCASD这类明确指定了字符串组成类型的操作。

 

2.2.4 NASM没有ASSUME

2.2.5 NASM不支持内存模型

2.2.6 浮点差异

2.2.7其他不同

由于历史原因,NASM使用关键字TWORDMASM及兼容汇编器使用TBYTE

 

在声明未初始化的存储区的区别:

MASM: stack db 64 dup (?)

NASM: stack resb 64

NASM不支持DUP

 

另外,宏和标示是完全不同

 

第三章       NASM语言

3.1 NASM源代码行布局

label: instruction operands    ; comment

当一行过长时,可以使用反斜杠(\)续行

 

有效的标签是字母,数字,_,$,@,~,.,?

标识符可以以字母,.,_,?开头,但一般.开头的标示有特殊意义,$开头暗示它将作为一个标示,而不是关键字,如$eax作为标示,而不是作为寄存器

 

指令域可以包含任意的机器指令: PentiumP6指令,FPU, MMX指令,甚至未归档的指令也都支持。指令可以带前缀如LOCK, REP, REPE/REPZ, REPNE/REPNZ.

显示的address-sizeoperand-size前缀A16, A32, O16, O32也提供支持。你也可以使用段寄存器名作为指令前缀: es mov [bx], ax等价于 mov [es:bx], ax;但我推荐后面一种语法,因为它很清晰。

 

3.2 伪指令

当前支持的伪指令有:DB, DW, DD, DQ, DT

它们的未初始化形式:RESB, RESW, RESD, RESQ, REST

还有: INCBIN, EQU, TIMES

3.2.1 DB一类:声明初始化的数据

db 0x55                        ;仅一个字节,值为0x55

db 0x55, 0x56, 0x57          ;三个连续字节

db ‘a’, 0x55                   ;字符常量是允许的

db ‘hello’, 13, 10, ‘$’     ;字符串常量也是允许的

dw 0x1234                      ;0x34 3x12 低地址->高地址

dw ‘a’                          ;0x61 0x00

dw ‘ab’                         ;0x61 0x62 一个字

dw ‘abc’                        ;0x61 0x62 | 0x63 0x00 两个字

dd 0x12345678                  ;0x78 0x56 0x34 0x12 一个双字

dd 1.234567e20                 ;浮点常量

dq 1.234567e20                 ;双精度浮点

dt 1.234567e20                 ;扩展精度浮点

 

DQDT不接受数字常量或字符常量作为操作数(言外之意,只用于浮点数??

3.2.2 RESB一类:声明未初始化的数据

RESB, RESW, RESD, RESQ, REST被设计用于一个模块的 BSS(section):它们声明未初始化的存储空间。每个带单个操作数,这表示要保留的字节数、字数、双字数或其他。

buffer:  resb 64      ;保留64字节

wordvar: resw 1       ;保留一个字

realarray resq 10     ;保留10个实数

3.2.3 INCBIN: 包含外部二进制文件

当需要直接包含图形或声音数据到一个游戏可执行文件时,这个伪指令是相当方便。它可以如下方式使用:

incbin “file.dat”             ;包含整个文件

incbin “file.dat”, 1024      ;略过第一个1024字节

incbin “file.dat”, 1024, 512;略过第一个1024字节,并实际包含之多512字节

 

3.2.4 EQU:定义常量

EQU定义一个符号为给定的常数值:当EQU被使用时,源代码行必须包含一个标签。这种定义是绝对的,并且不能以后改变。因此,例如:

message   db      ‘hello, world’

msglen    equ     $-message

这样,msglen被定义为常数12. msglen可能以后不被重定义。这不是一个预处理定义: msglen的值只被evaluate一次, 在定义处使用$的值,而不是无论何处引用并使用该处引用的$去被求值。

3.2.5 TIMES:重复指令或数据

TIMES前缀引起指令被汇编多次:

zerobuf:    times  64  db   0

 

TIMES实际功能更多,TIMES的参数不止是数字常量,也可以是数字表达式,如:

buffer:  db   ‘hello, world’

        times 64-$+buffer db ‘ ‘

这样将准确保留足够的空间来使整个buffer长度达到64

再如:times 100 movsb

3.3 有效地址

有效地址有非常简单的语法:它们包含表达式来求得需要的地址的值,表达式以方括号包围。

wordvar  dw   123

         mov  ax, [wordvar]

         mov  ax, [wordvar+1]

         mov  ax, [es:wordvar+bx]

 

3.4 常量(立即数)

3.4.1 数字立即数

3.4.2 字符常量

3.4.3 字符串常量

3.4.4 浮点常量

3.5 表达式

表达式语法上和C相似

NASM不保证整数的大小,这个常被用来在编译期求表达式的值:因为NASM能编译和运行在64-bit系统上,所以不要假设表达式在32-bit寄存器中求值并因此试图故意使用整数溢出。这可能不工作。NASM唯一保证的是由ANSI C保证的:你总是至少工作在32-bit

 

NASM在表达式中支持两种特殊的tokens,允许计算来包含当前汇编位置:$$$.

$能求值包含表达式的当前行首,而$$求值到当前section的开始,因此通过使用($-$$)你可以告知进入section多远

 

3.5.1 |:按位或操作符

3.5.2 ^:按位异或操作符

3.5.3 &:按位与操作符

3.5.4 <<>>:移位操作符

3.5.5 +- 加减操作符

3.5.6 *, /, //, %, %%:乘和除

*   

/    无符号除

//    有符号除

%   无符号求余

%%  有符号求余

3.5.7 一元操作符:+,-, ~, SEG

+  

-            

~   求反

SEG 提供操作数的段地址

3.6 SEGWRT

3.7 STRICT: 抑制优化

 

3.8 Critical Expressions

NASM是两遍汇编器。因此它不能处理非常复杂以至需要三次或更多遍的源文件。

 

第一遍用来决定所有汇编的代码和数据的大小,以便第二遍生成所有代码时知道代码引用的所有的符号地址。因此NASM不能处理的是这样的代码,它们的大小依赖于在该代码后声明的符号的值。例如:

times  (label-$)  db  0

label:  db   ‘Where am I?’

NASM拒绝这样的例子,这里有一个概念成为Critical Expression(关键表达式)

定义:这个表达式的值要求在第一遍被计算,并且因此它必须仅依赖于定义在它前面的符号

下面的例子:

           mov   ax, symbol1

symbol1    equ    symbol2

symbol2:

在第一遍中,不能决定symbol1的值,因为symbol2还没有看到

3.9 局部标签local label

NASM给予以.开头的符号以特殊意义。以句点.开头的标签被视为局部标签,这意味着它和它前面的非局部标签相关联。如:

label1           ; some code

.loop

                 ; some more code

            jne .loop

            ret

 

label2            ; some code

.loop

                 ; some more code

            jne  .loop

            ret

 

上述两个.loop分别与label1label2相关联

NASM提供了更进一步的方式定义局部标签

label1           ; some code

label.loop

                 ; some more code

            jne  label1.loop

            ret

 

label2            ; some code

.loop

                 ; some more code

            jne  label2.loop

            ret

这样定义局部标签和定义非局部标签形式上一样了

 

第四章       NASM预处理器

 

posted @ 2007-12-31 22:11  中土  阅读(1480)  评论(0编辑  收藏  举报
©2005-2008 Suprasoft Inc., All right reserved.