实验1 简易汇编程序调试
一、实验目的
1:掌握在集成开发软件环境中汇编程序的编写、调试方法。
2:学会用DOS功能调用(1号和2号)完成输入和输出。
二、实验内容
1-1:
在以BUF为首地址的字节存储区存放有若干个无符号数,求该序列中的最大值,并在屏幕上输出该最大值。输入如下源程序并运行,查看运行结果。要求:了解汇编指令,学会单步调试。
1-2:
在1-1程序的基础上,添加修改代码补充程序,要求能同时求出最大值和最小值,并输出。
2-1:
从键盘上输入一个字符,如果输入的是大写字母,则在屏幕上输出其对应的小写字母,如果输入了除大写字母外的其他字符,提示信息。
2-2:
在上面程序的基础上,添加修改代码补充程序,要求:判断输入的字符,如果是大写字母则输出其小写字母,如果输入的字符是小写字母则输出其对应的大写字母,输入其他字符则提示信息。
三、源程序代码(含详细注释)
1-1:
stack segment stack db 200 DUP(?) stack ends data segment buf db 12h,22h,4h,15h,9h,63h,1h,60h,62h ;buf区,db存放9个无符号数 N equ $-BUF ;N是buf区的数据个数 max db ? ;max存放db中的最大值,?表示还没有数据 min db ? ;min存放db中的最小值 data ends code segment assume cs:code,ds:data,ss:stack ;假定cs是code,ds是data,ss是stack start: mov ax,data ;把data送到ax mov ds,ax ;把ax送到ds mov si,offset buf ;buf首地址送到si,所以si存放数据段地址 mov cx,N ;把N送到cx,所以cx存放数据的数目 call maxmin ;调用maxmin子程序 mov cl,bh ;把bh送到cl,(bh是存放的最大值) mov ah,02h ;把02h送到ah,调用dos的2号功能 mov dl,cl ;把cl送到dl int 21h ;中断,输出 mov ax,4c00h ;返回dos int 21h ;中断,退出 maxmin proc ;子程序maxmin push ax ;将ax送入stack mov bh,[si] ;将si(buf首地址)送到bh mov bl,bh ;把bh送到bl(好像没什么用) dec cx ;cx自减1 A1: inc si ;si自增,即取下一个buf数据 mov al,[si] ;将新的数据送到al cmp al,bh ;比较al和bh的大小,al-bh=0,zf=1 jle A3 ;zf=1,转移A3(当前数和最大值相等) A2: mov bh,al ;把al送到bh,更新最大值 A3: loop A1 ;循环A1 pop ax ;弹出ax ret ;修改IP,实现近转移? maxmin endp ;子程序maxmin结束 code ends end start |
1-2:
stack segment stack db 200 DUP(?) stack ends data segment buf db 12h,22h,4h,15h,9h,63h,1h,60h,62h ;buf区,db存放9个无符号数 N equ $-BUF ;N是buf区的数据个数 max db ? ;max存放db中的最大值,?表示还没有数据 min db ? ;min存放db中的最小值 data ends code segment assume cs:code,ds:data,ss:stack ;假定cs是code,ds是data,ss是stack start: mov ax,data ;把data送到ax mov ds,ax ;把ax送到ds mov si,offset buf ;buf首地址送到si,所以si存放数据段地址 mov cx,N ;把N送到cx,所以cx存放数据的数目 call maxmin ;调用maxmin子程序 mov max,bh ;bh to max mov min,bl ;bl to min mov ah,02h ;把02h送到ah,调用dos的2号功能 mov dl,max int 21h ;中断,输出max mov ah,02h ;把02h送到ah,调用dos的2号功能 mov dl,min int 21h ;中断,输出min mov ax,4c00h ;返回dos int 21h ;中断,退出 maxmin proc ;子程序maxmin push ax ;将ax送入stack mov bh,[si] ;将si(buf首地址)送到bh mov bl,bh ;把bh送到bl dec cx ;cx自减1 A1: inc si ;si自增,即取下一个buf数据 mov al,[si] ;将新的数据送到al cmp al,bh ;比较al和bh的大小 jbe A2 ;if al <= bh, max still mov bh,al ;if al > bh, max update(bh) jle A3 ;if al <= bh, still in data A2: cmp al,bl ;compare al bl jae A3 ;if al >= bl, min still mov bl,al ;if al < bl, min update(bl) A3: loop A1 ;循环A1 pop ax ;弹出ax ret ;修改IP,实现近转移? maxmin endp ;子程序maxmin结束 code ends end start |
2-1:
stack segment stack db 200 dup(0) stack ends data segment string db 'Please input an English letter!', 0ah,0dh, '$' ;定义用户输入错误信息后的提示信息,同时采用换行0ah,0dh, '$' data ends code segment assume cs:code, ds:data, ss:stack
start: mov ax,data ;将data送入ax mov ds,ax ;将ax送入ds,即ds含data mov ah,01h ;调用func-1 int 21h ;中断 cmp al,'A' ;比较al和A jl exit ;如果al 小于 A,则跳转到exit,也就是说肯定不是大写字母 L1: cmp al,'Z' ;比较al和Z jg exit ;如果al 大于 Z,则跳转到exit,也就是说肯定不是大写字母 add al,32 ;将al自增32,当前的al是大写字母,加32是为了变成小写字母 mov cl,al ;将al送入cl,即cl含转化的小写字母
exit1: mov dl,cl ;将cl送入dl mov ah,02h ;调用func-2 int 21h ;中断 mov ax,4c00h ;返回dos int 21h ;中断
exit: mov dl,0ah ;将0a送入dl mov ah,02h ;调用func-2 int 21h ;中断 mov ax,data ;将data送入ax mov ds,ax ;将ax送入ds mov dx,offset string ;将string送入dx mov ah,09h ;调用func-9 int 21h ;中断 mov ax,4c00h ;返回dos int 21h ;中断 code ends end start |
2-2:
stack segment stack db 200 dup(0) stack ends data segment string db 'Please input an English letter!', 0ah,0dh, '$' data ends code segment assume cs:code, ds:data, ss:stack
start: mov ax,data ;data送入ax mov ds,ax ;ax送入ds,ds也有data mov ah,01h ;func-1 int 21h cmp al,'A' ;比较al和A jl exit ;如果al 小于 A,则去exit(非大写字母和小写字母) cmp al,'Z' ;比较al和Z jg NotUpper ;如果al 大于 Z,则去notupper(非大写字母,可能是小写字母) jmp Upper ;无条件去upper(一定是大写字母) NotUpper: cmp al,'a' ;比较al和a jl exit ;如果al 小于 a,则去exit(非小写字母) cmp al,'z' ;比较al和z jg exit ;如果al 大于 z,则取exit(非小写字母) jmp Lower ;一定是小写,无条件取lower Upper: add al,32 ;变成小写 mov cl,al ;al送到cl jmp exit1 ;无条件去exit1 Lower: sub al,32 ;变成大写 mov cl,al ;al送到cl
exit1: mov dl,cl ;和2-1一样的操作了,此处不再赘述 mov ah,02h int 21h mov ax,4c00h int 21h
exit: mov dl,0ah mov ah,02h int 21h mov ax,data mov ds,ax mov dx,offset string mov ah,09h int 21h mov ax,4c00h int 21h code ends end start |
四、遇到的问题和解决过程
问题1:在本地使用vscode编写asm代码完成后,用U盘传输到实验室电脑上的环境中,注释均乱码且无法编译成功。
解决1:发现是采用的编码格式不一样,本地使用UTF-8,而实验室电脑的环境使用ANSI。于是我们先在本地上用记事本打开asm文件,点击【文件】——【另存为】——【编码】处选择ANSI即可。最后注释均可以在实验室电脑上正常显示,编译也可以正常进行。
问题2:硬件插上后,实验室电脑并未显示连接成功。
解决2:发现实验箱未插电,后续找到黑色的电源线之后即可正常工作。
五、实验结果
1-1:
如上图所示,可以观察到终端窗口会输出c字符。由于本实验是输出buf区的最大字符,人为可以发现最大字符对应的16进制值是63h,查询ASCII表之后发现63h对应c,因此程序会输出c字符。
1-2:
如上图所示,可以观察到终端窗口会输出c字符和笑脸字符。由于本实验是输出buf区的最大字符和最小字符,人为可以发现最大字符对应的16进制值是63h和1h,查询ASCII表之后发现63h对应c、1h对应不可打印字符(笑脸),因此程序会输出c字符和笑脸。
2-1:
如上图所示,可以观察到终端窗口会输出大写字母A转化后的小写字母a,输出非大写字母a的提示信息【Please input an English letter!】。由于本实验是将输入的大写字母转为小写字母,将其他非大写字母的输入输出提示信息,因此程序在接收键盘输入的A后会输出a,在接受其他非大写字母输入后会输出预设的string。
2-2:
如上图所示,可以观察到终端窗口会输出小写字母a转化后的大写字母A。由于本实验是新增功能——将输入的小写字母转为大写字母,因此程序在接收键盘输入的a后会输出A。其他功能与2-1相似,此处不再赘述。
六、实验体会与总结
1:学会了查找十六进制数对应的ASCII码,来判断程序输出的结果是否正确。(ASCII码对照表 十六进制的字符对照表_未来无限的博客-CSDN博客)
2:学习了DOS功能调用的基本方法,例如1号功能是从键盘读入1个字符、9号功能是显示器输出一串字符,回车换行用0ah,0dh, '$'等知识点。(汇编--学习笔记(四)-DOS功能调用-CSDN博客)
3:学习了基本汇编语言指令的程序编写,特别是几类跳转指令,例如无条件跳转jmp等。(汇编语言跳转指令总结_汇编语言小于跳转指令-CSDN博客)