汇编程序编译连接过程

这章开始,我们将开始编写完整的汇编语言程序,用编译和连接程序将它们连接成可执行文件(如.exe文件)在DOS中运行。为了能够透彻地理解一个完整的程序(尽管它看上去十分简单),我们将经历一个漫长的过程。

目录

一.汇编程序的执行过程

​1.编写汇编源程序

2.对源程序进行编译连接

3.执行可执行文件中的程序

二.源程序

1.伪指令

1).xxx segment

2).end

3).assume

2.汇编指令

3.汇编程序的结构

1).定义一个段

2).往段中加入汇编指令

3).指明程序在何处结束

4).指明代码段

5).程序返回

三.编译

 四.连接

关于连接(仅作了解)

简化编译和连接的方法:

 五.程序执行过程的跟踪


一.汇编程序的执行过程

下图描述了一个汇编程序从写出到最终执行的简要过程:

1.编写汇编源程序

使用文本编辑器(记事本,Notepad++等),用汇编语言编写汇编源程序。这一步的工作产生了一个存储源文件的文本文件

2.对源程序进行编译连接

使用汇编语言编译程序对源程序文件中的源程序进行编译,产生目标文件;再用连接程序对目标文件进行连接,生成可在操作系统直接运行的可执行文件

可执行的文件包含两部分内容:

1).程序和数据:程序中的汇编指令翻译过来的机器码和源程序中定义的数据

2).相关的描述信息:程序多大,要占用多少内存空间等

3.执行可执行文件中的程序

在操作系统中,执行可执行文件中的程序。此时,操作系统依照可执行文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关的初始化(比如CS:IP指向第一条要执行的指令),然后由CPU执行程序。

二.源程序

下面来看一段简单的程序:

assume cs:codesg
codesg segment
    mov ax,0123H
    mov bx,0456H
    add ax,bx
    add ax,ax

    mov ax,4C00H
    int 21H
codesg ends
end

在汇编语言程序中,包含两种指令,一种是汇编指令,一种是伪指令。汇编指令是有对应机器码的指令,可以被编译成机器指令,最终被CPU执行。而伪指令并没有对应的机器码,最终不会被CPU执行,而是会被编译器所执行。

1.伪指令

1).xxx segment

xxx ends

segment 和 ends 是成对使用的伪指令,这是在写可被编辑器编译的汇编程序时必须要用到的一对伪指令。segment和ends的功能是定义一个段,segment说明一个段的开始,ends说明一个段的结束。在汇编源程序中,一个段必须要有一个名称表示,使用格式为:

段名 segment

段名 ends

像上述程序中:(定义了一个代码段)

codesg segment    ;定义了一个段,段的名称为codeseg,这个段从此开始
。。。。
codesg ends    ;名称为codeseg的段到此结束

当然一个源程序可以由多个段组成,可以用来存放代码,数据或者当作栈空间来使用。一个汇编源程序至少要有一个段:代码段。

2).end

end是一个汇编程序的结束标记,编译器在编译汇编程序的时候,如果碰到end,就会结束对源程序的编译,所以,我们在写程序的时候,程序结束的时候应该在结尾处加上伪指令end

3).assume

assume:假设,它可以用来假设某一段寄存器和程序中的某一个用segment...ends定义的段相关段。在编程时,我们需要使用assume将有特定用途的段和相关的段寄存器关联起来。

假如上述程序中定义了一个名为codesg的代码段,我们需要将CS段寄存器和该段进行关联,格式为 assume cs:codesg

如果你要关联多个段:可以使用如下格式

assume cs:codesg ds:datasg ss:stacksg

2.汇编指令

除了伪指令以外,还有最重要的汇编指令。

编程的最终目的是让计算机完成一定的任务,而任务的完成由汇编指令来指示。汇编指令经过编译连接之后转换成对应的机器码,如下图所示:

 除了上述内容外,我们还需要知道codesg的具体含义

它被称为标号。一个标号指代了一个地址。上述示例中codesg在segment前面,作为一个段的名称,最终在编译连接之后处理为一个段的段地址

认识上述指令之后,我们再来看一下汇编程序的结构,从整体上看一个汇编源程序应该需要什么

3.汇编程序的结构

1).定义一个段

当然可以有多个段,但至少要有一个代码段。比如定义了一个段,段名为abc

注意: ;在汇编语言中表示注释

abc segment
....
abc ends

2).往段中加入汇编指令

这三条汇编语句的作用是求2^3

abc segment
    mov ax,2
    add ax,ax
    add ax,ax
abc ends

3).指明程序在何处结束

abc segment
    mov ax,2    ;这三条汇编语句的作用是求2^3
    add ax,ax
    add ax,ax
abc ends
end

4).指明代码段

人为设置代码段编译器并不会也这么认为

assume cs:abc
abc segment 
    mov ax,2    ;这三条汇编语句的作用是求2^3
    mov ax,ax
    mov ax,ax
abc ends
end 

5).程序返回

他们的作用是程序返回,类似于C语言中的return

mov ax,4C00H
int 21H

我们不需要过多探究他们具体是什么意思,我们知道他们的功能是程序返回就可以了

所以上述程序还可以完善:(到此为止我们才算完成一个较为完整的汇编源程序)

assume cs:abc
abc segment
    mov ax,2
    add ax,ax
    add ax,ax

    mov ax,4C00H
    int 21H
