NASM和MASM区别
NASM中文手册
NASM 中文手册 (整理: Yonsm) 第一章: 简介 ...................................................................................................................................6 1.1 什么是NASM....................................................................................................................6 1.1.1 为什么还需要一个汇编器.....................................................................................6 1.1.2 许可条件.................................................................................................................7 1.2 联系信息............................................................................................................................7 1.3 安装....................................................................................................................................7 1.3.1 在dos和Windows下安装NASM.............................................................................7 1.3.2 在unix下安装NASM..............................................................................................8 第二章 运行NASM.........................................................................................................................9 2.1 NASM命令行语法.............................................................................................................9 2.1.1 "-o"选项:指定输出文件的文件名.....................................................................10 2.1.2 "-f"选项:指定输出文件的格式..........................................................................10 2.1.3 "-l" 选项: 产生列表文件.....................................................................................11 2.1.4 "-M"选项: 产生Makefile依赖关系......................................................................11 2.1.5 "-F"选项: 选择一个调试格式..............................................................................11 2.1.6 "-g" 选项:使调试信息有效..................................................................................11 2.1.7 "-E" 选项: 把错误信息输入到文件....................................................................11 2.1.8 "-s" 选项: 把错误信息输出到"stdout"................................................................12 2.1.9 "-i"选项: 包含文件搜索路径...............................................................................12 2.1.10 "-p" 选项: 预包含一个文件..............................................................................13 2.1.11 "-d"选项: 预定义一个宏....................................................................................13 2.1.12 "-u" 选项: 取消一个宏定义..............................................................................13 2.1.13 "-e"选项: 仅预处理............................................................................................14 2.1.14 "-a" 选项: 不需要预处理 ..................................................................................14 2.1.15 "-On"选项: 指定多遍优化.................................................................................14 2.1.16 "-t"选项: 使用TASM兼容模式..........................................................................15 2.1.17 "-w"选项: 使汇编警告信息有效或无效 ...........................................................15 2.1.18 "-v"选项: 打印版本信息....................................................................................16 2.1.19 "NASMENV"环境变量.......................................................................................16 2.2 MASM用户速成 ..............................................................................................................17 2.2.1 NASM是大小写敏感的........................................................................................17 2.2.2 NASM需要方括号来引用内存地址 ....................................................................17 2.2.3 NASM不存储变量的类型....................................................................................18 2.2.4 NASM不会 "ASSUME".......................................................................................18 2.2.5 NASM不支持内存模型........................................................................................18 2.2.6 浮点处理上的不同...............................................................................................18 2.2.7 其它不同...............................................................................................................19 第三章 NASM语言.......................................................................................................................20 3.1 NASM源程序行的组成...................................................................................................20 3.2 伪指令..............................................................................................................................21 3.2.1 "DB"一类的伪指令: 声明已初始化的数据........................................................21 3.2.2 "RESB"类的伪指令: 声明未初始化的数据........................................................22 3.2.3 "INCBIN":包含其它二进制文件..........................................................................22 3.2.4 "EQU": 定义常数.................................................................................................22 1 NASM 中文手册 (整理: Yonsm) 3.2.5 "TIMES": 重复指令或数据 .................................................................................23 3.3 有效地址..........................................................................................................................23 3.4 常数..................................................................................................................................24 3.4.1 数值常数...............................................................................................................24 3.4.2 字符型常数...........................................................................................................25 3.4.3 字符串常数...........................................................................................................25 3.4.4 浮点常量...............................................................................................................26 3.5 表达式..............................................................................................................................26 3.5.1 "|": 位或运算符.....................................................................................................27 3.5.2 "^": 位异或运算符 ...............................................................................................27 3.5.3 "&": 位与运算符..................................................................................................27 3.5.4 "<<" and ">>": 位移运算符 .................................................................................27 3.5.5 "+" and "-": 加与减运算符...................................................................................27 3.5.6 "*", "/", "//", "%"和"%%": 乘除法运算符...........................................................27 3.5.7 一元运算符: "+", "-", "~"和"SEG" ......................................................................28 3.6 "SEG"和"WRT"................................................................................................................28 3.7 "STRICT": 约束优化.......................................................................................................29 3.8 临界表达式......................................................................................................................29 3.9 本地Labels.......................................................................................................................30 第四章 NASM预处理器。...........................................................................................................32 4.1 单行的宏..........................................................................................................................32 4.1.1 最常用的方式: "%define"....................................................................................32 4.1.2 %define的增强版: "%xdefine"..............................................................................33 4.1.3 : 连接单行宏的符号: "%+"..............................................................................34 4.1.4 取消宏定义: "%undef".........................................................................................35 4.1.5 预处理器变量 : "%assign"..................................................................................35 4.2 字符串处理宏: "%strlen" and "%substr" ........................................................................36 4.2.1 求字符串长度: "%strlen".....................................................................................36 4.2.2 取子字符串: "%substr".........................................................................................36 4.3 多行宏: "%macro"...........................................................................................................37 4.3.1 多行宏的重载.......................................................................................................38 4.3.2 Macro-Local Labels...............................................................................................38 4.3.3 不确定的宏参数个数...........................................................................................39 4.3.4 缺省宏参数...........................................................................................................40 4.3.5 "%0": 宏参数个数计数器....................................................................................41 4.3.6 "%rotate": 循环移动宏参数.................................................................................41 4.3.7 连结宏参数...........................................................................................................42 4.3.8 条件代码作为宏参数...........................................................................................43 4.3.9 禁止列表扩展.......................................................................................................43 4.4 条件汇编..........................................................................................................................44 4.4.1 "%ifdef": 测试单行宏是否存在...........................................................................44 4.4.2 "ifmacro": 测试多行宏是否存在.........................................................................44 4.4.3 "%ifctx": 测试上下文栈.......................................................................................45 4.4.4 "%if": 测试任意数值表达式................................................................................45 2 NASM 中文手册 (整理: Yonsm) 4.4.5 "%ifidn" and "%ifidni": 测试文本相同................................................................46 4.4.6 "%ifid", "%ifnum", "%ifstr": 测试记号的类型....................................................46 4.4.7 "%error": 报告用户自定义错误 ..........................................................................47 4.5 预处理器循环: "%rep"....................................................................................................47 4.6 包含其它文件..................................................................................................................48 4.7 上下文栈..........................................................................................................................49 4.7.1 "%push" and "%pop": 创建和删除上下文 ..........................................................49 4.7.2 Context-Local Labels.............................................................................................49 4.7.3 Context-Local单行宏.............................................................................................50 4.7.4 "%repl": 对一个上下文改名................................................................................50 4.7.5 使用上下文栈的例子: Block IFs.........................................................................51 4.8 标准宏..............................................................................................................................52 4.8.1 "__NASM_MAJOR__", "__NASM_MINOR__", "__NASM_SUBMINOR__"和 "___NASM_PATCHLEVEL__": NASM版本宏............................................................52 4.8.2 "__NASM_VERSION_ID__": NASM版本ID......................................................52 4.8.3 "__NASM_VER__": NASM版本字符串 .............................................................53 4.8.4 "__FILE__" and "__LINE__": 文件名和行号.....................................................53 4.8.5 "STRUC" and "ENDSTRUC": 声明一个结构体数据类型.................................54 4.8.6 "ISTRUC", "AT" and "IEND": 声明结构体的一个实例.....................................55 4.9 TASM兼容预处理指令....................................................................................................56 4.9.1 "%arg"操作符........................................................................................................57 4.9.2 "%stacksize"指令...................................................................................................57 4.9.3 "%local"指令 .........................................................................................................58 4.10 其它的预处理指令........................................................................................................58 4.10.1 "%line"操作符.....................................................................................................59 4.10.2 "%!""<env>": 读取一个环境变量.....................................................................59 第五章: 汇编器指令......................................................................................................................60 5.1 "BITS": 指定目标处理器模式........................................................................................60 5.1.1 "USE16" & "USE32": BITS的别名 ......................................................................61 5.2 "SECTION"或"SEGMENT": 改变和定义段..................................................................61 5.2.1 宏 "__SECT__"....................................................................................................61 5.3 "ABSOLUTE": 定义绝对labels......................................................................................62 5.4 "EXTERN": 从其它的模块中导入符中.........................................................................63 5.5 "GLOBAL": 把符号导出到其它模块中........................................................................63 5.6 "COMMON": 定义通用数据域......................................................................................64 5.7 "CPU": 定义CPU相关.....................................................................................................65 第六章: 输出文件的格式。..........................................................................................................66 6.1 "bin": 纯二进制格式输出...............................................................................................66 6.1.1 "ORG": 二进制程序的起点位置.........................................................................66 6.1.2 "bin"对"SECTION"操作符的扩展 .......................................................................67 6.1.3 "Multisection" 支持BIN格式 ...............................................................................67 6.2 "obj": 微软OMF目标文件...............................................................................................68 6.2.1 "obj" 对"SEGMENT"操作符的扩展 ...................................................................69 6.2.2 "GROUP": 定义段组............................................................................................70 3 NASM 中文手册 (整理: Yonsm) 6.2.3 "UPPERCASE": 在输出文件中使大小写敏感无效...........................................70 6.2.4 "IMPORT": 导入DLL符号...................................................................................71 6.2.5 "EXPORT": 导出DLL符号 ..................................................................................71 6.2.6 "..start": 定义程序的入口点.................................................................................72 6.2.7 "obj"对"EXTERN"操作符的扩展 ........................................................................72 6.2.8 "obj"对"COMMON"操作符的扩展......................................................................73 6.3 "win32": 微软Win32 目标文件.......................................................................................73 6.3.1 "win32"对"SECTION"的扩展 ..............................................................................74 6.4 "coff": 通用目标文件格式..............................................................................................74 6.5 "elf": 可执行可连接格式目标文件................................................................................75 6.5.1 "elf"对"SECTION"操作符的扩展........................................................................75 6.5.2 地址无关代码: "elf"特定的符号和 "WRT" .......................................................76 6.5.3 "elf"对"GLOBAL"操作符的扩展.........................................................................76 6.5.4 "elf"对"COMMON"操作符的扩展.......................................................................77 6.6 "aout": Linux "a.out" 目标文件.......................................................................................77 6.7 "aoutb": NetBSD/FreeBSD/OpenBSD "a.out"目标文件 .................................................78 6.8 "as86": Minix/Linux "as86"目标文件..............................................................................78 6.9 "rdf": 可重定位的动态目标文件格式............................................................................79 6.9.1 需要一个库: "LIBRARY"操作符........................................................................79 6.9.2 指定一个模块名称: "MODULE"操作符 ............................................................79 6.9.3 "rdf"对"GLOBAL"操作符的扩展 ........................................................................80 6.10 "dbg": 调试格式 ............................................................................................................80 第七章: 编写 16 位代码 (DOS, Windows 3/3.1).........................................................................82 7.1 产生".EXE"文件..............................................................................................................82 7.1.1 使用"obj"格式来产生".EXE"文件 ......................................................................82 7.1.2 使用"bin"格式来产生".EXE"文件 ......................................................................84 7.2 产生".COM"文件 ............................................................................................................84 7.2.1 使用"bin"格式产生".COM"文件.........................................................................85 7.2.2 使用"obj"格式产生".COM"文件.........................................................................85 7.3 产生".SYS"文件..............................................................................................................86 7.4 与 16 位C程序之间的接口.............................................................................................86 7.4.1 外部符号名...........................................................................................................86 7.4.2 内存模式...............................................................................................................87 7.4.3 函数定义和函数调用...........................................................................................88 7.4.4 存取数据元素.......................................................................................................90 7.4.5 "c16.mac": 与 16 位C接口的帮助宏 ...................................................................91 第八章: 编写 32 位代码(Unix, Win32, DJGPP)...........................................................................93 8.1 与 32 位C代码之间的接口.............................................................................................93 8.1.1 外部符号名...........................................................................................................93 8.1.2 函数定义和函数调用...........................................................................................93 8.1.3 获取数据元素.......................................................................................................95 8.1.4 "c32.mac": 与 32 位C接口的帮助宏 ...................................................................96 8.2 编写NetBSD/FreeBSD/OpenBSD和Linux/ELF共享库.................................................97 8.2.1 取得GOT中的地址...............................................................................................97 4 NASM 中文手册 (整理: Yonsm) 8.2.2 寻址你的本地数据元素.......................................................................................98 8.2.3 寻址外部和通用数据元素...................................................................................99 8.2.4 把符号导出给库用户...........................................................................................99 8.2.5 从库外调用过程.................................................................................................100 8.2.6 产生库文件写好了一些代码模块并把它们汇编成".o"文件后,你就可以产生你 的共享库了,使用下面的命令就可以:.........................................................................101 第九章: 混合 16 位与 32 位代码................................................................................................102 9.1 混合Size的跳转.............................................................................................................102 9.2 在不同size的段间寻址..................................................................................................103 9.3 其它的混合size指令 .....................................................................................................104 第十章: 答疑 ...............................................................................................................................105 10.1 普遍性的问题..............................................................................................................105 10.1.1 NASM产生了低效的代码................................................................................105 10.1.2 我的jump指令超出范围...................................................................................105 10.1.3 "ORG"不正常工作............................................................................................105 10.1.4 "TIMES"不正常工作.........................................................................................106 10.2 Bugs..............................................................................................................................107 附录A: Ndisasm............................................................................................................................108 A.1 简介...............................................................................................................................108 A.2 开始: 安装....................................................................................................................108 A.3 运行NDISASM.............................................................................................................108 A.3.1 COM文件: 指定起点地址.................................................................................108 A.3.2 代码前有数据: 同步.........................................................................................109 A.3.3 代码和数据混合: 自动(智能)同步..................................................................110 A.3.4 其它选项............................................................................................................110 A.4 Bug和改进.....................................................................................................................111 5 NASM 中文手册 (整理: Yonsm) 第一章: 简介 1.1 什么是 NASM NASM 是一个为可移植性与模块化而设计的一个 80x86 的汇编器。它支持相当多的目标 文件格式,包括 Linux 和"NetBSD/FreeBSD","a.out","ELF","COFF",微软 16 位的"OBJ"和 "Win32"。它还可以输出纯二进制文件。它的语法设计得相当的简洁易懂,和 Intel 语法相似 但更简单。它支持"Pentium","P6","MMX","3DNow!","SSE" and "SSE2"指令集, 1.1.1 为什么还需要一个汇编器 NASM 当初被设计出来的想法是"comp.lang.asm.x86"(或者可能是"alt.lang.asm",我忘了), 从本质上讲,是因为没有一个好的免费的 x86 系例的汇编器可以使用,所以,必须有人来写 一个。 (*) "a86"不错,但不是免费的,而且你不可能得到 32 位代码编写的功能,除非你付费, 它只使用在 dos 上。 (*) "gas"是免费的,而且在 dos 下和 unix 下都可以使用,但是它是作为"gcc"的一个后台 而设计的,并不是很好,"gcc"一直就提供给它绝对正确的代码,所以它的错误检测功能相 当弱,还有就是对于任何一个想真正利用它写点东西的人来讲,它的语法简直太可怕了,并 且你无法在里面写正确的 16 位代码。 (*) "as86"是专门为 Minix 和 Linux 设计的,但看上去并没有很多文档可以参考。 (*) "MASM"不是很好,并且相当贵,还且只能运行在 DOS 下。 (*) "TASM"好一些,但却极入与 MASM 保持兼容,这就意味着无数的伪操作码和繁琐 的约定,并且它的语法本质上就是 MASM 的,伴随着的就是一些自相矛盾和奇怪的东西。 它也是相当贵的,并且只能运行在 DOS 下。 所以,只有 NASM 才能使您愉悦得编程。目前,它仍在原型设计阶段-我们不期望它能 够超越所有的这些汇编器。但请您发给我们 bug 报告,修正意见,和其它有用的信息,还有 其它任何你手头有的对我们有用的信息(感谢所有已经这样在做了的人们),我们还会不断地 改进它。 6 NASM 中文手册 (整理: Yonsm) 1.1.2 许可条件 请阅读作为 NASM 发布的一部分的文件"Licence",只有在该许可条件下你才可以使用 NASM。 1.2 联系信息 当前版本的 NASM(0.98.08)由一个开发小组在维护,你可以从"nasm-devel"邮件列表中得 到(看下面的链接),如果你想要报告 bug,请先阅读 10.2 节 NASM 有 一 个 主 页 :"http://www.web-sites.co.uk/nasm" , 更 多 的 信 息 还 可 以 在 "http://nasm.2y.net/"上获取。 最初的作者你可以通过 email:"jules@dsf.org.uk"和"anakin@pobox.com"和他们联系,但后 来的开发小组并不在其中。 最 新 的 NASM 发 布 被 上 传 至 官 方 网 站 "http://www.web-sites.co.uk/nasm" 和 "ftp.kernel.org","ibiblio.org" 公告被发布至"comp.lang.asm.x86", "alt.lang.asm" 和"comp.os.linux.announce" 如 果 你 想 了 解 NASM beta 版 的 发 布 , 和 当 前 的 开 发 状 态 , 请 通 过 在 "http://groups.yahoo.com/group/nasm-devel","http://www.pairlist.net/mailman/listinfo/nasm-devel " and"http://sourceforge.net/projects/nasm"注册来捐助"nasm-devel"邮件列表。 在网站 Sourceforge 上的列表是较好的一个列表,它也是最新 nasm 源代码与发布的一个 网站,另外的列表也是公开的,但有可能不会被继续长期支持。 1.3 安装 1.3.1 在 dos 和 Windows 下安装 NASM 如果你拿到了NASM的DOS安装包,"nasmXXX.zip"(这里."XXX"表示该安装包的NASM 版本号),把它解压到它自己的目录下(比如:"c:\nasm") 7 NASM 中文手册 (整理: Yonsm) 该包中会包含有四个可执行文件:NASM 可拟行文件"nasm.exe"和"nasmw.exe",还有 NDISASM 可执行文件"ndisasm.exe"和"ndisasmw.exe"。文件名以"w"结尾的是"Win32"可执行 格式。是运行在"Windows 95"或"Windows NT"的 Intel 处理器上的,另外的是 16 位的"DOS" 可执行文件。 NASM 运行时需要的唯一文件就是它自己的可执行文件,所以可以拷贝"nasm.exe"和 "nasmw.exe"的其中一个到你自己的路径下,或者可以编写一个"autoexec.bat"把 nasm 的路径 加到你的"PATH"环境变量中去。(如果你只安装了 Win32 版本的,你可能希望把文件名改成 "nasm.exe"。) 就这样,NASM 装好了。你不需要为了运行 nasm 而让"nasm"目录一直存在(除非你把它 加到了你的"PATH"中,所以如果你需要节省空间,你可删掉它,但是,你可能需要保留文档或 测试程序。 如果你下载了 DOS 版的源码包,"nasmXXXs.zip",那"nasm"目录还会包含完整的 NASM 源代码,你可以选择一个 Makefiles 来重新构造你的 NASM 版本。 注意源文件"insnsa.c", "insnsd.c", "insnsi.h"和"insnsn.c"是由"standard.mac"中的指令自动 生 成 的 , 尽 管 NASM0.98 发 布 版 中 包 含 了 这 些 产 生 的 文 件 , 你 如 果 改 动 了 insns.dat,standard.mac 或者文件,可能需要重新构造他们,在将来的源码发布中有可能将不 再包含这些文件,多平台兼容的 Perl 可以从 www.cpan.org 上得到。 1.3.2 在 unix 下安装 NASM 如果你得到了 Unix 下的 NASM 源码包"nasm-x.xx.tar.gz"(这里 x.xx 表示该源码包中的 nasm 的版本号),把它解压压到一个目录,比如"/usr/local/src"。包被解压后会创建自己的子目 录"nasm-x.xx" NASM 是一个自动配置的安装包:一旦你解压了它,"cd"到它的目录下,输入"./configuer", 该脚本会找到最好的 C 编译器来构造 NASM,并据此建立 Makefiles。 一旦 NASM 被自动配置好后,你可以输入"make"来构造"nasm"和"ndisasm"二进制文件, 然后输入"make install"把它们安装到"/usr/local/bin",并把 man 页安装到"/usr/local/man/man1" 下的"nasm.1 和"ndisasm.1"或者你可以给配置脚本一个"--prefix"选项来指定安装目录,或者 也可以自己来安装。 NASM 还附带一套处理"RDOFF"目标文件格式的实用程序,它们在"rdoff"子目录下,你 可以用"make rdf"来构造它们,并使用"make rdf_install"来安装。如果你需要的话。 如果 NASM 在自动配置的时候失败了,你还是可以使用文件"Makefile.unx"来编译它们, 把这个文件改名为"Makefile",然后输入"make"。在"rdoff"子目录下同样有一个 Makefile.unx 文件。 8 NASM 中文手册 (整理: Yonsm) 第二章 运行 NASM 2.1 NASM 命令行语法 要汇编一个文件,你可以以下面的格式执行一个命令: nasm -f <format> <filename> [-o <output>] 比如, nasm -f elf myfile.asm 会把文件"myfile.asm"汇编成"ELF"格式 的文件"myfile.o".还有: nasm -f bin myfile.asm -o myfile.com 会把文件"myfile.asm"汇编成纯二进制格式的文件"myfile.com"。 想要以十六进制代码的形式产生列表文件输出,并让代码显示在源代码的左侧,使用"-l" 选项并给出列表文件名,比如: nasm -f coff myfile.asm -l myfile.lst 想要获取更多的关于 NASM 的使用信息,请输入: nasm -h 它同时还会输出可以使用的输出文件格式,如果你使用 Linux 并且不清楚你的系统是 "a.out"还是"ELF",请输入: file nasm (在 nasm 二进制文件的安装目录下使用),如果系统输出类似下面的信息: nasm: ELF 32-bit LSB executable i386 (386 and up) Version 1 那么你的系统就是"ELF"格式的,然后你就应该在产生Linux目标文件时使用选项"-f elf", 如果系统输入类似下面的信息: nasm: Linux/i386 demand-paged executable (QMAGIC) 9 NASM 中文手册 (整理: Yonsm) 或者与此相似的,你的系统是"a.out"的,那你应该使用"-f aout"(Linux 的"a.out"系统很久 以前就过时了,现在已非常少见。) 就像其它的 Unix 编译器与汇编器,NASM 在碰到错误以前是不输出任何信息的,所以 除了出错信息你看不到任何其它信息。 2.1.1 "-o"选项:指定输出文件的文件名 NASM 会为你的输出文件选择一个文件名;具体如何做取决于目标文件的格式,对于微 软的目标文件格式("obj"和"win32"),它会去掉你的源文件名的".asm"扩展名(或者其它任何你 喜欢使用的扩展名,NASM 并不关心具体是什么),并替换上"obj"。对于 Unix 的目标文件 格式("aout","coff","elf"和"as86")它会替换成".o", 对于"rdf",它会使用".rdf",还有为"bin"格式, 它会简单地去掉扩展名,所以"myfile.asm"会产生的一个输出文件"myfile"。 如果输出文件已经存在,NASM 会覆盖它,除非它的文件名与输入文件同名,在这种情 况下,它会给出一个警告信息,并使用"nasm.out"作为输出文件的文件名。 在某些情况下,上述行为是不能接受的,所以,NASM 提供了"-o"选项,它能让你指定 你的输出文件的文件名,你使用"-o"后面紧跟你为输出文件取的名字,中间可以加空格也可 以不加。比如: nasm -f bin program.asm -o program.comnasm -f bin driver.asm -odriver.sys 请注意这是一个小写的 o,跟大写字母 O 是不同的,大写的是用来指定需要传递的选项 的数目,请参阅 2.1.15 2.1.2 "-f"选项:指定输出文件的格式 如果你没有对 NASM 使用"-f"选项,它会自己为你选择一个输出文件格式。在发布的 NASM 版本中,缺省的输出格式总是"bin";如果你自己编译你的 NASM,你可以在编译的时候 重定义"OF_DEFAULT"来选择你需要的缺省格式。 就象"-o","-f"与输出文件格式之间的空格也是可选的,所以"-f elf"和"-felf"都是合法的。 所有可使用的输出文件格式的列表可以通过运行命令"nasm -hf"得到。 10 NASM 中文手册 (整理: Yonsm) 2.1.3 "-l" 选项: 产生列表文件 如果你对 NASM 使用了"-l"选项,后面跟一个文件名,NASM 会为你产生一个源文件的 列表文件,在里面,地址和产生的代码列在左边,实际的源代码(包括宏扩展,除了那些指定 不需要在列表中扩展的宏,参阅 4.3.9)列在右边,比如: nasm -f elf myfile.asm -l myfile.lst 2.1.4 "-M"选项: 产生 Makefile 依赖关系 该选项可以用来向标准输出产生 makefile 依赖关系,可以把这些信息重定向到一个文件 中以待进一步处理,比如: NASM -M myfile.asm > myfile.dep 2.1.5 "-F"选项: 选择一个调试格式 该选项可以用来为输出文件选择一个调试格式,语法跟-f 选项相册,唯一不同的是它产 生的输出文件是调试格式的。 一个具体文件格式的完整的可使用调试文件格式的列表可通过命令"nasm -f <format> -y"来得到。 这个选项在缺省状态下没有被构建时 NASM。如何使用该选项的信息请参阅 6.10 2.1.6 "-g" 选项:使调试信息有效 该选项可用来在指定格式的输出文件中产生调试信息。更多的信息请参阅 2.1.5 2.1.7 "-E" 选项: 把错误信息输入到文件 在"MS-DOS"下,尽管有办法,但要把程序的标准错误输出重定向到一个文件还是非常 11 NASM 中文手册 (整理: Yonsm) 困难的。因为 NASM 常把它的警告和错误信息输出到标准错误设备,这将导致你在文本编 辑器里面很难捕捉到它们。 因此 NASM 提供了一个"-E"选项,带有一个文件名参数,它可以把错误信息输出到指定 的文件而不是标准错误设备。所以你可以输入下面这样的命令来把错误重定向到文件: nasm -E myfile.err -f obj myfile.asm 2.1.8 "-s" 选项: 把错误信息输出到"stdout" "-s"选项可以把错误信息重定向到"stdout"而不是"stderr",它可以在"MS-DOS"下进行重 定向。想要在汇编文件"myfile.asm"时把它的输出用管道输出给"more"程序,可以这样: nasm -s -f obj myfile.asm | more 请参考 2.1.7 的"-E"选项. 2.1.9 "-i"选项: 包含文件搜索路径 当 NASM 在源文件中看到"%include"操作符时(参阅 4.6),它不仅仅会在当前目录下搜索 给出的文件,还会搜索"-i"选项在命令行中指定的所有路径。所以你可以从宏定义库中包含 进一个文件,比如,输入: nasm -ic:\macrolib\ -f obj myfile.asm (通常,在 "-i"与路径名之间的空格是允许的,并且可选的。) NASM 更多的关注源代码级上的完全可移植性,所以并不理解正运行的操作系统对文件 的命名习惯;你提供给"-i"作为参数的的字符串会被一字不差地加在包含文件的文件名前。 所以,上例中最后面的一个反斜杠是必要的,在 Unix 下,一个尾部的正斜线也同样是必要 的。 (当然,如果你确实需要,你也可以不正规地使用它,比如,选项"-ifoo"会导致"%incldue "bar.i"去搜索文件"foobar.i"...) 如果你希望定义一个标准的搜索路径,比如像 Unix 系统下的"/usr/include",你可以在环 境变量 NASMENV 中放置一个或多个"-i"(参阅 2.1.19) 为了与绝大多数 C 编译器的 Makefile 保持兼容,该选项也可以被写成"-I"。 12 NASM 中文手册 (整理: Yonsm) 2.1.10 "-p" 选项: 预包含一个文件 NASM 允许你通过"-p"选项来指定一个文件预包含进你的源文件。所以,如果运行: nasm myfile.asm -p myinc.inc 跟在源文件开头写上"%include "myinc.inc"然后运行"nasm myfile.asm"是等效的。 为和"-I","-D","-U"选项操持一致性,该选项也可以被写成"-P" 2.1.11 "-d"选项: 预定义一个宏 就像"-p"选项给出了在文件头放置"%include"的另一种实现,"-d"选项给出了在文件中写 "%define"的另一种实现,你可以写: nasm myfile.asm -dFOO=100 作为在文件中写下面一行语句的一种替代实现: %define FOO 100 在文件的开始,你可以取消一个宏定义,同样,选项"-dFOO"等同于代码"%define FOO"。 这种形式的操作符在选择编译时操作中非常有用,它们可以用"%ifdef"来进行测试,比如 "-dDEBUG"。 为了与绝大多数 C 编译器的 Makefile 保持兼容,该选项也可以被写成"-D"。 2.1.12 "-u" 选项: 取消一个宏定义 "-u"选项可以用来取消一个由"-p"或"-d"选项先前在命令行上定义的一个宏定义。 比如,下面的命令语句: nasm myfile.asm -dFOO=100 -uFOO 13 NASM 中文手册 (整理: Yonsm) 会导致"FOO"不是一个在程序中预定义的宏。这在 Makefile 中不同位置重载一个操作时 很有用。 为了与绝大多数 C 编译器的 Makefile 保持兼容,该选项也可以被写成"-U"。 2.1.13 "-e"选项: 仅预处理 NASM 允许预处理器独立运行。使用"-e"选项(不需要参数)会导致 NASM 预处理输入文 件,展开所有的宏,去掉所有的注释和预处理操作符,然后把结果文件打印在标准输出上(如 果"-o"选项也被指定的话,会被存入一个文件)。 该选项不能被用在那些需要预处理器去计算与符号相关的表达式的程序中,所以如下面 的代码: %assign tablesize ($-tablestart) 会在仅预处理模式中会出错。 2.1.14 "-a" 选项: 不需要预处理 如果 NASM 被用作编译器的后台,那么假设编译器已经作完了预处理,并禁止 NASM 的预处理功能显然是可以节约时间,加快编译速度。"-a"选项(不需要参数),会让 NASM 把 它强大的预处理器换成另一个什么也不做的预处理器。 2.1.15 "-On"选项: 指定多遍优化 NASM 在缺省状态下是一个两遍的汇编器。这意味着如果你有一个复杂的源文件需要多 于两遍的汇编。你必须告诉它。 使用"-O"选项,你可以告诉 NASM 执行多遍汇编。语法如下: (*)"-O0"严格执行两遍优化,JMP 和 Jcc 的处理和 0.98 版类似,除了向后跳的 JMP 是短 跳转,如果可能,立即数在它们的短格式没有被指定的情况下使用长格式。 (*)"-O1"严格执行两遍优化,但前向分支被汇编成保证能够到达的代码;可能产生比 "-O0"更大的代码,但在分支中的偏移地址没有指定的情况下汇编成功的机率更大, 14 NASM 中文手册 (整理: Yonsm) (*)"-On" 多编优化,最小化分支的偏移,最小化带符号的立即数,当"strict"关键字没有 用的时候重载指定的大小(参阅 3.7),如果 2<=n<=3,会有 5*n 遍,而不是 n 遍。 注意这是一个大写的 O,和小写的 o 是不同的,小写的 o 是指定输出文件的格式,可参 阅 2.1.1 2.1.16 "-t"选项: 使用 TASM 兼容模式 NASM 有一个与 Borlands 的 TASM 之间的受限的兼容格式。如果使用了 NASM 的"-t" 选项,就会产生下列变化: (*)本地符号的前缀由"."改为"@@" (*)TASM 风格的以"@"开头的应答文件可以由命令行指定。这和 NASM 支持的"-@resp" 风格是不同的。 (*)扩号中的尺寸替换被支持。在 TASM 兼容模式中,方括号中的尺寸替换改变了操作 数的尺寸大小,方括号不再支持 NASM 语法的操作数地址。比如,"mov eax,[DWORD VAL]" 在 TASM 兼容语法中是合法的。但注意你失去了为指令替换缺省地址类型的能力。 (*)"%arg"预处理操作符被支持,它同 TASM 的 ARG 操作符相似。 (*) "%local"预处理操作符。 (*) "%stacksize"预处理操作符。 (*) 某些操作符的无前缀形式被支持。 ("arg", "elif","else", "endif", "if","ifdef", "ifdifi", "ifndef", "include","local") (*) 还有很多... 需要更多的关于操作符的信息,请参阅 4.9 的 TASM 兼容预处理操作符指令。 2.1.17 "-w"选项: 使汇编警告信息有效或无效 NASM 可以在汇编过程中监视很多的情况,其中很多是值得反馈给用户的,但这些情况 还不足以构成严重错误以使 NASM 停止产生输出文件。这些情况被以类似错误的形式报告 给用户,但在报告信息的前面加上"warning"字样。警告信息不会阻止 NASM 产生输出文件 15 NASM 中文手册 (整理: Yonsm) 并向操作系统返回成功信息。 有些情况甚至还要宽松:他们仅仅是一些值得提供给用户的信息。所以,NASM 支持"-w" 命令行选项。它以使特定类型的汇编警告信息输出有效或无效。这样的警告类型是以命名来 描述的,比如,"orphan-labels",你可以以下列的命令行选项让此类警告信息得以输出: "-w+orphan-labels",或者以"-w-orphan-labels"让此类信息不能输出。 可禁止的警告信息类型有下列一些: (*)"macro-params"包括以错误的参数个数调用多行的宏定义的警告。这类警告信息缺省 情况下是输出的,至于为什么你可能需要禁止它,请参阅 4.3.1。 (*)"orphan-labels"包含源文件行中没有指令却定义了一个没有结尾分号的 label 的警告。 缺省状况下,NASM 不输出此类警告。如果你需要它,请参阅 3.1 的例子。 (*) "number-overflow"包含那些数值常数不符合 32 位格式警告信息(比如,你很容易打 了很多的 F,错误产生了"0x7fffffffffff")。这种警告信息缺省状况下是打开的。 2.1.18 "-v"选项: 打印版本信息 输入"NASM -v"会显示你正使用的 NASM 的版本号,还有它被编译的时间。 如果你要提交 bug 报告,你可能需要版本号。 2.1.19 "NASMENV"环境变量 如果你定义了一个叫"NASMENV"的环境变量,程序会被把它认作是命令行选项附加的 一部分,它会在真正的命令行之前被处理。你可以通过在"NASMENV"中使用"-i"选项来定 义包含文件的标准搜索路径。 环境变量的值是通过空格符分隔的,所以值"-s ic:\nasmlib"会被看作两个单独的操作。也 正因为如此,意味着值"-dNAME="my name"不会象你预期的那样被处理, 因为它会在空格符 处被分开,NASM 的命令行处理会被两个没有意义的字符串"-dNAME="my"和"name""给弄 混。 为了解决这个问题,NASM 为此提供了一个特性,如果你在"NASMENV"环境变量的第 一个字符处写上一个非减号字符,NASM 就会把这个字符当作是选项的分隔符。所以把环 境变量设成"!-s!-ic:\nasmlib"跟"-s -ic:\nasmlib"没什么两样,但是"!-dNAME="my name"就会 正常工作了。 16 NASM 中文手册 (整理: Yonsm) 这个环境变量以前叫做"NASM",从版本 0.98.32 以后开始叫这个名字。 2.2 MASM 用户速成 如果你曾使用 MASM 写程序,或者使用在 MASM 兼容模式下使用 TASM, 或者使用 "a86",本节将阐述 MASM 与 NASM 语法之间的主要区别。如果你没有使用过 MASM,那 最好先跳过这一节。 2.2.1 NASM 是大小写敏感的 一个简单的区别是 NASM 是大小写敏感的。当你调用你的符号"foo","Foo",或"FOO"时, 它们是不同的。如果你在汇编"DOS"或"OS/2", ".OBJ"文件,你可以使用"UPPERCASE"操作 符来保证所有的导出到其它代码模式的符号都是大写的;但是,在仅仅一个单独的模块中, NASM 会区分大小写符事情。 2.2.2 NASM 需要方括号来引用内存地址 NASM 的设计思想是语法尽可能简洁。它的一个设计目标是,它将在被使用的过程中, 尽可能得让用户看到一个单行的 NASM 代码时,就可以说出它会产生什么操作码。你可以 在 NASM 中这样做,比如,如果你声明了: foo equ 1bar dw 2 然后有两行的代码: mov ax,foomov ax,bar 尽管它们有看上去完全相同的语法,但却产生了完全不同的操作码 NASM 为了避免这种令人讨厌的情况,拥有一个相当简单的内存引用语未能。规则是任 何对内存中内容的存取操作必须要在地址上加上方括号。但任何对地址值的操作不需要。所 以,形如"mov ax,foo"的指令总是代表一个编译时常数,不管它是一个 "EQU"或一个变量的 地址;如果要取变量"bar"的内容,你必须与"mov ax,[bar]"。 这也意味着NASM不需要MASM的"OFFSET"关键字,因为MASM的代码"mov ax,offset 17 NASM 中文手册 (整理: Yonsm) bar"同 NASM 的语法"mov ax,bar"是完全等效的。如果你希望让大量的 MASM 代码能够被 NASM 汇编通过,你可以编写"%idefine offset"让预处理器把"OFFSET"处理成一个无操作符。 这个问题在"a86"中就更混乱了。 NASM 因为关注简洁性,同样不支持 MASM 和它的衍生产品支持的的混合语法,比如 像:"mov ax, table[bx]",这里,一个中括号外的部分加上括号内的一个部分引用一个内存地址, 上面代码的正确语法是:"mov ax,[table+bx] 。同样,"mov ax,es:[di]"也是错误的,正确的应 该是"mov ax,[es:di]"。 2.2.3 NASM 不存储变量的类型 NASM 被设计成不记住你声明的变量的类型。然而,MASM 在看到"var dw 0"时会记住 类型,然后就可以隐式地合用"mov var, 2"给变量赋值。NASM 不会记住关于变量"var"的任 何东西,除了它的位置,所以你必须显式地写上代码"mov word [var],2"。 因为这个原因,NASM 不支持"LODS","MOVS","STOS","SCANS","CMPS","INS",或 "OUTS"指令,仅仅支持形如"LODSB","MOVSW",和"SCANSD"之灰的指令。它们都显式地 指定被处理的字符串的尺寸。 2.2.4 NASM 不会 "ASSUME" 作为 NASM 简洁性的一部分,它同样不支持"ASSUME"操作符。NASM 不会记住你往 段寄存器里放了什么值,也不会自动产生段替换前缀。 2.2.5 NASM 不支持内存模型 NASM 同样不含有任何操作符来支持不同的 16 位内存模型。程序员需要自己跟踪那些 函数需要 far call,哪些需要 near call。并需要确定放置正确的"RET"指令("RETN"或"RETF"; NASM 接受"RET"作为"RETN"的另一种形式);另外程序员需要在调用外部函数时在需要的 编写 CALL FAR 指令,并必须跟踪哪些外部变量定义是 far,哪些是 near。 2.2.6 浮点处理上的不同 18 NASM 中文手册 (整理: Yonsm) NASM 使用跟 MASM 不同的浮点寄存器名:MASM 叫它们"ST(0)","ST(1)"等,而"a86" 叫它们"0","1"等,NASM 则叫它们"st0","st1"等。 在版本 0.96 上,NASM 现在以跟 MASM 兼容汇编器同样的方式处理"nowait"形式的指 令,0.95 以及更早的版本上的不同的处理方式主要是因为作者的误解。 2.2.7 其它不同 由于历史的原因,NASM 把 MASM 兼容汇编器的"TBYTE"写成"TWORD"。 NASM 以跟 MASM 不同的一种方式声明未初始化的内存。MASM 的程序员必须使用 "stack db 64 dup (?)", NASM 需要这样写:"stack resb 64",读作"保留 64 字节"。为了保持可移 植性,NASM 把"?"看作是符号名称中的一个有效的字符,所以你可以编写这样的代码"? equ 0", 然后写"dw ?"可以做一些有用的事情。"DUP"还是一个不被支持的语法。 另外,宏与操作符的工作方式也与 MASM 完全不同,可以到参阅第 4,第 5 章。 19 NASM 中文手册 (整理: Yonsm) 第三章 NASM 语言 3.1 NASM 源程序行的组成 就像很多其它的汇编器,每一行 NASM 源代码包含(除非它是一个宏,一个预处理操作 符,或一个汇编器操作符,参况第 4,5 章)下面四个部分的全部或某几个部分: label: instruction operands ; comment 通常,这些域的大部分是可选的;label,instruction,comment 存在或不存在都是允许的。 当然,operands 域会因为 instruction 域的要求而必需存或必须不存在。 NASM 使用反斜线(\)作为续行符;如果一个以一个反斜线结束,那第二行会被认为是前 面一行的一部分。 NASM 对于一行中的空格符并没有严格的限制:labels 可以在它们的前面有空格,或其 它任何东西。label 后面的冒号同样也是可选的。(注意到,这意味着如果你想要写一行"lodsb", 但却错误地写成了"lodab",这仍将是有效的一行,但这一行不做任何事情,只是定义了一个 label。运行 NASM 时带上命令行选项"-w+orphan-labels"会让 NASM 在你定义了一个不以冒 号结尾的 label 时警告你。 labels 中的有效的字符是字母,数字,"-","$","#","@","~","."和"?"。但只有字母".",(具有 特殊含义,参阅 3.9),"_"和"?"可以作为标识符的开头。一个标识符还可以加上一个"$"前缀, 以表明它被作为一个标识符而不是保留字来处理。这样的话,如果你想到链接进来的其它模 块中定义了一个符号叫"eax",你可以用"$eax"在 NASM 代码中引用它,以和寄存器的符号 区分开。 instruction 域可以包含任何机器指令:Pentium 和 P6 指令,FPU 指令,MMX 指令还有 甚至没有公开的指令也会被支持。这些指令可以加上前缀"LOCK","REP","REPE/REPZ"或 "REPNE"/"REPNZ",通常,支持显示的地址尺寸和操作数尺寸前缀"A16","A32","O16"和 "O32"。关于使用它们的一个例子在第九章给出。你也可以使用段寄存器名作为指令前缀: 代 码"es mov [bx],ax"等效于代码"mov [es:bx],ax"。我们推荐后一种语法。因为它和语法中的其 它语法特性一致。但是对于象"LODSB"这样的指令,它没有操作数,但还是可以有一个段 前缀, 对于"es lodsb"没有清晰地语法处理方式 在使用一个前缀时,指令不是必须的,像"CS","A32","LOCK"或"REPE"这样的段前缀可 以单独出现在一行上,NASM 仅仅产生一个前缀字节。 作为对实际机器指令的扩展,NASM 同时提供了一定数量的伪操作指令,这在 3.2 节详 细描述。 20 NASM 中文手册 (整理: Yonsm) 指令操作数可以使用一定的格式:它们可以是寄存器,仅仅以寄存器名来表示(比如: "ax","bp","ebx","cr0":NASM 不使用"gas"的语法风格,在这种风格中,寄存器名前必须加上 一个"%"符号),或者它们可以是有效的地址(参阅 3.3),常数(3.4),或表达式。 对于浮点指令,NASM 接受各种语法:你可以使用 MASM 支持的双操作数形式,或者 你可以使用 NASM 的在大多数情况下全用的单操作数形式。支持的所以指令的语法细节可 以参阅附录 B。比如,你可以写: fadd st1 ; this sets st0 := st0 + st1fadd st0,st1 ; so does this fadd st1,st0 ; this sets st1 := st1 + st0fadd to st1 ; so does this 几乎所有的浮点指令在引用内存时必须使用以下前缀中的一个"DWORD",QWORD"或 "TWORD"来指明它所引用的内存的尺寸。 3.2 伪指令 伪指令是一些并不是真正的 x86 机器指令,但还是被用在了 instruction 域中的指令,因 为使用它们可以带来很大的方便。当前的伪指令有"DB","DW","DD","DQ"和"DT",它们对 应的未初始化指令是"RESB","RESW","RESD","RESQ"和"REST","INCBIN"命令,"EQU" 命令和"TIEMS"前缀。 3.2.1 "DB"一类的伪指令: 声明已初始化的数据 在 NASM 中,"DB", "DW", "DD", "DQ"和"DT"经常被用来在输出文件中声明已初始化的 数据,你可以多种方式使用它们: db 0x55 ; just the byte 0x55db 0x55,0x56,0x57 ; three bytes in successiondb 'a',0x55 ; character constants are OKdb 'hello',13,10,"$" ; so are string constantsdw 0x1234 ; 0x34 0x12dw 'a' ; 0x41 0x00 (it"s just a number)dw 'ab' ; 0x41 0x42 (character constant)dw 'abc' ; 0x41 0x42 0x43 0x00 (string)dd 0x12345678 ; 0x78 0x56 0x34 0x12dd 1.234567e20 ; floating-point constantdq 1.234567e20 ; double-precision floatdt 1.234567e20 ; extended-precision float "DQ"和"DT"不接受数值常数或字符串常数作为操作数。 21 NASM 中文手册 (整理: Yonsm) 3.2.2 "RESB"类的伪指令: 声明未初始化的数据 "RESB", "RESW", "RESD", "RESQ" and "REST"被设计用在模块的 BSS 段中:它们声明 未初始化的存储空间。每一个带有单个操作数,用来表明字节数,字数,或双字数或其它的 需要保留单位。就像在 2.2.7 中所描述的,NASM 不支持 MASM/TASM 的扣留未初始化空 间的语法"DW ?"或类似的东西:现在我们所描述的正是 NASM 自己的方式。"RESB"类伪指 令的操作数是有严格的语法的,参阅 3.8。比如: buffer: resb 64 ; reserve 64 byteswordvar: resw 1 ; reserve a wordrealarray resq 10 ; array of ten reals 3.2.3 "INCBIN":包含其它二进制文件 "INCBIN"是从老的 Amiga 汇编器 DevPac 中借过来的:它将一个二进制文件逐字逐句地 包含到输出文件中。这能很方便地在一个游戏可执行文件中包含中图像或声音数据。它可以 以下三种形式的任何一种使用: incbin "file.dat" ; include the whole fileincbin "file.dat",1024 ; skip the first 1024 bytesincbin "file.dat",1024,512 ; skip the first 1024, and; actually include at most 512 3.2.4 "EQU": 定义常数 "EQU"定义一个符号,代表一个常量值:当使用"EQU"时,源文件行上必须包含一个label。 "EQU"的行为就是把给出的 label 的名字定义成它的操作数(唯一)的值。定义是不可更改的, 比如: message db 'hello, world'msglen equ $-message 把"msglen"定义成了常量 12。"msglen"不能再被重定义。这也不是一个预自理定义: "msglen"的值只被计算一次,计算中使用到了"$"(参阅 3.5)在此时的含义。注意"EQU"的操 作数也是一个严格语法的表达式。(参阅 3.8) 22 NASM 中文手册 (整理: Yonsm) 3.2.5 "TIMES": 重复指令或数据 前缀"TIMES"导致指令被汇编多次。它在某种程序上是 NASM 的与 MASM 兼容汇编器 的"DUP"语法的等价物。你可以这样写: zerobuf: times 64 db 0 或类似的东西,但"TEIMES"的能力远不止于此。"TIMES"的参数不仅仅是一个数值常数, 还有数值表达式,所以你可以这样做: buffer: db 'hello, world'times 64-$+buffer db ' ' 它可以把"buffer"的长度精确地定义为 64 字节,"TIMES"可以被用在一般地指令上,所 以你可像这要编写不展开的循环: times 100 movsb 注意在"times 100 resb 1"跟"resb 100"之间并没有显著的区别,除了后者在汇编时会快上 一百倍。 就像"EQU","RESB"它们一样, "TIMES"的操作数也是严格语法的表达式。(见 3.8) 注意"TIMES"不可以被用在宏上:原因是"TIMES"在宏被分析后再被处理,它允许 "TIMES"的参数包含像上面的"64-$+buffer"这样的表达式。要重复多于一行的代码,或者一 个宏,使用预处理指令"%rep"。 3.3 有效地址 一个有效地址是一个指令的操作数,它是对内存的一个引用。在 NASM 中,有效地址的 语法是非常简单的:它由一个可计算的表达式组成,放在一个中括号内。比如: wordvar dw 123mov ax,[wordvar]mov ax,[wordvar+1]mov ax,[es:wordvar+bx] 任何与上例不一致的表达都不是 NASM 中有效的内存引用,比如:"es:wordvar[bx]"。 更复杂一些的有效地址,比如含有多个寄存器的,也是以同样的方式工作: mov eax,[ebx*2+ecx+offset]mov ax,[bp+di+8] 23 NASM 中文手册 (整理: Yonsm) NASM 在这些有效地址上具有进行代数运算的能力,所以看似不合法的一些有效地址使 用上都是没有问题的: mov eax,[ebx*5] ; assembles as [ebx*4+ebx]mov eax,[label1*2-label2] ; ie [label1+(label1-label2)] 有些形式的有效地址在汇编后具有多种形式;在大多数情况下,NASM 会自动产生最小 化的形式。比如,32 位的有效地址"[eax*2+0]"和"[eax+eax]"在汇编后具有完全不同的形式, NASM 通常只会生成后者,因为前者会为 0 偏移多开辟 4 个字节。 NASM 具有一种隐含的机制,它会对"[eax+ebx]"和"[ebx+eax]"产生不同的操作码;通常, 这是很有用的,因为"[esi+ebp]"和"[ebp+esi]"具有不同的缺省段寄存器。 尽管如此,你也可以使用关键字"BYTE","WORD","DWORD"和"NOSPLIT"强制 NASM 产生特定形式的有效地址。如果你想让"[eax+3]"被汇编成具有一个 double-word 的偏移域, 而不是由 NASM 缺省产生一个字节的偏移。你可以使用"[dword eax+3]",同样,你可以强 制 NASM 为一个第一遍汇编时没有看见的小值产生一个一字节的偏移(像这样的例子,可以 参阅 3.8)。比如:"[byte eax+offset]"。有一种特殊情况,"[byte eax]"会被汇编成"[eax+0]"。 带有一个字节的 0 偏移。而"[dwordeax]"会带一个 double-word 的 0 偏移。而常用的形式, "[eax]"则不会带有偏移域。 当你希望在 16 位的代码中存取 32 位段中的数据时,上面所描述的形式是非常有用的。 关于这方面的更多信息,请参阅 9.2。实际上,如果你要存取一个在已知偏移地址处的数据, 而这个地址又大于 16 位值,如果你不指定一个 dword 偏移,NASM 会让高位上的偏移值丢 失。 类似的,NASM 会把"[eax*2]"分裂成"[eax+eax]" ,因为这样可以让偏移域不存在以此节省 空间;实际上,它也把"[eax*2+offset]"分成"[eax+eax+offset]",你可以使用"NOSPLIT"关键 字改变这种行为:"[nosplit eax*2]"会强制"[eax*2+0]"按字面意思被处理。 3.4 常数 NASM 能理解四种不同类型的常数:数值,字符,字符串和浮点数。 3.4.1 数值常数 一个数值常数就只是一个数值而已。NASM 允许你以多种方式指定数值使用的进制,你 可以以后缀"H","Q","B"来指定十六进制数,八进制数和二进制数,或者你可以用 C 风格的 前缀"0x"表示十六进制数,或者以 Borland Pascal 风格的前缀"$"来表示十六进制数,注意, 24 NASM 中文手册 (整理: Yonsm) "$"前缀在标识符中具有双重职责(参阅3.1),所以一个以"$"作前缀的十六进制数值必须在"$" 后紧跟数字,而不是字符。 请看一些例子: mov ax,100 ; decimalmov ax,0a2h ; hexmov ax,$0a2 ; hex again: the 0 is requiredmov ax,0xa2 ; hex yet againmov ax,777q ; octalmov ax,10010011b ; binary 3.4.2 字符型常数 一个字符常数最多由包含在双引号或单引号中的四个字符组成。引号的类型与使用跟 NASM 其它地方没什么区别,但有一点,单引号中允许有双引号出现。 一个具有多个字符的字符常数会被 little-endian order,如果你编写: mov eax,"abcd" 产生的常数不会是"0x61626364",而是"0x64636261",所以你把常数存入内存的话,它 会读成"abcd"而不是"dcba"。这也是奔腾的"CPUID"指令理解的字符常数形式(参阅 B.4.34) 3.4.3 字符串常数 字符串常数一般只被一些伪操作指令接受,比如"DB"类,还有"INCBIN"。 一个字符串常数和字符常数看上去很相像,但会长一些。它被处理成最大长度的字符常 数之间的连接。所以,以下两个语句是等价的: db 'hello' ; string constantdb 'h','e','l','l','o' ; equivalent character constants 还有,下面的也是等价的: dd 'ninechars' ; doubleword string constantdd 'nine','char','s' ; becomes three doublewordsdb 'ninechars',0,0,0 ; and really looks like this 注意,如果作为"db"的操作数,类似"ab"的常数会被处理成字符串常量,因为它作为字 符常数的话,还不够短,因为,如果不这样,那"db 'ab'"会跟"db 'a'"具有同样的效果,那是 很愚蠢的。同样的,三字符或四字符常数会在作为"dw"的操作数时被处理成字符串。 25 NASM 中文手册 (整理: Yonsm) 3.4.4 浮点常量 浮点常量只在作为"DD","DQ","DT"的操作数时被接受。它们以传统的形式表达:数值, 然后一个句点,然后是可选的更多的数值,然后是选项"E"跟上一个指数。句点是强制必须 有的,这样,NASM 就可以把它们跟"dd 1"区分开,它只是声明一个整型常数,而"dd 1.0" 声明一个浮点型常数。 一些例子: dd 1.2 ; an easy onedq 1.e10 ; 10,000,000,000dq 1.e+10 ; synonymous with 1.e10dq 1.e-10 ; 0.000 000 000 1dt 3.141592653589793238462 ; pi NASM 不能在编译时求浮点常数的值。这是因为 NASM 被设计为可移植的,尽管它常 产生 x86 处理器上的代码,汇编器本身却可以和 ANSI C 编译器一起运行在任何系统上。所 以,汇编器不能保证系统上总存在一个能处理 Intel 浮点数的浮点单元。所以,NASM 为了 能够处理浮点运算,它必须含有它自己的一套完整的浮点处理例程,它大大增加了汇编器的 大小,却获得了并不多的好处。 3.5 表达式 NASM 中的表达式语法跟 C 里的是非常相似的。 NASM 不能确定编译时在计算表达式时的整型数尺寸:因为 NASM 可以在 64 位系统上 非常好的编译和运行,不要假设表达式总是在 32 位的寄存器中被计算的,所以要慎重地对 待整型数溢出的情况。它并不总能正常的工作。NASM 唯一能够保证的是:你至少拥有 32 位长度。 NASM 在表达式中支持两个特殊的记号,即"$"和"$$",它们允许引用当前指令的地址。 "$"计算得到它本身所在源代码行的开始处的地址;所以你可以简单地写这样的代码"jmp $" 来表示无限循环。"$$"计算当前段开始处的地址,所以你可以通过($-$$)找出你当前在段内 的偏移。 NASM 提供的运算符以运算优先级为序列举如下: 26 NASM 中文手册 (整理: Yonsm) 3.5.1 "|": 位或运算符 运算符"|"给出一个位级的或运算,所执行的操作与机器指令"or"是完全相同的。位或是 NASM 中优先级最低的运算符。 3.5.2 "^": 位异或运算符 "^" 提供位异或操作。 3.5.3 "&": 位与运算符 "&" 提供位与运算。 3.5.4 "<<" and ">>": 位移运算符 "<<" 提供位左移, 跟 C 中的实现一样,所以"5<<3"相当于把 5 乘上 8。">>"提供位右移。 在 NASM 中,这样的位移总是无符号的,所以位移后,左侧总是以零填充,并不会有符号 扩展。 3.5.5 "+" and "-": 加与减运算符 "+"与"-"运算符提供完整的普通加减法功能。 3.5.6 "*", "/", "//", "%"和"%%": 乘除法运算符 "*"是乘法运算符。"/"和"//"都是除法运算符,"/"是无符号除,"//"是带符号除。同样的, "%"和"%%"提供无符号与带符号 NASM(Netwide Assembler)是一个开源的汇编语言编译器,它支持多种平台和目标文件格式,包括但不限于Linux、Windows、NetBSD、FreeBSD、OpenBSD、ELF、COFF、a.out、OMF以及纯二进制文件格式。NASM以其简洁的语法、强大的预处理功能、灵活的模块化设计而著称。它支持各种指令集,包括Pentium、P6、MMX、3DNow!、SSE和SSE2等。 NASM的设计理念注重于可移植性和易用性,它的语法风格类似于Intel语法,同时尝试做到简洁易懂。NASM的一个重要特征是它不会存储变量的类型,与MASM不同,它不自动处理段寄存器,也不支持内存模型的概念。这使得NASM在编译时需要程序员提供更多的信息。 NASM支持大小写敏感,这意味着在代码中引用标号、变量和寄存器时,需要严格区分大小写。这与MASM或TASM等汇编器的大小写不敏感特性形成对比。此外,NASM要求使用方括号引用内存地址,而MASM在某些情况下可以省略方括号。 NASM还包含了一系列伪指令(Pseudo-instructions)和预处理器指令(Preprocessor directives),以方便编程。伪指令如DB、DW、DD、DQ和DT用于声明已初始化的数据;RESB、RESW、RESD、RESQ和REST用于声明未初始化的数据;INCBIN用于包含其他二进制文件;EQU用于定义常数;TIMES用于重复指令或数据。 NASM的预处理器非常强大,它提供了定义宏(宏定义可以通过%define、%xdefine)、连接宏(%+)、取消宏定义(%undef)、预处理器变量(%assign)、字符串处理宏(%strlen、%substr)以及多行宏(%macro)等功能。这些预处理器指令增强了NASM的灵活性,使得它可以应对各种复杂的编程需求。 NASM支持条件汇编,包括单行宏的测试(%ifdef、%ifndef)、多行宏的存在测试(ifmacro)、上下文栈测试(%ifctx)、数值表达式测试(%if)、文本相同测试(%ifidn、%ifidni)、记号类型测试(%ifid、%ifnum、%ifstr)以及自定义错误报告(%error)。此外,它还支持预处理器循环(%rep),允许条件执行多个重复指令。 NASM还支持各种目标文件格式的输出,例如bin(纯二进制格式)、obj(微软OMF目标文件格式)、win32(微软Win32目标文件格式)、coff(通用目标文件格式)、elf(可执行可连接格式目标文件)、aout(Linux a.out格式)、as86、rdf(可重定位的动态目标文件格式)以及dbg(调试格式)。 安装NASM相对简单,它提供了在不同操作系统下的安装指南,包括DOS/Windows和Unix系统。安装过程中,NASM为用户提供了详细的信息,包括许可条件、联系信息以及具体的安装步骤。 在源程序行的组成方面,NASM源代码的每一行通常由标签(label)、指令(instruction)、操作数(operands)和注释(comment)四个部分构成。标签用于标识地址,指令用于指定操作,操作数提供了指令的参数,而注释则提供了对代码的解释,这些注释不会被编译器处理。 NASM中的表达式语法与C语言类似,支持位运算符、算术运算符、位移运算符以及一元运算符。NASM还支持直接对特定段进行寻址(SEG)和相对于段寻址(WRT)的操作,以及启用或禁用严格优化模式(STRICT)。 NASM提供了本地标签(LocalLabels)的概念,使得在宏中或特定的作用域内可以使用相同的标签名,而不会产生冲突。这种机制对于编写可重用的代码模块非常有用。 NASM是一个功能强大、灵活且具有多种平台支持的汇编器,它适合于需要精细控制目标代码的场合,同时也适合于那些对性能和可移植性有严格要求的项目。NASM中文手册为用户提供了详尽的指南,帮助用户更好地利用NASM进行汇编语言编程。