一、实验目的
1. 理解80×25彩色字符模式显示原理
2. 理解转移指令jmp, loop, jcxz的跳转原理,掌握使用其实现分支和循环的用法
3. 理解转移指令call, ret, retf的跳转原理,掌握组合使用call和ret/retf编写汇编子程序的方法,掌握
参数传递方式
4. 理解标志寄存器的作用
5. 理解条件转移指令je, jz, ja, jb, jg, jl等的跳转原理,掌握组合使用汇编指令cmp和条件转移指令实
现分支和循环的用法
6. 了解在visual studio/Xcode等环境或利用gcc命令行参数反汇编c语言程序的方法,理解编译器生成
的反汇编代码
7. 综合应用寻址方式和汇编指令完成应用编程
二、实验内容与结论
1.实验任务1
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'
① 通过edit命令进入编辑器,录入代码。
② 在DOSBox中进行汇编(masm)、链接(link)并查看文件是否正确成功生成。
③ 运行生成的exe文件,验证结果。
④ 代码实现分析
- 首先是定义数据段,第一行定义了需要显示的字符,一共是16个字节;第二行定义了字符的颜色属性;第三行是通过80*25色彩模式下,计算中间行(应该是12、13和14行),得到字符开始的显示位置。
- 然后定义一个栈段,能够存储16个字节的数据。
- 在代码段中,首先通过ax寄存器将数据段的起始地址送给ds,将栈段的起始地址送给ss,将目标地址段的起始地址送给es。
- 在实现循环过程中,使用的是loop,其中一个重点是,为了避免因为cx的值共用对内外层循环造成影响,在进入另一层循环前,利用栈,先将cx的现值保存在栈中。
2.实验任务2
编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
① 通过edit命令进入编辑器,录入代码。
② 在DOSBox中进行汇编(masm)、链接(link)并查看文件是否正确成功生成。
③ 执行exe文件,验证输出。
④ 把line3改为:str 1 db 'another try', 0;把line12改为mov al, 4。重新汇编、链接执行观察结果。
⑤ 实验问题回答
- line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
- 避免局部的更改对算法造成影响,临时保存进行数据保护。
- line30的功能是什么?
- 将目标值存到目的地址中(最内部的es:di),又因为一个数据占两个字节(显示的字符和它的颜色属性值)每次偏移地址di需要加2。
3.实验任务3
使用任意文本编辑器,录入汇编源程序task3.asm。
- 子任务1
对task3.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编,使用g命令执行
到line15(程序退出之前),使用d命令查看数据段内容,观察是否把转换后的数字字符串'1984'存放
在数据段中str标号后面的单元。
- 子任务2
对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,
实现对转换后的字符串进行输出。
① 通过edit命令进入编辑器,录入代码。
② 在DOSBox中进行汇编(masm)、链接(link)并查看文件是否正确成功生成。
③ 使用debug对生成的exe文件进行调试。
- 使用u命令进行反汇编。
- 使用g命令执行到程序退出之前(INT 21)。
- 使用d命令查看str标号后的单元。
可以看到成功把转换后的数字字符串'1984'存放到数据段中str标号后面的单元中了。
④ 对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,实现对转换后的字符串进行输出。
- 补充代码:
首先在主程序中,将数字转换为数字字符串后,调用将字符串打印的子程序;
其中mov al,2是设置输出串颜色属性为实验要求中的绿色。
子程序间后三个截图。
- 测试结果:
成功完成。
⑤ 把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,观察结果。
4.试验任务4
录入汇编源程序task4.asm,结合运行结果,理解程序功能,了解软中断指令。
① 通过edit命令进入编辑器,录入代码。
② 在DOSBox中进行汇编(masm)、链接(link)并查看文件是否正确成功生成。
③ 执行exe文件,验证功能。
将测试字符串输入完毕后,将结束符‘#’输入,程序立刻将测试字符串打印出来了。
④ 实验问题回答
- line12-19实现的功能是?
- 键盘输入,并一‘#’作为输入结束的标志:
利用int 21h从键盘输入单个字符,然后通过cmp判断输入的字符是否为‘#’;
如果相等那么je指令就会跳转到next段,反之就会循环输入过程。
- line21-27实现的功能是?
- 实现输出:
首先读取si的值给cx,这本来是输入字符串存入的偏移地址,此时看做了字符串输入的个数,然后循环输出输入的值。
5.实验任务5
在visual studio集成环境中,编写一个简单的包含有函数调用的c程序;在line7, line13分别设置断点,在调试模式下,查看反汇编代码。分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,以及,参数入
栈顺序,返回值的带回方式,等等。
① 编写程序。
② 设置断点、反汇编并查看。
③ 分 析。
高级语言中参数传递和返回值在汇编语言中是通过栈,使用cal指令操作,使用eax、ebp等寄存器来实现的。
1.将函数参数入栈,第一个参数在栈顶,最后一个参数在栈底。
2.执行CALL指令,调用该函数,进入该函数代码空间。
2.1 执行CALL指令,将CALL指令下一行代码的地址入栈。
2.2 进入函数代码空间后,将基址指针EBP入栈,然后让基址指针EBP指向当前堆栈栈顶,并使用它访问存在堆栈中的函数输入参数及堆栈中的其他数据。
2.3 堆栈指针ESP减少一个值,如44H,向上移动一个距离,留出一个空间给该函数作为临时存储区。
{
// 以上准备工作做好后,函数正式被执行,如下所示。
2.3.1 将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
2.3.2 执行代码。
2.3.3 执行return()返回执行结果,将要返回的值存入EAX中。
2.3.4 步骤2.d中的指针出栈。
}
2.4 将EBP的值传给堆栈指针ESP,使ESP复原为2.c之前的值。此时进入函数时EBP的值在栈顶。
2.5 基址指针EBP出栈,复原为2.b之前的EBP的值。
2.6 执行RET指令,“调用函数”的地址出栈,本函数返回到CALL指令的下一行。
3.函数返回到CALL指令下一行,将堆栈指针加一个数值,以使堆栈指针恢复到以上步骤1执行之前的值。该数值是上面第一步入栈参数的总长度。
三、实验总结
-
本次实验时,我又遇到了一个新的问题,在进行masm汇编时,报错unable to open input file:原因是因为,asm文件的文件名过长。
-
子程序是在该程序中,其实现的功能会被重复使用到的一段程序。
-
call和ret、retf指令组合可以实现子程序的编写,执行时,对于ip或cs和ip的入栈/出栈操作,及跳转后目标地址的计算,都是由cpu自动完成的。
- OFFSET是将数值回送变量或标号的偏移地址值。
- 高级语言参数传递和返回值的实现间实验结论5中的分析。