实验三
实验结论:
练习一:
第一步(编写t1.asm源文件):
在路径D:\masm下创建文本文档,在其中打入如下代码:
assume cs:code
code segment
mov ah,2H
mov dl,3H
add dl,30H
int 21H
mov ah,2H
mov dl,6H
add dl,30H
int 21H
mov ax,4c00H
int 21H
code ends
end
第二步(使用dosbox对源文件进行编译、连接、执行):
此处使用一个批处理文件process.bat对源文件进行编译、连接:
编译、连接过程如下图:
生成exe文件:
清屏并执行t1.exe(如下图):
得到输出结果:两个数字3和6。
第二步:将 4 和9行 中寄存器 dl 的值分别修改为5和7,并重新汇编→ 连接→运行,观察结果的变化(如下):
输出结果为5和7。
第三步:用 debug 对生成的可执行文件 t1.exe 进行调试。
使用r命令查看当前状态下的各寄存器中的值(如下图):
发现cx中的值为17h,为十进制中的23,在查看所写代码的长度恰好为23个字节,ds和cs中的值分别为075A和076A,恰好满足cs=ds+10h。
第四步:查看PSP(程序段前缀)的头两个字节,验证是否为CD和20:
第五步:使用 u 命令对 t1.exe 进行反汇编,观察反汇编得到的源代码:
第六步:使用 t 命令和 p 命令(遇到 int 命令时,用 p 命令)单步调试,观察结果:
由此可发现屏幕上显示的5和7并不是五十七,而是分次输出的5和7,原理是将需要输出的数据放入dl中,输出就是将dl中的数据通过ascll码转为对应的字符,并显示在屏幕上。
练习二:
第一步(编写t2.asm源文件):
在路径D:\masm下创建文本文档,在其中打入如下代码:
assume cs:code
code segment
mov ax,0b800H
mov ds,ax
mov bx,0H
mov [bx],0433h
mov bx,2H
mov [bx],0436h
mov ax,4c00H
int 21H
code ends
end
写完之后保存为asm文件。
第二步(使用dosbox对源文件进行编译、连接、执行):
此处使用一个批处理文件process.bat对源文件进行编译、连接:
编译、连接过程如下图:
编译生成obj文件:
连接生成可执行的exe文件:
清屏之后执行t2.exe:
通过对程序运行结果的观察发现在屏幕左上角出现了红色的36。
第三步:重新打开t2.asm并将7行和10行赋给[0]和[2]的值改为0432h和0439h,再次对t2.asm进编译、连接、执行:
执行结果如下图:
第四步:将t2.asm文件中的7和10行中赋给[0]和[2]的值改为0333h和0336h后,对t2.asm进行汇编、连接、执行:
结果如下图:
得到蓝色的36。
猜想:0b800h这个段地址是文本模式显示内存的段地址,通过对其中写出字型数据,就可以使屏幕上显示对应的数值并控制数值的颜色。
尝试:将t2.asm改写为以下的内容:
assume cs:code
code segment
mov ax,0b800H
mov ds,ax
mov bx,0H
mov [bx],0333h
mov bx,2H
mov [bx],0436h
mov bx,4H
mov [bx],0237h
mov ax,4c00H
int 21H
code ends
end
注:令数据段寄存器中所存储的数据为b800h之后,从偏移地址为0的地方依次向内存单元写入数据,发现低位字节用来控制输出什么字符,高位字节用来控制输出的字符的颜色。
在此基础上继续对t2.asm进行更改:更改如下:
assume cs:code
code segment
mov ax,0b800H
mov ds,ax
mov bx,1H
mov [bx],0333h
mov bx,3H
mov [bx],0436h
mov bx,5H
mov [bx],0237h
mov ax,4c00H
int 21H
code ends
end
更改后的代码与原代码的区别在于:人为的向内存中写入数据不再是从偏移地址为0处开始写的,而是从偏移地址为1处开始写,对更改过的t2.asm进行汇编、连接、执行(执行结果如下图):
出现问题,输出并不是不同颜色的367,而是其他字符,对修改过的t2.exe进行debug,查看b800相关偏移地址中存放的数据是什么(如下图):
执行完了t2.exe之后对b800:0到b800:6中的数据进行查看:发现对对应偏移地址的数据写入确实成功了,并且右侧确实按照ascll码显示出了3,6,7这三个数字,但是屏幕左上角出来的的字符中并没有367,显示出来的字符是从偏移地址为0处开始2个2个向后看,每看两个在屏幕上显示一个字符。
经过验证:[0]中存放的字型数据3320h(在debug对内存的查看,发现20这个字节数据并没有字符和它对应如图:
)就是蓝色块,[2]中的3603h就是出现的蓝色背景的红心图案,而[4]中存放的3704h就是背景为蓝色的灰色菱形图案,[6]中存放的0702h就是灰色笑脸图案。
另外:在尝试的过程中,给以b800位段地址的偏移地址[bx]赋值的时候,好像只可以传字型数据,如果传送字节型数据,会报severe error错误。
再次改变t2.asm中的代码如下:
assume cs:code
code segment
mov ax,0b800H
mov ds,ax
mov bx,2H
mov [bx],0333h
mov bx,4H
mov [bx],0436h
mov bx,6H
mov [bx],0237h
mov ax,4c00H
int 21H
code ends
end
结果如图:
成功地将367显示出来,猜想得到验证。
附:
在集成实验环境下运行t2.asm:
打入代码保存运行:报错A2070
经过查阅资料发现:在使用mov指令时最规范的写法是将操作数的长度规定好(即类型的强制转换)。
原代码:
改过后的代码:
经修改,运行成功(如下):
实验感悟:
练习一:通过对d中数据的操作,了解到通过给dl赋值可以在屏幕上打印dl中所存的数据对应ascll码的字符。以及cs和ds中数据的关系、cx中存放数值的意义。
练习二:通过对t2代码的改写,了解到:b800h是文本模式显示内存的段地址,并且对字符的显示是从0偏移地址开始的,并且是按字数据读取(高位字节控制属性,低位字节控制显示字符)。
与实验一练习四的对比:
实验一中要求从b810:0处通过e命令开始向内存写入数据,练习二中使用的是改变ds寄存器中的值为b800,并通过[address]来实现向内存中写入数据,但它们本质上都是改变内存中的数据。并且还发现:b8000h和b8100h这两个物理地址位于同一个段(b800:0~b800:ffff)中。(思考:这一个地址段的作用是什么?这一个地址段是文本模式显示内存吗?从字面意思对应到实验过程,确实发现这一个地址段可以实现文本+模式+显示的作用)