本文将开始编写完整的汇编语言程序,用编译器将它们编译成为可执行文件(如:*.exe文件),在操作系统中运行。
本文地址:http://www.cnblogs.com/archimedes/p/assembly-first-program.html,转载请注明源地址。
1、一个源程序从写出到执行的过程
编写--〉编译--〉连接--〉执行
2、源程序
先看一段代码:
assum cs:codesg codesg segment start: mov ax,0123H mov bx,0456H add ax,bx add ax,ax mov ax,4c00h int 21h codesg ends end
段名 segment
段名 ends
assume cs:abc abc segment mov ax,2 add ax,ax add ax,ax abc ends end
应该在程序的末尾添加返回的程序段。
mov ax,4c00H int 21H
这两条指令所实现的功能就是程序返回。
3、编辑源程序
进入DOS方式,运行edit,在其中编辑程序,如下图所示:
4、编译
进入DOS方式,进入 C:masm 目录,运行masm.exe。如果源程序文件不是以 asm 为扩展名的话,就要输入它的全名。比如p1.txt。在输入源程序文件名的时候一定要指明它所在的路径。如果文件就在当前路径下,只输入文件名就可以。
输入要编译的源文件文件名后,按 Enter键。目标文件(*.obj)是我们对一个源程序进行编译要得到的最终结果。编译程序默认要输出的目标文件名为1.obj,所以可以不必再另行指定文件名。
编译程序提示输入交叉引用文件的名称。
一般来说,有两类错误使我们得不到所期望的目标文件:
(1)我们程序中有“Severe Errors”;
(2)找不到所给出的源程序文件。
5、连接
在对源程序进行编译得到目标文件后,我们需要对目标文件进行连接,从而得到可执行文件。继续上面的过程,我们再将C:masm1.obj连接为C:masm1.exe。
进入DOS方式,进入C:masm目录,运行link.exe。如果目标文件不是以obj为扩展名的话,就要输入它的全名。比如:p1.bin。在输入目标文件名的时候,要注意指明它所在的路径。这里,我们要连接的文件是当前路径下1.obj,所以此处输入“1”。
输入要连接的目标文件名后,按Enter键。可执行文件是我们对一个程序进行连接要得到的最终结果。连接程序默认要输出的可执行文件名为 1.EXE ,所以可以不必再另行指定文件名。我们直接按 Enter 键,使用连接程序设定的可执行文件名。
映像文件是连接程序将目标文件连接为可执行文件过程中产生的中间结果。可以不生成这个文件,直接按 Enter 键即可。
连接程序提示输入库文件的名称。
库文件里包含了一些可以调用的子程序,如果我们的程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和我们的目标文件连接到一起,生成可执行文件。
如果没有调用任何子程序,直接按Enter键即可。
连接的作用:
当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件;
程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件;
一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这此内容处理为最终的可执行信息。
所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件。
6、以简化的方式进行编译和连接
我们编译、连接的最终目的是用源程序文件生成可执行文件。在这个过程中所产生的中间文件都可以忽略。我们可以用一种较为简捷的方式进行编译、连接。
编译:
连接:
7、1.exe的执行
现在,终于将我们的第一个汇编程序加工成了一个可在操作系统下执行的程序文件。1.exe的执行情况:
我们的程序没有像显示器输出任何信息。程序只是做了一些将数据送入寄存器和加法的操作,而这些事情,我们不可能从显示屏上看出来。程序执行完成后,返回,屏幕上再次出现操作系统的提示符。
8、可执行文件中的程序装入内存并运行的原理
DOS中有一个程序command.com ,这个程序在 DOS 中称为命令解释器,也就是DOS系统的shell。
(1)我们在DOS中直接执行 1.exe 时,是正在运行的command将1.exe中的程序加载入内存。
(2)command设置CPU的CS:IP指向程序的第一条指令(即程序的入口),从而使程序得以运行。
(3)程序运行结束后,返回到command中,CPU继续运行command。
9、程序执行过程的跟踪
为了观察程序的运行过程 ,我们可以使用Debug。
Debug 可以将程序加载入内存,设置CS:IP指向程序的入口,但Debug并不放弃对CPU 的控制,这样,我们就可以使用Debug 的相关命令来单步执行程序 ,查看每条指令指令的执行结果。
EXE文件中的程序的加载过程:
总结:
程序加载后,ds中存放着程序所在内存区的段地址,这个内存区的偏移地址为 0 ,则程序所在的内存区的地址为:ds:0;这个内存区的前256 个字节中存放的是PSP,dos用来和程序进行通信。
从 256字节处向后的空间存放的是程序。所以,我们从ds中可以得到PSP的段地址SA,PSP的偏移地址为 0,则物理地址为SA×16+0。
SA×16+0+256= SA×16+16×16=(SA+16)×16+0
可用段地址和偏移地址表示为:SA+10:0
用U命令查看一下其他指令:
用T命令但不执行程序中的每一条指令,并观察每条指令的执行结果,到了 int 21,我们要用P命令执行:
int 21 执行后,显示“Program terminated normally”,返回到Debug中。表示程序正常结束。
注意,要使用P命令执行int 21。
参考资料
《汇编语言》--王爽