【目的】

​ 汇编程序的编写和提高

【要求】

  1. 使用记事本编写.asm 源程序
  2. 对于按程序进行汇编及连接,产生.exe 文件
  3. 使用visio 绘制流程图

【内容】

【第一个实验】显示复制字符串

编写一个汇编程序,实现字符串的复制功能,并且将复制的字符串显示出来。(选做部分:倒

序显示复制字符串)

(1)实验流程图:

(2)实验源代码(粘贴源代码):

DATAS SEGMENT ;定义DATAS 代码段string_str db 'The school of Information Science and Engineering Shandong University','$'
;定义string_str 字符串
DATAS ENDS ;EXT SEGMENT ;定义EXT 附加段string_ext db 100 dup (?) ;为字符串string_ext 定义一个100 个字节大小的栈段
EXT ENDS ;STACKS SEGMENT ;定义栈段
STACKS ENDS ; CODES SEGMENT ;CODES 代码段ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EXT
;将CODES 和CS 连接,DATAS 和DS 连接,EXT 和ES 连接
START:MOV AX,DATAS ;把DATAS 的地址存入AX中MOV DS,AX ;用 DS 存储DATAS 的地址MOV AX,EXT ;把EXT 的地址存入AX 中MOV ES,AX ;用ES 存储EXT 的地址LEA SI,string_str ; 取string_str 的地址放置到SI 寄存器中LEA DI,string_ext ; 取string_ext 的地址放置到DI 寄存器中MOV CX,70 ;CX代表循环次数,由于字符总有70个字符,因此这里循环70次。STD ;将标志寄存器Flag的方向标志位DF置1,DF=1使串操作指令中操作数地址自动递减,说明字符串的处理是从高地址向低地址方向进行REP MOVSB ;使用字符串传送指令MOVSB,这条指令按字节传送数据,用SI 和DI 这两个寄存器控制字符串的源地址和目标地址LEA DX,string_ext ;将DX 和string_ext 的地址连接起来MOV AH,9INT 21H ;调用DOS 功能,输出字符串MOV AH,4CH ;令AH等于4CHINT 21H ;返回DOS
CODES ENDS END START ;程序结束

(3)实验代码、过程、相应结果(截图)并对实验进行说明和分析:

实验结果如下图所示,实现了复制字符串并显示,符合题意。

【第一个实验】倒序显示复制字符串

(1)实验流程图:

(2)实验源代码(粘贴源代码):

DATAS SEGMENT;定义DATAS 段string_str db 'The School of Information Science and Engineering Shandong University','$'
;定义string_str字符串
DATAS ENDS;
EXT SEGMENT;定义附加段string_ext db 100 dup(?);为string_ext定义一个100 个双字节空间
EXT ENDS
STACKS SEGMENT;定义栈段
STACKS ENDS
CODES SEGMENT;定义CODES段ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EXT;将CODES 和CS 连接,DATAS 和DS 连接,EXT 和ES 连接
START:MOV AX,DATAS;把DATAS 的地址存入AX中MOV DS,AX ;用 DS 存储DATAS 的地址MOV AX,EXT;把EXT 的地址存入AX 中MOV ES,AX;用ES 存储EXT 的地址LEA SI,string_str; 取string_str 的地址放置到SI 寄存器中LEA DI,string_ext ; 取string_ext 的地址放置到DI 寄存器中MOV CX,69 ;CX代表循环次数,这里循环69次CLD;将标志寄存器Flag的方向标志位DF清零,这里令DF=0使串操作指令中操作数地址自动递增,说明字符串的处理是从低地址向高地址方向进行。REP MOVSB;使用字符串传送指令MOVSB,这条指令按字节传送数据,,用SI 和DI 这两个寄存器控制字符串的源地址和目标地址,即复制string_str的内容到string_extLEA DX,string_ext;链接DX 与STRING_EXTMOV AH,9INT 21H;显示字符串MOV AH,2MOV DL,0DHINT 21HMOV DL,0AHINT 21H;换行输出MOV CX,69;使循环的次数为69MOV SI,68;令SI 为68,也就是最后一个字符(不包括$)
LOOPPART:;定义循环部分MOV DL,[SI];将si起始的一个字符数据存入DL中;MOV AH,2INT 21H;将该字符输出DEC SI;将SI 自减,实现SI 的前移,逐个输出从而实现这种倒序输出LOOP LOOPPART;循环LOOPPART部分MOV AH,4CH;令AH等于4CHINT 21H;返回DOS
CODES ENDSEND START;程序结束

