汇编语言程序实例的上机步骤

一个汇编源程序从写出到最终执行,需要经过如下几个步骤。

(1)编写汇编源程序;

(2)对源程序进行汇编和连接;

(3)执行或调试可执行文件中的程序。

其中,第 2 步编译链接后出现错误,则会回到第 1 步。第 3 步执行时可以直接执行,也可以使用 Debug 环境进行调试和跟踪,了解程序的详细信息,下面将详细介绍每一步的实现。

一、编辑——建立 ASM 源程序文件

下面开始建立第一个实例程序了,首先写源程序。编辑 ASM 源程序文件就是在机器上写程序,大多数文字编辑软件都可用来输入和修改汇编语言源程序,DOS 命令行方式下的 EDIT 使用很方便。也可以使用 Windows下的记事本(Notepad)、写字板(Writer)。但要注意,源程序文件一定要储存为“纯文本”格式,源程序文件应该使用“ASM”作为扩展名。

下面介绍用 EDIT 编辑ASM源文件的步骤。

(1)进入 DOS 命令行方式。

(2)假定汇编语言的系统工作文件目录为 D:\MASM6.15\,其中 D:\ 表示 D 盘的根目录。可以通过以下命令指向 D 盘:

1
D: ↙ (↙表示 Enter 键)

(3)如果屏幕显示不在此目录,可以通过以下命令进入该目录:

1
D:\>CD \MASM6.15 ↙

当屏幕显示进入该目录后,用如下命令编辑源程序文件:

1
D: \>MASM6.15\>EDIT HELLO.ASM ↙

源程序文件须用“ASM”作为扩展名。最好存放在系统工作目录,便于下一步汇编。

EDIT 编辑源文件如图 3 所示。如果屏幕显示区太小,可用 Alt 键和 Enter 键组合扩大显示区。EDIT 以下拉式菜单操作,用 Alt 键可激活菜单。

EDIT 编辑源文件

图 3 EDIT 编辑源文件

二、汇编——产生 OBJ 二进制目标文件

汇编程序的作用是把汇编语言源程序翻译成为机器代码,产生二进制格式的目标文件(Object File)。

假定汇编语言源程序文件 HELLO.ASM 已经在当前目录 D:\MASM6.15\ 下,用如下命令进行汇编:

1
D:\>MASM6.15\>MASM HELLO.ASM ↙ 或者 D:\>MASM6.15\>MASM HELLO ↙

该命令执行后,将产生一个同名的二进制目标文件 HELLO.OBJ,如图 4 所示。

MASM 编辑源文件

图 4 MASM 编辑源文件

如果源程序有语法错误,则不会产生目标文件,同时报错,提示源程序的出错位置和错误原因。

三、连接——产生 EXE 可执行文件

连接就是使用连接程序 LINK 把目标文件(OBJ)转换为可执行的 EXE 文件。键入以下命令:

1
D:\>MASM6.15\>LINK HELLO.OBJ ↙ 或者 D:\>MASM6.15\>LINK HELLO ↙

如果文件 HELLO.OBJ 存在,机器有如下回应,要求用户对话,如图 5 所示。

LINK 编辑源文件

图 5 LINK 编辑源文件

用户只需回车键认可默认值即可,这样就得到 HELLO.EXE 可执行的文件。

因为源程序中没有定义堆栈段,所以连接程序给出无堆栈段的警告,其实并不是错误,并不影响程序的运行。到此为止,连接过程已经结束。

四、LST 列表文件

如果希望在汇编的同时还得到一个列表文件,可以用如下命令进行汇编:

1
D:\>MASM6.15\>MASM HELLO HELLO HELLO↙

即给出 3 个 HELLO 作为命令参数,以空格分隔,该命令执行后,将产生 MY.OBJ 和列表文件 MY.LST。即使源程序有语法错误,而得不到目标文件,也会产生列表文件 HELLO.LST,如图 6 所示。

产生列表文件的汇编命令

图 6 产生列表文件的汇编命令

列表文件报告了汇编过程中产生的很多有价值的参考信息。主要包括源程序和机器语言清单、指令和变量的偏移地址等。列表文件是文本文件,可用 EDIT 调入。列表文件是可有可无的。例 2 的列表文件 HELLO.LST 如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Microsoft(R)Macro Assembler Version 6.00 02/09/06 16:16:26

HELLO.ASM Page 1-1

0000 DATA SEGMENT

0000 48 45 4C 4C 4F 2C STRING DB'HELLO,WORLD!$'

20 57 4F 52 4C 44

20 21 24

000F DATA ENDS

0000 CODE SEGMENT

ASSUME CS:CODE,DS:DATA

0000 START:

0000 B8----R MOV AX,DATA

0003 8E D8 MOV DS,AX

0005 BA 0000 R MOV DX,OFFSET STRING

0008 B4 09 MOV AH,9

000A CD 21 INT 21H

000C B4 4C MOV AH,4CH

000E CD 21 INT 21H

0010 CODE ENDS

END START

Microsoft(R)Macro Assembler Version 6.00 02/09/06 16:16:26

HELLO.ASM Symbols 2-1

Segments and Groups:

Name Size Length Align Combine Class

CODE.............. 16 Bit 0010 Para Private

DATA.............. 16 Bit 000F Para Private

Symbols:

Name Type Value Attr

START .............L Near 0000 CODE

STRING.............Byte 0000 DATA

0 Warnings

0 Errors

列表文件 HELLO.LST 可以看成上下两个部分。

