NASM网际编译器手册_第1页
NASM网际编译器手册_第2页
NASM网际编译器手册_第3页
NASM网际编译器手册_第4页
NASM网际编译器手册_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 NASM 网际编译器手册网际编译器手册 第第 1 章章 简简介介 1 1 什么是什么是 NASM 网际汇编器 NASM 是一个模块化和便携性的 80 x86 汇编编译器 它支持多种目标格式 包含 Linux 的 a out ELF NetBSD FreeBSD COFF Microsoft 的 16 位 OBJ 和 Win32 它输出 平坦模式的二进制文件 它在语法设计上简单且容易理解 和 Intel 的相似但没有那么复 杂 它支持 Pentium P6 和 MMX 操作码 并且宏操作方面兼容 1 1 1 为什么不用其它编译器 为什么不用其它编译器 网际编译器是在基于 comp lang asm x86 也可能是 alt lang asm 我记不清了 上的思想 成长起来的 它在本质上不象周围很好的自由 x86 系列编译器 并且应有人写一个 a86 是比较好的 但并不免费 通常你不能得到任何 32 位兼容的除非你付费 它只支持 DOS gas 是免费的 并且适应于 DOS 和 Unix 但它不是很好用 由于它被设计成相对 于 gcc 的后端 所以必须给它输入一些正确的密码 导致它的错误检查是很小 因此 从这方面来看待和真正写些代码来说 它的语法是很难懂的 另外你不能用它写 16 位代 码 正常情况下 as86 是 Linux 专用的 并且有很多文档 至少对我来说 MASM 不是 很好用 它太贵了 并且只能在 DOS 下运行 TASM 好一些 但仍在和 MASM 相兼容 意味着将会有不计其数的指令的官文 它的语法本质上和 MASM 相同 但它也很贵 只在 DOS 下运行 因此 这里为了编码的快乐 用 NASM 现在它仍然处理试验阶段 我 不能保证它这些编译器好 但请向我们报告程序中的问题 修改意见及帮助信息 和任何 你现有的信息 感谢很多人会这样做 你知道你也会 我们将不断的发展它 1 1 2 软件许可协议软件许可协议 请查看许可协议文件 做为 NASM 描述档案的一部分提供 你可以在许可协议下使 用 NASM 1 2 联系方式联系方式 当前版本的 NASM 从 0 98 是由 H Peter Anvin hpa 维护的 如果你想报 告任何程序问题 请先读一下第 10 2 节 NASM 有一个网页为 htt 原始作者可邮寄电子信箱 jules 和 anakin 最新版本的 NASM 已经上传到 ftp kernel org sunsite unc edu 和 通 告将发布在 comp lang asm x86 alt lang asm comp os linux announce 和 comp archives msdos announce 最后一个将自动传到 上 如果你没有新闻组可以 访问 或者更喜欢用电子邮件进行交流 你可以发送一行包含 subscribe nasm announce 的 内容的邮件到 majordomo linux kernel org 如果你想了解 NASM beta 版的有关信息 请发送 一封含有 subscribe nasm beta 信息的电子邮件到 1 3 安装安装 1 3 1 在在 MS DOS 或或 Windows 下安装下安装 NASM 当你得到 NASM 的 DOS 版本的文件时 nasmXXX zip XXX 表示 NASM 的版本号 将 它解压到当前目录下 例如 C NASM 2 这个文件包含 4 个执行文件 NASM 的执行文件为 nasm exe 和 nasmw exe 和 NDISASM 的执行文件 ndisasm exe ndisasmw exe 这个文件夹里文件名后有 w 为一个 win32 可执行文件 被设计在 windows95 或 windows NT 下运行 另外的是 16 位的 DOS 执 行程序 NASM 文件要运行它的自运行文件 因此拷贝 至少 nasm exe 和 nasmw exe 的 一个到你的目录下 或选择一个编辑 autoexec bat 文件将 nasm 的路径加到你的 PATH 目录 上 如果你要节省空间可以删除它 然而 你可以保留这个文件或测试程序 如果你 下载了 DOS 的源码文件包 nasmXXXs zip nasm 目录将包含完事的 NASM 源代码 你可 以选择一个 MAKEFILE 推荐 来重新编译 NASM README 文件列出了这些 MAKEFILE 之间的不同和用什么编译程序编译的 注意源文件 insnsa c insnsd c insnsi h 和 insnsn c 是自动从 Perl 角本文件 主指令列表文件 insns dat 生成的 文件 macros c 是通过 另一个 Perl 角本从 standard mac 生成的 虽然 NASM 0 98 的发布包含这些生成文件 但如 果你改变了 insns dat standard mac 或相关文档 你还是需要重新编译它 因此你需要一个 Perl 解释器 也许以后的源码发布文档根本就不包含这些文件 Perl 在不同平台 包含 DOS 和 Windows 的输出变化 在 http www cpan org 可以找到 1 3 2 在在 Unix 下安装下安装 NASM 一旦你得到 NASM 的 Unix 源码文件 nasm X XX tar gz 这里 X XX 表示档案中包含 NASM 的版本号 你就可以把它解压到如 usr local src 的目录下 这个档案一旦解压会生 成它自己的子目录 nasm X XX NASM 是一个自配置压缩包 你解压后 用 cd 命令到它解 压的目录下 然后用 type configure 命令 这个 shell 角本将会找到最好的 c 编译器来编译 NASM 并建立相应的 Makefiles 文件 一旦 NASM 自动配置后 你就可以用命令 type make 来编译 nasm 和 ndisasm 二进制文件 然后用命令 install 来将它们安装到 usr loacl bin 下 将 nasm 1 和 ndisasm 1 的帮助文件安装到 usr local man man1 目录下 对于有选择的 你可 以给出如 prefix 来配置角本 关于安装的详细信息见 INSTALL 文件 或者安装你自己的程 序 NASM 也提供一些关于 RDOFF 自定义目标文件格式的工具 这些在 NASM 压缩包的 rdoff 子目录下 如果你想用他们的话 如果 NASM 自配置失败的话 你可以用 Unix 的失 败后退 makefile 文件 Makefile unx 来编译它 对 Makefile 文件拷贝或重命名文件 并试关 重新编译 在 rdoff 子目录下也有一个 Makefile unx 文件 第二章第二章 运行运行 NASM 2 1NASM 命令行参数命令行参数 为了汇编一个文件 你必须用一个命令行来实现 nasm f o 例子 nasm f elf myfile asm 将文件 myfile asm 汇编成一个 elf 目标文件 myfile o nasm f bin myfile asm o 将文件 myfile asm 汇编成一个二进制文件 为了生成一个列表文件 用参数 l 来给出一个列表文件名 例如 nasm f coff myfile asm l myfile lst 为了得到更多关于 NASM 指令用法请用命令 nasm h 3 这也可以列出有效的输出文件格式 及它们是什么 如果你用 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 或相似的一些信息 你的系统应该是 a out 的 你应该用 use f aout 来代替 Linux a out 系统被认为淘汰了 现在很小见 象一些 Unix 编译器 NASM 是默认的除非它出错 你瘵不能看到它输出任何信息 除非它显示错 误信息 2 1 1 o 参数参数 指定输出文件名指定输出文件名 NASM 正常情况下将为你指定输出文件名 它对目标文件格式是独立的 对于微软的 目标格式文件 obj 和 win32 它将从你的源文件移走 asm 扩展名 或者你用 NASM 来忽略 并加上 obj 扩展名 对于 Unix 目标文件格式 aout coff elf 和 as86 它将为 rdf 加上 o 它将用 rdf 而对于二进制文件它只是简单的移去扩展名 所以 myfile asm 文件将生成名为 myfile 的 输出文件 如果输出文件存在 NASM 将覆盖它 除非它有相同名字的输入文件 这种情况 它将组出一个警告并用 nasm out 来代替输出文件名 这种替换行为是不允许的 NASM 提 供 o 命令行参数来允许你指定你想要的输出文件名 你可以在 o 后边加空格或不加空格 然后在加文件名 如 nasm f bin program asm o nasm f bin driver asm odriver sys 2 1 2 f 参数 指定输出文件格式参数 指定输出文件格式 如果你不用 f 参数指定文件格式 NASM 将为你指定一种格式 在 NASM 的发布版本中 默认的为 bin 如果你编译你自己的 NASM 拷贝 你可以在编译时重新定义 OF DEFAULT 并且选择你想默认的文件名 象 o 参数一样 在 f 和输出文件格式之间的空格是可选的 所 以 f elf 和 felf 都是有效 一个完整的输出文件格式列表可能过命令 nasm h 来得到 2 1 3 l 参数 生成列表文件参数 生成列表文件 如果你用 NASM 的 l 参数 后面加文件名 通常中间加 NASM 将生成一个源码列表文件 生成的代码和地址被列在左边 还有真正的源码 并带有多行宏的扩展 除了指定在要求 在源码列表不扩展 见第 4 2 9 节 在右边 例如 nasm f elf myfile asm l myfile lst 2 1 4 E 参数 将错误信息输出到文件中参数 将错误信息输出到文件中 在 MS DOS 下将程序的错误信息输入到一个文件中是比较困难 虽然这有方法 因 此 NASM 通常将警告信息和错误信息显示在屏幕上 如果你想捕获这些信息并存入到编辑 器中将是比较困难的事 NASM 因此提供了 E 参数然后加上文件名将会使错误输出到文件 中而不是标准错误设备上 因此你可以通过命令 typing nasm E myfile err f obj myfile asm 重新将错误信息输出到文件中 2 1 5 s 参数 将错误输出到标准输出上参数 将错误输出到标准输出上 s 参数将错误信息重新定位到标准输出面不是标准错误上 因此它能在 MS DOS 下运 4 行 为了汇编文件 myfile asm 并且将它通过管道输出到其它程序中 你可以通命令 nasm s f obj myfile asm more 关于 E 参数的详细信息请看第 2 1 4 节 2 1 6 i 参数 头文件设置路径参数 头文件设置路径 当 NASM 在源文件中查看 include 定向符号时 详细信息见第 4 5 节 它将搜索在命 令行中指定的目录而不只是当前目录中文件 你也可以从一个宏库文件中包含文件 例如 用命令 nasm ic macrolib f obj myfile asm 通常在 i 和路径名中的空格是可选的 NASM 在源码级兼容方面比较感兴趣 不用理 解不同操作系统间文件名的转换 你提供的字符串做为 i 参数将写到头文件的名字 因此 在上面的例子中加反斜杠是需要的 在 Unix 下 在前面加上一个斜杠也是需要的 你可 以利用这点 如果你真想做的话 那么参数 ifoo 将引起 include bar i 来搜索文件 foobar i 如果你想要定义一个标准头文件搜索路径 在 Unix 系统上象 usr include 你应该在 NASM 的环境变量中用一个或多个 i 定向符 见第 2 1 13 节 为了与许多的 C 编译器的 Makefile 相兼容 这个参数也可以指定为 I 2 1 7 p 参数 预包含头文件参数 预包含头文件 NASM 允许你通过 p 参数指定文件预包含到你的源文件中 所以命令 nasm myfile asm p myinc inc 和运行 nasm myfile asm 然后在文件的开始置换 include myinc in 等价 和 I D U 参数一 样 这个操作也可以写成 P 2 1 8 d 参数 预定义宏参数 预定义宏 p 参数给出了一个在源文件开始处可选择 include 定向符的方法 d 参数给出了可选择 define 定向符的方法 你可以将代码 nasm myfile asm dFOO 100 写成 define FOO 100D 在 文件开始时 你可以关掉宏的值如 dFOO 等价与 define FOO 这个定向符的表格对汇 编时的参数选择有用 如 ifdef 例如 dDEBUG 为了和许多 C 编译器的 Makefile 文件兼容 这个参数可以写成 D 2 1 9 u 参数 取消一个宏的定义参数 取消一个宏的定义 u 参数在已经预定义一个宏的情况下取消一个宏的定义 并且自动取消前面命令行中的 p 或 d 参数 例如 命令行参数 nasm myfile asm dFOO 100 uFOO 的作用是在程序中取消以前定义的 FOO 宏 这对于在 Makefile 中重载参数比较有用 为了许多 C 编译器的 Makefile 兼容 这个参数可以指定为 U 2 1 10 e 参数 只进行预处理参数 只进行预处理 NASM 允许在它运行时进行预处理到某一点 用 e 参数 不需参数 将会使 NASM 在它的输 入文件中进行预处理 扩展所有宏参数 移去注释和预处理符 并且在标准输出上显示结 果文件 也可以用 o 参数将结果存到文件中 这个参数不能应用于那些对独立符号值进 5 行预处理的操作如 assign tablesize tablestart 将在只进行预处理模式中引起一个错误 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 而产生 0 x7ffffffff 的错误 这个警告默认情况是允许 的 2 1 13 NASM 的环境变量的环境变量 如果你定义了一个叫 NASM 的环境变量 程序将会把它解释为为一个外部命令行参数 在真正的命令行以前进行处理 你可以用这个来为头文件定义标准的搜索路径 通过在 NASM 变量中用 i 操作 这个变量的值用空格分开 以致于 s ic nasmlib 将做为 2 个单独的 操作 然而 这意味着变量 dNAME my name 不会做你想要做的事 因为它将在空格处分开 并且 NASM 命令行处理器将会得到两个无意义的字 dNAME my and name 为了可以这样 做 NASM 提供了一个操作 如果你在变量的前面字符加一个不为负号的字符 NASM 将会这 个符号做为分隔符 所以设置变量 s ic nasmlib 等价于 s ic nasmlib 但 dNAME my name 将会工作 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 6 那么下面两行代码 mov ax foo 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 不同 详细信息请见第四章和第五章 7 第三章第三章 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 前缀 8 3 2 1 DB 和有关指令 定义初始化数据 DB DW DD DQ 和 DT 在 MASM 中用的很多 它们是用来定义输出文件的初始化数 据了解的 它们使用的方式很 多 db 0 x55 只定义一个字节 0 x55 db 0 x55 0 x56 0 x57 成功定义三个字节 db a 0 x55 定义字符常量 db hello 13 10 这是字串常量 dw 0 x1234 0 x34 0 x12 dw a 0 x41 0 x00 它只是一个数字 dw ab 0 x41 0 x42 字符常量 dw abc 0 x41 0 x42 0 x43 0 x00 字串 dd 0 x12345678 0 x78 0 x56 0 x34 0 x12 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 file dat 包含整个文件 incbin file dat 1024 跳过前 1024 个字节 incbin file dat 1024 512 跳过前 1024 个字节 并且最多只包含 512 个字节 3 2 4 EQU 定义常量 定义常量 EQU 字义一个给定的符号为常数 当 EQU 被用时 源码行必须包含一个标号 EQU 的用法 是给一个数定义一个标号名字 这个定义是固定的 不能在以后的代码改变它 例如 message db hello world msglen equ message 定义 msglen 为常数 12 msglen 不能在以后重新定义 这也不是一个预处理定义 msglen 是 9 当时就被赋值的 用 符号 见第三 3 5 节关于 的说明 定义时 意思是说它的值为后面字串 的长度 要注意的是 EQU 也是一个临界表达式 说明见 3 7 3 2 5 TIMES 重复指令和数据重复指令和数据 TIMES 前缀将使指定的指令多次进行编译 这个指令等价于在 MASM 及其兼容的编译器 中的 DUP 指令的用法 在你的代码中可以这样写 buffer db hello world times 64 buffer db 以上指令将会使用一个存储空间 这个空间会存储缓冲区上限到 64 时的总长度 最后 TIMES 可以和普通指令用 你可以用以下指令来执行一个不用回退的动作 times 100 movsb 要注意的是 指令 times 100 resb 1 和 resb 100 之间是没有什么区别的 准确的说后者在编 译器的内部运行时将比前者快 100 倍左右 TIMES 指令与 EQU RESB 及其它相关指令一 样 是一个临界的表达式 见第 3 7 节说明 注意 TIMES 也不被用于宏操作上 原因是 TIMES 将在宏操作后面才处理 因此编译器允许 TIMES 后面加参数象上面的 64 buffer 一样 为了重复执行一个以上的代码行或复杂的宏 应该用预处理符 rep 3 3 关于有效地址关于有效地址 一个有效地址是一个引用内存有效地址的指令中的操作数 在 NASM 中 有更简单的语法 它由一个含有方括号 和方括号中的要求地址组成 例如 wordvar dw 123 mov 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 NASM 兼容这些有效地址的代数运算 所以有些看起来不对的实际上确是完全正确的 mov eax ebx 5 象汇编语句 ebx 4 ebx 一样 mov eax label1 2 label2 等价于 label1 label1 label2 有些有效地址格式有很多种形式 NASM 在这种情况将会生成最小的一种格式 这将不同 于 32 位的有效地址 eax 2 0 和 eax eax NASM 通常对后者将会用 4 个字节来存储一个 0 偏移 NASM 有一个提示机制来使 eax ebx 和 ebx eax 来生成不同的操作数 由于 esi ebp 和 ebp esi 用不同的默认值寄存器 然而 你可以用关键字 BYTE WORD DWORD 和 NOSPLIT 来限制 NASM 在一个特殊的表格中生成一个有效 地址 如果你想用双字偏移来编译 eax 3 来代替 NASM 通常的一个字节 你可以用 dword eax 3 同样 你可以用 byte eax offset 来限制 NASM 用一个字节偏移来编译一个第 一遍没有编译的小值 第 3 7 节有这样的一个例子 byte eax 将会用一个人偏移来编译 eax 0 而 dword eax 将用一个双字节的 0 偏移 正常格式的 eax 是没有偏移的这个域的 同样的 NASM 由于允许偏移域和空间被存储 所以会将 eax 2 分成 eax eax 事实上 它 也会将 eax 2 offset 分成 eax eax offset 你也可以 NOSPLIT 关键字来阻止这种情况产生 10 nosplit eax 2 将会变成 eax 2 0 3 4 常量常量 NASM 将常量分成 4 种类型 数字 字符 字串和浮点数 3 4 1 数字常量数字常量 数字常量是简单的数字 NASM 允许你指定不同进制来定义数字常量 你可以用后缀 H Q B 来分别表示十六进制 八进制 二进制 或者你也可以用前缀 0 x 来表示 C 形式 的十六进制 或者你也可以用前缀 来表示 Pascal 形式的十六进制 注意 前缀 有两种用 法 见第 3 1 节 所以一个十六进制用前缀 来表示时 必须用一个数字做为第一个字母 例如 mov ax 100 十进制 mov ax 0a2h 十六进制 mov ax 0a2 还是十六进制 0 是需要的 mov ax 0 xa2 还是十六进制 mov ax 777q 十进制 mov ax 10010011b 二进制 3 4 2 字符常量字符常量 一个字符常量为一个由单引号或以引号包含的最多面手个字符的形式 这种引用方式对 NASM 没有区别 除非有后的常量用单引号引用允许在里面用双引号 反之亦然 多于一 个字符的字符常量将会以 little endian 来排列 例如 mov eax abcd 那么常量将不是 0 x61626364 而是 0 x64636261 所以如果你想将一个值存到内存中 它将 读成 abcd 而不是 dcba 这也是字符常量被 Pentium sR CPUID 指令接受的原因 3 4 3 字串常量字串常量 字串常量只能被命令为 DB 系列和 INCBIN 伪操作符处理 一个字串常量看起来更象一个字 符常量 只是长度不同 它的处理方式为根据实际情况将最大尺寸的字符常量连接而成 所以下而的例子是等价的 db hello 字串常量 db h e l o 等价的字符常量 下面的也是相互等价的 dd ninechars 双字字串常量 dd nine char s 为三个双字常量 db ninechars 0 0 0 看起来更合理些 注意当用 db 做为操作数时 一个象 ab 这样的常量做为字串常量时将会尽量变成一个短的 字符常量 因为 db ab 将简单和 db a 等价 同样 三个字符和四个字符的常量用 dw 来处理时是一 样的 3 4 4 浮点数常量浮点数常量 浮点数只能用 DD DQ 和 DT 伪操作来处理 他们将在一个传统的格式表达 数字 数值 11 然后是一系列可选项的数字然后是一个以指数 E 结尾 所以 NASM 将会区分出 dd 1 为定 义一个整数常量而 dd 1 0 为定义一个浮点数常量 例子 dd 1 2 一个简单例子 dd 1 e10 10 000 000 000 dd 1 e 10 与 1 e10 相同 dd 1 e 10 0 000 000 000 1 dd 3 141592653589793238462 pi NASM 不能对浮点数常量进行编译时算术运算 这是因为 NASM 被设计成便携的 虽然它 经常生成可以在 x86 上 运行的代码 汇编程序将用 ANSI C 的编译器运行在任何系统上 然而 编译器将不能保 证 Intel 的数字格式 上浮点数的兼容性 所以 NASM 只能处理它自己的浮点数运算 使汇编器由于一点好处而 增加尺寸 3 5 表达式表达式 NASM 里的表达式与 C 语言中的相似 NASM 不能保证编译时表达式的整数尺寸 因此 NASM 能够很轻松的在 64 位系统上编译并运行 不能假设表达式等同与 32 位寄存器而故 意使整型溢出 这样它或许不能工作 NASM 能保证 ANSI C 做到的都能做到 你到少在 32 位上工作 NASM 支持两种特殊的表达式 允许计算当前汇编的位置 和 为到表达式行开始的 位置且包含表达式 所以你可以用 JMP 来处理一个无限循环的操作 当前段的位置 所以你可以用 得到当前位置到当前段有多远的 按优等权的等级 将算术操作符列在下面 3 5 1 或操作 或操作 操作给出了一个或逻辑运算 和 OR 机器指令一样 OR 是 NASM 中算术运算级别最低的 3 5 2 异或运算异或运算 提供一个异或运算操作 3 5 3 weird seg 是一个段基址 mov ea ax mov bx symbol wrt weird seg 取 ES BX 的方法不同 但实现的功能相同 指针都指向符号 symbol NASM 支持一个远调用 内部段 及一个段 偏移形式的跳转 这里段和偏移都是立即数 所以进行一个远调用 你也可以用以下代码 call seg procedure procedure call weird seg procedure wrt weird seg 为了更详细说明括号里的为注释 可以不要 NASM 支持远调用的语法 和上面第一种用 法相同 JMP 和 CALL 工作方法相同 在数据段里为了定义一个远指针 你必须这样写 dw symbol seg symbol 虽然你可以经常构造一些宏观世界处理 但 NASM 支持象上面的不方便的方式 3 7 临界表达式临界表达式 NASM 的一个局限性在于它是一个两遍的编译器 不象 TASM 或其它的编译器 它只做两 遍编译 因而它不能应付哪些要二遍以上的复杂源码文件 第一遍编译用来检查被编译数 据和代码的尺寸 而第二遍编译用来生成物所有代码 已知的符号地址和代码引用地址 所以 NASM 不能处理的一件事情是代码的尺寸由一个在定义在代码后的决定的情况 例如 times label db 0 label db Where am I 在这个例子中 TIME 后的参数根本什么都不等于 NASM 将拒绝这种情况由于它不能确 TIMES 行的尺寸 下面的代码也是不对的 times label 1 db 0 13 label db Now where am I 这里对于 TIMES 后参数的任何值的定义都是错的 NASM 所拒绝的这些例子及相关表达 式被称为临界表达式 也就是说明一个表达式的值必须在第一遍编译时就确定 并且只依 赖于它前面的符号定义 对于 TIMES 前缀是一个临界表达式 同样对于 RESB 系列的参数 伪操作数的参数也是临界表达式 临界表达式可以使上下文保持好 考虑以下代码 mov ax symbol1 symbol1 equ symbol2 symbol2 在第一遍编译时 NASM 不能决定 symbol1 的值 由于定义 symbol1 的 symbol2 没有被 NASM 找到 第二遍编译时 它遇到了 mov ax symbol1 它由于仍然不知道 symbol1 的值 所以仍然不能生成代码 当它处理下一行时 它找到 EQU 并且得到解决 symbol1 的值 但 这已经太晚了 NASM 通过定义一个 EQU 的右边临界表达式来解决这个问题 这样在第 一遍编译时 symbol1 将会被拒绝 这有一些相关的例子 mov eax ebx offset offest equ 10 NASM 在第一遍编译时 必须计算出指令 mov eax ebx offset 的尺寸 虽然不知道 offset 的值 它无法知道 offset 是一个 1 字节的小值还是短整型格式有效地址的编码 它所能知 道的就是在第一遍编译中 offset 应为一个代码 的一个符号 它可能用 4 个字节来填充 所以它为了适应 4 字节地址部分来记算指令的尺寸 在第二遍编译中 为了维持这个判断 它要被迫使指令变得很大 所以这种方式产生的代码将不再是以前哪么小 这种问题可以 通过在 offset 前定义它或用 byte ebx offset 来限制有效地址的尺寸 3 8 本地标号本地标号 NASM 对标号开始的部分进行了特殊处理 一个在单周期开始的标号为一个本地标号 也 就是说它与以前的非 本地标号有关 所以例如 label1 一些代码 loop 一些代码 jne loop ret label2 一些代码 loop 更多的代码 jne loop ret 在上面的代码中 每个 JNE 都跳到它前面的行中 这是因为两个 loop 的定义被前面的非本 地标号分开了 本地标号的处理方式是从旧 Amiga 汇编器 DevPac 中借鉴来的 然而 NASM 对其进一步发展了 允许访问其它代码中的本地标号 这意味着在前面非本地标号 中定义标号是可以的 上面的第一个 loop 的定义是定义一个符号 label1 loop 第二个定义 是定认一个符号 label2 loop 所以你可以这样写代码 label3 一些代码 更多代码 jmp label1 loop 这样做是可以的 在宏中 例如可以定义一个在任何地方被访问的标号但不能被正常本地标 号机制所打扰 这样的标号不能是非本地标号 因为它将被除数后来本地标号的定义 引 14 用所打扰 它也不能是本地的 因为定义它的宏不知道这个标号的全名字 NASM 因此引 用了第三种标号 它只在宏定义中有用 如果一个标号用一个前缀 那么它在本地标 号机制中什么都不做 所以你可以写 label1 一个非本地标号 local 这是一个标号 label1 local foo 这是第三种标号 label2 另一个非本地宏 local 这是一个标号 label2 local jmp foo 这将向前跳三行 NASM 也兼容在双周期定义其它的指定符号例如 start 用来指定 obj 输出格式的入口点 见第 6 2 6 节 字的地址重定位引用 或一个寄存器的执行 4 2 多行宏 多行宏 macro 多行宏与 MASM 和 TASM 中的宏类型有些相似 一个 NASM 中的多行宏象下面这样 macro prologue 1 push ebp mov ebp esp sub esp 1 endmacro 这里定义了一个 C 样式的宏 prologue 所以你可以象下面这样用 call 来调用这个宏 myfunc prologue 12 它会扩展成三行 myfunc push ebp mov ebp esp sub esp 12 宏 macro 后面的数字 1 定义了 prologue 宏将要接受的参数的个数 宏里面的符号 1 是对 调用宏时第一个参数的引用 当宏要引用多个参数时 它会用 2 3 来表示 多行宏象 单行宏一样是区分大小写的 除非你用 imacro 来定义多行宏 如果你要将逗号做为多行 宏中参数的一部分时 你可以将整个参数放到一个括号中 如下所示 macro silly 2 2 db 1 endmacro silly a letter a letter a db a silly ab string ab string ab db ab silly 13 10 crlf crlf db 13 10 4 2 1 重载多行宏重载多行宏 与单行宏一样 多行宏也可以用相同名字不同参数的宏在后面进行重载 这也包含一个参 数都一带的宏 所以你可以定义 macro prologue 0 push ebp mov ebp esp endmacro 15 定义一个重载的宏将不会分配本地的堆栈空间 然而有时 你可能想用 overlod 重载一个 机器指令 如 macro push 2 push 1 push 2 macro 这样你的代码会变成 push ebx 这行不是宏调用 push eax ecx 这行是 通常 NASM 对上同两行会出警告信息 因为 push 被定义一个宏 然后会用一个没有定义 的参数来执行

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论