(3)实验代码、过程、相应结果(截图)并对实验进行说明和分析:

实验结果如下图所示,实现了复制字符串并倒序显示,符合题目要求。

【第二个实验】

利用中断调用,在屏幕上显示1—9 之间随机数,中断号86H。

(1)实验流程图:

(2)实验源代码(粘贴源代码):

DATAS SEGMENT ;定义DATAS 段string DB 0DH,0AH,'The Random Number is:','$';定义字符串提示显示随机数
DATAS ENDS STACKS SEGMENT STACK ;定义栈段DB 200 DUP(0) ;定义200 字节为0 的栈段
STACKS ENDS CODES SEGMENT ;定义CODES 段ASSUME DS:DATAS,SS:STACKS,CS:CODES
;将DATAS 和DS 连接,STACKS和SS 连接,CODES 和CS 连接CREATENUM PROC ;定义子程序CREATENUM,产生随机数PUSH CX ;将CX 入栈PUSH DX ;将DX 入栈MOV AH,0 ;令AH的内容为0INT 1AH ;设置时钟的“滴答”计数,CX:DX=时钟“滴答”计数,并将之作为随机数生成的种子MOV AX,DX ;将DX中的内容存放至AX中MOV DX,0 ;将0存放至DX中MOV BX,10 ;将10存放至BX中DIV BX ;除10从而得到1~9 的随机数ADD DL,30H ;将DL中的内容转换为其对应的ASCII码MOV AH,02HINT 21H ;输出数字POP DX ;将CX 出栈POP CX ;将CX 出栈IRET ;中断返回
CREATENUM ENDP;子程序结束START: MOV AX,DATAS ;将DATAS的地址存入AXMOV DS,AX ;将AX的内容入DS中LEA DX,string ;将DX与string 地址链接MOV AH,9INT 21H ;调用DOS 功能,输出字符串MOV AX,0 ;将0存放至AX中MOV DS,AX ;段偏移地址指向0000MOV BX,86H*4 ;将中断86H 的地址赋给BX,其中每个中断都有CS和IP,一共4个字节,因此乘4CLI ;禁止中断发生,在CLI起效之后,所有外部中断都被屏蔽,保证当前运行的代码不被打断,起到保护代码运行的作用MOV WORD PTR DS:[BX],OFFSET CREATENUM ;字操作.将CREATENUM的偏移地址存入ES:BX中MOV WORD PTR DS:[BX+2],SEG CREATENUM ;字操作.将CREATENUM的段基地址存入ES:[BX+2]中STI ;允许中断发生,在STI起效之后,所有外部中断都被恢复,以打破被保护代码的运行,允许硬件中断转而处理中断的作用。INT 86H ;调用CREATENUM子程序MOV AH,4CH INT 21H ;返回DOS
CODES ENDS END START ;程序结束

(3)实验代码、过程、相应结果(截图)并对实验进行说明和分析:

​ 在此实验中,我采用当前时钟滴答计数,并将之作为随机数生成的种子,利用了中断调

用,多次实验结果如下图所示,产生随机数满足题目要求。

【第三个实验】

键盘输入10 个学生的成绩,编写一个程序统计60-69 分,70-79 分,80-89 分,90-99 分及

100 分的人数,分别存放在Score6,Score7,Score8,Score9 和Score10 单元中。

【输入10 个学生的成绩如下】:65 98 78 82 88 95 72 62 90 100
(1)实验流程图:



(2)实验源代码(粘贴源代码):

