汇编语言中源程序的编程、编译、连接、跟踪

时间:2021-07-29 01:16:41

前言

一个汇编语言程序从写出到最终执行的简要过程如下:

  • 第一步:编写汇编源程序
  • 第二步:对源程序进行编译连接
  • 第三步:执行可执行文件中的程序

即编写->编译连接->执行

源程序基本结构知识

源程序:源程序文件中的所有内容

程序:源程序中最终由计算机执行、处理的指令或数据

在汇编语言源程序中,包含两种指令,一种是汇编语言,一种是伪指令。汇编指令是有对应的机器码的指令,可以编译为机器指令,最终为CPU所执行。而伪指令没有对应的机器指令,它是由编译器来执行的指令

汇编语言中源程序的编程、编译、连接、跟踪

一个源程序中所有被计算机所处理的信息:指令、数据、栈,被划分到了不同的段中

一个有意义的汇编程序中至少有一个段,这个段用来存放代码

我们由一个简单的例子来介绍一个源程序的基本结构知识

汇编语言中源程序的编程、编译、连接、跟踪

首先,我们可以将例子中的指令分为汇编指令和伪指令

汇编指令:第5、6、7、8、10、11行

伪指令:第1、3、13、15行

伪指令分析:

(1)段名 segment ...... 段名 ends

segment和ends是一对成对使用的伪指令,它们的功能是定义一个段并且一个段必须有一个名称来标识

segment说明一个段开头,ends说明一个段结束

(2)end

end是一个汇编程序的结束标记,程序结尾处必须加上伪指令end,否则编译器在编译程序中无法知道程序在何处结束

(3)assume

assume的含义为“假设”,它假设某一段寄存器和程序中的某一个用segment...ends定义的段相关联,比如说我们可以将test这个代码段和CPU中的段寄存器cs联系起来

(4)标号

汇编源程序中,除了汇编指令和伪指令外,还有一些标号,比如说“test”。一个标号代指了一个地址。比如test在segment的前面,作为一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的段地址

(5)程序返回

一个程序结束后,将CPU的控制权交还给使他得以运行的程序,我们称这个过程为:程序返回

汇编语言中源程序的编程、编译、连接、跟踪

这两条指令所实现的功能就是程序返回

在DOS(一个单任务操作系统)的基础上,一个程序P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载入内存后,将CPU的控制权交给P2,P2才能得以运行。P2开始运行后,P1暂停运行

而当P2运行完毕后,应该将CPU的控制权交还给P1,此后,P1继续运行

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

mov ax,4c00H

int 21H

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

(6)语法错误和逻辑错误

当一个源程序没有程序返回时,是不会在编译的时候是不会表现出来的

一般来说,程序在编译时被编译器发现的错误是语法错误

在源程序编译后,在运行时发生的错误是逻辑错误

编辑源程序

可以使用任意的文本编辑器编辑源程序,只要最终将其存储为纯文本文件即可

在这里我们使用DOS下的Edit

汇编语言中源程序的编程、编译、连接、跟踪

汇编语言中源程序的编程、编译、连接、跟踪

将程序保存为文件demo01.asm后,退出Edit,结束对源程序的编辑

编译

在完成对源程序的编辑后,得到一个源程序文件demo01.asm,然后我们将其进行编译,生成包含机器代码的目标文件

进入DOS后,运行masm

运行masm后,首先显示出一些版本信息,然后提示输入将要被编译的源程序文件名称+后缀(文件后缀为.asm的直接输入文件名即可)

注意:如果没有在同一级目录下,需输入该文件的路径

汇编语言中源程序的编程、编译、连接、跟踪

在编译过程中,我们提供一个输入,即源文件。最多可以得到三个输出:目标文件(.obj)、列表文件(.lst)、交叉引用文件(.crf)。除了目标文件的另外两个文件只是中间结果,我们可以忽略其生成

连接

得到目标文件后,我们需要将目标文件进行连接,从而得到可执行文件

在DOS下运行link

输入一个目标文件后可再输入库文件(.lib),最多得到三个文件:可执行文件(.exe)、映像文件(.map)

映像文件(.map)是连接程序将目标文件连接为可执行文件过程中产生的中间结果,在此我们忽略此文件的生成

此程序没有调用任何子程序,所以我们也忽略库文件名的输入

注意:如果没有在同一级目录下,需输入该文件的路径

汇编语言中源程序的编程、编译、连接、跟踪

这个程序中出现了一个警告错误:“没有栈段”,我们在这里不予理会

如果我们在连接过程中出现错误,是不会生成可执行文件的

简化方式的编译和连接

简化使用即masm或link后跟文件名与分号“ ; ”

汇编语言中源程序的编程、编译、连接、跟踪

汇编语言中源程序的编程、编译、连接、跟踪

执行

直接在此目录下执行文件名即可 

汇编语言中源程序的编程、编译、连接、跟踪

 由于我们没有向显示器输出任何信息,所以我们并不能明显的看到程序的运行

DOS中有一个程序command.com,这个程序在DOS中称为命令解释器,也就是DOS的shell

DOS启动时,先完成其他重要的初始化工作,然后运行command.com,command.com运行后,执行其他的相关任务后,在屏幕上显示出由当前盘符和当前路径组成的提示符(如:“c:/”)来等待用户的输入

因此,执行可执行文件时,就是由command将可执行文件加载入内存中

跟踪

在我们了解到执行可执行文件时,是由另一个程序将它加载入内存并使它获得CPU的控制权

因此我们可以使用Debug来将可执行文件加载入内存,需要注意的时Debug并不会放弃对CPU的控制权,因此我们就可以使用Debug的相关命令来单步执行程序

CX中存放的是程序的长度,其机器码共有15个字节

现在我们可以开始跟踪了,用T指令执行程序中的每一条指令,到了int 21,我们要用P命令执行

汇编语言中源程序的编程、编译、连接、跟踪

汇编语言中源程序的编程、编译、连接、跟踪

DOS下文件程序加载过程结构如下:

汇编语言中源程序的编程、编译、连接、跟踪

  1. 找到一段起始地址为SA:0的容量足够的空闲内存区
  2. 在这段内存区的前256字节中,创建一个称为程序段前缀(PSP)的数据区,DOS要利用PSP来和被加载程序来进行通行

0~255字节为PSP,从256字节处开始存放程序

为了区分PSP和程序,DOS一般将它们划分到不同的段中:

  • 空闲内存区:SA:0
  • PSP区:SA:0
  • 程序区:SA+10H:0

所以,从ds中可以得到PSP的段地址SA,PSP的偏移地址为0,则物理地址为SA×16+0

因为PSP占据256(100H)字节,所以程序的物理地址为

SA×16+0+256=SA×16+16×16+0=(SA+16)×16+0,用段地址和偏移地址为SA+10H:0