【汇编语言】第一个程序(三)—— 深度剖析汇编程序的执行流程:编辑、编译、连接与运行

文章目录

  • 前言
  • [1. 编辑源程序](#1. 编辑源程序)
    • [1.1 找到执行程序的目录](#1.1 找到执行程序的目录)
    • [1.2 进入文本编辑器,编辑程序](#1.2 进入文本编辑器,编辑程序)
    • [1.3 保存源程序文件,推出编辑](#1.3 保存源程序文件,推出编辑)
  • [2. 启动DOS模拟器------DOSBox](#2. 启动DOS模拟器——DOSBox)
    • [2.1 执行挂载操作](#2.1 执行挂载操作)
    • [2.2 转换到C盘](#2.2 转换到C盘)
  • [3. 编译](#3. 编译)
    • [3.1 编译源程序](#3.1 编译源程序)
    • [3.2 忽略列表文件](#3.2 忽略列表文件)
    • [3.3 忽略交叉引用文件](#3.3 忽略交叉引用文件)
    • [3.4 编译结束的结果](#3.4 编译结束的结果)
  • [4. 连接](#4. 连接)
    • [4.1 连接目标文件](#4.1 连接目标文件)
    • [4.2 忽略映像文件](#4.2 忽略映像文件)
    • [4.3 忽略库文件](#4.3 忽略库文件)
    • [4.4 连接结束的结果](#4.4 连接结束的结果)
    • [4.5 连接的作用](#4.5 连接的作用)
  • [5. 简化编译和连接的过程](#5. 简化编译和连接的过程)
    • [5.1 简捷的编译](#5.1 简捷的编译)
    • [5.2 简捷的连接](#5.2 简捷的连接)
  • [6. 1.exe 的执行](#6. 1.exe 的执行)
  • 结语

前言

📌

汇编语言是很多相关课程(如数据结构、操作系统、微机原理)的重要基础。但仅仅从课程的角度出发就太片面了,其实学习汇编语言可以深入理解计算机底层工作原理,提升代码效率,尤其在嵌入式系统和性能优化方面有重要作用。此外,它在逆向工程和安全领域不可或缺,帮助分析软件运行机制并增强漏洞修复能力。

本专栏的汇编语言学习章节主要是依据王爽老师的《汇编语言》来写的,和书中一样为了使学习的过程容易展开,我们采用以8086CPU为中央处理器的PC机来进行学习。

通过前面的学习我们已经知道一个汇编源程序应该是什么样的,本文我们将会从一个源程序的编辑到最终的运行完整的过程展现出来。

在本节中将要用到我们之前在
【汇编语言】寄存器(CPU工作原理)(七)------ 查看CPU和内存,用机器指令和汇编指令编程

这篇文章中所下载的软件和执行程序了。

1. 编辑源程序

可以用任意的文本编辑器来编辑源程序,只要最终将其存储为纯文本文件即可。在这里我们将用Notepad++来进行编辑程序,并且以如下程序作为示例:

assembly 复制代码
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

1.1 找到执行程序的目录

我们首先要找到当初下载的执行程序的目录,之后编辑好的源程序要放在该目录下才可以被执行,因为这样才能被执行程序所找到。

1.2 进入文本编辑器,编辑程序

在Notepad++中编辑程序,如下图所示。

1.3 保存源程序文件,推出编辑

将源程序文件保存在执行程序的目录下,比如说我这里是:D:\DOSBox\MASM\1.asm。(汇编源程序文件的后缀是.asm)

2. 启动DOS模拟器------DOSBox

2.1 执行挂载操作

首先打开DOSBox程序后,将我们执行程序的路径挂载到DOSBox的C盘上(这样就把我们的d盘里的这个执行程序所在的文件夹当作模拟器里面的C盘使用了)。

2.2 转换到C盘

将模拟器的当前位置转到模拟器的C盘上。

执行dir命令可以看当前位置下,我们所具备的文件和文件夹。

3. 编译

在我们得到一个源程序文件D:\DOSBox\MASM\1.asm后。可以对其进行编译,生成包含机器代码的目标文件。

在编译一个源程序之前首先要找到一个相应的编译器。我们这里就是使用的之前下载的文件名为masm.exe执行程序。

3.1 编译源程序

在执行文件的目录下,运行masm.exe。输入要编译的源程序文件名后,按Enter键,屏幕显示如下图所示。

上图中,在执行命令后,程序继续提示我们输入要编译出的目标文件的名称,目标文件是我们对一个源程序进行编译要得到的最终结果。

注意屏幕上的显示:"[1.OBJ]",因为我们已经输入了源程序文件名为1.asm,则编译程序默认要输出的目标文件名为1.obj,所以可以不必再另行指定文件名。

直接按Enter键,编译程序将在当前的目录下,生成1.obj 文件。

3.2 忽略列表文件

确定了目标文件的名称后,屏幕显示如下图所示。

上图中,编译程序提示输入列表文件的名称,这个文件是编译器将源程序编译为目标文件的过程中产生的中间结果。可以让编译器不生成这个文件,直接按Enter键即可。

3.3 忽略交叉引用文件

忽略了列表文件的生成后,屏幕显示如下图所示。

上图中,编译程序提示输入交叉引用文件的名称,这个文件同列表文件一样,是编译器将源程序编译为目标文件过程中产生的中间结果。可以让编译器不生成这个文件,直接按 Enter 键即可。

3.4 编译结束的结果

忽略了交叉引用文件的生成后,屏幕显示如下图所示。

上图中,对源程序的编译结束,编译器输出的最后两行告诉我们这个源程序没有警告错误和必须要改正的错误。

上面我们通过对 C盘根目录下的 1.asm 进行编译的过程,展示了使用汇编编译器对源程序进行编译的方法。按照上面的过程进行了编译之后,在编译器masm.exe 运行的目录下(即当前路径下),将出现一个新的文件:1.obj,如下图所示,这是对源程序 1.asm 进行编译所得到的结果。当然,如果编译的过程中出现错误,那么将得不到目标文件。

一般来说,有两类错误使我们得不到所期望的目标文件:

  1. 程序中有"Severe Errors"

  2. 找不到所给出的源程序文件。

注意,在编译的过程中,我们提供了一个输入,即源程序文件。最多可以得到3个输出:目标文件(.obj)、列表文件(.lst)、交叉引用文件(.crf),这3个输出文件中,目标文件是我们最终要得到的结果,而另外两个只是中间结果,可以让编译器忽略对它们的生成。在汇编课程中,我们不讨论这两类文件。

4. 连接

在对源程序进行编译得到目标文件后,我们需要对目标文件进行连接,从而得到可执行文件。在这里我们需要使用到的可执行文件名为link.exe。

4.1 连接目标文件

仍然在执行文件目录下,运行link.exe。

上图中,在执行命令后,程序继续提示我们输入要生成的可执行文件的名称,可执行文件是我们对一个程序进行连接要得到的最终结果。注意屏幕上的显示:"[1.EXE]",因为已经确定了目标文件名为1.obj,则程序默认要输出的可执行文件名为1.EXE,所以可以不必再另行指定文件名。

直接按Enter键,编译程序将在当前的目录下,生成 1.EXE 文件。

4.2 忽略映像文件

确定了可执行文件的名称后,屏幕显示如下图所示。

上图中,连接程序提示输入映像文件的名称,这个文件是连接程序将目标文件连接为可执行文件过程中产生的中间结果,可以让连接程序不生成这个文件,直接按Enter键即可。

4.3 忽略库文件

忽略了映像文件的生成后,屏幕显示如下图所示。

上图中,连接程序提示输入库文件的名称。库文件里面包含了一些可以调用的子程序,如果程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和目标文件连接到一起,生成可执行文件。

但是,这个程序中没有调用任何子程序,所以,这里忽略库文件名的输入,直接按Enter 键即可。

4.4 连接结束的结果

忽略了库文件的连接后,屏幕显示如下图所示。

上图中,对目标文件的连接结束,连接程序输出的最后一行告诉我们,这个程序中有一个警告错误:"没有栈段",这里我们不理会这个错误。

上面我们通过对当前路径下的1.obj进行连接的过程,展示了使用连接器对目标文件进行连接的方法。按照上面的过程进行了连接之后,在连接器link.exe运行的目录下(即当前路径下),将出现一个新的文件:1.exe,如下图所示,这是对目标文件1.obj进行连接所得到的结果。当然,如果连接过程中出现错误,那么将得不到可执行文件。

4.5 连接的作用

连接的作用是什么呢?

对于连接,我们也不想过多地讨论。实际上,在汇编学习中,我们将会接触到许多知识、概念,对于这些,我们并不是都有深入讨论的必要。

这里再次强调一下,我们学习汇编的主要目的,就是通过用汇编语言进行编程而深入地理解计算机底层的基本工作机理,达到可以随心所欲地控制计算机的目的。基于这种考虑,我们的编程活动,大都是直接对硬件进行的。我们希望直接对硬件编程,却并不希望用机器码编程。我们用汇编语言编程,就要用到编辑器(Edit)、编译器(masm)、连接器(link)、调试工具(Debug)等所有工具,而这些工具都是在操作系统之上运行的程序,所以我们的学习过程必须在操作系统的环境中进行。我们在一个操作系统环境中,使用了许多工具,这势必要牵扯到操作系统、编译原理等方面的知识和原理。我们只是利用这些环境、工具来方便我们的学习,而不希望这些东西分散了我们的注意力。所以,对于涉及而又不在我们学习的主要内容之中的东西,我们只做简单的解释。

✍我们简单地讲一下连接的作用,连接的作用有以下几个。

  1. 当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件。
  2. 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件。
  3. 一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件。

❗注意,对于连接的过程,可执行文件是我们要得到的最终结果。

5. 简化编译和连接的过程

在前面的内容里,介绍了如何使用masm和link进行编译和连接。

可以看出,我们编译、连接的最终目的是用源程序文件生成可执行文件。在这个过程中所产生的中间文件都可以忽略。所以我们可以用一种较为简捷的方式进行编译、连接。

还是一样,需要在执行程序的目录下执行所有过程。

5.1 简捷的编译

过程如下图所示。

见上图可知,直接在masm后面加上被编译的源程序文件名,然后再加上分号,按Enter键后,编译器就对源程序文件进行编译,在当前路径下生成目标文件1.obj,并在编译的过程中自动忽略中间文件的生成。

5.2 简捷的连接

过程如下图所示。

见上图可知,直接在link 后面加上被连接的目标文件名,再加上分号,按Enter键后,连接程序就对当前路径下的1.obj进行处理,在当前路径下生成可执行文件1.exe,并在过程中自动忽略中间文件的生成。

6. 1.exe 的执行

现在,终于将我们的第一个汇编程序加工成了一个可在操作系统下执行的程序文件我们现在执行一下,下图展示了 1.exe 的执行情况。

奇怪吗?

程序运行后,竟然没有任何结果,就和没有运行一样。那么,程序到底运行了吗?

程序当然是运行了,只是从屏幕上不可能看到任何运行结果,因为,我们的程序根本没有向显示器输出任何信息。程序只是做了一些将数据送入寄存器和加法的操作,而这些事情,我们不可能从显示屏上看出来。程序执行完成后,返回,屏幕上再次出现操作系统的提示符。

当然,我们不能总是写这样的看不到任何结果的程序,随着之后的进一步学习,我们将会向显示器上输出信息,请大家耐心等待。

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

相关推荐
wqq_99225027721 分钟前
springboot基于微信小程序的食堂预约点餐系统
数据库·微信小程序·小程序
爱上口袋的天空23 分钟前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse
转世成为计算机大神27 分钟前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海1 小时前
scala String
大数据·开发语言·scala
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala
yqcoder1 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
baivfhpwxf20231 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
许嵩661 小时前
IC脚本之perl
开发语言·perl