DATAS SEGMENT;定义DATAS段SIGN DB 0DH,0AH,'PLEASE INPUT THE SCORES:','$';定义string 字符串,提示输入OUTSCORE6 DB 0DH,0AH,'SCORE6:','$';定义输出时的提示字符串OUTSCORE7 DB 0DH,0AH,'SCORE7:','$'OUTSCORE8 DB 0DH,0AH,'SCORE8:','$'OUTSCORE9 DB 0DH,0AH,'SCORE9:','$'OUTSCORE10 DB 0DH,0AH,'SCORE10:','$'SCOREOUT DB 0DH,0AH,'OUTSCORE:','$'SCORE6 DB 30H;将SCORE全部定义为0的ASCII码值30HSCORE7 DB 30H;SCORE8 DB 30H;SCORE9 DB 30H;SCORE10 DB 30H;
DATAS ENDS ;DATAS段结束STACKS SEGMENT ;定义栈段DB 200 DUP(0);定义200 字节为0 的栈段
STACKS ENDS;栈段结束CODES SEGMENT;定义CODES段ASSUME CS:CODES,DS:DATAS,SS:STACKS
;将DATAS 和DS 连接,STACKS和SS 连接,CODES 和CS 连接
START:MOV AX,DATAS;将DATAS的地址存入AXMOV DS,AX;将AX中的内容放入DS中LEA DX,SIGN;将DX 与SIGN连接MOV AH,9INT 21H;调用DOS 功能,输出SIGNMOV CX,10;CX代表循环次数,即循环10次S:;定义S段MOV AH,1INT 21H;从键盘上输入一个字符,将其对应字符的ASCII 码送入AL 中,然后输出MOV DL,AL;将存储在AL 中的输入字符拷贝到DL 中INT 21H ;再输入一个字符,存在AL 中CALL COUNT;调用COUNT 子程序进行比较分类MOV DL,32;让DL 等于32及空格对应的ASCII 码MOV AH,2INT 21H;输出空格LOOP S;循环输入给定的成绩CALL OUTPUT ;调用OUTPUT子程序MOV AH,4CHINT 21H;返回DOSCOUNT PROC;定义COUNT 子程序PUSH DX;将DX入栈以保护数据CMP DL,31H;让DL(最高位)与31H即1的ASCII码比较JZ S10;若相等则跳转到S10CMP DL,36H;将DL(最高位)与36H即6的ASCII码比较JZ S6;若相等则跳转到S6CMP DL,37H;将DL与37H即7的ASCII码比较JZ S7;若相等则跳转到S7CMP DL,38H;将DL与38H即8的ASCII码比较JZ S8;若相等则跳转到S8CMP DL,39H;将DL与39H即9的ASCII码比较JZ S9;若相等则跳转到S9JMP OVER;跳转到OVERS6:ADD [SCORE6],1;60-69区间的人数加一JMP OVER;跳转到OVER
S7:ADD [SCORE7],1;70-79区间的人数加一JMP OVER;跳转到OVER
S8:ADD [SCORE8],1;80-89区间的人数加一JMP OVER;跳转到OVER
S9:ADD [SCORE9],1;90-99区间的人数加一JMP OVER;跳转到OVER
S10:ADD [SCORE10],1;100区间的人数加一MOV AH,1INT 21H ;由于是100,需要多输入一位数字JMP OVER;跳转到OVERover:;OVER 段POP DX;将DX出栈RET;返回主程序
COUNT ENDP;CONUT子程序结束OUTPUT PROC;定义OUTPUT子程序LEA DX,OUTSCORE6;将DX与OUTSCORE6的段地址链接MOV AH,9INT 21H;调用DOS 功能,输出OUTSCORE6MOV DL,[SCORE6];将[SCORE6]的值存入DLMOV AH,2INT 21H;输出在60-69区间段的人数MOV DL,10INT 21H;输出空格LEA DX,OUTSCORE7;将DX 与OUTSCORE7地址链接MOV AH,9INT 21H;调用DOS 功能,输出OUTSCORE7MOV DL,[SCORE7];将[SCORE7]的值存入DLMOV AH,2INT 21H;输出70-79区间段的人数MOV DL,10INT 21H;输出空格LEA DX,OUTSCORE8;将DX 与OUTSCORE8地址链接MOV AH,9INT 21H;调用DOS 功能,输出OUTSCORE8MOV DL,[SCORE8];将[SCORE8]的值存入DLMOV AH,2INT 21H;输出80-89区间段的人数MOV DL,10INT 21H;输出空格LEA DX,OUTSCORE9;将DX 与OUTSCORE9地址链接MOV AH,9INT 21H;调用DOS 功能,输出OUTSCORE9MOV DL,[SCORE9];将[SCORE9]的值存入DLMOV AH,2INT 21H;输出90-99区间段的人数MOV DL,10INT 21H;输出空格LEA DX,OUTSCORE10;将DX 与OUTSCORE10地址链接MOV AH,9INT 21H;调用DOS 功能,输出OUTSCORE10MOV DL,[SCORE10];将[SCORE10]的值存入DLMOV AH,2INT 21H;输出100区间段的人数MOV DL,10INT 21H;输出空格RET;返回主程序OUTPUT ENDP;OUTPUT子程序结束
CODES ENDSEND START;主程序结束

