Catálogo
7. 4.9 程序执行过程的跟踪
4.1 一个源程序从写出到执行的过程
- 编写汇编源程序
- 产生一个存储源程序的文本文件
- 对源程序进行编译链接
- 使用汇编语言编译程序对源程序文件中的源程序进行编译,产生目标文件进行链接。生成可在操作系统中直接运行的可执行文件
- 可执行文件包含两部分内容
- 程序和数据
- 程序:从源程序中的汇编指令翻译过来的机器码
- 数据:源程序中定义的数据
- 相关的描述信息
- 描述类似程序多大、占用多少内存空间等等
- 程序和数据
- 执行可执行文件中的程序
- 操作系统依照可执行文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关的初始化(比如设置 CS:IP 指向第一条要执行的指令),容纳后由 CPU 执行程序
4.2 源程序
下面时一段简单的汇编程序:
1 | assume cs:codesg |
程序说明
伪指令
在汇编程序中有两种指令:
- 汇编指令
- 对应机器码,被编译为机器指令,最终被 CPU 执行
- 伪指令
- 编译器执行伪指令。编译器将根据伪指令来进行相关的编译工作
在上面的例子中的伪指令:1
2
3
4
5XXX segment
:
:
:
XXX ends
segment
和ends
是成对使用的伪指令这是在写可被编译器编译的汇编程序时必须要用到的一对伪指令
segmnet
和ends
的功能是定义一个段segment
说明一个段的开始ends
说明一个段的结束
使用格式
1
2
3段名 segment
:
段名 ends
一个汇编程序由多个段组成,这些段被用来存放代码、数据或当作栈空间来使用
end
- 汇编程序的结束标记
- 如果程序写完了,就要在结尾处加上指令
end
,否则编译器无法知道程序在何处结束
assume
- 这条伪指令的含义为“假设”。他假设某一段寄存器和程序中的某一个
segment...ends
定义的段相关联,通过assume
说明这种关联 - 在需要的情况下,编译程序可以将段寄存器和某一个具体的段相联系
- 这条伪指令的含义为“假设”。他假设某一段寄存器和程序中的某一个
在例子中,code segment...codeseg ends
定义了一个名为 codeseg
的段,在这个段中存放代码,所以这个段是一个代码段。在程序的开头,用 assume cs:codeseg
将用作代码段的段 codeseg
和 CPU 中的段寄存器 cs
联系起来。
源程序中的“程序”
用汇编语言写的源程序,包括伪指令和汇编指令:
- 汇编指令组成了最终由计算机执行的程序
- 源程序中的伪指令由编译器执行
源程序汇总最终由计算机执行、处理的程序或数据,称为程序 。 程序最先以汇编指令的形式存在于源程序中,经过编译、链接后转变为机器码,存储在可执行文件中。
标号
- 源程序中除了汇编指令和伪指令外,还有一些标号,比如
codeseg
- 一个标号指代了一个地址
codeseg
在segment
的前面,作为一个段的名称,这个段最终将被编译、链接程序处理为一个段的段地址
程序的结构
定义一个程序段
1
2
3abc segment
:
abc ends
在段中写入指令,实现任务
1
2
3
4
5abc segment
mov ax, 2
add ax, ax
add ax, ax
abc ends
指出程序在何时结束
1
2
3
4
5
6
7abc segment
mov ax, 2
add ax, ax
add ax, ax
abc ends
end
将程序段和寄存器联系起来
1
2
3
4
5
6
7assume cs:abc
abc segment
mov ax, 2
add ax, ax
add ax, ax
abc ends
end
程序返回
- 当一个程序结束后,将 CPU 的控制权交还给是他得以运行的程序,这个过程就叫程序返回
- 在程序的末尾添加返回的程序段以实现程序返回
1 | mov ax, 4c00H |
语法错误和逻辑错误
4.3 编辑源程序
- 可以使用
Edit
的方式编辑源程序 - 也可以使用其他类型文本编辑器,然后保存后缀为
asm
文件
4.4 编译
source.asm
–>target.obj
- 源文件编译之后产生目标文件
- 中途可以选择生成 列表文件,这个文件是编译器将源程序编译为目标文件的过程中产生的中间结果
- 中途还可以加入 交叉引用文件
- 编译环境
编译的环境,从 windows 的masm
和ml
到 Linux 的fasm
,不一而足。不同的环境对编译伪指令的支持不一样,需要查阅文档。
4.5 链接
target.obj
–> Linked –>execute.exe
- 将目标文件链接之后产生可执行文件
- 链接环境
windows 下的link.exe
和ml.exe
- 链接的作用是什么?
- 如果源程序很大,可以将它分为多个源程序来编译,每个源程序编译成目标文件后,再用链接程序将它们链接到一起,生成一个可执行文件
- 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件链接到一起,生成一个可执行文件
- 一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容不能直接用来生成可执行文件,链接程序将这些内容处理为最终的可执行信息
4.6 谁来执行可执行文件?
- CPU 控制权
- 在 DOS 中,可执行文件中的程序
P1
若要运行,必须由一个正在运行的程序P2
,将P1
从可执行文件中载入内存,将 CPU 的控制权交给它;当P1
运行完毕后,P1
将 CPU 控制权交还P2
- 在 DOS 中,可执行文件中的程序
在上述程序中,将 1.exe
载入内存的,就是shell
。
操作系统的 Shell
- 任何通用的操作系统,都要提供一个 shell (外壳)程序,供操作人员使用这个程序来操作计算机
- DOS 的 shell
- DOS 中有一个
command.com
,这个被称为命令解释器的东西就是 DOS 系统的 shell 了 - DOS 启动完成初始化之后,就会运行
command.com
command.com
运行后,执行完其他任务之后,在屏幕上显示出当前盘符和路径组成的提示符,等待用户输入
- DOS 中有一个
4.9 程序执行过程的跟踪
- 为了查看程序运行过程的细节,以便跟踪错误,我们可以使用
debug
来查看单步执行的过程
1 | debug 1.exe |
进入 debug
环境后,就可以使用 debug
的指令来控制程序的运行了。
r
CX
寄存器表示当前程序的长度
程序被藏在了哪里?
debug
会先找一个单元作为起止地址为SA:0000
(即起止地址的偏移地址为 0)的容量足够的空闲内存区- 在这段内存区的前 256 个字节中,创建一个称为程序段前缀(PSP)的数据区,DOS 要利用 PSP 来和被加载的程序进行通信
- 从这段内存区的 256 字节处开始(在 PSP 的后面),将程序装入,程序的地址被设为
SA+10H:0
- 将该段内存区的段地址存入
ds
中,初始化其他相关寄存器后,设置CS:IP
指向程序的入口
int 21
执行之后,程序显示出Program terminated normally
返回到debug
中,则表示程序正常结束了- 要使用
P
命令执行int 21
- 要使用