首页 汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用

汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用

举报
开通vip

汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用 福建农林大学东方学院 信息工程类 实验报告 课程名称: 汇编语言 姓 名: 廖少兵 系: 计算机系 专 业: 电子信息工程 2010 年 级: 1050302103 学 号: 指导教师: 职 称: 2012年 6 月 17 日 福建农林大学东方学院信息工程类实验报告 系: 计算机系 专业: 电子信息工程 年级: 10 姓名: 廖少兵 学号: 1050302103 实验课程: 汇编语言 实验室号:__...

汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用
汇编实验报告:汇编程序的汇编及运行_顺序程序 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 _分支循环程序设计_子程序设计_dos功能调用 福建农林大学东方学院 信息工程类 实验报告 课程名称: 汇编语言 姓 名: 廖少兵 系: 计算机系 专 业: 电子信息工程 2010 年 级: 1050302103 学 号: 指导教师: 职 称: 2012年 6 月 17 日 福建农林大学东方学院信息工程类实验报告 系: 计算机系 专业: 电子信息工程 年级: 10 姓名: 廖少兵 学号: 1050302103 实验课程: 汇编语言 实验室号:_______ 实验设备号: 实验时间: 指导教师签字: 成绩: 实验一 汇编程序的汇编及运行 1(实验目的和要求 1、 熟悉汇编程序的汇编、连接、执行过程 2、 生成LST文件,查看LST文件 3、 生成OBJ文件,修改语法错误 4、 生成EXE文件 5、 执行 2(实验的原理和主要仪器设备 IBM—PC机及其兼容机 实验的软件环境是: 操作系统:DOS 2.0以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、WPS.EXE;宏汇编程序:MASM.EXE(或ASM .EXE);连接装配程序:LINK .EXE;交叉引用程序:CREF.EXE(可有可无)。 3(实验内容及实验数据记录 1、将数据段输入,取名1.txt,保存在MASM文件夹下。生成LST文件,(不必连接、运行)用EDIT查看1.LST文件。试回答:DA1,DA2的偏移量分别是多少,COUNT的值为多少, DATA SEGMENT ORG 20H NUM1=8 NUM2=NUM1+10H DA1 DB ‘IBM PC’ DA2 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(操作方法及实验步骤 编写各代码并存储为源程序asm文件,对其进行汇编、连接。 1、Dos进入masm目录 2、masm 文件名(对文件进行编译) 3、link 文件名(对生成OBJ目标文件进行连接) 4、由dos加载连接后生成的可执行文件来执行程序 5(实验数据处理和 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 (1) (2)如图输入代码编译未能通过,提示出错有9处 其中2、3、9行均为符号未定义错误,其中修改ODH中O在十六进制中未定义(不 存在)、而A4H以字母开头必须添上数字0)、寄存器中没有DE故而修改之。 第十行我们暂且放着,第十四行提示说操作数必须指定大小空间由代码可知,立即数ABH传给内存单元时,必须指定内存大小空间,所以可修改该句为MOV BYTE PTR 0ABH。而15行的错误提示与17行一样均不能找到段寄存器所分配的地址,15行从代码格式上看除了位数不一致外并不是如是的所提错误,而17行是错在两个立即数作为MOV指令的操作数,我们先跳过。下面16行的错误是非法错误的操作数格式,这里两个操作数均是内存单元里的数据,可修改【BX】为BX。由21行错误可知START未定义,之前程序入口中出现了标识符BEING,因此这里改为BEING。同时可知刚刚第十行错误就显而易见了,标识的格式错 了。应该为BEING:。 部分修改后代码如下: 重新编译得如下错误提示第2行中300超出了所分配的看空间字节大小, 这里把它改为30,比较之前的出错提示17行和15行的均改变了,这才具体指出了出错原因。这里15行我们就修改AX为AL,匹配两操作数位数。17行中我们为不改变原意可以用如下指令替代:MOV CX,VAR4; MOV VAR5+4,CX; (3)编辑源程序后编译未能通过,提示如图: 我们打开源程序看到如图所示: 我们之前定义的是DATAS而不是DATAX,修改之。编译通过,我们link进行连接如图: 已生成可执行文件3.exe。 6. 实验结果 (1)编辑源程序后编译生成list文件提示时输入文件名得到1.list文件。 打开如图得知:DA1、DA2的偏移量分别是0020H和0026H。 (2)通过以上调试分析,最终修正代码,如图已能通过编译。 (3)运行3.exe文件,结果如图: 7. 总结,质疑,建议,问 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 讨论 通过此次上机实验进行从编辑源程序到最终的可执行文件的生成并运行。加深了我对程序编译连接运行程序的整个过程的理解,而其中的编译过程让我看到了一个不显眼list文件对之后查错,核实各个指令运行的正确性应该说是程序员的理解与系统处理是否存在出入的重要性,其次让我更加懂得去读懂出错提示,根据提示定位代码的错误之处并修正,再者从实验中发现了重要的一点,要让编译器给出正确或说是更确切的指示,我们应该先保证自己编写的代码语法上的严谨与 规范 编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载 ,如17行与15行的错误提示由于程序入口标识符的错误定义而受影响的情况。 实验二 顺序程序设计 1(实验目的和要求 (1) 学习使用DEBUG的命令; (2) 使用DEBUG命令在数据段中查看程序运行的结果; (3) 利用DEBUG运行简单的程序段。 2(实验用的软硬件环境 实验的硬件环境是: IBM—PC机及其兼容机 实验的软件环境是: 操作系统:DOS 2.0以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、WPS.EXE;宏汇编程序:MASM.EXE(或ASM .EXE);连接装配程序:LINK .EXE;交叉引用程序:CREF.EXE(可有可无)。 3(实验内容及实验数据记录 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)下列程序单步运行,注意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 3)程序的跟踪执行操作 在DOS下直接输入文件主名就可以执行文件了,有的程序会显示结果,可能执行后什么结果都没有,是因为程序中没有显示命令。那么如何查看程序的运 行结果呢, 程序执行过程的跟踪操作步骤如下: (1)在DOS下输入:DEBUG 文件名.EXE (2)在DEBUG提示符下输入U命令 (3)可以用T命令单步执行指令,执行到 MOV AH, 4CH时结束,也可以用 G命令执行整个程序,输入:G=B地址(如:G=0000) (4)用D命令查看程序执行后数据段的变化 输入:D K地址:0 (如:D1260:0) 在显示的数据中,对照源程序或LST文件查看结果所在的偏移地址的内容。 4)输入下面程序,按实验一和上面步骤运行一遍 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 5)编写调试下面的程序,用DEBUG查看数据段中的结果 Z,((W,X)*10,5)/(X,Y)(1),X,Y,W为字节类型变量,结果存于Z 单元,写出数据段和代码段。(无符号数) Z,((X,Y)*8,(X,Y)*2)/16(2)X,Y为字节类型数,求,写出完整的数据段和代码段,不用乘除指令。(无符号数) 4(操作方法及实验步骤 1) (1)、dos进入debug环境,输入a进行程序段写入内存操作,如图: (2)、输入t单步运行跟踪观察到各寄存器的变化如图: (3)、在执行第一条指令MOV AX, 4E20后寄存器AX内容随即变为4E20,而当执行第二条指令ADD AX, 1416后AX变为了6236,运行随后的指令各寄存器 的变化完全吻合程序段所实现的功能,并且不难看到IP由0103不断的增加,而CS保留为13A1不变。 2) (1)、由文本编辑内容2中的程序段存为II2.txt文件,并masm编译link连接通过,如图: 3)& 4) (1)、文本编辑内容4中代码段保存为II4.txt,masm编译link连接通过: (2)、d命令查看MSG2单元中存放的值,如图(执行AND AX,MSG1+2后,未执行MOV MSG2,AX指令): 5) (5-1)编写程序段如下: (1)、分析题目可知数据段中有X、Y、W、Z和常数10、5,所以有: DATA DB 5,10 X DB 2 Y DB 8 Z DW ? W DB 10 (2)、代码段中先执行(W-X)*10有: MOV AL,W SUB AL,X CBW;之前误解为乘指令操作数需16位故而出现此错误。 MUL DATA+1 之后加5结果除于X+Y有: ADD AX,DB ;DATA错输入为DB MOV CL,X ADD CL,Y DIV CL (3)、所以有最初代码如下(错误) DSEG SEGMENT DATA DB 5,10 X DB 2 Y DB 8 Z DW ? W DB 10 DSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG START: MOV AX,DSEG MOV DS,AX MOV AL,W SUB AL,X CBW MUL DATA+1 ADD AX,DB MOV CL,X ADD CL,Y DIV CL CSEG ENDS END START (5-2)编写程序段如下 (1)、分析题目可知数据段中有X、Y、Z和常数8、2、16,所以有: DATA DB 8,2,16 X DB 5 Y DB 3 Z DW ? (2)、代码段先实现(X+X)*8有如下: MOV AL,X ADD AL,AL ;实现X+X MOV CL,3 SHL AL,CL ;逻辑左移3位实现乘8 实现(X-Y)*2有: MOV BL,X SUB BL,Y ;实现X-Y MOV CL,1 SHL BL,CL ;逻辑左移1位实现乘2 实现分子部分(X+X)*8-(X-Y)*2:SUB AL,BL 实现除于16并把结果送Z: MOV CL,4 SHR AL,CL ;逻辑右移4位实现除于16 MOV Z,AL (3)、程序段通过编译并并成功链接,如图: 5(实验数据处理与分析 (1)、直接运行II2.exe文件可以看到dos窗口未显示任何信息,于是debug II2.exe文件跟踪执行,如图: (2)、t命令单步运行观察到IP在不断得递增指向下一条指令: 执行第一和第二次时CX递减,可以看到CX=0002,CX=0001,'a'变为了大写'A,'b'变为了大写'B': 同理之后可以看到CX=0000时执行循环结束完成字符串大小写转换。 5-1) (1)、编译未能通过如图: (2)、修改未定义标识符DB为DATA,编译仍然出错: (3)、操作数位数不一致,分析可知在执行(W-X)*10后结果存放在AX中 为能满足除法指令要求被除数为字节时,默认隐含除数为(AX),于是修改代 码段如下: START: MOV AX,DSEG MOV DS,AX MOV AL,W SUB AL,X MUL DATA+1 MOV BX,AX ;注1 MOV AL,DATA ;注2 CBW ;注3 ADD AX,BX ;实际上注释的指令完全可以用ADD AL,DATA代替,之前是 在多此一举,自己在给自己添麻烦。 MOV CL,X ADD CL,Y DIV CL CSEG ENDS END START (4)、最终编译连接成功如下: (1)、 debug II5b.exe 跟踪程序,u反汇编可以看到数据段段地址为076A;再从lise文件中查看得Z得偏移量为0002,如图: (2)、因此执行完程序段后可以看到AX=0704为即是AL=04,结果正确; 6. 实验结果 1)对比之前我们程序段录入时前段显示的正是13A1且“:”之后的数字和IP的变化一致,可知cpu在执行指令时是通过CS代码寄存器定位代码段所处内存单元和改变IP指令寄存器中的地址(偏移量)来具体指定所要执行的指令。 2)& 3)程序段实现了转输入字符串转小写为大写的功能: 通过d命令跟踪到数据段的变化对比程序段可知通过该指令 AND AL, 11011111B可知在原字符的ASCII码中的第五位逻辑与上‘0’其他为不变,其 5值相当于减小了2=32实现了小写到大写的转换,同理若要将大写转换为小写只 5需将该句改写成OR AL,00100000(加上2=32)即可。 4)查看list文件不难得知MSG2偏移地址为0004,如图: 执行MOV MSG2,AX指令后d查看1415:0004即是MSG2单元内容为2010: 5-1)DEBUG查看到AX结果为0508即商为8余数为5如图: 由list可查看到z的偏移量为0004: D076A:0004命令查看到如图Z中为空,遗忘了将AX数据传送给了Z; 代码段中补充指令MOV Z,AX 执行d076A:0004最终得到Z中结果0805即是商8余5,如图: 5-2)由之前操作后可执行d076A:0002即可查看Z单元数据为04即是所求商如图: 7. 质疑,建议,问题讨论,总结 实验中我掌握了编写简单的程序,并且高效得运用debug进行调试,有效地跟踪指令观察各指令所实现得功能,并熟练运用其查看数据段的内容。在编写并调试程序得环节中,由于对指令得不熟悉导致了一些不必要得麻烦,如第五题1中得设计,由于对部分隐含寄存器操作的不确定使得在符号扩展方面上出现 问题最后竟绕了个圈。程序最终虽能通过编译并连接运行得到正确得结果,但总认为缺少些什么 ,如在对DS装入时AX的改变有可能对后面得指令造成影响,因而就必须对其装入后其他指令使用其前进行清零操作XOR AX,AX。而至于DOS的功能调用方面由于在这里对程序影响不大,同时略去 MOV AH,4CH ; INT 21H;的一个好处就是让我更好了解到t跟踪运行多条指令的好处并能很好得运用它,使我更深刻理解了调试程序对整个程序设计得重要。总而言之该次实验让我看到了自己很多不足并学到了很多,很好得巩固升华了理论知识。 实验三 分支循环程序设计 1(实验目的和要求 1、学习调试程序,查找逻辑错误; 2、学习分支语句的编程和调试; 3、学习循环语句的编程和调试。 2(实验用的软硬件环境 实验的硬件环境是: IBM—PC机及其兼容机 实验的软件环境是: 操作系统:DOS 2.0以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、WPS.EXE;宏汇编程序:MASM.EXE(或ASM .EXE);连接装配程序:LINK .EXE;交叉引用程序:CREF.EXE(可有可无)。 3(实验内容及实验数据记录 6、 有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 数据段中是一组无符号数,将最小数存放在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 7、 编程:在首地址为BUF开始的内存单元中存有10个字节数,求 其中0的个数,并将结果存于RESULT中。 iiY,A,B,i,1,88、 编程:,Ai,Bi为字节型无符号数,分别存于 NUM1和NUM2开始的连续存储单元中,结果存于REST单元中。 4(操作方法及实验步骤 1)编辑代码,编译连接均可通过,亦能正常运行。 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 查看list文件得知M单元偏移量为000A,如图: g命令运行后,d命令查看(d1415:000A)得知M中值为09即是正数有9个,显然 是不正确的如图 2)同一编辑如下代码进行编译连接运行均正常; 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 由指令MSG DB 13, 15, 7, 25, 24 M DB ? 可计算0005为M的的偏移量。 如图,g命令运行后,d命令查看(d1415:0005)知M中值为0DH=13即最小的数是13,显然不正确。 3) 3.1据题意有如下要求 a定义:首地址BUF,结果RESULT b数据:10个字节数 c实现:查找0的个数 3.2分析满足要求 : 满足a&b有 BUF DB 4, -2, -6, 0, 5, 0, 8, -3, 5, 0 RESULT DB ? 实现c: MOV CX,10 ;控制循环次数 MOV AL,0 ;AL用于存放临时个数,清零 CMMP: CMP [SI],0 ;比较[SI]所指与0 JNE NEXT ;[SI]所指不等0跳入NEXT标号所指指令 INC AL ;[SI]所指等于0,AL加1 NEXT: INC SI ;指针下一指向下一个即将比较的数 LOOP CMMP ;循环比较直至CX=0; 3.4最初程序代码 DATA SEGMENT ;数据段DATA开始 BUF DB 4,-2,-6,0,5,0,8,-3,5,0;分配字节空间首地址BUF RESULT DB ? ;存放结果 DATA ENDS ;数据段DATA结束 CODE SEGMENT ;代码段CODE开始 ASSUME DS:DATA,CS:CODE ;DATA,CODE对应挂钩DS,CS START: MOV AX,DATA ;程序入口 MOV DS,AX ;数据段装入 MOV CX,10 ;初始循环次数 MOV AL,0 ;AL用于存放0的个数,初始为0 CMMP: CMP [SI],0 ;当前指针指向的数据与0比较 JNE NEXT ;所指数据不等于0跳至NEXT标号处指令 INC AL ;相等则AL加1 NEXT: INC SI ;NEXT入口,指针加1下移指向下一个数 LOOP CMMP ;进入循环CMMP,继续比较当前数 MOV RESULT,AL ;将结果传送至RESULT中 MOV AL,0 ;AL清零 MOV AH,4CH INT 21H ;调用dos返回dos界面功能 CODE ENDS ;代码段CODE开始 END START ;程序结束 4) 4.1据题意有如下要求 a 存在两组数据每组8个,均为无符号字节数 b 每组数据分别以NUM1、NUM2为首地址,结果存放在REST中 c 实现两组数据两两相乘后共8组数据,最终求总和 4.2分析处理满足要求 满足a&b: NUM1 DB 1,2,3,4,5,6,7,8 NUM2 DB 8,7,6,5,4,3,2,1 REST DW ?(由于结果可能很大故而开辟word空间) 实现c: 首先是进行两两相乘,可以分别用一指针SI,DI同时自上而下取数进行相乘并将结果临时存放于AX,其次将下一次(当前)结果与AX中上一次结果相加,通过循环便可达到实现要求c中的功能,由于第一次结果的存放不再循环之内,可以将其单独列出,这样难免显得程序冗长,拖沓。因此可以优化其,将AX先初始化为0,把第一次相乘也列入循环中。问题便可以很好得到解决。这里有一个问题就是简单的通过SI和DI来进行相乘时忽略了一个问题就是两个操作数不能同时为内存单元的数,因此必须借助于寄存器临时存储其中一个数。而AL在每一次乘法操作时均被作为隐含操作数而用到因而可直接由AL来存放其中一个数,而存放和的AX这里应由其他寄存器暂代之如BX。所以优化上图后如下: 4.3根据以上设想设计流程图:(loop的错误理解导致了这里循环的控制上有 DI 问题,其中的注(1)应该放在注(2)之后loop之前) 4.4最初程序代码(错误) DATA SEGMENT ;数据段DATA开始 NUM1 DB 1,2,3,4,5,6,7,8;第一组数分配字节空间首地址NUM1 NUM2 DB 8,7,6,5,4,3,2,1;第二组数分配字节空间首地址NUM2 REST DW ? ;存放结果 DATA ENDS ;数据段DATA结束 CODE SEGMENT ;代码段CODE开始 ASSUME DS:DATA,CS:CODE ;DATA,CODE对应挂钩DS,CS START: MOV AX,DATA ;程序入口 MOV DS,AX ;数据段装入 MOV AX,0 ;AX清零 MOV BX,0 ;BX清零 LEA SI,NUM1 ;将NUM1首地址传送给SI LEA DI,NUM2 ;将NUM2首地址传送给DI NEXT: ADD BX,AX ;BX<—AX+BX MOV AL,[SI] ;将[SI]所指单元数据传送给AL MUL [DI] ;[DI]所指单元数据与AL相乘结果存放在AX INC SI ;指针SI下移,指向NUM1下一个数 INC DI ;指针DI下移,指向NUM2下一个数 LOOP NEXT ;循环跳至NEXT标号处直至CX自减至0 MOV AH,4CH INT 21H ;调用dos返回dos界面功能 CODE ENDS ;代码段CODE开始 END START ;程序结束 5(调试过程 1) 1.1单步调试程序跟踪找到程序的错误。 如图:第一次调入[si]=04到BL并进行BL与0比较指令由当前的1416:0013执行后执行0015指令并没有立即跳至0017指令INC Al可知第一次比较得与正确处理执行正数个数加一,指针下移操作 1.2进入循环继续跟踪 调入BL第二个数[si]=-2=FEH,再一次比较0此时符合条件JBE中的below即小于应该跳过0015指令执行0017指令INC SI,可从跟踪结果看到0015指令INC Al依然被执行了,结果当然是正数个数AL=2多加了1不符合实际,如图: 由此已经找到了出错位置即在此无需继续跟踪。 1.3分析并修改错误 我们知道-2显然符合“小于(below)或者等于(equal)零”的条件,为什么程序却判断-2比零大呢,可知因该句条件并没错语法上也正确,现在唯一的问题给 忽略了就是符号了,我们知道数据的存储方式是补码形式,-2的补码为FE而程序条件是BE是对无符号数的操作FE自然是大于0了,由此我们改该指令为有符号操作即JLE NEXT或者JNG NEXT,重新编译连接并运行程序最终得正确结果6 。 2) 2.1单步调试找到错误 t单步跟踪得到如图在执行调入第一个数到AL后并比较[SI]如图[SI]是01即指向数15,由代码可知此时符合JMP条件B(below)跳转至0014指令(段内) LOOP L1即进入循环进行下一次比较CMP AL [SI],这里可以看到[SI]依旧是01仍指向15,并没有下移,由此可知程序出错在于[SI]未能下移指向下一个即将要比较的数。从代码上看也容易得知程序至终都未曾移动[SI]指向。 2.2分析并改错 结合程序代码和题目要求,为了找到最小的数并把他存放在M中,程序基本完成了比较部分和存放功能,唯一的错误是在[SI]的移动未实现,可知在进入循环L1,CMP比较之前因该找到下一个比较的数,而无论比较结果如何下移[SI]操作均需要执行到,因此在NEXT: 里LOOP L1之前添加INC [SI]实现指针自加功能。具体如下: „„ NEXT: INC SI LOOP L1 „„ 3) 3.1编译以上代码出错提示未能通过,出错如下: 提示11行中操作数未指定大小,查看代码知[SI]为内存单元数据,必须指定大 小是byte还是word。 3.2修改其为:CMP BYTE PTR [SI],0重新编译, 如图已能顺利通过编译并连接。 3.3进入debug环境 u命令反汇编得知数据段地址076A,RESULT偏移量000A如图 4) 4.1编译最初代码未能通过提示如下图: 4.2分析并改错 第10行超出内存范围,查看代码为: 可知指令并没错,错误在于注释中的“;”应该为“;”后面的随之修改后,重 新编译,依然存在错误如图提示未指定操作数大小: 我们知道在数据传送指令中有目的操作数若是内存单元数据和源操作数是立即数时必须指定大小,而若有一是寄存器数据是可无需指定。疏忽了在单操作数的乘除指令也同样必须指定大小使之位数一致。为什么出现这样情况可想而知因为乘除指令的隐含操作数所在寄存器可能是AL或AX,其选择决定于源操作数的位数。因此修改原指令为“MUL BYTE PTR [DI] ”。继续重新编译 终于顺利通过编译并连接如图: 4.3debug调试检查结果 g运行程序,要进行d查看时才发现忘了将结果传送给REST,在原代码LOOP指令后添加指令:MOV REST BX,重新回到编译阶段,继续编译,还好正常通过了。 完成以上操作后,u反汇编得到数据段首地址076A和REST偏移量0010后,d076a:0010查看REST中内容为6A8C=(6A为高地址所在)如图:通过计算器计算得120对比之得知结果不正确。 4.4再次分析并改错 结合流程图仔细浏览推敲程序,基本上并没问题,最终结果如此大,一个可能便是加上了不必要即定义段之外的数据,首先想到的是所用寄存器的初始化问题,检查之均无误(还是漏了检查CX);其次是一个严重的问题,可能是循环超出了范围(在初始化了CX后,由循环控制理解错误导致),核实代码果真是这样,在第一次执行到NEXT指令时不是由LOOP跳转过来的而此时SI和DI均已经指向了各自数据段首,在执行第一次LOOP时SI,DI执行了加1操作,CX这才减1,而CX减至1时,SI和DI均已指向了最后一个数,最后结果便是加上了[0008]*[0011]的值。T单步跟踪验证如下: 看来还是没仔细的检查,CX=45竟忘了初始化为8了。流程图有了,可代码 中却遗漏了。所以之前的猜想可能是错的,先修改之( 在MOV AX,0之前添上指令MOV CX,8 )。重新编译连接运行,查看一下结果是70相比正确结果少了8。 T命令跟踪之: 如上图,第一组乘积8正确加到BX;可以推断是最后一组乘积遗漏了。 跟踪发现至CX=1时,LOOP并没有执行到如下图,看来是自己理解错了,LOOP是先执行CX自减操作,再判断CX是否为零才执行跳转与否的。因此可以有两种修改方法,一是将CX初始为9,这样避免大幅度修改代码。而修改代码也不难,错误的原因是ADD BX,AX放在了AL*[DI]前导致少加了一次。直接将其移到MUL [DI]之后便可。这里选择后者虽然修改前面的流程图麻烦,给自己个教训,好下次别在这“想当然”的地方再摔倒。 6. 实验结果 以下均已在debug环境中。 1)g运行程序,d1415:000A查看M内容为06即有6个是正数正确,如图 2)g运行程序,d1415:0005查看M内容为07即最小数是7正确,如图 3)g运行程序,d076a:000a查看RESULT内容为03即有3个数为0正确,如图 4)修改后重复以上步骤得到最终结果为78H=120答案正确如下图: 7. 总结,质疑,建议,问题讨论 通过此次实验才发现自己有多么的不足,题目并不难甚至可以说是很简单。可就这么简单的几道题由于自己对一些指令没有深透的理解,给自己找了不少苦头,一二题很容易跟踪就可以找到出错位置分析修改之。至于第三题中未能一次编译通过是自己形而上学没有牢记操作数位数一致的指令 规则 编码规则下载淘宝规则下载天猫规则下载麻将竞赛规则pdf麻将竞赛规则pdf 。一个晚上大半时间是死在了最后一题上。先是又一次犯了第三题中同样的错误,原因是自己并没有真正深入理解操作数位数一致的规则,因单操作数而忽略了它,光是记住还是不行,该错误的再次出现让我深刻理解了该规则,希望以后 仍铭记。后是CX忘了初始化,忘了,添上了就没话说,竟然一直自以为是的认为已经初始化过了而把自己引向了另一个方向,胡乱猜了一大堆可能性,引自己到了另一胡同里。直到debug调试T跟踪后才发现,竟是简单的CX未初始化,而LOOP的理解错误的的确确给自己添了不少麻烦,不过通过T跟踪很快就发现了。 此次实验虽然磕磕绊绊的,但很大程度上提升了我的分析问题解决问题的能力,更重要的是让我的思维更开放了,如最后一题的羁绊,虽然猜想错误了,但让我在以后同类的问题中有了个预先的警示。并且深入问题后让我发现,一个问题牵扯出了没有发生但该注意的其他问题,如在最后一题我所犯错误的修改上,第一中改法可以(调试过),是因为在该题中0011所指向的也是数据,并且在该数据段内。而如果REST在其他地方定义的话,或者说0010已经是该数据段结尾了,那么第一种改法很可能就会是错的了。 实验四 子程序设计 1(实验目的和要求 1、学习子程序的编写,主子程序的调用 2、不同模块间程序的调用和调试 2(实验用的软硬件环境 实验的硬件环境是: IBM—PC机及其兼容机 实验的软件环境是: 操作系统:DOS 2.0以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、 WPS.EXE;宏汇编程序:MASM.EXE(或ASM .EXE);连接装配程序:LINK .EXE;交叉引用 程序:CREF.EXE(可有可无)。 3(实验内容及实验数据记录 1、数据段中的3个字符,调用子程序将其逐个显示出来。子程序的功能是 显示一个字符。单步执行,观察IP的变化 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替代 4(操作方法及实验步骤 1-1)文本编辑程序保存V1.asm,编译并连接后debug调试V1.exe。跟踪如下 u反汇编观察CALL指令所在程序段偏移量为000F而且Call到哪显而易见是0019即Mov AH,02与源程序一致而RET指令偏移量为001D但从中我们并不能得知其具体执行过程。 1-2)t单步跟踪,图为执行CALL指令前各个寄存器的状态及查看SS:IP(d0769:0000) 即栈顶内容为零。BP始终都为0实际上直到目前都没用到该堆栈。 1-3)继续单步执行,此时IP指向下一条指令CALL 0019。即执行该指令,结果如下可看到SP变为了FFFE 可知执行该指令的同时堆栈处于忙碌的变更中。之后IP直接指向CALL 所指0019。 d0769:fffe查看栈顶内容如下高向低读为0012 由之前的反汇编得知0012正是INC SI指令的偏移量,而该指令位于Call指令的下一条。 1-4)由此我们推断RET指令的作用就是弹出栈顶内容至IP来使得程序接着运行执行CALL指令后的程序。同样T单步执行观察如下 很明显执行RET后IP指向了0012。SP又指向了栈底。得以证实了CALL调用子程序是通过堆栈保护了现场进入子程序,之后再通过RET恢复到了原状态 2-1)单独阅读两个程序模块似乎毫无瓜葛,只知道S32.ASM模块中是实现的是二进制数转化为十六进制数并在显示器上显示的功能。S31.ASM实现的是通过子程序TRAN的调用完成对主程序着中获取的两位非压缩BCD数的二进制转化。按题目要求分别会变S31.asm和S32.asm如下 2-2)分别编辑程序存为S31.asm和S32.asm文件。进入masm目录。汇编连接如下均正常通过。 2-3)运行程序S31.exe结果如下等待输入两位字符: 输入两个字符1和2立即就跟出了000C,输入字符4和5跟出了002D,程序实现了将2位非压缩BCD码转化为了16进制数并打印输出到显示器。可见diso子程序虽然在另一个程序段中但在主程序中还是能被CALL唯一和在同一段内 的调用方式不同的是需要指明是段内子程序,还是段外子程序。指令中的NEAR PTR或FAR PTR正是此作用。 3-1)分析题目要求容易得知,程序可分为两部分,一是控制数据缓冲区的数据获取,而自然就是数据处理了亦是题目要求中的子程序实现的功能。 首先定义数据缓冲区有 BUF1 DB 'MY NAME IS ZERO!' LEN1 EQU $-BUF1 BUF2 DB 'YOU ARE MY GIRL,RIGHT?' LEN2 EQU $-BUF2 这里就有一个值得考虑的问题,就是缓冲区内的数据长度不等该怎么处理。对以等长直接下两指针即可方便循环控制。为方便起见,当然取短的不失为是好的选择,在与长的字符串中比较至短字符串长度LEN1结束并输出不等字符后指针DI所指向字符余下部分直接输出。 因此有如下示 输出BQ„„ 3-2)因而如何取较短的一者作为循环条件及SI和DI的初始成了问题。 BUF2送BX。然后比较可取的方法是先将LEN1假设为最短,传送给CX,同时将BUF1送AX,比较CX与LEN2,分支中处理数据交换。于是有 MOV CX,LEN1 MOV AX,BUF1 MOV BX,BUF2 CMP CX,LEN2 JB L SUB CX,LEN1-LEN2 XCHG AX,BX L: MOV SI,AX MOV DI,BX 问题得以解决。既然这样设计,则字符显示功能就应该分离出子程序另作为又一个子程序,方便主程序和比较字符的子程序的调用。 3-3)于是有代码如下 DATA SEGMENT BUF1 DB 'MY NAME IS ZERO!' LEN1 EQU $-BUF1 ;计算BUF1长度 BUF2 DB 'YOU ARE MY GIRL,RIGHT?' LEN2 EQU $-BUF2 ;计算BUF2长度 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV CX,LEN1 ;假设BUF1最短送入CX MOV AX,BUF1 ;AX存放短字符串首偏移// MOV AX,OFFSET BUF1 MOV BX,BUF2 ;BX存放长字符串首偏移// MOV BX,OFFSET BUF2 ;MOV DH,LEN2-LEN1 ;下一个类似语句仅在分支中忽略了LEN2大于LEN1 CMP CX,LEN2 JB L SUB CX,LEN1-LEN2 MOV DX,CX ;暂时存放两字符串差// MOV DH,CL XCHG AX,BX ;LEN2较短则交换数据 L: MOV SI,AX ;SI定位较短者 MOV DI,BX ;DI定位较长者 S: CALL CMPP ;调用子程序CMPP INC SI INC DI LOOP S ;比较字符未完成继续 Y: INC DI ;应该移至Call后才正确 MOV CX,DX ; MOV CL,DH并移至Y之前 MOV AL,[DI] ;MOV DL,[DI] CALL SHOW ;较长字符串余下部分输出 CMPP PROC MOV AL,[SI] ;MOV DL,[SI] CMP AL,[DI] ;CMP DL,[DI] JE SKIP CALL SHOW ;字符不等调用子程序输出字符 MOV AL,[DI] ;MOV DL,[DI] INT 21H SKIP: RET CMPP ENDP SHOW PROC MOV AH,2 ;子程序调用dos的2号功能 INT 21H RET SHOW ENDP CODE ENDS END START 4-1)要求子程序首先检索字符缓冲区内的N,并用Y替代。首先是各个缓冲区定义如下: DATA SEGMENT BUF1 DB 'MN name is ZERO!' BUF2 DB 'NOU ARE MN GIRL,RIGHT?' BUF3 DB 'no,you are MN Friend!' LEN DB $ DATA ENDS 4-2)由于各个缓冲区大小不一,所以各缓冲区大小的获取很重要,它将是每一轮循环的控制参数CX。可将它作为子程序的入口参数,来实现。而另一入口参数自然就是各缓冲区的首字符的偏移量SI。所以子程序实现: Displace PROC S: CMP [SI],'N' JNE NEXT MOV [SI],'Y' NEXT: INC SI LOOP S RET Displace NEDP 4-3)主程序实现入口参数的初始化过程,所以有BUF1的实现,其它如是: MOV CX,BUF2-BUF1 ;一直犯同样的错误 MOV SI,BUF1 ;CX初始化字符串长度,SI初始为字符串入口 CALL Displace ;调用Displace子程序 4-4)所以有最初代码如下为便于观察,处理后打印输出各字符串 DATA SEGMENT BUF1 DB 'MY NAME IS ZERO!' BUF2 DB 'NOU ARE MN GIRL,RIGHT?' BUF3 DB 'NO,YOU ARE MY FRIEND!' LEN DB $ DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV CX,BUF2-BUF1 MOV SI,BUF1 CALL Displace MOV CX,BUF3-BUF2 MOV SI,BUF2 CALL Displace MOV CX,LEN-BUF3 MOV SI,BUF2 CALL Displace MOV AH,4CH INT 21H Displace PROC S: CMP [SI],'N' JNE NEXT MOV [SI],'Y' NEXT:MOV DL,[SI] CALL Show INC SI LOOP S RET Displace NEDP Show PROC MOV AH,2 INT 21H RET Show EDNP 5实验数据处理和分析 3-1)编辑最初代码编译出错 更正错误MOV AX,BUF1为 MOV AX,OFFSET BUF1 MOV BX,BUF2为 MOV BX,OFFSET BUF2 及录入错字,正常通过编译。运行程序出错如下: 显然忘了退出到dos界面是一个原因,但不是主要原因。检查程序发现对于较长字符串的 余下部分的处理忘了循环。修正后出现如下错误: 修改MOV 4CH 为MOV AH,4CH重新编译。运行结果仍旧如上不停打印字符,显然问题很大。 3-2)还是单步跟踪来找错,debug V3.exe进入debug环境调试V3.exe。 如图发现虽然调用了dos的2号输出字符功能,但把本该传送给DL的字符错传给了AL,更正之。并替换之前的DX的使用。终于输出如下结果,为了便已对比,为程序添加换行输出功能。 4-1)编辑程序代码,编译出错,安提示定位到错误处修改之。 没引起注意,还是同样的错误, MOV CX,BUF2-BUF1 、MOV SI,BUF1 修改为 MOV CX,OFFSET BUF2-BUF1 、MOV SI,OFFSET BUF1 为了引以为戒,这以后干脆直接用LEA指令,以避免事后犯同样的错误。而Constant expected不知到是否和程序指令冲突了定义还是怎么,先修改之为LENTH。错误23和25行均容易更正。指定内存大小BYTE PTR即可。 4-2)之后才发现程序段未下结束标记修改之,重新编译如下看来其它错误并非由以上引起。同时LENTH还是不行。 所以猜想是后边的DB问题,恍然大悟,这里无须开辟空间,直接用伪指令EQU即可。修改后:LEN EQU $。重新编译。至于后面的问题是由于修改之前的初始化过程LEA又犯了其它错误,LEA 指令将地址载入目的操作数。可是操作数明明可以是表达式的,为什么提示当前模式非法呢。 4-3)暂时用原始方法修改回来:MOV CX,OFFSET BUF2-BUF1,其它同。可又出现了如下错误: 17行中 MOV CX,LEN-BUF1提示操作数不在同一段内或是常量,对比之前(上一题)的使用,我们忽略了这样一个问题,由于EQU并没在内存开辟新空间,为此将LEN视为常量,之前我们都是常量表达式出现,所以未出错。这里BUF1是地址即内存操作数,所以猜想问题可能处在此处。修改EQU 指令为LEN EQU $-BUF3,同时修改指令MOV CX,LEN-BUF3为MOV CX,LEN,问题应该可以解决。31和36是子程序的标识,想是违反了命名规则。修改为大写一试,错误并非由此引起。仔细观察子程序的定义,原来是ENDP错写成EDNP。修改之正常通过编译并连接运行。 4-4)经以上修改,最终完整程序代码如下 DATA SEGMENT BUF1 DB 'MN name is ZERO!' BUF2 DB 'NOU ARE MN GIRL,RIGHT?' BUF3 DB 'no,you are MN Friend!' LEN EQU $-BUF3 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV CX,OFFSET BUF2-BUF1 LEA SI,BUF1 ;CX初始化BUF1长度,SI初始为BUF1入口 CALL RE ;调用子程序进行字符检索和替换 MOV CX,OFFSET BUF3-BUF2 LEA SI,BUF2 ;CX初始化BUF2长度,SI初始为BUF2入口 CALL RE ;调用子程序进行字符检索和替换 MOV CX,LEN LEA SI,BUF3 ;CX初始化BUF3长度,SI初始为BUF3入口 CALL RE ;调用子程序进行字符检索和替换 MOV AH,4CH INT 21H ;退出到DOS界面 RE PROC S: CMP BYTE PTR [SI],'N' ;检索字符‘N’ JNE NEXT MOV BYTE PTR [SI],'Y' ;找到‘N’则替换为‘Y’ NEXT: MOV DL,[SI] ;将每一个遍历字符传送给DL准备显示 CALL SHOW ;显示字符的子程序 INC SI LOOP S RET RE ENDP ;字符处理操作子程序 SHOW PROC MOV AH,2 INT 21H RET SHOW ENDP ;子程序调用DOS的2号显示功能 CODE ENDS END START 6. 实验结果 3)对比字符串得知结果比较部分正确,但”RIGHT,“部分只有输出'I'。 仔细检查代码发现在给CL赋值前CH并未初始化为0。在Y:前添加MOV CH,0;修改之,但不是问题所在,忽略了一个很大的问题就是由于CX是在分支里保存两串差值,导致了在LEN1小于LEN2时并没给CX第二次初始化为差值,所以有了该问题。因此在MOV BX,OFFSET BUF2后添加指令MOV DH,LEN2-LEN1,将MOV CL,DH提前出Y之上。修改后最终还露了’R‘,原因就是进入余下字符串前DI多加了1,将INC DI移动至CALL之后,重新编译运行的结果正确如下: 4)运行程序输出正确结果,至此该程序实现了所设计的功能。 7. 质疑,建议,问题讨论,总结 在前几次实验的基础与学习中不断的吸取教训,此次实验完成的很顺利,设计的逻辑很少出现问题,唯一应该引起注意的是指令的语法规则在这次实验中是阻碍实验前行的一大障碍,粗心大意的编辑程序没有保持分析设计需求时的严谨态度,给自己添了原本不该出现的不少麻烦。总之几次实验下来,受益匪浅,不仅是巩固了理论知识,还很大程度上提升了我分析并解决问题的能力,更重要的是每一次实验中的羁绊让我对生活和学习的态度的着重要性有了新的认识。这将会是我人生中的一大财富。 实验五 DOS功能调用 1(实验目的和要求 9、 学会DOS中关于显示功能调用指令的用法。 10、 领会修改显存方法显示字符。 2(实验用的软硬件环境 实验的硬件环境是: IBM—PC机及其兼容机 实验的软件环境是: 操作系统:DOS 2.0以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、WPS.EXE;宏汇编程序:MASM.EXE(或ASM .EXE);连接装配程序:LINK .EXE;交叉引用程序:CREF.EXE(可有可无)。 3(实验内容及实验数据记录 4、输入一个字符,显示出来 5、输入一个字符串,显示出来 6、buf开始的3个的16位二进制数用十六进制数的形式显示出来 (1)理解程序 (2)输入程序,汇编,运行(在DOS状态下输入:文件名.EXE),观察结果。 (3)如果要分行显示,程序要如何修改, DATA SEGMENT 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 7、运行下列程序,在屏幕的第1行,会显示一个字符X,理解程序段 STACK SEGMENT DB 128 DUP(0) STACK ENDS CODE SEGMENT ASSUME CS:CODE,SS:STACK START: MOV AX,STACK MOV SS,AX MOV SP,128 MOV AX,0B800H MOV ES,AX MOV AH,0 ;BIOS 10H的0号功能,设置80X25的彩色字符模式 MOV AL,03H INT 10H MOV AH,'X' MOV ES:[160*1+40*2],AH MOV AL,0 MOV AH,4CH INT 21H CODE ENDS END START 8、显示 ********* ******* ***** *** * 6、 编写程序,统计字缓冲区中的20个数据的正数、负数、0的个数,并将统 计结果以16进制形式显示出来。 4(操作方法及实验步骤 1)直接调用DOS 1号功能即可,debug环境中a命令直接编辑代码写入 内存如下指令 MOV AH,01 INT 21H MOV AH,4C INT 21H 2)字符串的输入和显示,原以为在调用10号功能后需要调用9号显示功 能,因此编辑代码如下 DATA SEGMENT BUF DB 10 DB ? DB 10 DUP(?) ;DB '$' DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV DX,OFFSET BUF MOV AH,10 INT 21H ;MOV DX,OFFSET BUF+2 ;MOV AH,9 ;INT 21H MOV AH,4CH INT 21H CODE ENDS END START 3) 3.1&3.2我们知道要将数以16进制的形式显示就必须找到其对应的字母ABCDEF的ASCII码,ASCII码48是数字0的开始也就是16进制中的30,而3AH开始至40H为7个常用符号的ASCII码值,从41H开始才是大写字母的ASCII码值,因此将所要转化的四位二进制数与10做比较,若小于10可直接加30H得到其对应的ASCII码,若大于等于10则应多加上7跳过7个符号ASCII码得到其对应的16进制ASCII码以达到转换的目的即显示时打印其相应的ASCII码对应的字符。 3.3要达到题目要求的分行显示,从程序的跟踪可以看出在在取数时分为了两个情况,一个通过SI定位内存单元一次性取得一个16位二进制数,另一个是处理数据时循环移位取高四位数。而要使得数据显示时换行只要在完成一个16位数据的转换后取下一个16位数时进行调用DOS 2号功能输出换行符ASCII码为10即0AH便可。所以在源代码的基础上在两次INC SI前JNZ L间添加指令如下 MOV DL,0AH MOV AH,2 INT 21H 4)可以看到程序首先通过 MOV AX,0B800H MOV ES,AX 在内存开辟了附加段,段首地址为B800H并通过MOV ES:[160*1+40*2],AH以 便于向B80F0H(位于B8000H,BFFFFH彩色字符模式显示缓冲区)执行MOV AH,'X' 写入字符‘X’,以达到直接改变显存内容显示。 5) 5.1分析图案 第1行打印了9列 ********* 第2行打印了7列 ******* 第3行打印了5列 ***** 第4行打印了3列 *** 第5行打印了1列 * 因此有两种思路,一是通过调用DOS 2号功能配合循环逐一打印字符'*',二是借鉴4)中的方法直接改变内存内容显示'*'。但两种方法都用到了双重循环, 外层循环控制行的打印,内层循环控制列的打印。结合图案分析和循环数与行序号不然找到如下关系: a、1<=列数<= 2*当前行序号-1 而行控制参是外层循环CX的变动,所以有 b、6-CX=当前行序号。 5.2这里选择第二种以熟悉并掌握4)中的方法 首先按a和b式,就有了偏移地址的计算式:160*(6-CX)+2*Y。其中1<=Y<=2*CX-1,可通过内层循环实现。 5.4因此有最初代码(错误) 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 CL,5 ;循环控制次数为5 MOV CH,0 ;高位清零 MOV DH,'*' ;初始打印字符 MOV AX,0 H: ;MOV BL,1 ;从1列开始显示 MOV DL,6 ;行控制参数 SUB DL,CL ;控制当前行 MOV AL,160 MUL DL MOV DI,AX ;保存行参数 MOV AL,2 MUL CL DEC AL (L:) MOV AL,2 MUL BL ;控制当前列 ADD AX,DI ;显存空间定位 MOV ES:[AX],DH ;通过显存显示 INC BL ;列打印自加 ;INC BX (L:) MOV AL,2 MUL CL DEC AL ;DEC AX ;MOV SI,AX CMP BL,AL ;检验打印上限 ;CMP BX,SI JNA L ;未打印完当前行返回继续打印 MOV DL,0AH MOV AH,2 INT 21H ;打印完一行则换行 LOOP H ;行打印循环 MOV AH,4CH INT 21H ;退出到DOS界面 CSEG ENDS END START 6) 6.1分析题目要求有三,首先定义缓冲区存放20个有符号数据,其次对于正负数和零的统计可通过两次筛选来完成,最后是16进制的转换这在3)中已得以解决,因此有部分流程如下 这样在16进制转换时就有了一个取数的麻烦,为此考虑如果多开辟一个缓冲区BUF2来存放三个结果,下一个指针DI,一来解决了这个问题,二来筛选时通过指针的跳动也同时使得统计结果的代码得以简化,所以就有了如下流程: 6.2按分析结合流程编辑代码如下 DATA SEGMENT BUF1 DB 1,-3,5,26,0,6,0,24,-17,-10, -21,-5,33,48,0,32,0,10,44,-1 BUF2 DB 3DUP(0) DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV CX,20 MOV AL,0 ;MOV SI,OFFSET BUF1 (1) ;MOV DI,OFFSET BUF2 S: CMP [SI],AL JGE NEXTCMP JMP ADDD ;负数的个数 NEXTCMP:INC DI CMP [SI],AL JZ ADDD ;零的个数 INC DI ADDD: ADD BYTE PTR [DI],1 ;正数的个数 INC SI LOOP S ;统计个数 MOV DI,OFFSET BUF2 P: MOV BX,[DI];以下为16进制的转换并显示注释参考3)见附录 MOV CH,4 ;L: MOV CL,4 ROL BX,CL ;ROL BL,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 MOV AH,0AH ;MOV AH,2 ;MOV DL,0AH INT 21H INC DI CMP DI,OFFSET BUF2+2 JNA P MOV AH,4CH INT 21H CODE ENDS END START 5(实验数据处理和分析 2)按最初想法汇编程序得到了下面可怕的结果 由此单步跟踪观察,d定位到输入的字符串所在查看,如图得知10号功能 的调用并没出错,所以应该是9号的问题 单步到9号功能调用指令,p执行后,发现在debug确实调用,并显示了字符串 但在返回DOS界面却显示先前的一大堆乱码,所以认为是结束字符'$'的关系,于是修改字符缓冲区为如下 BUF DB 10 DB ? DB 10 DUP(?) DB '$' 结果出现了如下情况,只要输入的字符少于9个都会缺失掉前面几个不唯一。 至于问题处在哪,琢磨了好一段时也没弄清楚,猜想是10号功能的调用是否已自动回显了字符串而立刻调用9号功能是不是产生了覆盖。于是注释9号功能的调用。结果单一的10号功能的调用就已会显了字符串,符合题目要求。 3) 3.1-1debug调试,单步跟踪如图程序进行取数操作: 不难理解,程序首先通过循环左移4位将数据高4位(二进制数)移出并补到数据低位,再将内存中一单元的数据(数的低8位二进制数 )传送至寄存器DL如上图。 3.1-2数据处理操作 通过指令AND DL,0FH将高四位清零保留低四位如图a可以看到DX由0094变为了0004,至此取得二进制数的最高四位。将所要转化的四位二进制数与10做比较,若小于10即0到9可直接加30H得到其对应的ASCII码30H到39H如图b所示,相反若大于等于10则应多加上7跳过7个符号ASCII码得到其对应的16进制ASCII码41H到46H以达到转换的目的即显示时打印其相应的ASCII码对应的字符。 图a 图b 3.2输入程序,编译,连接,运行结果如下虽然达到了以16进制的形式打印要求却连续输出了三个数。 图c 4)立即的显示结果混在了debug环境其他字符中,以至于没能注意到,老怀疑是自己显卡的显存空间分配彩色字符缓冲区不在内存的B8000H,BFFFFH间,导致了随机更改ES段首地址,结果可想而知,无意清屏时直接在DOS下运行终于看到了字符‘X’。 5) 5.1间接寻址,MOV ES:[AL],DH寄存器的错误应用即相对适用的寄存器只有BX,BP,SI和DI错误提示如下 通过添加ADD AX,DI 和 MOV DI,AX 指令,写入字符指令相应地改为了MOV ES:[DI],DH。 5.2更正了错误后并排错语法错误后运行结果仍然出现问题如下 结果并没有如预期的一样,从图案可以看出,错误肯定是在于列打印的控制上, debug单步跟踪发现DI中保存的参数在每次打印时都更新为了前一次打印所计算的偏移地址也就是加上了列的增量,如下图所示,打印1行2列时,DI由00A2H即162变成了00A6即166。 5.3因此在下一行打印之前必须保证DI不变动,所以这里的DI应由其他寄存器代替,便修改之为BP,编译运行也就得到了预期的图案。 6)汇编代码出错如下 修改错误,保证语法的正确性后,运行程序得到结果如下,显然dos2号功能调用出错了,统计结果也不正确,为此只能单步跟踪 在第一次循环时过程和数据处理均正常如下 图a第一个数第一次筛选 图b第一个数为大于等于0,DI下移 ,DI继续下移一位至0016,实现结果加1 图c第一个数大于0 继续跟踪发现,问题出在了每次处理完一个数据后DI未能刷新至原点0014图下 修改S:标号至(1)处,MOV DI,OFFSET BUF2 得到结果如下 不难发现,除了dos2号功能未修改错外,结果中后两位才是正确的结果,检查代码得知是16进制转换时寄存器高8位无用数据参与了转换,为此修改 P: MOV BX,[DI] MOV CH,4 L: MOV CL,4 ROL BX,CL 为 P: MOV BX,[DI] MOV CH,2 L: MOV CL,4 ROL BL,CL 问题想是可以得以解决。重新汇编,并运行程序。 6. 实验结果 1)G运行后提示符提示输入字符,结果如下回显输入的字符 2)DOS 10号功能调用,输入字符串到自定义的缓冲区内,并会显字符串到屏幕,如下a为debug下,b为dos界面下。 图a 图b 3) 未进行换行操作 换行后显示结果如下 4)通过MOV ES:[160*1+40*2],AH向B80F0H写入字符'X',立即显示结果如下 5) 5.1修改DI变动的问题后,运行结果和预期的差不多,但由于是通过显存修改来显示,之前的内容未被清零,就出现了覆盖现象如下 对此,只要修改首列显示位置,及列显示上限即可,于是修改MOV BL,1 为MOV BL,35(从35列开始打印),修改 DEC AX 和MOV SI,AX为ADD AX,34结果是整体移动了位置,却又出现了错误的图案如下 原本一个简单的加法,因被我忽略了未修改时起始位子1,而多加了一个打印上限,被弄的晕头转向的,最终还是在debug单步运行时发现了问题所在。 修改34为33,终于得到了正确的结果如图 6)分析并修改一系列错误后,更正DOS 2号功能调用输出换行符,得到预期结果如下,其中一行为负数个数,二行为0的个数,三行为正数个数。 7. 质疑,建议,问题讨论和总结 此次实验是上机以来花了最长时间的一次,从分析各个程序,单步跟踪来理解程序的个步骤及作者的整体思路,加之利用所学分析并解决问题,让我更深入的看到了设计一个程序的思路的严谨的重要性,其中修改显存显示的方法让我掌握了一个简单却实用的DOS调用功能,而通过5)要求的再一次利用与实现使我对其认识更进一层,通过自己分析5)和6)的问题转换为数学逻辑表达式使得本繁杂的程序得以很大程度上得以简化,总之长时间的付出并没白费,虽然其中确实不甘心一次openoffice崩溃导致文档的从头重新编写,不过还算顺利完成了任务,也给自己一个不备份文件的教训了。
本文档为【汇编实验报告:汇编程序的汇编及运行_顺序程序设计_分支循环程序设计_子程序设计_dos功能调用】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_769254
暂无简介~
格式:doc
大小:1MB
软件:Word
页数:77
分类:互联网
上传时间:2017-09-27
浏览量:139