(3)实验代码、过程、相应结果(截图)并对实验进行说明和分析:

以题目中的65 98 78 82 88 95 72 62 90 100为测试样例,实验结果如下图所示,符合题意。

【总结心得】

1、CLD与STD总结:

CLD即(CLear Direction flag)

功能:
将标志寄存器Flag的方向标志位DF清零。在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后。

STD即(SeT Direction flag)

功能:

与CLD相反功能指令是STD,即将方向标志位DF置1。在字串操作中使SI或DI的地址指针自动递减,字串处理由后往前。STD用于将方向标志设置为1,使得Si和/或DI将自动递减到当其中一个字符串指令执行时指向下一个字符串元素。如果方向标志被设置,SI/DI对于字节字符串将减1,对于字符串将减2。

2、MOVSB总结

MOVSB即字符串传送指令,这条指令按字节传送数据。通过SI和DI这两个寄存器控制字符串的源地址和目标地址,比如DS:SI这段地址的N个字节复制到ES:DI指向的地址,复制后DS:SI的内容保持不变。

3、CLI和STI总结

CLI汇编指令全称为Clear Interupt,该指令的作用是禁止中断发生,在CLI起效之后,所有外部中断都被屏蔽,这样可以保证当前运行的代码不被打断,起到保护代码运行的作用。

STI汇编指令全称为Set Interupt,该指令的作用是允许中断发生,在STI起效之后,所有外部中断都被恢复,这样可以打破被保护代码的运行,允许硬件中断转而处理中断的作用。

4、REP总结

REP 指令即“重复前缀指令”, REP 前缀一次只能应用于一条字符串指令。要重复指令块,需要使用 LOOP 指令或其它循环结构。因此需要一个寄存器来控制串长度。这个寄存器就是CX,指令每次执行前都会判断CX 的值是否为0(为0 结束重复,不为0,CX 的值减1),以此来设定重复执行的次数。

