汇编语言程序设计的实验环境及上机步骤
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
汇编语言程序设计上机实验指导书
电子信息工程学院工业自动化教研室
2008年4月15日
汇编语言程序设计的实验环境及上机步骤
一、实验环境
汇编语言程序设计的实验环境如下:
1. 硬件环境
微型计算机(Intel x86系列CPU)一台
2. 软件环境
Windows98/2000/XP操作系统
任意一种文本编辑器(EDIT、NOTEPAD(记事本)、UltraEDIT等)
汇编程序(MASM.EXE或TASM.EXE)
连接程序(LINK.EXE或TLINK.EXE)
调试程序(DEBUG.EXE或TD.EXE)
文本编辑器建议使用EDIT或NOTEPAD,汇编程序建议使用MASM.EXE,连接程序建议使用LINK.EXE,调试程序建议使用DEBUG.EXE。
二、上机实验步骤
1.确定源程序的存放目录
建议源程序存放的目录名为MASM中,MASM子目录在C盘或D盘的根目录下。
2.建立ASM源程序
建立ASM源程序可以使用EDIT或NOTEPAD(记事本)文本编辑器。
下面的例子说明了用EDIT文本编辑器来建立ASM源程序的步骤(假定要建立的源程序名为HELLO.ASM),用NOTEPAD(记事本)建立ASM源程序的步骤与此类似。
在Windows中点击桌面左下角的“开始”按钮→选择“运行”→在弹出的窗口中输入“”,屏幕上出现EDIT的编辑窗口。
窗口标题行显示了EDIT程序的完整路径名。
紧接着标题行下面的是菜单行,窗口最下面一行是提示行。
菜单可以用Alt键激活,然后用方向键选择菜单项,也可以直接用Alt-F 打开File文件菜单,用Alt-E打开Edit编辑菜单,等等。
如果键入EDIT命令时已带上了源程序文件名(C:\ASM\HELLO.ASM),在编辑窗口上部就会显示该文件名。
如果在键入EDIT 命令时未给出源程序文件名,则编辑窗口上会显示“UNTITLED1”,表示文件还没有名字,在这种情况下保存源程序文件时,EDIT会提示输入要保存的源程序的文件名。
编辑窗口用于输入源程序。
EDIT是一个全屏幕编辑程序,故可以使用方向键把光标定位到编辑窗口中的任何一个位置上。
EDIT中的编辑键和功能键符合Windows的标准,这里不再赘述。
源程序输入完毕后,用Alt-F打开File菜单,用其中的Save功能将文件存盘。
如果在键入EDIT命令时未给出源程序文件名,则这时会弹出一个“Save as”窗口,在这个窗口中输入你想要保存的源程序的路径和文件名(本例中为D:\MASM\HELLO.ASM)。
注意,汇编语言源程序文件的扩展名要用.ASM,这样能给后面的汇编和连接操作带来很大的方便。
3.用MASM.EXE汇编源程序产生OBJ目标文件
源文件HELLO.ASM建立后,要使用汇编程序对源程序文件汇编,汇编后产生二进制的目标文件(.OBJ文件)。
具体操作如下:
在Windows中点击桌面左下角的“开始”按钮→选择“运行”→在弹出的窗口中输入CMD
提示符窗口,然后用CD命令转到源程序目录下,接着输入MASM命令:回车
C:> \.........\D: <回车>
D:>CD \MASM<回车>
D:\MASM>MASM HELLO.ASM<回车>
进入MASM程序后,都会提示让你输入目标文件名(Object filename),并在方括号中显示默认的目标文件名,建议输入目标文件的完整路径名,如:D:\MASM\HELLO.OBJ〈回车〉。
后面的两个提示为可选项,直接按回车。
注意,若打开MASM程序时未给出源程序名,则MASM 程序会首先提示让你输入源程序文件名(Source filename),此时输入源程序文件名HELLO.ASM并回车,然后进行的操作与上面完全相同。
如果没有错误,MASM就会在当前目录下建立一个HELLO.OBJ文件(名字与源文件名相同,只是扩展名不同)。
如果源文件有错误,MASM会指出错误的行号和错误的原因。
图3是在汇编过程中检查出两个错误的例子。
在这个例子中,可以看到源程序的错误类型有两类:警告错误(Warning Errors)。
警告错误不影响程序的运行,但可能会得出错误的结果。
严重错误(Severe Errors)。
对于严重错误,MASM将无法生成OBJ文件。
在错误信息中,园括号里的数字为有错误的行号,后面给出了错误类型及具体错误原因。
如果出现了严重错误,你必须重新进入EDIT编辑器,根据错误的行号和错误原因来改正源程序中的错误,直到汇编没有错为止。
注意,汇编程序只能指出程序的语法错误,而无法指出程序逻辑的错误。
4.用LINK.EXE产生EXE可执行文件
在上一步骤中,汇编程序产生的是二进制目标文件(OBJ文件),并不是可执行文件,要想使我们编制的程序能够运行,还必须用连接程序(LINK.EXE)把OBJ文件转换为可执行的EXE文件。
具体操作如下:
D:\MASM>LINK HELLO.OBJ<回车>
进入LINK程序后,都会提示让你输入可执行文件名(Run file),并在方括号中显示默认的可执行文件名,建议输入可执行文件的完整路径名,如:C:\ASM\HELLO.EXE〈回车〉。
后面的两个提示为可选项,直接按回车。
注意,若打开LINK程序时未给出OBJ文件名,则LINK程序会首先提示让你输入OBJ文件名(Object Modules),此时输入OBJ文件名HELLO.OBJ 并回车,然后进行的操作与上面完全相同。
如果没有错误,LINK就会建立一个HELLO.EXE文件。
如果OBJ文件有错误,LINK会指出错误的原因。
对于无堆栈警告(Warning:NO STACK segment)信息,可以不予理睬,它不影响程序的执行。
如链接时有其它错误。
须检查修改源程序,重新汇编、连接,直到正确。
5.执行程序
建立了HELLO.EXE文件后,就可以直接在DOS下运行此程序,如下所示:
D:\MASM> HELLO〈回车〉
D:\MASM>
程序运行结束后,返回DOS。
如果运行结果正确,那么程序运行结束时结果会直接显示
在屏幕上。
如果程序不显示结果,我们如何知道程序是否正确呢?例如,这里的HELLO.EXE 程序并未显示出结果,所以我们不知道程序执行的结果是否正确。
这时,我们就要使用DEBUG.EXE调试工具来查看运行结果。
此外,大部分程序必须经过调试阶段才能纠正程序执行中的错误,调试程序时也要运行DEBUG.EXE程序。
6.使用DEBUG调试和运行可执行文件
用户程序经过编辑、汇编、连接后得到一个可执行文件(.EXE),这时借助于调试程序DEBUG对用户程序进行调试,查看程序是否能完成预定功能。
对于初学者,如何选用DEBUG 中各命令,有效地调试与运行程序,需要一个学习过程。
在初次使用DEBUG时,可参照下列步骤进行。
<1>.调用DEBUG,装入用户程序
可以在调用DEBUG是直接装入用户程序可执行文件,也可以在进入DEBUG环境后使用N 命令和L命令装入用户程序可执行文件。
无论用哪种方法,装入用户程序可执行文件时,一定要指定文件全名(即文件名和扩展名)。
<2>.观察寄存器初始状态
程序装入内存后,用R命令查看寄存器内容。
从各段寄存器现在的内容,便能了解用户程序各逻辑段(代码段,堆栈段等)在内存的分布及其段基值。
R命令亦显示了各通用寄存器和标志寄存器的初始值,显示的第三行就是即将执行的第一条指令。
<3>.以单步工作方式开始运行程序
首先用T命令顺序执行用户程序的前几条指令,直到段寄存器DS和/或ES已预置为用户的数据段。
在用T命令执行程序时,每执行一条指令,显示指令执行后寄存器的变化情况,以便用户查看指令执行结果。
<4>.观察用户程序数据段初始内容
在第3步执行后DS和/或ES已指向用户程序的数据段和附加段,这时用D命令可查看用户程序的原始数据。
<5>.继续以单步工作方式运行程序
对于初学者,一般编写的程序比较短,用T命令逐条执行指令,可清楚地了解程序的执行过程:现在执行的是什么指令,执行后的结果在哪里(寄存器,存储单元)?所得结果是否正确?…等等。
在逐次使用T命令时,若有需要,可选用D命令了解某些内存单元的变化情况。
用T命令逐条执行程序时,如遇上用户程序中的软中断指令INT(如INT 21H),这时,通常不要用单步工作方式执行INT指令。
因为系统提供的软中断指令INT是以中断处理子程序形式实现功能调用,且这种处理子程序常常是较长的。
若用T命令去执行INT指令,那么将跳转到相应的功能调用于程序中,要退出该子程序需要化费较多时间。
如果既要执行INT指令,又要跳过这段功能调用子程序,则应使用连续工作方式(G命令),且设置断点,其断点应为INT指令的下一条指令。
例如要以单步工作方式执行下面一段程序:
10B0:0022MOV DX,0010
10B0:0026MOV AH,09
10B0:0028INT21
10B0:002A MOV CX,00
当用T命令完成“MOV AH,09”指令后,应使用G命令:
-G002A
这样,以连续工作方式实现功能调用后,即暂停在偏移量为002A的“MOV CX,00”指令处(未执行),如同用单步工作方式完成INT指令的执行一样。
<6>.连续工作方式运行程序
在用单步工作方式运行程序后,可再用连续工作方式从头开始运行程序,查看运行结果。
在用G命令时,注意指定运行程序的起始地址。
若G命令中未指定起始地址,就隐含为从当前CS:IP指向的指令开始。
<7>.修改程序和数据
经过上面几步后,若发现程序有错,则需要适当进行修改。
这时,如果仅需作个别修改,可在DEBUG状态下,使用A命令。
这种修改仅仅是临时修改内存中的可执行文件,未涉及源程序。
当确认修改正确后,应返回至编辑程序,修改源程序,然后再汇编、连接。
为了确认用户程序的正确性,常常需用几组不同的原始数据去运行程序,查看是否都能获得正确结果。
这时,可用E命令在用户程序的数据段和附加段中修改原始数据,然后再用T 命令或G命令运行程序,查看运行结果,直到各组数据都能获得正确结果为止。
<8>.运用断点调试程序
如果已确认程序是正确的,在连续工作方式下,可快速地运行程序;如果已知程序运行结果不正确,用G命令运行程序,中途不停,很难查找错误。
改用T命令,虽然可以随意暂停程序的执行,但是运行速度慢,如果运用断点,可快速查找错误。
这里的“断点”是程序连续运行时要求暂停的指令位置(地址),用要求暂停的一条指令首字节地址表示。
当程序连续运行到这断点地址时,程序就暂停,并显示现在各寄存器内容和下面将要执行的指令(即断点处指令)。
为了准确设置断点,可用反汇编命令U 察看源程序。
运用断点,可以很快地查找出错误发生在哪一个程序段内,缩小查找错误的范围。
然后在预计出错的范围内,再用T命令仔细观察程序运行情况,确定出错原因和位置,完成程序的调试。
例5 现有一个双字加法源程序如下,其中存在错误。
现假设已汇编、连结生成了可执行文件HELLO.EXE,存放在D:\MASM\目录下。
请使用DEBUG对其进行调试。
Code SEGMENT
ASSUME CS:code,DS:code
ORG 100H;从100H处开始存放下列指令
Start: MOV AX,code;将DS置成code段的首地址
MOV DS,AX
MOV SI,200H;取第一个数的首地址
MOV AX,[SI];将第一个数的低16位取到AX
MOV DI,204H;取第二个数的首地址
ADD AX,[DI];第一个数和第二个数的低16应相加
MOV [SI+8],AX ;低16位相加的结果送到208H和209H单元
MOV AX,[SI+2] ;取第一个数的高16位送到AX中
ADD AX,[DI+2] ;两个数的高16位相加
MOV [SI+0AH],AX;高16位相加的结果送到20AH,20BH单元
MOV AX,4C00H;使用DOS的4CH号功能调用
INT 21H ;进入功能调用,返回DOS
ORG 200H;从200H处开始存放下列数据
DD 12345678h,654387A9h,0h ;被加数、加数、和
Code ENDS
END start
调试过程:
(1)进入DEBUG并装入可执行文件HELLO.EXE
D:\MASM>DEBUG HELLO.EXE(如果已在DEBUG环境下用_n XXX.exe)
-
(2)观察寄存器初始状态
-R
AX=0000BX=0000CX=020C DX=0000SP=0000BP=0000SI=0000DI=0000
DS=1892ES=1892SS=18A2CS=18A2IP=0100NV UP EI PL NZ NA PO NC
18A2:0100 B8A218MOV AX,18A2
(3)以单步工作方式开始运行程序
首先用T命令顺序执行用户程序的前l两条指令,将段寄存器DS预置为用户的数据段。
-T
AX=18A2BX=0000CX=020C DX=0000SP=0000BP=0000SI=0000DI=0000
DS=1892ES=1892SS=18A2CS=18A2IP=0103NV UP EI PL NZ NA PO NC
18A2:0103 8ED8 MOV DS,AX
-T
AX=18A2BX=0000CX=020C DX=0000SP=0000BP=0000SI=0000DI=0000
DS=18A2ES=1892SS=18A2CS=18A2IP=0105NV UP EI PL NZ NA PO NC
18A2:0105 BE0002MOV SI,0200
(4) 观察用户程序数据段初始内容
-D 200 20F
-18A2:020078 56 34 12 A9 87 43 65-00 00 00 00 00 74 13 50xV4...Ce.....t.P
(5) 连续工作方式运行程序至返回DOS前(设断点),查看运行结果。
为此,现使用U命令反汇编。
-U 100
18A2:0100 B8A218MOV AX,18A2
18A2:0103 8ED8 MOV DS,AX
18A2:0105 BE0002MOV SI,0200
18A2:0108 8B04 MOV AX,[SI]
18A2:010A BF0402MOV DI,0204
18A2:010D 0305 ADD AX,[DI]
18A2:010F 894408MOV[SI+08],AX
18A2:0112 8B4402MOV AX,[SI+02]
18A2:0115 034502ADD AX,[DI+02]
18A2:0118 89440A MOV[SI+0A],AX
18A2:011B B8004C MOV AX,4C00
18A2:011E CD21 INT21
-
可见,要执行10条指令,至011B处停止
-G=100,011B
AX=7777BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=011B NV UP EI PL NZ NA PE NC
18A2:011B B8004C MOV AX,4C00
-D 200 20F
18A2:020078 56 34 12 A9 87 43 65-21 DE 77 77 43 43 83 06xV4...Ce!.wwCC.. -
和为7777DE21H,正确。
(6) 再取一组数据,查看运行结果。
为此,首先用E命令修改数据。
-E 200 CD,AB,78,56,90,EF,34,12
-D 200 20F
18A2:0200CD AB 78 56 90 EF 34 12-21 DE 77 77 43 43 83 06..xV..4.!.wwCC.. -G=100,11B
AX=68AC BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=011B NV UP EI PL NZ NA PE NC
18A2:011B B8004C MOV AX,4C00
-D 200 20F
18A2:0200CD AB 78 56 90 EF 34 12-5D 9B AC 68 43 43 83 06..xV..4.]..hCC.. -
和为68AC9B5DH,错误。
说明程序有问题。
(7) 再将断点设在完成低位字加法后,查看运行结果。
-G=100,112
AX=9B5D BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=0112NV UP EI NG NZ NA PO CY
18A2:0112 8B4402MOV AX,[SI+02] DS:0202=5678
-D 200 20F
18A2:0200CD AB 78 56 90 EF 34 12-5D 9B AC 68 43 43 83 06..xV..4.]..hCC.. -
低位和为9B5D,正确。
说明错误可能出在后面
(8) 使用T命令从刚才的断点处向后单步调试,查看运行结果。
-T=112
AX=5678BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=0115NV UP EI NG NZ NA PO CY
18A2:0115 034502ADD AX,[DI+02] DS:0206=1234
-T
AX=68AC BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=0118NV UP EI PL NZ NA PE NC
18A2:0118 89440A MOV[SI+0A],AX DS:020A=68AC
-
AX寄存器的结果为68AC,而应为68AD。
可见是本条加法指令使用错误,这里应使用带进位加法指令。
(9)使用A命令装入正确指令后再次运行,察看结果。
-A 115
18A2:0115 ADC AX,[DI+02]
18A2:0118
-G=100,11B
AX=68AD BX=0000CX=020C DX=0000SP=0000BP=0000SI=0200DI=0204
DS=18A2ES=1892SS=18A2CS=18A2IP=011B NV UP EI PL NZ NA PO NC
18A2:011B B8004C MOV AX,4C00
-D 200 20F
18A2:0200CD AB 78 56 90 EF 34 12-5D 9B AD 68 43 43 83 06..xV..4.]..hCC.
-
和为68AD9B5DH,正确。
对于这样一个简单程序一般来说不会再有问题。
退出后修改源程序即可。
(10)退出
-Q
C:\DOS>
需要说明的是此程序很简单,只需使用T命令逐条单步调试即可。
本例采用的调试方法似乎过于繁琐,但这是为了说明程序调试的一般方法,以便读者调试复杂程序时借鉴。