abc ends
end

源程序和程序的区别:我们称源程序中的所有内容称为源程序,比如1.asm中的内容。将源程序重点,最终由计算机执行,处理的指令或数据称为程序。

到此为止,我们已经接触了几个和结束相关的内容:段结束,程序结束,程序返回,下图展示了他们的区别

目的相关指令指令性质指令执行者
通知编辑器一个段结束段名 ends伪指令编译时,由编译器执行
通知编译器程序结束end伪指令编译时,由编译器执行
程序返回

mov ax.4C00h

int 21H

汇编指令执行时,由CPU执行

三.编译

上节内容已经可以完成一个源程序的编写,我们将其保存为1.asm之后就可以得到一个源程序文件。在这之后我们就可以对其进行编译了,下面我们来讲解编译过程。

编译需要借助相应的编译器,我们采用的是masm汇编编译器。在上一章中我们已经讲解了如何进行源程序的编译连接过程。现在我们来详细看看编译的过程。

进入DOS,并且进入到MASM目录(我们放在虚拟C盘中,如果不是的可以使用cd指令进入对应目录)

如上图,运行masm后,首先显示出一些版本信息,然后提示输入将要被编译的程序文件的名(.ASM)

我们默认的拓展名是asm,如果要编译的源程序名为p1.asm,在这里只需要输入p1 即可。如果源程序文件的名字不是asm的拓展名则需要输入全名。比如文件名为p1.txt,就要输入全名。

当然我们输入文件名的目的是让系统根据对应的文件名找到对应的文件,我们输入文件名的时候还需要指明这个文件的所在路径,比如p1.txt在c:code\下,则输入应为:c:code\p1.txt

如果你的可执行文件和masm文件在同一级目录,则可以直接输入名字即可,后续中文间.obj同理。

使用masm编译了源文件之后会生成一个目标文件.obj,我们也可以制定这个文件的名字,示意如下:

不输入Object filename 程序默认名称为1.obj.

后续还会有两个提示,分别是提示生成列表文件和引用文件 ,当然我们可以直接忽略这两个文件,他们属于中间文件,之后一直按enter即可。

最终出现如下界面:(红线画的就是列表文件和引用文件)

 当然,编译过程中如果出现错误的话将不会生成最终的目标文件。程序出错的表示:

1.程序中有Severe Errors--->语法错误

2.找不到所给出的源程序文件:文件路径给错

如下,当我的C盘中没有2.asm,我却用masm对2.asm进行编译

 四.连接

在对源文件进行编译得到目标文件之后,我们需要对目标文件进行连接,从而得到可执行文件。在这里我们需要使用到连接工具,文件名问LINK.EXE.下面我们来看连接过程。

 

输入link之后,系统提示你输入要进行连接的目标文件(.obj),而Run File这一行则是提示你是否要指定生成的可执行文件的名字,不指定则默认为【】中的名字,上述 图示中为指定默认可执行文件名为1.exe,之后一直按Enter即可

 

当然上述图片中有一个警告错误:没有栈段。在这里我们不去理它。这之后将生成一个可执行文件1.exe,后续直接在命令行输入1.exe即可执行该可执行文件

关于连接(仅作了解)

类似于C语言中的多文件

1.当源程序很大时,我们可以将它分为很多源程序进行编译,每个源程序都将产生一个目标文件,我们需要用连接程序将多个目标文件连接成一个可执行文件

2.程序中调用某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接在一起,最终生成一个可执行文件

3.一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用于生成可执行文件,需要经过连接程序将这些内容处理为最终的可执行信息。所以即使只有一个源文件和没有调用某个库的时候也需要进行连接

简化编译和连接的方法:

1.编译:masm 1.asm;

2.连接:link 1.obj;

上述的两个指令指定了需要编译或连接的文件,并且用“;”表示生成默认的文件,

编译指令中,;表示默认生成1.obj

连接指令中,;表示默认生成1.exe

效果图如下:

 五.程序执行过程的跟踪

我们可以利用Debug来跟踪一个程序运行过程,这通常是必须要做的工作。我们写的程序在逻辑上不一定总是正确的,对于简单的错误,仔细检查一下源程序即可发现。但是对于隐藏较深的错误,就需要对程序的总执行过程进行跟踪分析才可以发现。

这个过程我们需要借助工具debug。debug可以将程序加载入内存,设置CS:IP指向程序的入口。

具体用法如下图:

接下来可以使用R命令来查看各个寄存器的设置情况,如下:

 可以看到,现在的CS:IP指向073F:0100内存单元,也就是说第一条要执行的指令在该地址单元中。 

仔细看图的左下角:073F:1000 B80200 MOV AX,0002 ,这里提示了第一条指令的地址,机器码,对应的汇编指令,我们可以用u查看一下其他的指令,如下

我们可以看到073F:0100到073F:011F都是程序的机器码。

到这里我们可以来进行跟踪了,使用T命令进行单步执行,并观察每一条指令执行后对寄存器的影响。

当然,到了int 21这条指令时我们需要用P命令执行,如下图

上述执行完 INT 21之后显示 “ program terminated normally”,返回debug中。表示程序正常结束。

 需要注意的是,执行INT 21这条语句时需要用P命令去执行。

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jjj34

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值