文章目录[隐藏]
可以用任意的文本编辑器来编辑源程序,只要最终将其存储为纯文本文件即可。在我们的课程中,使用DOS下的Edit。以程序4.1为例,说明工作过程。
编辑源程序
我们直接采用记事本编辑另存为C盘 根目录 1.asm
assume cs:codesg codesg segmend mov ax,0123H mov bx,0456H add ax,bx add bx,bx mov ax,4c00H int 21H codesg ends end
编译
在4.3节中,完成对源程序的编辑后,得到一个源程序文件c:\l.asm 可以对其进行编译,生成包含机器代码的日标文件。
在编译一个源程序之前首先要找到一个相应的编译器。在我们的课程中,采用微软的masm5.0汇编编译器,文件名为masm.exe 假设汇编编译器在c:\masm目录下。可以按照下面的过程来进行源程序的编译,以c:\l.asm为例。
(1)进入DOS方式,进入c:\masm目录,运行masm.exe,如图4.5所示。
图4.5中,运行masm后,首先显示出一些版本信息,然后提示输入将要被编译的源程序文件的名称。注意,"[.ASM]”提示我们,默认的文件扩展名是asm,比如,要编译的源程序文件名是,"pl.asm",只要在这里输入“p1”即可。可如果源程序文件不是以asm为扩展名的话,就要输入它的全名。比如源程序文件名为“p1 .txt",就要输入全名。
在输入源程序文件名的时候一定要指明它所在的路径。如果文件就在当前路径下,只输入文件名就可以,司一如果文件在其他的日录中,则要输入路径,比如,要编译的文件p1 .txt在“c:\windows\desktop”下,则要输入“c:\windows\desktop\p l .txt”。
这里,我们要编译的文件是C盘根录下的l .asm,所以此处输入“c:\l.asm "。
(2)输入要编译的源程序文件名后,按Enter键,屏幕显示如图4.6所示。
图4.6中,在输入源程序文件名后,程序继续提示我们输入要编译出的目标文件的名称,目标文件是我们对一个源程序进行编译要得到的最终结果。注意屏幕上的显示:
"[ 1.OBJ]",因为我们己经输入了源程序文件名为1.asm,则编译程序默认要输出的目标文件名为l.obj,所以可以不必再另行指定文件名。直接按Enter键,编译程序将在当前的目录下,生成l .obj文件。
这里,也可以指定生成的目标文件所在的目录,比如,想让编译程序在"c:\windows\desktop”下生成目标文件l.obj,则可输入“c:\windows\desktop\1 "。
我们直接按Enter键,使用编译程序设定的目标文件名。
(3)确定了目标文件的名称后,屏幕显示如图4.7所示。
图4.7中,编译程序提示输入列表文件的名称,这个文件是编译器将源程序编译为目标文件的过程中产生的中间结果。可以让编译器不生成这个文件,直接按Enter键即可。
(4)忽略了列表文件的生成后,屏幕显示如图4.8所示。
图4.8中,编译程序提示输入交叉引用文件的名称,这个文件同列表文件一样,是编译器将源程序编译为目标文件过程中产生的中间结果。可以让编译器不生成这个文件,直接按Enter键即可。
(5)忽略了交叉引用文件的生成后,屏幕显示如图4.9所示。
图4.9中,对源程序的编译结束,编译器输出的最后两行告诉我们这个源程序没有警告错误和必须要改正的错误。
上面我们通过对C盘根目录下的l .asm进行编译的过程,展示了使用汇编编译器对源程序进行编译的方法。按照上面的过程进行了编译之后,在编译器masm.exe运行的目录c:\1.asm下(即当前路径下),将出现一个新的文件:l.obj,这是对源程序l .asm进行编译所得到的结果。当然,如果编译的过程中出现错误,那么将得不到目标文件。一般来说,有两类错误使我们得不到所期望的目标文件:
(1)程序中有“Severe Errors";
(2)找不到所给出的源程序文件。
注意,在编译的过程中,我们提供了一个输入,即源程序文件。最多可以得到3个输出:目标文件(.obj)、列表文件(.lst)、交叉引用文件(.crf),这3个输出文件中,目标文件是我们最终要得到的结果,而另外两个只是中间结果,可以让编译器忽略对它们的生成。在汇编课程中,我们不讨论这两类文件。
连接
在对源程序进行编译得到目标文件后,我们需要对目标文件进行连接,从而得到可执行文件。接续上一节的过程,我们已经对c:\l.asm进行编译得到c:\masm\ l .obj,现在再将c:\masm\l .obj连接为c:\masm\l .exe
我们使用微软的Overlay Linker3.60连接器,文件名为link.exe,假设连接器在c:\masm目录下。可以按照下面的过程来进行程序的连接,以c:\masm\ l .obj为例。
(1)进入DOS方式,进入c:\masm目录,运行link.exe,如图4.10所示。
图4.10中,运行link后,首先显示出一些版本信息,然后提示输入将要被连接的目标文件的名称。注意,"[.OBJ]”提示我们,默认的文件扩展名是obj,比如要连接的目标文件名是“pl.obj",只要在这里输入“p1”即可。可如果文件不是以obj为扩展名,就要输入它的全名。比如目标文件名为“pl.bin",就要输入全名。
在输入目标文件名的时候,要注意指明它所在的路径。这里,要连接的文件是当前目录下的l .obj,所以此处输入“1"。
(2)输入要连接的目标文件名后,按Enter键,屏幕显示如图4.11所示。
图4.11中,在输入目标文件名后,程序继续提示我们输入要生成的可执行文件的名称,可执行文件是我们对一个程序进行连接要得到的最终结果。注意屏幕上的显示:
"[1.EXE]",因为己经确定了!J标文件名为l.obj,则程序默认要输出的可执行文件名为1.EXE,所以可以不必再另行指定文件名。自接按Enter键,编译程序将在当前的目录下,生成1.EXE文件。
这里,也可以指定生成的可执行文件所在的目录,比如,想让连接程序在" c:\windows\desktop”下生成可执千J:文件1. EXE,则可输入“c:\windows\desktop\1"
我们直接按Enter键,使用连接程序设定的可执行文件名。
(3)确定了可执行文件的名称后,屏幕显示如图4.12所示。
图4.12中,连接程序提示输入映像文件的名称,这个文件是连接程序将目标文件连接为了丁执行文件过程中产生的中问结果,可以让连接程序不生成这个文件,直接按Enter键即可。
(4)忽略了映像文件的生成后,屏幕显示如图4.13所示。
图4.13中,连接程序提示输入库文件的名称。库文件里面包含了一些可以调用的子程序,如果程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和目标文件连接到一起,生成可执行文件。但是,这个程序中没有调用任何子程序,所以,这里忽略库文件名的输入,直接按Enter键即可。
(5)忽略了库文件的连接后,解幕显示如图4.14所示。
图4.14中,对目标文件的连接结束,连接程序输出的最后一行告诉我们,这个程序中有一个警告错误:“没有栈段”,这里我们不理会这个错误。
上面我们通过对当前路径下的l.obj进行连接的过程,展示了使用连接器对目标文件进行连接的方法。按照上面的过程进行了连接之后,在连接器link.exe运行的目录c:\masm下(即当前路径下),将出现一个新的文件:l .exe,这是对目标文件1 .obj进行连接所得到的结果。当然,如果连接过程中出现错误,那么将得不到可执行文件。
连接的作用是什么呢了
对于连接,我们也不想过多地讨论。实际上,在汇编课程中,我们将会接触到许多知识、概念,对于这些,我们并不是都有深入讨论的必要。
这里再次强调一下,我们学习编程的主要目的,就是通过用汇编语言进行编程而深入地理解计算机底层的基本工作机理,达到可以随心所欲地控制计算机的目的。基于这种考虑,我们的编程活动,大都是直接对硬件进行的。我们希望直接对硬件编程,却并不希望用机器码编程。我们用汇编语言编程,就要用到编辑器(Edit)、编译器(masm)、连接器(link)、调试工具((Debug)等所有工具,而这些工具都是在操作系统之上运行的程序,所以我们的学习过程必须在操作系统的环境中进行。我们在一个操作系统环境中,使用了许多工具,这势必要牵扯到操作系统、编译原理等方面的知识和原理。我们只是利用这些环境、〕一具来方便我们的学习,而不希望这些东西分散了我们的注意力。所以,对于涉及而又不在我们学习的主要内容之中的东西,我们只做简单的解释。
好了,我们简单地讲连接的作用,连接的作用有以下几个。
(1)当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件;
(2)程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件;
(3)一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件。注意,对于连接的过程,可执行文件是我们要得到的最终结果。
以简化的方式进行编译和连接
在前面的内容里,介绍了如何使用masm和link进行编译和连接。可以看出,我们编译、连接的最终目的是用源程序文件生成可执行文件。在这个过程中所产生的中间文件都可以忽略。我们可以用一种较为简捷的方式进行编译、连接。简捷的编译过程如图4.15所示。
注意图4.15中的命令行“masm c:\ 1; ",在masm后面加上被编译的源程序文件的路径、文件名,在命令行的结尾再加上分一号,按Enter键后,编译器就对c:\ l .asm 进行编译,在当前路径下生成目标文件1 .obj,并在编译的过程中自动忽略中间文件的生成。
图4.16展示了简捷的连接过程。
注意图4.16中的命令行“link 1;",在link后面加上被连接的目标文件的路径、文件名,在命令行的结尾再加上分号,按Enter键后,连接程序就对当前路径下的l.obj进行处理,在当前路径下生成可执行文件l.exe,并在过程中自动忽略中间文件的生成。
1.exe的执行
现在,终于将我们的第一个汇编程序加工成了一个可在操作系统下执行的程序文件,我们现在执行一下,图4.17展示了l .exe的执行情况。
奇怪吗?程序运行后,竟然没有任何结果,就和没有运行一样。那么,程序到底运行了吗? 程序当然是运行了,只是从屏幕上不可能看到任何运行结果,因为,我们的程序根本没有向显示器输出任何信息。程序只是做了一些将数据送入寄存器和加法的操作,而这些事情,我们不可能从显示屏上看出来。程序执行完成后,返回,屏幕上再次出现操作系统的提示符(图4.17中第2行)。 当然,我们不能总是写这样的看不到任何结果的程序,随着课程的进行,我们将会向
显示器上输出信息,不过那将是几章以后的事情了,请耐心等待。
谁将可执行文件中的程序装载进入内存并使它运行?
我们在前面讲过,在DOS中,可执行文件中的程序P1若要运行,必须有一个正在运行的程序P2,将P1从可执行文件中加载入内存,将CPU的控制权交给它,P1才能得以运行;当P1运行完毕后,应该将CPU的控制权交还给使它得以运行的程序P2
按照上面的原理,再来看一下4.7节中l .exe的执行过程(思考相关的问题)。
(1)在提示符“c:}masm”后面输入可执行文件的名字“I",按Enter键。这时,请思考问题4.1
(2) l.exe中的程序运行。
(3)运行结束,返回,再次显示提示符“c:\masm "。请思考问题4.2 0
问题4.1
此时,有一个正在运行的程序将l .exe中的程序加载入内存,这个正在运行的程序是什么?它将程序加载入内存后,如何使程序得以运行?
问题4.2
程序运行结束后,返回到哪里?
如果你对DOS有比较深入的了解,那么,很容易回答问题4.1、问题4.2中所提出的问题。如果没有这种了解,可以先阅读下面的内容。
操作系统的外壳
操作系统是申多个功能模块组成的庞大、复杂的软件系统‘任何通用的操作系统,都要提供一个称为shell(外壳)的程序,角户(操作人员)使用这个程序来操作计算机系统进行工作。
DOS中有一个程序command.com,这个程序在DOS中称为命令解释器,也就是DOS系统的shell
DOS启动时,先完成其他重要的初始化工作,然后运行command.com. command.com运行后,执行完其他的相关任务后,在屏幕上显示出由当前盘符和当前路径组成的提示符,比如:" c:\”或"c:\windows”等,然后等待用户的输入。
用户可以输入所要执行的命令,比如,cd, dir, type等,这些命令由~d执行,command执行完这些命令后,再次显示由当前盘符和当前路径组成的提示符,等待用户的输入。
如果用户要执行一个程序,则输入该程序的可执行文件的名称,command首先根据文件名找到可执行文件,然后将这个可执行文件中的程序加载入内存,设置CS:IP指向程序的入口。此后,command暂停运行,CPU运行程序。程序运行结束后,返回到command中,command再次显示由当前盘符和当前路径组成的提示符,等待用户的输入。
在DOS中,command处理各种输入:命令或要执行的程序的文件名。我们就是通过command来进行工作的。
现在回答问题4.1和4.2中所提出的问题。
(1)在DOS中直接执行l .exe时,是正在运行的command,将l .exe中的程序加载入内存;
(2) command设置CPU的CS:IP指向程序的第一条指令(即程序的入口),从而使程序得以运行;
(3)程序运行结束后,返回到command中,CPU继续运行command