5、时钟服务INT 1AH总结

  1. 功能号:00H

    功能: 读取时钟“滴答”计数
    入口参数:AH=00H
    出口参数:AL=00H—未过午夜,否则,表示已过午夜
    CX:DX=时钟“滴答”计数

  2. 功能号:01H

    功能:设置时钟“滴答”计数
    入口参数:AH=01H
    CX:DX=时钟“滴答”计数
    出口参数:无

  3. 功能号:02H

    功能:读取时间
    入口参数:AH=02H
    出口参数:CH=BCD码格式的小时
    CL=BCD码格式的分钟
    DH=BCD码格式的秒
    DL=00H—标准时间,否则,夏令时
    CF=0—时钟在走,否则,时钟停止

  4. 功能号:03H

    功能: 设置时间
    入口参数:AH=03H
    CH=BCD码格式的小时
    CL=BCD码格式的分钟
    DH=BCD码格式的秒
    DL=00H—标准时间,否则,夏令时
    出口参数: 无

  5. 功能号:04H

    功能:读取日期
    入口参数:AH=04H
    出口参数:CH=BCD码格式的世纪
    CL=BCD码格式的年
    DH=BCD码格式的月
    DL=BCD码格式的日
    CF=0—时钟在走,否则,时钟停止

  6. 功能号:05H

    功能:设置日期
    入口参数:AH=05H
    CH=BCD码格式的世纪
    CL=BCD码格式的年
    DH=BCD码格式的月
    DL=BCD码格式的日
    出口参数: 无

  7. 功能号:06H

    功能:设置闹钟
    入口参数:AH=06H
    CH=BCD码格式的小时
    CL=BCD码格式的分钟
    DH=BCD码格式的秒
    出口参数: CF=0—操作成功,否则,闹钟已设置或时钟已停止

  8. 功能号:07H

    功能:闹钟复位
    入口参数:AH=07H
    出口参数:无

  9. 功能号:0AH

    功能:读取天数计数,仅在PS/2有效

  10. 功能号:0BH

    功能:设置天数计数,仅在PS/2有效

  11. 功能号:80H

    功能描述:设置声音源信息
    入口参数:AH =80H
    AL =声音源
    =00H——8253可编程计时器,通道2
    =01H——盒式磁带输入
    =02H——I/O通道上的"Audio In"
    =03H——声音产生芯片

    出口参数: 无

​ 有了前几次实验的经历,这次的实验写起来也相对地熟练一些,这次汇编程序的编写和提高的实验也带给我了很多的收获,通过实践的方法使用了MOVSB、CLD与STD、CLI和STI、REP指令等等,但是仍然遇到了一些问题。

​ 在第一个实验中,我认真读了实验资料中的几个串操作类指令的例子,通过这些例子,我大概有了关于复制并显示字符串的思路,我按照思路先画出了实验的流程图,并且通过MOVSB、REP指令写出了程序的实现片段,然后就面临着两个实验共有的问题,如何设定复制字符串的方向,我在网上查阅了相关的资料,看到了有关于CLD和STD的实现,但是有关于ES寄存器的部分让我有点陌生,然后我又复习了王爽的书中有关于这一部分的讲解,将标志寄存器Flag的方向标志位DF清零。在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后,反之,STD即将方向标志位DF置1。在字串操作中使SI或DI的地址指针自动递减,字串处理由后往前。在弄懂程序的基础上,对我写的代码片段进行了完善,最终实现了正序/倒序显示复制字符串的要求。

​ 在第二个实验中,依照老师给出的通过时钟计数,并将之作为随机数生成的种子的方法,按照思路我学习了关于时钟服务INT 1AH的用法,同时又去查询了一次中断表,不得不感叹中断在汇编程序中作用之大,同时也学会了自己设置中断的方法,掌握了CLI 指令:即禁止中断发生,在CLI起效之后,所有外部中断都被屏蔽,保证当前运行的代码不被打断,起到保护代码运行的作用,和STI指令:即允许中断发生,在STI起效之后,所有外部中断都被恢复,以打破被保护代码的运行,允许硬件中断转而处理中断的作用。

​ 第三个实验与以前C语言的实验程序很相似,我先画出了程序的流程图,大概将程序按照功能的模块化思想进行了分类,分为主程序,count计数子程序以及output输出子程序,主要通过比较、跳转至对应的人数SCORE加一的顺序实现,整体来说比较顺利。但是在最后输入成绩时由于S6-9的设置导致S10也只能输入两位数字,虽然不影响最终统计结果,但是我通过给S10多加了一位输入解决了这个小bug。

​ 整体来说,这次实验做的比较顺利,在实验过程中也让我收获颇丰,通过这门课也让我真正地了解到处理器的架构、指令集、寄存器等知识,通过汇编语言也让我从实践的角度强化了对这些知识的理解。

初学汇编,可能存在错误之处,还请各位不吝赐教。

受于文本原因,本文相关实验工程无法展示出来,现已将资源上传,可自行下载。

山东大学微处理器原理实验4工程文件 汇编程序设计编程

