一、实验目的
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
教材「实验9 根据材料编程」(P187-189)
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。
源程序:
1 assume cs:code 2 data segment 3 db 'welcome to masm!' 4 db 02h,24h,71h ; 要求的三个颜色对应的16进制代码 5 data ends 6 stack segment 7 db 16 dup(0) 8 stack ends 9 code segment 10 start: 11 ; 设置data段,以及ds:bx指向data段的第一个单元, 12 ; 即ds:[bx]的内容就是data段第一个单元的内容 13 mov ax,data 14 mov ds,ax 15 16 mov ax,0b800h ;设置起始缓存 17 mov es,ax 18 19 mov ax,stack 20 mov ss,ax 21 mov sp,10h ;指向栈顶 22 23 mov bx,780h ; 行 从12-14(注意:从第1行开始计数) 24 mov si,10h ; 颜色的偏移量,三次循环每次 25 ; 增加 1h 指向下一个颜色 26 27 mov cx,3 ; 三次循环改变行 28 s: mov ah,ds:[si] ;颜色事先存放在ah中 29 push cx 30 push si 31 32 mov cx,16 ; 16次循环改变列 33 mov si,64 34 mov di,0 35 36 s0: mov al,ds:[di] ;将date段中的字符一个一个传入es中 37 mov es:[bx+si],al ; 低位存放字符 38 mov es:[bx+si+1],ah ; 高位存放颜色 39 40 add si,2 ;显示缓存区字符ASCII码偏移量为2 41 add di,1 ;data段字符的偏移量,每次加 1 42 43 loop s0 44 45 pop si 46 pop cx ;后进先出,先出栈si,再出栈cx 47 48 add si,1h ;指向下一个颜色 49 add bx,0a0h ;指向下一行 160=0a0h 50 loop s 51 52 mov ax,4c00h 53 int 21h 54 code ends 55 end start
mov si,64 从64开始是因为:(1)字符串为32字节,16字节ASCLL码,16字节属性
(2)每一行有160列,那么余下有 160-32=128列为空白,要使得字符串居中显示,那么字符串的左边
右边,都应该是64字节(128/2),而列数是从0开始计数,所以左边的64字节为0-63,所以这里偏移量
为64。
汇编、链接、执行后实验结果:
2.实验任务2
编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
使用任意文本编辑器,录入汇编源程序task2.asm。
1 assume cs:code, ds:data 2 data segment 3 str db 'try', 0 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 11 mov si, offset str 12 mov al, 2 13 call printStr 14 15 mov ah, 4ch 16 int 21h 17 18 printStr: 19 push bx 20 push cx 21 push si 22 push di 23 24 mov bx, 0b800H 25 mov es, bx 26 mov di, 0 27 s: mov cl, [si] 28 mov ch, 0 29 jcxz over 30 mov ch, al 31 mov es:[di], cx 32 inc si 33 add di, 2 34 jmp s 35 36 over: pop di 37 pop si 38 pop cx 39 pop bx 40 ret 41 42 code ends 43 end start
汇编、链接、运行程序,观察运行结果:
对源程序做如下修改:
把line3改为:
str db 'another try', 0
把line12改为:
mov al, 4
再次汇编、运行程序,观察运行结果:
基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在line18-40中:
line19-22, line36-39,这组对称使用的push、pop,目的是保护和恢复各寄存器的值,可以更好的利用寄存器空间。
line30的功能是读取目标数据存入es,将cx中存放的字符及其颜色属性送入显存中,实现在屏幕上的显示。
3.实验任务3
使用任意文本编辑器,录入汇编源程序task3.asm。
子任务1
对task3.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编,使用g命令执行
到line15(程序退出之前),使用d命令查看数据段内容,观察是否把转换后的数字字符串'1984'存放
在数据段中str标号后面的单元。
观察发现成功把转换后的数字字符串‘1984’存放在数据段中str标号后面的单元。
子任务2
对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,
实现对转换后的字符串进行输出。
源代码:
1 assume cs:code, ds:data 2 data segment 3 x dw 1984 4 str db 16 dup(0) 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov ax, x 12 mov di, offset str 13 call num2str 14 15 mov si, offset str 16 mov al, 2 17 call printStr 18 19 mov ah, 4ch 20 int 21h 21 22 num2str: 23 push ax 24 push bx 25 push cx 26 push dx 27 28 mov cx, 0 29 mov bl, 10 30 s1: 31 div bl 32 inc cx 33 mov dl, ah 34 push dx 35 mov ah, 0 36 cmp al, 0 37 jne s1 38 s2: 39 pop dx 40 or dl, 30h 41 mov [di], dl 42 inc di 43 loop s2 44 45 pop dx 46 pop cx 47 pop bx 48 pop ax 49 50 ret 51 52 printStr: 53 push bx 54 push cx 55 push si 56 push di 57 58 mov bx, 0b800H 59 mov es, bx 60 mov di, 0 61 s: mov cl, [si] 62 mov ch, 0 63 jcxz over 64 mov ch, al 65 mov es:[di], cx 66 inc si 67 add di, 2 68 jmp s 69 70 over: pop di 71 pop si 72 pop cx 73 pop bx 74 ret 75 76 code ends 77 end start
把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,观察结果。
把line3中整数改为1314:
4.实验任务4
使用任意文本编辑器,录入汇编源程序task4.asm。
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 12 s1: 13 mov ah, 1 14 int 21h 15 mov [si], al 16 cmp al, '#' 17 je next 18 inc si 19 jmp s1 20 next: 21 mov cx, si 22 mov si, 0 23 s2: mov ah, 2 24 mov dl, [si] 25 int 21h 26 inc si 27 loop s2 28 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
汇编、链接、运行程序,输入一个字符串并以#结束(比如,2020, bye#)观察运行结果。
结合运行结果,理解程序功能,了解软中断指令。具体地:
line12-19实现的功能是:通过中断转移指令和条件跳转指令,从键盘中读取字符存入指定内存单元,直到遇到'#'结束。
line21-27实现的功能是:通过循环指令,依次输出保存在栈内的字符。
5.实验任务5
在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
1 #include <stdio.h> 2 int sum(int, int); 3 4 int main() { 5 int a = 2, b = 7, c; 6 7 c = sum(a, b); 8 9 return 0; 10 } 11 12 int sum(int x, int y) { 13 return (x + y); 14 }
在line7, line13分别设置断点:
在调试模式下,查看反汇编代码:
分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,以及,参数入栈顺序,返回值的带回方式,等等。
高级语言中参数传递和返回值都是通过栈实现的,数据从ptr [a]、ptr [b]传入eax、ecx等寄存器。
调用函数时,形参参数入栈自右向左。先借助寄存器,将参数b 的地址压入堆栈寄存器eax,再将参数a 的值压入堆栈寄存器ecx。
用call命令调用sum函数,最后返回真正的值为eax,再传入双字数据ptr[c],函数的返回值放在eax寄存器中,