上面一部分列出程序清单。左边第一列 4 位十六进制数表示程序的偏移地址,第二列若干位十六进制数表示指令的机器码即机器指令,它们当中有些不是十六进制数,如 B8—-R,BA 0000 R,“R”表示该指令的操作数需要重定位,即地址值在汇编时还无法确定,必须在 LINK 时进行定位后才能确定机器指令。暂时还不能确定的机器指令,只能得到一个指令的半成品。但请特别注意,这条指令的长度已经确定,这样不会影响后面指令的偏移地址的确定。第三列显然是汇编语言指令。

下面一部分列出程序中所有名字的信息。对段名,将列出其大小(16 位或 32 位段)、长度、定位类型和组合类型等信息;对标号和变量,将列出其类型、偏移地址值和其所属的段名等信息。

最后报告的 0 Warnings,0 Errors,表示无警告性错误,无致命性错误。如果有致命性错误,则不产生 .OBJ 目标文件。

无致命性错误,则产生 .OBJ 目标文件,只是说明源程序没有语法错误,至于程序的算法或其他语义错误要在程序的调试过程中来发现。

五、程序的运行

当汇编源程序编辑完成,经过汇编和连接后将生成 *.EXE 文件,即一个可以直接在操作系统下执行的程序文件。只需在命令行输入所需执行的文件名称,回车,即可得到运行结果。如执行 HELLO.EXE,命令如下:

1
HELLO.EXE ↙ 或 HELLO ↙

注意

程序文件必须在当前目录下。这里文件扩展名 EXE 可省略。真正的可执行文件是生成的,不是用改名操作得到的。运行结果如图 7 所示,分别给出了加扩展名和不加扩展名的运行结果。

exe 文件运行结果举例

图 7 exe 文件运行结果举例

六、程序的跟踪和调试

有些程序没有要求显示结果,程序运行结束,结果也已经得到,存放在某寄存器中或内存中,只是没有显示输出。那么程序执行的结果是否正确呢? 此外,即使程序有显示输出,却是错误的结果,如何知道错在哪里呢?因此,必须经过调试阶段,才能观测结果和发现程序中的错误。调试程序 Debug.EXE 由 Windows 系统自带,使用方便,下面结合实例 2 的 HELLO 程序予以介绍。

在 Debug 下调试运行程序,并输入命令如下:

1
Debug HELLO.EXE ↙

用 Debug 调入 HELLO.EXE,出现“-”Debug 命令提示符。在“-”后可键入 Debug 命令,如图 8 所示。

Debug 界面

图 8 Debug 界面

1. 反汇编命令 U

U 命令把机器语言反汇编为汇编语言,便于用户看程序。命令格式为 U[地址范围]。方括号表示可选。图 9 所示为反汇编命令 U 的执行结果。

反汇编命令 U 的执行结果

图 9 反汇编命令 U 的执行结果

图中分 3 列,第 1 列表示各条指令的逻辑地址,即段地址:偏移地址,用十六进制表示。如 076B:0000 是第一条指令 MOV AX,076A 的逻辑地址,显然其物理地址是 076B0H。

第 2 列为各条指令的机器码(十六进制),如第一条指令的机器码 B86A07 为 3 个字节长度,占 0 到 2 共 3 个内存单元,所以第二条指令的偏移地址是 0003H。

第 3 列为汇编语言指令。本程序只有 7 条指令,在偏移地址 0010H 前就结束了。

那么,程序中定义的字符串‘HELLO,WORLD !$’在那里呢?

2. 运行程序命令 G

G 命令用于执行程序,命令格式为 G[=起始地址][中止地址]。其中 [中止地址] 是为了给程序设置断点,让程序暂停在某个位置,便于观测。本例中用 G=0 命令,即从偏移地址 0000 处执行程序,如图 10 所示。

G 命令运行结果

图 10 G 命令运行结果

3. 跟踪程序命令 T

T 命令用于单步执行程序,所以又叫跟踪程序。命令格式为 T[=起始地址][指令条数]。可以控制程序每执行一条指令就暂停,并显示当前机器情况。图 11 为跟踪程序命令 T 执行一次的结果。

跟踪程序命令 T 的执行结果

图 11 跟踪程序命令 T 的执行结果

注意,上图的运行结果是在 U 命令之后,为了显示寄存器内容的变化,首先用 R 命令查看各寄存器的值,再输入 T 命令。

当输入 T=0 命令,从偏移地址 0000 处开始执行一条指令就暂停,也即执行了第一条指令 MOV AX,076A,注意命令执行后的 AX 发生了变化。指令指针寄存器 IP 由 0 变成 3,意味着下条指令位于 0003 处。可见寄存器 IP 总是指向下条将执行的指令。如果继续跟踪,只需用 T 命令即可,无需跟参数。

这里需要特别指出:对于 INT 指令不能使用 T 命令跟踪。因为 INT 指令实质上是调用一个系统例行程序,T 命令使程序进入了一个陌生的系统程序之中,如图 12 所示,当需要执行的单条指令为“INT 21H”时,则会出现陌生的系统程序。

跟踪执行系统例行程序指令的结果

图 12 跟踪执行系统例行程序指令的结果

4. 单步执行程序命令 P

针对单步跟踪命令 T 的局限性,现介绍 P 命令。P 命令用以执行循环、重复的字符串指令、软件中断或子例程。例如 T 命令无法一次执行的 INT 指令,P 命令就可以一次执行完这个系统例行程序,回到用户程序中。运行结果如图 13 所示。

命令执行系统例行程序指令后的结果

图 13 P 命令执行系统例行程序指令后的结果

5. 退出命令 Q

用 Q 命令退出 Debug。运行结果如图 14 所示。

Q 命令运行结果

图 14 Q 命令运行结果

以上举例介绍的 U、G、T、P 是最常用的 Debug 命令,熟练掌握它们就可以有效地进行程序调试。

请参阅

(完)

comments powered by Disqus