| 分类: 大学实验报告 |
实验一 汇编程序的汇编及运行
1.实验目的
(1)熟悉汇编程序的汇编、连接、执行过程;
(2)生成LST文件,查看LST文件;
(3)生成OBJ文件,修改语法错误;
(4)生成EXE文件;
(5)执行程序。
2.实验涉及知识
汇编程序从编写到执行的过程
编程→.ASM→编译→.OBJ→连接→.EXE→加载→内存中的程序→执行
1)编写源程序
用EDIT或记事本输入各段,并存储成源程序(保存在MASM目录下),扩展名为ASM。
2)对源程序进行汇编、连接
操作如下:
(1)在DOS状态下,进入MASM目录;
(2)输入命令:MASM 文件名(连同扩展名);
(3)在系统出现的提示中输入:
object filename[.obj]:按回车键。
Source listling[nul.lst]:输入:文件主名,生成lst文件,也可以不生成,直接按回车键。Lst文件用于查看编译为目标文件的过程中产生的中间结果。
Cross-reference [nul.crf]:按回车键。
(4)如果系统没有提示出错,那么编译过程就完成了。如果提示错误则应用edit打开源文件进行修改,然后再重复2和3步骤
(5)输入:link 文件主名(不要输扩展名,也可以输入扩展名.obj)
run file [.exe]:按回车键。
List file [nul.map]:按回车键。
Libraries [.lib]:按回车键。
(6)没有提示错误,汇编过程就结束了,产生了exe可执行文件。如果出现‘no strack segment’的错误警告,不用理会。
3)执行程序(由DOS中的COMMAND命令将文件加载入内存)
在DOS提示符下直接输入文件主名就可以执行文件了。程序执行后,有的会显示结果,有的可能执行后什么结果都没有,是因为程序中没有显示命令。
3.实验内容
1)将下面的数据段输入,取名1.ASM,保存在MASM文件夹下。生成LST文件,(不必连接、运行)用EDIT查看1.LST文件。试回答:DA1,DA2的偏移量分别是多少?COUNT的值为多少?
DATA SEGMENT
ORG 20H
NUM1=8
NUM2=NUM1+10H
DA1 DB ‘IBM PC’
DB 0AH, 0DH
COUNT EQU $-DA1
DATA ENDS
END
2)输入下面错误的文件,修改错误语句。(MASM没有出现错误即可。不必连接、运行。)
DATA SEGMENT
VAR1 DB 0, 25, ODH, 300
VAR2 DB 12H, A4H, 6BH
VAR3 DB ’ABCDEF’
VAR4 DW 1234H, 5678H
VAR5 DW 10H DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DE: DATA
BEING MOV AX, DATA
MOV DS, AX
LEA SI, VAR5
MOV BX, OFFSET VAR2
MOV [SI], 0ABH
MOV AX, VAR1+2
MOV [BX], [SI]
MOV VAR5+4, VAR4
MOV AH, 4CH
INT 21H
CODE ENDS
END START
3)输入下面程序并运行
STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DATAS SEGMENT
STRING DB ‘WELCOME!’, 13, 10, ‘$’
DATAS ENDS
CODES SEGMENT
ASSUME CS: CODES, DS: DATAS
START: MOV AX, DATAS
MOV DS, AX
LEA DX, STRING
MOV AH, 9
INT 21H
MOV AH, 4CH
INT 21H
CODES ENDS
END START
4.实验结果
(1)
http://s6/middle/6ea6cd6a496512ac1ada5&690
所以DA1的偏移量为20,count的值为8。
分析过程:org伪指令用来设置当前地址计数器的值,EQU和=伪指令是不占存储空间的,所以DA1的偏移地址为20;$是表示当前地址计数器的值,又因为DA1存的是字节类型,所以COUNT EQU $-DA1指令就是求count的值为8。
(2)
http://s9/middle/6ea6cd6a496512af9b308&690
应用edit打开源文件进行修改
http://s2/middle/6ea6cd6a496512b05a0f1&690
因为O不在十六进制里面,所以应该把O DH改为0DH,因为VAR1是字节类型,所以数字最大范围为255,所以把300是错误的,改为30;第九行应该把DE改为DS.
http://s11/middle/6ea6cd6a496512b1d3a6a&690
MOV指令中,立即数传送给内存单元时要说明是送到一个内存单元还是两个内存单元,所以十四行应改为MOV BYTE PTR[SI],0ABH。而且MOV OPD,OPS中的OPD和OPS的位数必须一致,所以第十五行应改为MOV AL,VAR1+2.由于MOV指令的OPD和OPS不能同时是内存单元,所以需要把第十六行改为MOV BX,SI.需要在两个内存中传数据,得先把一个内存单元内容移到寄存器,所以第十七行改为MOV AX,VAR4 MOV VAR5+4,AX。
下面为修改后的结果:
http://s13/middle/6ea6cd6a496512b30016c&690
(3)
编译:
http://s13/middle/6ea6cd6a496512b622ddc&690
连接:
http://s13/middle/6ea6cd6a496512b7d408c&690
执行:
http://s7/middle/6ea6cd6a496512bb94c26&690
5.实验总结
通过本次实验,我熟练掌握了如何使用汇编环境,掌握了如何编译、如何连接、如何执行命令,还熟悉了点如何修改错误语句。
实验二DEBUG的使用
1.实验目的
(1)学习使用DEBUG的命令;
(2)使用DEBUG命令在数据段中查看程序运行的结果;
(3)利用DEBUG运行简单的程序段。
2.实验内容
1)输入程序观察寄存器变化
使用DEBUG命令,将下面的程序段写入内存,逐条执行,观察每条指令执行后,CPU中相关寄存器的内容变化。注意用T命令执行时,CS: IP寄存器的内容
MOV AX, 4E20
ADD AX, 1416
MOV BX, 2000
ADD AX, BX
MOV BX, AX
ADD AX, BX
MOV AX, 001A
MOV BX, 0026
ADD AL, BL
ADD AH, BL
ADD BH, AL
MOV AH, 0
ADD AL, BL
ADD AL, 9C
2)输入下面的程序,这是一个两个数相与的程序。结果存放在MSG2单元中,偏移地址为?值为多少?
DSEG SEGMENT
MSG1 DW 7856H, 2038H
MSG2 DW ?
DSEG ENDS
CSEG SEGMENT
ASSUME CS: CSEG, DS: DSEG
START: MOV AX, DSEG
MOV DS, AX
MOV AX, MSG1
AND AX, MSG1+2
MOV MSG2, AX
MOV AL, 0
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
程序的跟踪执行操作
在DOS下直接输入文件主名就可以执行文件了,有的程序会显示结果,可能执行后什么结果都没有,是因为程序中没有显示命令。那么如何查看程序的运行结果呢?
程序执行过程的跟踪操作步骤如下:
(1)在DOS下输入:DEBUG 文件名.EXE
(2)在DEBUG提示符下输入U命令
如果程序中有数据段,可以看到反汇编后第一句可执行语句为:
A地址:B地址 MOV AX, K地址 如:1261:0000 MOV AX, 1260
其中:K地址就是数据段的段寄存器内容,A地址为代码段段寄存器地址,B地址为程序第一条指令的偏移地址。
(3)可以用T命令单步执行指令,执行到 MOV AH, 4CH时结束,也可以用G命令执行整个程序,输入:G=B地址(如:G=0000)
(4)用D命令查看程序执行后数据段的变化
输入:D K地址:0 (如:D1260:0)
在显示的数据中,对照源程序或LST文件查看结果所在的偏移地址的内容。
3. 实验结果
1. http://s5/middle/6ea6cd6a496512bc6e564&690
http://s9/middle/6ea6cd6a496512bcf4718&690
http://s15/middle/6ea6cd6a496512be4315e&690
http://s7/middle/6ea6cd6a496512c068896&690
2)反汇编u:
http://s15/middle/6ea6cd6a0756e8468694e&690
用t单步执行:
http://s11/middle/6ea6cd6a496512cb0c0da&690
因为AND是逻辑与运算指令,对相与的两个数都为1的时候,值才为1.所以在单步执行AND AX,[0002]后,AX寄存器内的值变为2010.又MOV 【0004】,AX,所以MSG2的值为2010H。
用D命令查看程序执行:
http://s6/middle/6ea6cd6a496512cc88045&690
用edit查看:
http://s13/middle/6ea6cd6a0756e847c317c&690
由上图可知,MSG2的偏移地址为0004。
4.实验总结
通过这次实验,掌握了了使用debug的命令,还有怎么使用debug命令在数据段中查看程序运行的结果。我明白了,debug是一种很好的调试程序工具。
实验三 顺序程序设计
1、 实验目的:
(1) 熟练使用DEBUG命令。
(2) 学习使用简单的汇编指令编写程序。
(3) 了解循环语句的执行过程
2、 实验内容
1)下列程序单步运行,注意AL,BX,CX寄存器的变化,并观察数据段字母的变化。如果是将小写字母改成大写字母带注释的语句该如何修改?
DSEG SEGMENT
MSG1 DB ‘abc’
DSEG ENDS
CSEG SEGMENT
ASSUME CS: CSEG, DS: DSEG
START: MOV AX, DSEG
MOV DS, AX
LEA BX, MSG1
MOV CX, 3
S: MOV AL, [BX]
AND AL, 11011111B ;将AL中的ASCII码的第5位置0,
;变成大写字母。
MOV [BX], AL
INC BX
LOOP S
MOV AL, 0
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
2)编写调试下面的程序,用DEBUG查看数据段中的结果
http://s15/middle/6ea6cd6a496512ce78f1e&690,X,Y,W为字节类型变量,结果存于Z单元,写出数据段和代码段。
3)编写程序。X,Y为字节类型数,求http://s16/middle/6ea6cd6a0756e847ec9cf&690,写出完整的数据段和代码段,不用乘除指令。
3、 实验结果
1.反汇编
http://s8/middle/6ea6cd6a496512cfe2f77&690
单步执行:
http://s16/middle/6ea6cd6a496512d192fbf&690
http://s7/middle/6ea6cd6a0756e8483cc26&690
http://s1/middle/6ea6cd6a496512d372e90&690
http://s10/middle/6ea6cd6a496512d3d91f9&690
http://s14/middle/6ea6cd6a496512d525a6d&690
http://s7/middle/6ea6cd6a496512d59bd26&690
如果是将小写字母改成大写字母,只要把AND AL,11011111B改成OR AL,00100000B就可以。因为小写字母比大写字母的十六进制ASCII码大了20H,所以只要把把AL中的ASCII码的第六位置1即可。
3.
(1)
http://s11/middle/6ea6cd6a496512d74be4a&690
调试结果:
http://s16/middle/6ea6cd6a496512d831b3f&690
所以修改程序:
http://s8/middle/6ea6cd6a0756e84900097&690
调试结果:
http://s13/middle/6ea6cd6a496512db1554c&690
使用debug查看:
反汇编
http://s8/middle/6ea6cd6a496512db54087&690
单步执行:
http://s7/middle/6ea6cd6a496512dd05b36&690
http://s7/middle/6ea6cd6a0756e84961f36&690
http://s11/middle/6ea6cd6a496512dede27a&690
(2)
http://s13/middle/6ea6cd6a0756e849abd2c&690
调试结果:
http://s5/middle/6ea6cd6a496512e10e274&690
使用debug
反汇编
http://s1/middle/6ea6cd6a496512e2bc8e0&690
单步执行
http://s2/middle/6ea6cd6a496512e2e5311&690
http://s16/middle/6ea6cd6a496512e77ab0f&690
http://s6/middle/6ea6cd6a496512e838625&690
http://s6/middle/6ea6cd6a0756e84a7fc55&6904.实验总结
通过本次实验,我学会了使用简单的汇编指令编写程序。并掌握了循环语句的执行过程。
实验四 程序的调试及循环语句
1.实验目的
(1)学习调试程序,查找逻辑错误;
(2)学习分支语句的编程和调试;
(3)学习循环语句的编程和调试。
2.实验内容
1)有10个数,统计正数的个数,存放在变量M中中。经过汇编后,形成EXE文件。在DEBUG中,先用G=0命令执行程序,用D命令查看M单元的内容,会发现结果不正确。用单步执行命令T=0,单步执行程序,查找程序中的逻辑错误,注意每一次循环中AL寄存器中值的变化是否正确?(AL寄存器中存放正数的个数)
DSEG SEGMENT
MSG DB 4, -2, -6, 0, 5, 67, 8, -3, 5, 6
M DB ?
DSEG ENDS
CSEG SEGMENT
ASSUME CS: CSEG, DS: DSEG
START: MOV AX, DSEG
MOV DS, AX
MOV CX, 10
MOV AL, 0
LEA SI, MSG
L1: MOV BL, [SI]
CMP BL, 0
JBE NEXT
INC AL
NEXT: INC SI
LOOP L1
MOV M, AL
MOV AL, 0
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
2)数据段中是一组无符号数,将最小数存放在M单元中。按上题方法查找一处逻辑错误。
DSEG SEGMENT
MSG DB 13, 15, 7, 25, 24
M DB ?
DSEG ENDS
CSEG SEGMENT
ASSUME CS: CSEG, DS: DSEG
START: MOV AX, DSEG
MOV DS, AX
MOV CX, 4
MOV AL, MSG
MOV SI, OFFSET MSG+1
L1: CMP AL, [SI]
JB NEXT
MOV AL, [SI]
NEXT: LOOP L1
MOV M, AL
MOV AL, 0
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
3)编程:在首地址为BUF开始的内存单元中存有10个字节数,求其中0的个数,并将结果存于RESULT中。
4)编程:http://s10/middle/6ea6cd6a496512e991619&690,Ai,Bi为字节型无符号数,分别存于NUM1和NUM2开始的连续存储单元中,结果存于REST单元中。
3.实验结果
1)编译http://s10/middle/6ea6cd6a496512eb0c689&690
结果明显错误,单步执行:
http://s13/middle/6ea6cd6a496512ec395ec&690
http://s15/middle/6ea6cd6a0756e84ae9a9e&690
当4h和0比较,结果正确,使得SI和AX都自增加一,即AX=1,SI=1;
http://s10/middle/6ea6cd6a496512eee6989&690
http://s9/middle/6ea6cd6a496512ef4b758&690
从这边可以看出,-2h和0比较,结果AX和SI 也自增加一,这不是我们要结果,认真查看代码,原来是使用了JBE指令,JBE指令是无符号数比较状态转移指令。而我们需要的是统计正数的个数,所以,明显是要有符号数比较状态转移指令。因此把JBE指令改为JLE.
http://s13/middle/6ea6cd6a496512f0c51cc&690
http://s8/middle/6ea6cd6a0756e84b63ce7&690
http://s14/middle/6ea6cd6a496512f2caccd&690
从这边可以看出这正是我们要的结果,-2h和0比较,使得SI自增加一,而AL不加一。因为AL记录的是正数的个数。
所以直接执行,得到如下
http://s14/middle/6ea6cd6a0756e84b930dd&690
得到六个正数,所以得到修改后的代码是正确的。
2)编译:
http://s8/middle/6ea6cd6a496512f421557&690
得到最小值为13,明显不对,所以单步执行:
http://s14/middle/6ea6cd6a496512f5cfb1d&690
http://s7/middle/6ea6cd6a496512f5f7916&690
从这可以看出是SI没自增加一,导致无限循环。修改代码,在NEXT:后面添加INC SI.
http://s3/middle/6ea6cd6a496512f7716f2&690
http://s7/middle/6ea6cd6a496512f999166&690
http://s7/middle/6ea6cd6a496512fb4cf36&690
在此可以看到,SI=0002和AX=0b13的时候,比较得到SI小于AX,所以赋值给AX,等于07.
所以继续执行得到
http://s16/middle/6ea6cd6a0756e84c6831f&690
得到SI=4,AX=07,根据题目要求,证明了这个结果是正确的。
3)根据题目,(编程见附录),编译通过:
http://s15/middle/6ea6cd6a496512fd707be&690
http://s1/middle/6ea6cd6a0756e84cea160&690
检查1,0,3,-5,0,2,4,6,5,1这组数,可以得到只有两个数的值为0。所以所编的程序是正确的。
4)根据题目要求,编程代码见附录,运行编译如下:
http://s11/middle/6ea6cd6a496513026eaaa&690
http://s2/middle/6ea6cd6a496513041e6c1&690
验证答案,结果是为78h,为正确答案,所以程序正确。
4.实验总结
通过这次实验,我学习到了调试程序,及如何查找逻辑错误;学习分支语句的编程和调试;学习循环语句的编程和调试。
附录:
程序代码如下:
3)
;计算0的个数
STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DSeg Segment
buf db 1,0,3,-5,0,2,4,6,5,1
result db ?
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
mov al,0
lea si,buf
mov cx,10
again: cmp BYTE PTR[si],0
jne l3
inc al
l3: inc si
loop again
mov result,al
mov bl,al
mov bh,0
mov al,0
mov ah,4ch
int 21h
CSeg ends
end Start
4)
;Y=∑Ai*Bi ,i=1—8 , Ai, Bi为字节型无符号数,分别存于NUM1和NUM2开始的连续存储单元中,结果存于REST单元中。
DSeg Segment
num1 db 1h,2h,3h,4h,5h,6h,7h,8h
num2 db 8h,7h,6h,5h,4h,3h,2h,1h
rest dw ?
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
mov cx,8
mov bx,0
mov si,offset num1
mov di,offset num2
again: mov al,[si]
mul byte ptr[di]
add bx,ax
inc di
inc si
loop again
mov rest,bx
mov al,0
mov ah,4ch
int 21h
CSeg ends
end Start
实验五 DOS功能调用
1.实验目的
(1)学会DOS中关于显示功能调用指令的用法;
(2)领会修改显存方法显示字符。
2.实验内容
1)输入一个字符,显示出来。
2)输入一个字符串,显示出来。
3)BUF开始的3个16位二进制数用十六进制数的形式显示出来。
(1)理解程序
(2)输入程序,汇编,运行(在DOS状态下输入:文件名.EXE),观察结果。
(3)如果要分行显示,程序要如何修改?
BUF DW 4F59H, 56A8H, 0FF90H
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV SI, 0
P: MOV BX, BUF[SI]
MOV CH, 4
L: MOV CL, 4
ROL BX, CL
MOV DL, BL
AND DL, 0FH
CMP DL, 10
JB NEXT
ADD DL, 7
NEXT: ADD DL, 30H
MOV AH, 2
INT 21H
DEC CH
JNZ L
INC SI
INC SI
CMP SI, 4
JNA P
MOV AH, 4CH
INT 21H
CODE ENDS
END START
4)直接改变显存内容显示。
(1)显存空间分配:
内存地址空间中,B8000H-BFFFFH共32KB的空间,为80×25彩色字符模式显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。
80×25=2000个字符,每个字符在缓冲区中占2个字节,一个字节存放ASCII码,一个字节存放字符属性(字符颜色、字符背景颜色、闪烁、高亮度)
(2)偏移地址计算:
如第2行,第40列:(2-1)×160+40×2 这个偏移地址中存放字符的ASCII码,
(2-1)×160+40×2+1这个偏移地址中存放字符的属性。
第M行,第N列的一般计算公式为:
(M-1)×160+N*2 存放ASCII码
(M-1)×160+N*2+1 存放属性
(3)运行下列程序,在屏幕的第1行,会显示一个字符X。根据上面(1)、(2)点理解程序段。
STACK SEGMENT
DB 128 DUP (0)
STACK ENDS
CSEG SEGMENT
ASSUME CS: CSEG, SS: STACK
START: MOV AX, STACK
MOV SS, AX
MOV SP, 128
MOV AX, 0B800H
MOV ES, AX
MOV AH, ‘X’
S: MOV ES: [160*1+40*2], AH
MOV AL, 0
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
5)编程显示以下图案。
*********
*******
*****
***
*
6)编写程序,统计字缓冲区中的20个数据的正数、负数、0的个数,并将统计结果以16进制形式显示出来。
3.实验结果
1)
http://s8/middle/6ea6cd6a49651304460d7&690
2)程序代码见附录,编译如下:
http://s4/middle/6ea6cd6a49651304cb7a3&690
3)原程序运行结果
http://s14/middle/6ea6cd6a0756e84d64bdd&690
修改后的代码运行结果
http://s14/middle/6ea6cd6a49651306d1f6d&690
4)运行结果如下:
http://s9/middle/6ea6cd6a49651306be428&690
5)代码见附录,结果如下:
http://s11/middle/6ea6cd6a49651307588da&690
6)代码见附录,结果如下:
http://s2/middle/6ea6cd6a4965130bbf941&690
4.实验总结
通过这次实验,我知道写程序需要注意的一些细节。字符串的输入时,第一个字节是由系统自动生成的,所以要输出用户的字符串,要在用mov dx,offset buf+2。计数时用cx和bx,不能用ch和bh。还有jmp的功能,无条件转移。
附录
STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
CSeg Segment para public 'CODE'
Assume cs:CSeg
Start:
mov AH,1
INT 21H
mov al,0
mov ah,4ch
int 21h
CSeg ends
end Start
2)STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DSeg Segment
buf db 20
db ?
db 20 dup(?)
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
mov ah,10
mov dx,offset buf
int 21h
lea dx,mesg ;回车换行
mov ah,09h
int 21h
mov dx,offset buf+2
int 21h
mov al,0
mov ah,4ch
int 21h
CSeg ends
end Start
3)修改后的代码
DATA SEGMENT
mesg db 0db,0ah,’$’
BUF DW 4F59H, 56A8H, 0FF90H
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV SI, 0
P: MOV BX, BUF[SI]
MOV CH, 4
L: MOV CL, 4
ROL BX, CL
MOV DL, BL
AND DL, 0FH
CMP DL, 10
JB NEXT
ADD DL, 7
NEXT: ADD DL, 30H
MOV AH, 2
INT 21H
DEC CH
JNZ L
INC SI
INC SI
CMP SI, 4
lea dx,mesg ;回车换行
mov ah,09h
int 21h
JNA P
MOV AH, 4CH
INT 21H
CODE ENDS
END START
5)STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DSeg Segment
mesg db 0dh,0ah,'$'
buf db 10 dup(?)
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
mov si,1
mov bx,9
contiue:mov cx,bx
next: mov dl,'*'
mov ah,2
int 21h ;显示
loop next
lea dx,mesg ;回车换行
mov ah,09h
int 21h
dec bx
dec bx
inc si
cmp si,5
jbe contiue
mov al,0
mov ah,4ch
int 21h
CSeg ends
end Start
6);有数据段
STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DSeg Segment
buf db 0h,-1h,5h,1h,0h,-10h,-2h
numb equ $-buf
cout1 dw ? ;0的个数
cout2 dw ? ;正数的个数
cout3 dw ? ;负数的个数
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
lea si,buf
mov cx,0
lp: mov al,[si]
cmp al,0
jnl next
inc cout3
jmp last
next:je contiue
inc cout2
jmp last
contiue:inc cout1
last: inc si
inc cx
cmp cx,numb
jl lp
mov bx,cout1
call DISP
mov bx,cout2
call DISP
mov bx,cout3
call DISP
mov al,0
mov ah,4ch
int 21h
DISP PROC ;显示BX中的数
mov ch,4
roll: mov cl,4
rol bx,cl
mov dl,bl
and dl,0fh
cmp dl,9
jbe next1
add dl,07h
next1: add dl,30h
mov ah,02h
int 21h
dec ch
jnz roll
RET
DISP ENDP
CSeg ends
end Start
实验六 子程序设计
1.实验目的
(1)学习子程序的编写,主子程序的调用;
(2)不同模块间程序的调用和调试。
2.实验内容
1)数据段中的3个字符,调用子程序将其逐个显示出来。子程序的功能是显示一个字符。单步执行,对CALL语句和RET语句观察SP,IP的变化,并用D命令查看栈顶的内容。
DATA SEGMENT
MAG DB ‘ABC’
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV SI, 0
MOV CX, 3
LL: MOV DL, MAG[SI]
CALL MADD
INC SI
LOOP LL
MOV AH, 4CH
INT 21H
MADD PROC
MOV AH, 02H
INT 21H
RET
MADD ENDP
CODE ENDS
END START
2)阅读S31.ASM和S32.ASM两个模块中的程序,并分别汇编,然后连接成一个可执行文件S31.EXE。
具体步骤如下:
MASM S31.ASM(分别汇编)
MASM S32.ASM
LINK S31 S32 (将两个文件连接成为一个文件名为S31)
S31.EXE (运行)
3)编程:利用主程序调用子程序,比较BUF1和BUF2缓冲区中不相等的字符,并将不相等的字符显示出来。(也可以将找到的不相等字符逐个显示,用INT 21H的02功能调用)
4)编程:子程序搜索指定字符缓冲区中是否有N,如果有用Y替代。调用子程序将BUF1,BUF2,BUF3中的N全部用Y替代。
3.实验结果
1.
http://s4/middle/6ea6cd6a0756e84df5a03&690
2.编辑s31和s32文件,输入程序,保存。打开命令提示符运行:
http://s3/middle/6ea6cd6a4965130c8b452&690
编译s32文件:http://s2/middle/6ea6cd6a4965130d10571&690
http://s15/middle/6ea6cd6a4965130ddef0e&690
链接s31和s32文件:http://s12/middle/6ea6cd6a4965131178fbb&690
无错误输出,运行程序:http://s1/middle/6ea6cd6a49651319190e0&690
3.代码见附录,结果如下:
http://s13/middle/6ea6cd6a0756e84f63b1c&690
4.代码见附录,结果如下
http://s10/middle/6ea6cd6a4965131ad93d9&690
4.实验总结
通过这次实验,我知道了写代码要细心,有的错误是隐藏的,编译是检查不出的错误。指令的参数的使用。
附录:
2. NAME S31.ASM
不同模块间的段间调用。从键盘输入2位非压缩BCD数,存入AX寄存器中。为了将其转换为二进制数,编写一个子程序TRAN。显示子程序DISP完成将16进制数转换为对应的ASCII码并显示该字符,显示子程序在另一模块S32中。输入数据为00时结束。
EXTRN DISP: FAR
CODE SEGMENT PARA ‘CODE’
ASSUME CS: CODE
START: MOV AH, 01H
INT 21H
MOV BL, AL
INT 21H
MOV AH, AL
MOV AL, BL
CMP AX, 3030H
JE EXIT
CALL NEAR PTR TRAN
CALL FAR PTR disp
JMP START
EXIT: MOV AH, 4CH
INT 21H
TRAN PROC NEAR ;将输入的ASCII码转换成2进制数
AND AX, 0F0FH ;将ASCII码转换成非压缩BCD码,
;高位在AL中
MOV BL, AH
MOV CL, 10D
MUL CL
ADD AL, BL
RET
TRAN ENDP
CODE ENDS
END START
NAME S32.ASM
PUBLIC DISP
CODE1 SEGMENT PARA ‘CODE’
ASSUME CS: CODE1
DISP PROC FAR
MOV BL, AL
MOV BH, 00
MOV CH, 4
ROLL: MOV CL, 4
ROL BX, CL
MOV DL, BL
AND DL, 0FH
CMP DL, 9
JBE NEXT1
ADD DL, 07H
NEXT1: ADD DL, 30H
MOV AH, 02H
INT 21H
DEC CH
JNZ ROLL
RET
DISP ENDP
CODE1 ENDS
END
3.
data segment
buf1 db " aabbccvvxx$"
buf2 db " aabccvvvxz$"
buf3 db 20 dup(?)
data ends
code segment
assume cs:code,ds:data
start:mov ax,data
mov ds,ax
mov si,0
mov di,0
call bijiao
lea dx,buf3
mov ah,09h
int 21h
mov ax,4c00h
int 21h
bijiao proc
mov al,[si]
cmp al,'$'
je exit
mov ah,buf2[si]
cmp al,ah
je next
mov buf3[di],al
mov buf3[di+1],ah
add di,2
next:inc si
jmp bijiao
exit:mov buf3[di],al
ret
bijiao endp
code ends
end start
4.
;有数据段
STACKS SEGMENT STACK
DW 128 DUP(?)
STACKS ENDS
DSeg Segment
mesg db 0dh,0ah,'$'
buf1 db "YYNYYN$"
numb1 equ $-buf1
buf2 db "NNNNYY$"
numb2 equ $-buf2
buf3 db "YYYNNN$"
numb3 equ $-buf3
buf db 20 dup(?)
DSeg ends
CSeg Segment para public 'CODE'
Assume cs:CSeg,ds:DSeg
Start: mov ax,DSeg
mov ds,ax
lea si,buf1
mov cx,numb1
call modify
call disp
lea si,buf2
mov cx,numb2
call modify
call disp
lea si,buf2
mov cx,numb2
call modify
call disp
mov ah,4ch
int 21h
modify proc
lp: cmp byte ptr[si],'N'
jne contiue
mov al,'Y'
mov buf[si],al
inc si
jmp lp
contiue: mov ah,[si]
mov buf[si],ah
inc si
loop lp
mov ah,9
lea dx,buf
int 21h
ret
modify endp
disp proc
lea dx,mesg ;回车换行
mov ah,09h
int 21h
ret
disp endp
CSeg ends
end Start
实验七 字符处理程序设计
1.实验目的
(1)熟悉串操作指令的功能与应用;
(2)掌握串操作指令的寻址方式及使用方法,编写常用的字符串处理程序。
2.实验内容
从键盘键入一个字符串,存入内存BUF为首地址的单元中,现要求统计其中含有小写字母的个数,并将统计结果以两位十进制数形式显示在屏幕上。
3.调试过程
http://s6/middle/6ea6cd6a4965131bb8805&690
因为程序中有三处单词写错了,修正后,就ok了.但是虽然没有编译时没出现错误,运行时出现了下面的错误.
http://s5/middle/6ea6cd6a4965131c53934&690
仔细分析,原来dos系统功能调用的程序落下了很重要的一句话:mov ah,2
4.实验结果
http://s1/middle/6ea6cd6a0756e84fbf610&690
5.实验总结
通过这次实验,我知道作为一个程序员来说,细心是必须的,否则一个小错误,就会让你焦头烂额。
附参考源程序:
DATA SEGMENT
BUF DB 90 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV CX, 0
LEA DI, BUF
AGAIN: MOV AH, 1
INT 21H
CMP AL, 0DH
JZ DONE
MOV [DI], AL
INC DI
INC CX
JMP AGAIN
DONE: MOV DL, 0DH
MOV AH, 2
INT 21H
MOV DL, 0AH
MOV AH,2
INT 21H
LEA SI, BUF
MOV CH, 0
MOV BL, 0
CLD
NEXT1: LODSB
CMP AL, 61H
JB NEXT2
CMP AL, 7AH
JA NEXT1
INC BL
NEXT2: LOOP NEXT1
MOV AL, BL
MOV AH, 0
MOV CL, 10
DIV CL
XCHG AH, AL
PUSH AX
MOV DL, AH
OR DL, 30H
MOV AH, 2
INT 21H
POP AX
MOV DL, AL
OR DL, 30H
MOV AH,2
INT 21H
MOV AH, 4CH
INT 21H
CODE E NDS
END START

加载中…