一、实验目的
- 能分析跳转指令构成的程序的运行原理
- 会用跳转指令构造循环解决应用问题
- 体验显示缓冲区的要求
二、实验内容过程记录
任务1-奇怪的程序?(教材实验8)
人工分析下面的程序,然后再在Debug程序中单步执行,观察每一步完成后的结果,并解释出现的现象。
程序如下:
assume cs:codesg
codesg segment
mov ax,4c00h
int 21h
start: mov ax, 0
s: nop
nop
mov di, offset s
mov si, offset s2
mov ax, cs:[si]
mov cs:[di], ax
s0:jmp short s
s1:mov ax, 0
int 21h
mov ax, 0
s2:jmp short s1
nop
codesg ends
end start
程序的执行结果将是:
可以正常结束
将连接好的程序加载后单步运行。
下面是运行过程中看到的代码变化的截屏:
(特别注意程序未开始执行时s处和s2处对应的指令及机器码,以及程序执行到s0处时,s处对应的指令和机器码。)
1.指令:mov ax,0000
指令描述:把0值送入ax寄存器
2.指令:nop
指令描述:预留一字节空间,两个nop就是一个字的空
3.指令:mov di, offset s
指令描述:将s的偏移地址0008存入di中
4.指令:mov si, offset s2
指令描述:把s2的偏移地址0020存入si
5.指令: mov ax, cs:[si]
指令描述:将cs:[si]中的数据存入ax,si中存的是0020,而cs为076A,且076A:0020指向的是EBF6,所以将EBF6存入ax中,ah存放F6,al存放EB
6.指令:mov cs:[di], ax
指令描述:将ax中存放的EBF6放入cs:[di]中,此时cs为076A,di为0008,所以是将ax中的EBF6存入076A:0008中,覆盖刚刚预留的一个字的内存空间,并且EBF6对应的指令为jmp 0000,使用u命令即可看见对应的指令
7.指令:s0:jmp short s
指令描述:进行jmp转移指令,跳转到标号为s的地址,s对应的偏移地址为0008,所以会跳转到刚刚覆盖上的jmp 0000指令
8.指令:jmp 0000
指令描述:跳转到076A:0000的指令
9.指令:mov ax,4c00h
int 21h
指令描述:进行程序返回
从这个程序中,我学到了
CPU 在执行 jmp 指令时并不需要转移的目的地址,而是通过位移来定位转移后指令的地址。这样做的好处是,方便程序段在内存中的浮动装配,使带转移的程序在内存中的不同位置都可以正确执行,因为跳转指令只涉及目的地址的偏移而不是地址。
其中,转移位移通过标号处的地址减去 jmp 指令后的第一个字节的地址得到,所以此时的位移可能为负数。在汇编语言中,转移的位移使用补码表示。
任务2- 循环程序的实现
在下面的数据段中,给出了全班3名同学OS、AL、SE、DB课程的成绩,请编程计算出平均成绩,写在 ? 处。要求用jcxz指令构造循环
datasg segment
db '201658501101','ZhangSan',90,100,76,89,0
db '201658501102','LiSi ',97,82,79,88,0
db '201658501103','WangWu ',77,98,89,91,0
db 4 ;这是课程门数,将要用于作除数,偏移量为75
datasg ends
下面是程序流程图:
下面是程序,以及运行后的截图,程序中已经加入了必要的注释:
开始的时候使用了loop循环去实现本题:
然后又使用jcxz改了一下上面的代码,如下图:
经过对比,发现两者有一些相似之处:
运行结果:
任务3- 向显存中传入字符(即教材实验9)
编程序,在屏幕的中间分别显示绿色、绿底红色、白底蓝色的字符串 'YantaiUniversity'
提示:要计算出“屏幕的中间”对应的内存单元,然后将字符以及对应的属性字节写入到内存中。
下面是程序
运行结果如下:
三、实验总结
我从实验中学到了:
1.跳转指令只涉及目的地址的偏移而不是地址。其中,转移位移通过标号处的地址减去 jmp 指令后的第一个字节的地址得到,所以此时的位移可能为负数。在汇编语言中,转移的位移使用补码表示。
2.80*25彩色字符模式显示缓冲区结构,内存地址B8000H~BFFFFH,编程中要加上0在最开头,不然就错了。0B8000H~0BFFFFH;向这个地址空间写入数据,写入的内容将 立即出现在显示器。
3.显示器可以显示25行,每行80个字符(00 00),每个字符有256中属性。(背景色、前景色、闪烁、高亮等组合信息)
4.一个字符在显示缓冲区要占两个字节(00 00),分别存放字符ascii和属性。一屏的内容在显示缓冲区占4000个字节。
5.显示缓冲区分8页,显示第0页的内容就是0B8000H~B8F9F
产生的问题及我的解决方案:
开始看了很久任务一,感觉应该是不能正常返回的。后来仔细单步执行发现。解决任务一的关键是将标号 s2 处的指令 jmp short s1 赋值到标号 s 处,由于转移指令使用位移表示,真正赋值的内容是 EBF6 而非 jmp short s1。
任务二的时候 写完之后运行发现程序卡死了,单步执行发现程序进入了死循环,经过分析发现判定条件 jcxz ok 的位置出现了问题,应该是先判断所取的值是否为0然后在进行+1取下一个值的操作。
任务三开始没有头绪,查阅网上资料跟看书上知识明白了显存的模式以及原理
题目要在屏幕中间,就应该在第12行显示第一串字符,每行0~159个字符,11*160=1760(6E0H)刚好是第12行首地址;
我的感受:
CPU 在执行 jmp 指令时并不需要转移的目的地址,而是通过位移来定位转移后指令的地址。我觉得这样做的好处是,方便程序段在内存中的浮动装配,使带转移的程序在内存中的不同位置都可以正确执行。
jcxz指令的功能相当于 if(cx==0) jmp short 标号;
loop指令的功能相当于 cx--; if(cx!=0) jmp short 标号;
将一道题用两种指令来写发现它们是有很大的相似之处的,它们都是短转移,对IP修改范围都是-128~127,并且在对应的机器码中包含的是转移的位移,而不是目的地址。
汇编也是可以实现结构体的,另外汇编语言可以直接修改显存使屏幕上的每个点发生变化
由此体会汇编语言其实也是很强大的!