汇编上机第一部分.docx
《汇编上机第一部分.docx》由会员分享,可在线阅读,更多相关《汇编上机第一部分.docx(13页珍藏版)》请在冰豆网上搜索。
![汇编上机第一部分.docx](https://file1.bdocx.com/fileroot1/2023-1/4/697a94c7-57e4-4900-bef0-e66d3ddd0b38/697a94c7-57e4-4900-bef0-e66d3ddd0b381.gif)
汇编上机第一部分
一、实验目的
汇编语言程序设计是一门实践性很强的课程,通过上机更好地理解课堂所学理论知识,进一步掌握程序设计的基本方法和技能,熟练掌握用汇编语言设计、编写、调试和运行程序的方法;锻炼动手能力,提高分析、解决具体问题的能力,从而使程序设计能力达到较高水平;通过独立设计应用方案和对程序执行结果的分析、整理,培养创新思维、编写实验报告的能力,为后续课程打下坚实的基础。
二、实验要求
1.每人准备一本实验本子,上机前要作好充分的准备,包括实验题目、程序框图、源程序清单、调试步骤、测试方法及数据。
2.上机时要遵守机房的规章制度,爱护实验设备。
要熟悉与实验有关的系统软件(如编辑程序、汇编程序、连接程序和调试程序等)的使用方法。
在调试程序的过程中,有意识地学习及掌握调试程序Debug的各种操作命令,以便掌握程序调试方法及技巧。
3.为更好地进行上机管理,要求在可读写的硬盘分区上建立自己的工作目录,将汇编环境和源程序均放于该目录下,一方面便于工作,另一方面以避免文件被别人删除。
有关Command命令窗口的目录操作命令见附录。
此外,为便于统一管理硬盘中的文件,要求实验者按以下形式命名实验文件:
【班级】【学号】【实验题序号字母】.【扩展名】
其中实验题序号字母按实验顺序从a至z排列。
如计011班学号为06学生的第二个实验程序所对应的文件名应为j01106b.asm。
4.程序调试完后,须由指导教师在机器上检查运行结果,经教师认可后,请指导教师在实验本子上签字。
每个实验完成后,在实验本子上补充完下列内容:
(1)设计说明:
用来说明程序的功能、结构。
包括:
程序名、功能、原理及算法说明、程序所用数据结构、主要符号名的说明等。
(2)调试说明:
便于学生总结经验、提高编程及调试能力。
包括:
调试情况,如上机时遇到的问题及解决办法,观察到的现象及其分析,对程序设计技巧的总结及分析等;程序的输出结果及对结果的分析;实验的心得体会等内容。
(3)使用说明:
程序提供给用户使用时必须作出的说明。
如:
程序的使用方法,调用方式,操作步骤等;要求输入的参数、返回值的类型及格式;出错信息的含义及程序的适用范围等。
实验方法
有关汇编语言程序设计的上机过程请读者参见本书附录部分。
在这里,我们通过一个例子简要说明该过程以及程序的调试方法。
例1.1求平均数。
试编写一程序:
在数据段中定义一个5字节数据的数组array,把它们看作有符号数求其平均数,结果送avg内存单元。
程序框图见图1.1:
图1.1例1.1的程序框图
上机过程如下:
1.调用文本编辑程序Edit建立asm文件
Edit是Dos系统环境下的编辑工具,当然读者也可以用其它的W32编辑工具如EditPlus、Ultraedit、NotePad等软件在Windows下来建立源文件。
下面假设启动的是Dos操作系统或启动Windows切换到Command命令窗口(为便于讨论下面均以Dos系统说明之),汇编语言上机的工作环境在E:
\masm子目录下。
键入以下命令:
E:
\masm\editsample.asm
使用该命令建立以sample.asm为文件名的源文件如图1.2所示。
然后,保存文件返回到Dos系统。
;******************************************************************************
datasegment;定义数据段
arraydb1,2,3,4,5
avgdb?
dataends
;******************************************************************************
codesegment;定义代码段
;------------------------------------------------------------------------------
mainprocfar;定义主过程
assumeds:
data,cs:
code
start:
;程序的入口地址标号
pushds;以下3条指令为返回Dos系统做准备
xorax,ax
pushax
;
movax,data;装载Ds段寄存器
movds,ax
;
leasi,array;设置数组的指针si
movcx,5;装载循环计数器cx
moval,0;累加器al清零
next:
;循环求累加和
movdl,[si]
addal,dl
incsi
loopnext
cbw;将al中的累加和扩展到ax
movbl,5
idivbl;商在al中,余数在ah中
movavg,al
;
ret;返回到Dos系统
mainendp;主过程结束
;---------------------------------------------------------------------------------------------------------------------
codeends;代码段结束
;******************************************************************************
endstart;整个程序结束
;
图1.2例1.1的源文件sample.asm
2.调用汇编程序Masm对源文件汇编产生目标文件sample.obj
键入以下命令:
E:
\masm\masmsample
屏幕显示如下:
Microsoft(R)MacroAssemblerVersion5.00
Copyright(C)MicrosoftCorp1981-1985,1987.Allrightsreserved.
Objectfilename[sample.OBJ]:
Sourcelisting[NUL.LST]:
Cross-reference[NUL.CRF]:
50956+450516Bytessymbolspacefree
0WarningErrors
0SevereErrors
上述三个问题以回车作为默认回答,如汇编指示出错则须重新调用编辑程序修改错误,直至汇编通过为止。
如调试时需要列表文件lst,则应在汇编过程中建立该文件。
键入以下命令:
E:
\masm\masmsample
屏幕显示如下:
Microsoft(R)MacroAssemblerVersion5.00
Copyright(C)MicrosoftCorp1981-1985,1987.Allrightsreserved.
Objectfilename[sample.OBJ]:
Sourcelisting[NUL.LST]:
smpl
Cross-reference[NUL.CRF]:
50414+451058Bytessymbolspacefree
0WarningErrors
0SevereErrors
则生成smpl.lst列表文件,该文件是纯文本文件,可用编辑程序打开,以获得相应的汇编信息。
还可以键入以下命令,可省略三个问题从而加速汇编。
E:
\masm\masmsample;
屏幕显示如下:
Microsoft(R)MacroAssemblerVersion5.00
Copyright(C)MicrosoftCorp1981-1985,1987.Allrightsreserved.
50956+450516Bytessymbolspacefree
0WarningErrors
0SevereErrors
3.调用连接程序Link对目标文件连接产生可执行文件sample.exe
键入以下命令:
E:
\masm\linksample
屏幕显示如下:
Microsoft(R)OverlayLinkerVersion3.60
Copyright(C)MicrosoftCorp1983-1987.Allrightsreserved.
RunFile[SAMPLE.EXE]:
ListFile[NUL.MAP]:
Libraries[.LIB]:
LINK:
warningL4021:
nostacksegment
上述三个问题以回车作为默认回答。
该警告错误不影响连接的通过,已产生可执行文件sample.exe。
以下命令可加速连接:
E:
\masm\linksample;
屏幕显示如下:
Microsoft(R)OverlayLinkerVersion3.60
Copyright(C)MicrosoftCorp1983-1987.Allrightsreserved.
LINK:
warningL4021:
nostacksegment
4.调用调试程序Debug对可执行文件调试、运行
本程序执行结果没有送往显示器输出,因此,不能从Dos系统运行,否则看不到结果,只能通过Debug装载运行查看内存内容。
键入以下命令:
E:
\masm\Debugsample.exe
屏幕显示如下:
-
Debug以短横作为应答,此时,Debug已将可执行程序sample.exe装入内存,进入调试运行状态。
一般先反汇编,将机器码反汇编成汇编语言指令,提供一些相关的调试信息。
命令如下:
-u
0B40:
00001EPUSHDS
0B40:
000133C0XORAX,AX
0B40:
000350PUSHAX
0B40:
0004B83F0BMOVAX,0B3F
0B40:
00078ED8MOVDS,AX
0B40:
00098D360000LEASI,[0000]
0B40:
000DB90500MOVCX,0005
0B40:
0010B000MOVAL,00
0B40:
00128A14MOVDL,[SI]
0B40:
001402C2ADDAL,DL
0B40:
001646INCSI
0B40:
0017E2F9LOOP0012
0B40:
001998CBW
0B40:
001AB305MOVBL,05
0B40:
001CF6FBIDIVBL
0B40:
001EA20500MOV[0005],AL
其中第一列为代码段的段地址0B40H,该值由系统自动分配;第二列为代码段内的偏移地址,后面所选断点只能从这一列根据需要选取;第三列为机器语言指令;最后是汇编语言的符号指令。
输入如下命令,接着前面继续往后反汇编。
-u
0B40:
0021CBRETF
0B40:
002240INCAX
0B40:
002350PUSHAX
0B40:
00248D4680LEAAX,[BP-80]
0B40:
002750PUSHAX
0B40:
00288D867AFELEAAX,[BP+FE7A]
0B40:
002C50PUSHAX
0B40:
002DE8E270CALL7112
0B40:
003083C406ADDSP,+06
0B40:
0033B8C805MOVAX,05C8
0B40:
003650PUSHAX
0B40:
00378D4680LEAAX,[BP-80]
0B40:
003A50PUSHAX
0B40:
003BE83E0DCALL0D7C
0B40:
003E83C404ADDSP,+04
很显然,反汇编结果中仅第一行0B40:
0021CBRETF与本程序有关,其后的内容是系统中已经存在的,我们不必关心。
如果想再看看前面机器码反汇编的结果可用带起始地址的反汇编命令,如:
-u0
0B40:
00001EPUSHDS
0B40:
000133C0XORAX,AX
0B40:
000350PUSHAX
0B40:
0004B83F0BMOVAX,0B3F
0B40:
00078ED8MOVDS,AX
0B40:
00098D360000LEASI,[0000]
0B40:
000DB90500MOVCX,0005
0B40:
0010B000MOVAL,00
0B40:
00128A14MOVDL,[SI]
0B40:
001402C2ADDAL,DL
0B40:
001646INCSI
0B40:
0017E2F9LOOP0012
0B40:
001998CBW
0B40:
001AB305MOVBL,05
0B40:
001CF6FBIDIVBL
0B40:
001EA20500MOV[0005],AL
表示再从头反汇编。
为了看到在数据段中定义的5个字节数据,必须将程序执行到装载Ds段寄存器之后,所以可将断点设置在0009H处(当然可写成9)。
比较:
-d0
0B2F:
0000CD20FF9F009AF0FE-1DF04F0352058A03.........O.R...
0B2F:
00105205170352054105-0101010002FFFFFFR...R.A.........
0B2F:
0020FFFFFFFFFFFFFFFF-FFFFFFFFFF0A4C01..............L.
0B2F:
0030120A140018002F0B-FFFFFFFF00000000....../.........
0B2F:
00400500000000000000-0000000000000000................
0B2F:
0050CD21CB0000000000-0000000000202020.!
...........
0B2F:
00602020202020202020-0000000000202020.....
0B2F:
00702020202020202020-0000000000000000........
d命令默认显示ds段内容,其中第一列为当前数据段的段地址0B2FH,该值由系统自动分配;第二列为数据段内存储单元的偏移地址;中间为存储单元的内容,每行对应16个字节,前8个字节与后8个字节以短横隔开,共8行;最右边是将各个字节作为ASCII码值对应的可显示字符。
这里显示的是系统本来就存在的内容。
没有装载Ds寄存器,所以不能显示自己定义的5个字节数据。
下面先执行程序,再用d命令显示。
-g9
AX=0B3FBX=0000CX=0032DX=0000SP=FFFCBP=0000SI=0000DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0009NVUPEIPLZRNAPENC
0B40:
00098D360000LEASI,[0000]DS:
0000=0201
-d0
0B3F:
00000102030405000000-0000000000000000................
0B3F:
00101E33C050B83F0B8E-D88D360000B90500.3.P.?
....6.....
0B3F:
0020B0008A1402C246E2-F998B305F6FBA205......F.........
0B3F:
003000CB40508D468050-8D867AFE50E8E270..@P.F.P..z.P..p
0B3F:
004083C406B8C805508D-468050E83E0D83C4......P.F.P.>...
0B3F:
005004C786FEFE0000EB-0590FF86FEFEA156...............V
0B3F:
0060073986FEFE737D8B-9EFEFED1E3D1E38B.9...s}.........
0B3F:
007087BE220B87C02274-E18B9EFEFED1E3D1.."..."t........
g9表示从当前IP(=0)所指指令处执行到地址9处的指令停下。
注意:
可执行程序刚被Debug装载入内存时,IP=0。
此时,数据段寄存器Ds的内容变成了0B3FH,我们的数据段的段地址就是该值,可查看自己定义的5个字节数,在这一行内:
0B3F:
00000102030405000000-0000000000000000................
对应着源程序,我们不难发现avg单元的偏移地址是0005H(这一点是要理解的吆!
)。
好了,到这儿我们已经初步领略了汇编语言程序调试的要点那就是:
根据需要找出断点、分段执行程序、查看相关内容、比较是否与自己设想的内容一致、决定下一步做什么。
当前程序执行到什么地方,我们可用R命令显示,如下所示:
-r
AX=0B3FBX=0000CX=0032DX=0000SP=FFFCBP=0000SI=0000DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0009NVUPEIPLZRNAPENC
0B40:
00098D360000LEASI,[0000]DS:
0000=0201
说明下面要执行LEASI,[0000]指令。
当前SI=0000,因为LEASI,[0000]执行后SI仍为0,为了能反映出SI的变化,我们先改掉SI的值,如下所示:
-rsi
SI0000
:
1234
-r
AX=0B3FBX=0000CX=0032DX=0000SP=FFFCBP=0000SI=1234DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0009NVUPEIPLZRNAPENC
0B40:
00098D360000LEASI,[0000]DS:
0000=0201
SI的值修改成了1234H。
OK!
我们现在可以单步执行一条指令,如下所示:
-t
AX=0B3FBX=0000CX=0032DX=0000SP=FFFCBP=0000SI=0000DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=000DNVUPEIPLZRNAPENC
0B40:
000DB90500MOVCX,0005
显然,此时SI是0000,下面要执行的指令为MOVCX,0005。
我们当然也可以单步执行2条指令,如下所示:
-t2
AX=0B3FBX=0000CX=0005DX=0000SP=FFFCBP=0000SI=0000DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0010NVUPEIPLZRNAPENC
0B40:
0010B000MOVAL,00
AX=0B00BX=0000CX=0005DX=0000SP=FFFCBP=0000SI=0000DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0012NVUPEIPLZRNAPENC
0B40:
00128A14MOVDL,[SI]DS:
0000=01
执行结果是将计数器CX赋值为5,将累加器AL清为0。
下面,我们将断点设在0019H,亦即执行到循环退出,如下所示:
-g19
AX=0B0FBX=0000CX=0000DX=0005SP=FFFCBP=0000SI=0005DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0019NVUPEIPLNZNAPENC
0B40:
001998CBW
g19表示从当前IP(=0012H)所指指令处执行到CBW指令停下。
此时,累加和在AL中且值为0FH,与所设想的值15一致,说明没有发现程序错误。
注意:
没有发现错误并不能表示程序一定对。
下面把断点放在0021H处,执行命令如下:
-g21
AX=0003BX=0005CX=0000DX=0005SP=FFFCBP=0000SI=0005DI=0000
DS=0B3FES=0B2FSS=0B3FCS=0B40IP=0021NVUPEIPLNZNAPENC
0B40:
0021CBRETF
至此,平均数已经求出在AL中且送到了avg内存单元。
我们可用d命令显示如下:
-d0
0B3F:
00000102030405030000-0000000000000000................
0B3F:
00101E33C050B83F0B8E-D88D360000B90500.3.P.?
....6.....
0B3F:
0020B0008A1402C246E2-F998B305F6FBA205......F.........
0B3F:
003000CBE9B300893EE6-99C606E89900803E......>........>
0B3F:
0040A49801751DE857E3-751850A0C6960441...u..W.u.P....A
0B3F:
0050E82E01B03AE82901-58893EE699C606E8....:
.).X.>.....
0B3F:
00609900E87EE07406E8-1701ACEB78803EA4...~.t......x.>.
0B3F:
007098017503E896E03C-2E7509FE06E999C6..u....<.u......
这一轮的调试就结束了。
在调试过程中,如果要执行某一段程