源程序的开发过程都需要编辑、编译(汇编)、连接、调试,如图1-8所示。首先,用一个文本编辑器形成一个以ASM为扩展名的源程序文件;然后,用汇编程序翻译源程序,将ASM文件转换为OBJ目标模块文件;最后,用连接程序将一个或多个目标文件(含.LIB库文件)连接成一个.EXE可执行文件。
图1-8 可执行文件的开发过程
要开发汇编语言程序,首先需要安装开发软件。微软MASM原是为开发DOS应用程序设计的,独立的MASM软件包不适合开发32位应用程序。现在的MASM软件集成于Visual C++集成开发环境中,对于初学者来说又显得过于庞大和复杂。本书从MASM 6.11和Visual C++6.0集成开发环境中抽取有关文件,构造了一个基本的MASM开发软件包,主要包含如下程序。
1)BIN子目录保存进行汇编、连接及配套的程序文件,包括:
● MASM 6.15的汇编程序ML.EXE和配套的汇编错误信息文件ML.ERR。这些程序取自Visual C++6.0,用于汇编32位和16位汇编语言程序。NASM汇编程序NASM.EXE,版本2.16.01。
● 32位连接程序LINK32.EXE和配套的动态库文件MSPDB60.DLL,32位子程序库创建、管理文件LIB32.EXE,32位可执行程序、目标模块等二进制文件的结构显示和反汇编程序DUMPBIN.EXE,使用Windows基本API函数所需要的开发导入库文件KERNEL32.LIB等。这些程序取自Visual C++6.0,用于开发32位Windows应用程序。本书将其中连接程序和库管理程序文件名后增加了“32”,以便与16位相应程序区别。由于库管理程序、反汇编程序要调用连接程序,且仍然使用LINK.EXE文件名,所以32位连接程序有名为LINK32.EXE和LINK.EXE的两个文件,但两者实际上是相同的。
● 16位连接程序LINK16.EXE,16位子程序库创建、管理文件LIB16.EXE。这些程序取自MASM 6.11,用于开发16位DOS应用程序。
2)BIN64子目录保存在64位Windows平台,开发64位汇编语言程序的程序文件(64位汇编程序ML64.EXE、连接程序及导入库等文件),取自Visual Studio 2005相关目录。
3)PROGS子目录中存放本书所有示例程序。
4)MASM主目录中主要是本书作者提供的包含文件、库文件、批处理文件等,包括:
● 本书作者编写的32位Windows控制台环境的输入/输出子程序库文件IO32.LIB和配套的包含文件IO32.INC,16位DOS环境的输入/输出子程序库文件IO16.LIB和配套的包含文件IO16.INC,以及配合NASM使用的包含文件IO32N.INC。
● 本书作者编辑的方便操作的快捷方式和多个批处理文件。例如,WIN32.BAT是进入32位控制台的批处理文件,DOS16.BAT是进入16位模拟DOS的批处理文件。再如,MAKE32.BAT用于创建32位Windows控制台应用程序,MAKE16.BAT用于创建16位DOS应用程序,NMAKE32.BAT使用NASM汇编程序生成32位Windows应用程序。
建议将本书配套的MASM软件包安装到硬盘D分区的MASM目录(否则,最好将WIN32.BAT和DOS16.BAT中的设置路径命令“D:\MASM”修改为相应的分区和目录),且将正在进行创建的汇编语言程序存放在MASM主目录中,开发过程中生成的各种文件自然也存放于此,以避免指明文件路径的麻烦和出现找不到文件的错误。
这样,在Windows资源管理器中双击批处理文件即可直接进入MASM目录,用一个简单的命令就可以生成可执行文件(假设源程序文件名是EG0101.ASM,扩展名一定是ASM):
图1-9为快速开发并运行程序的屏幕截图,其中带有下划线的部分是用户输入内容,其他是程序显示结果。
当然,大家还可以使用其他开发软件包,如Steve Hutchesson的免费集成软件包MASM32,但要注意按照其格式要求编写汇编语言程序文件。
源程序文件的形成(编辑)可以使用任何一个文本编辑器,但使用功能完善的编辑软件会提高编程效率。例如,可以使用Windows提供的记事本(Notepad)、DOS中的全屏幕文本编辑器EDIT或者MS Word。大家也可以使用自己熟悉的其他程序开发工具中的编辑环境,如Visual C++或Turbo C的编辑器。一些专用于各种源程序文件编写的文本编辑软件也非常好用。
图1-9 快速开发并运行程序的操作过程
本书配套开发软件MASM主目录中的Notepad2.exe程序也很好用。建议在“设置”菜单中使用“文件关联”命令将汇编语言程序.ASM文件与其建立关联(以后双击.ASM程序就可以打开该记事本),还可以在“查看”菜单中选择使用汇编程序语法高亮方案和语法高亮配置(便于区别助记符、数据等)。另外,在“查看”菜单中选中“行号”,该记事本就可以给程序标示行号,以便出现错误时能够根据提示的行号快速定位到错误语句。
源程序文件是无格式文本文件,注意把它保存为纯文本类型,MASM要求其源程序文件要以ASM为扩展名。现在可以将例1-1的源程序输入编辑器,并以EG0101.ASM为文件名保存在MASM目录下。为了便于操作,本书要求将源程序文件保存在MASM主目录下,开发过程中生成的可执行程序等文件也将保存在MASM主目录下,开发完成后的程序可以放到另外一个目录下保存。为了便于管理,本书中源程序文件的命名规则是:EG表示例题,EX表示习题,前两个数字表示程序所在章号,后两个数字表示例题或习题序号,数字后的字母表示同一个程序的不同格式或解答。
汇编是将汇编语言源程序翻译成由机器代码组成的目标模块文件的过程。MASM 6.x提供的汇编程序是ML.EXE。进入已建立的MASM目录,键入如下命令及相应参数即可以完成源程序的汇编:
其中,ML表示运行ML.EXE程序(保存在BIN子目录下,如果已经建立搜索路径,则可以省略“BIN\”),参数“/c”(小写字母,ML.EXE的参数是大小写敏感的)表示仅利用ML实现源程序的汇编,参数“/coff”(小写字母)表示生成COFF(Common Object File Format)目标模块文件。COFF是32位Windows和UNIX操作系统使用的目标文件格式。上述两个参数必须有,注意参数之间一定要用空格分隔。参数也可以使用短线引导,例如:
如果源程序中没有语法错误,MASM将自动生成一个目标模块文件(EG0101.OBJ),否则MASM将给出相应的错误信息。这时应根据错误信息重新编辑修改源程序文件后,再进行汇编。另外,了解MASM所有的选项参数,可以使用“/?”参数:
【 NASM 】
使用NASM汇编的命令是:
其中,选项参数“-f win32”表示生成32位Windows的目标文件,文件名默认与源程序文件名相同,但扩展名是OBJ。参数“-1”表示生成列表文件,参数“-prefix _”表示将所有函数名前加上前缀下划线(这样,汇编语言程序就可以直接使用函数名,无须添加前缀下划线)。
另外,要获得NASM选项参数的帮助信息,可以使用“nasm -h”命令;要获得其版本信息,则使用“-v”参数。
连接程序能把一个或多个目标文件和库文件合成一个可执行文件。在MASM目录下有了EG0101.OBJ文件,键入如下命令实现目标文件的连接:
其中,参数“/subsystem:console”必须有,表示生成Windows控制台(Console)环境的可执行文件。如果生成图形窗口的可执行文件,则应该使用“/subsystem:windows”参数。参数“/libpath:bin”给出连接时使用各种库文件的路径。如果使用C语言函数,还需要加上参数“/defaultlib:msvcrt.lib”,表明使用包含C标准函数的导入库。
如果连接过程没有错误,将自动生成一个可执行文件(EG0101.EXE),否则连接程序将给出错误信息。这时应根据错误信息相应修正,再进行汇编和连接。
软件开发的主要步骤是编译(汇编)和连接。为了方便操作,可以编辑一个批处理文件MAKE32.BAT,将其中的汇编和连接以及需要的参数事先设置好,例如:
@echo off表示不显示下面的命令,@echo on则表示显示命令。REM开头表示这是一个注释行。汇编和连接命令中使用“%1”代表输入的第一个文件名(扩展名已经表示出来,所以不需要输入英文句号及扩展名)。如果汇编和连接过程中没有错误,将在MASM目录生成列表文件、目标文件和可执行文件等,并使用文件列表DIR命令进行显示。如果汇编或连接有错误,“if-goto”命令将跳转到terminate位置,结束处理。
汇编程序ML和连接程序LINK支持很多参数,以便控制汇编和连接过程,用“/?”参数就可以看到帮助信息。例如,ML可以用空格分隔多个ASM源程序文件,以便一次性汇编多个源文件。LINK也可以将多个模块文件连接起来(用加号“+”分隔),形成一个可执行文件;还可以带LIB库文件进行连接。再如,ML的参数“/Fl”表示生成列表文件(稍后介绍);要在调试程序中直接使用程序定义的各种标识符,可在ML命令中增加参数“/Zi”,LINK命令中增加参数“/debug”,表示生成调试用的符号信息。
【 NASM 】
使用NASM汇编生成的目标文件使用相同的连接程序生成可执行文件,例如:
由于NASM源程序没有指明起始执行位置,所以,需要加上“/entry:start”参数。
例1-2中的程序调用C语言函数,所以使用“/defaultlib:msvcrt.lib”参数。同样,可以将NASM汇编和连接过程编辑为一个批处理文件NMAKE32.BAT。不过,它只需要将MAKE32.BAT中的汇编命令和连接命令更换为:
运行Windows控制台(或模拟DOS环境)的可执行文件,需要首先进入控制台(或模拟DOS)环境,然后在命令行提示符下输入文件名(可以省略扩展名)并按下回车键:
操作系统将该文件载入主存,开始运行。如果发现运行错误,可以从源程序开始进行静态排错,也可以利用调试程序进行动态排错。一般不要在Windows资源管理器下双击文件名启动Windows控制台(或DOS)可执行文件,这样往往看不到运行的显示结果,屏幕显示只是一闪而过。
列表文件(List File)是一种文本文件,扩展名为LST,包含源程序和目标代码,对大家学习汇编语言和发现错误很有用。创建列表文件时,需要ML汇编程序使用“/Fl”参数(大写字母F,接着小写字母l,不是数字1),例如,输入如下命令:
该命令除产生模块文件EG0101.OBJ外,还将生成列表文件EG0101.LST。列表文件有两部分内容,第一部分是源程序及其代码,如下所示:
在第一部分中,最左列是数据或指令在该段从0开始的相对偏移地址(十六进制数形式),中间是存放在主存的数据或指令的机器代码(从低地址开始,十六进制数形式,操作码部分以字节为单位,操作数则以数据类型为单位),最右列则是汇编语言语句。机器代码后有字母“R”,表示该指令的立即数或位移量现在不能确定或只是相对地址,它将在程序连接或进入主存时才能定位。调用指令代码后的字母“E”表示子程序来自外部(External),详见附录E。如果程序中有错误(Error)或警告(Warning),也会在相应位置提示。Error是比较严重的语法错误,不能产生机器代码或产生的代码无法正确运行;Warning一般是不太关键的语法错误,有些警告并不影响程序的正确性。
列表文件的第二部分是各种标识符的说明,部分内容如下所示:
这部分列表文件中罗列了程序中使用的宏(Macros)、段和组(Segments and Groups),以及标号、变量名、子程序名等符号(Symbols)的有关信息。这些信息包括类型(Type)、段的操作数和地址长度(Size)、段的字节数量(Length)、变量的初始数值(Value)等。读者在学习第2章后才能理解这些内容。
学习程序设计和进行实际的程序开发往往离不开调试程序,有时还会用到反汇编程序等工具软件。为了让调试程序方便进行源程序级调试,汇编时需要增加参数“/Zi”,连接命令中增加参数“/debug”。这时,连接过程还将生成增量状态文件(.ILK,微软连接程序的数据库,用于增量连接。重新连接时会提示警告信息,不必理会)和程序数据库文件(.PDB,保存调试和项目状态信息,使用这些信息可以对程序的调试配置进行增量连接)。
本书主要介绍微软免费提供的Windows调试程序WinDbg(Microsoft Debugging Tools For Windows),其使用方法详见附录A,配合汇编语言的具体应用将在随后章节逐渐引入。