DOS汇编程序提高练习相关推荐

  1. 使用MASM03 - Win32汇编语言011

    使用MASM03 让编程改变世界 Change the world by program 代码段 .code段是代码段,所有的指令都必须写在代码段中,在可执行文件中,代码段是放在_TEXT节区(区块) ...

  2. win32 009 masm32

    签: model语句, 使用MASM, 内存模式, 指令集 Win32汇编 使用MASM01 让编程改变世界 Change the world by program 使用MASM 经过上一讲的准备工作 ...

  3. win32汇编 MASM03

    http://blog.fishc.com/738.html#codesyntax_5 让编程改变世界 Change the world by program 代码段 .code段是代码段,所有的指令 ...

  4. FAQ7: 如何正确的对待汇编学习和反汇编学习?

    FAQ7: 如何正确的对待汇编学习和反汇编学习? 答: 首先要学会正确的学习方式.       学习汇编的正确方式: 1> 建议以 王爽汇编这本教材 为初级入门书籍                ...

  5. 毕业论文浅析计算机病毒,浅析计算机病毒的有效防御论文

    浅析计算机病毒的有效防御论文 摘要:改革开放以来,随着时代的发展与社会的进步.人们的生产.生活都离不开计算机的存在,计算机也成为家家户户的必备品.人们可以通过计算机强大的功能,及时.方便.有效地获取各 ...

  6. 电驴 emule 源码分析 (1)

    关于电驴emule 的源码,网上有一个  叫刘刚的人 分析的 很多,但是如果你只是看别人的分析,自己没有亲身去阅读代码的话,恐怕很难  剖析整个系统. 关于emule  主要就是 连接 kad网络部分 ...

  7. “高手”和“菜鸟”的区别

    对于程序员来说,"高手"和"菜鸟"之间的区别实际上只有两个因素:一是从事编程时间的长短不同,使经验的多少有所区别 :第二个因素就是手头掌握资料的多少了 , 因为 ...

  8. 选择那个汇编编译器,和如何编译16位dos和32位汇编程序。

    学习汇编语言第一步,选择编译器.建议使用MASM32 下载地址: http://www.masm32.com/masmdl.htm 这个可以编译16位dos编译程序,也可以编译32位的程序. 程序安装 ...

  9. 汇编程序员之代码风格指南

    Style Guidelines for Assembly Language Programmers 汇编程序员之代码风格指南 作者:Randall Hyde   http://webster.cs. ...

最新文章

  1. Android定位方式和测试方法
  2. wds和dhcp分开做需要注意问题
  3. Android开发--初探SQLiteDataBase/数据库的创建,更新,插入,查询
  4. USB驱动程序之概念介绍学习笔记
  5. php如何存到磁盘,php缓存----磁盘缓存
  6. [译]如何在visual studio中调试Javascript
  7. Spring多数据源解决方案
  8. DB,Cache和Redis应用场景分析
  9. Linux vi的复制和粘贴快捷键
  10. Ubuntu 14.04 配置caffe环境
  11. td中bug处理过程_特斯拉的致命BUG,埃安LX的L3能解开吗?
  12. 虚函数(动态绑定)对于 OO/C++的重要性
  13. [转载] Python 完整实现的简单遗传算法(SGA)
  14. matlab改变示波器颜色,[转载]matlab/simulink 示波器颜色设置
  15. java expression 强制出现_Java中带有强制括号对的单行循环
  16. Android 获取sim卡序列号
  17. MySQL Oracle默认排序_PostgreSQL、MySQL、Oracle,查询的默认排序是怎样的?
  18. arc和非arc完美支持
  19. 苹果无线笔记本怎么连不上win服务器,苹果笔记本连不上无线_苹果笔记本连不上wifi...
  20. ftp 命令访问 ftp服务器

热门文章

  1. web服务器的相关配置
  2. java创造新世界下载_创造新世界3D
  3. 第三次作业 - 结对项目1
  4. 基于51单片机的智能自动晾衣架proteus仿真原理图程序设计
  5. dom---认识dom和dom的常用方法
  6. J2SE、J2EE、J2ME
  7. 李开复台大演讲:人工智能来了,别怕
  8. wsl2中安装中文输入法
  9. 你是当“鸡头”还是做“凤尾”
  10. 解读scrapy各个组件中的from_crawler()方法