实验4 汇编应用编程和c语言程序反汇编分析

一、实验目的
  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!'。
  tips:
  这道编程练习需要考虑的两个关键问题:
  (1)屏幕中间对应的显存位置的计算 —— 第×行第×列对应的显存地址单元
  (2)字符串颜色属性的设置
  上述两个问题,请参考教材188-189或第9章课件,内有:
  80×25彩色字符模式显示缓冲区结构说明
  字符属性字节的设置依据
  字符串及其颜色属性信息,可以提前定义在数据段中。
  要显示字符串,本质上,就是把字符及其颜色属性信息,复制到相应的显存空间,借助寻址方式和循环实现。附: 本练习中显示字符串所对应的显存空间偏移地址
  80×25的彩色字符模式,即一屏25行80列。
  每一行显示一个字符需要两个字节(低位字节存放字符的ASCⅡ码值,高位字节存放字符的显示属性),一共160个字节。
  默认,在显存第0列显示时,对应的显存空间为B8000H ~ B8F9FH。如果以B800H作为段地址,
  则一屏25行对应的偏移地址如下。请据此计算出屏幕中间位置对应的显存地址。
 1 assume cs:code, ds:data, ss:stack
 2 
 3 data segment
 4     db 'welcome to masm!' 
 5     db 02H, 24H, 71H
 6     dw 0720H, 07C0H, 0860H    ;11*160+64,12*160+64,13*160+64
 7 data ends
 8 
 9 stack segment 
10     dw 8 dup(0)
11 stack ends
12 
13 code segment
14 start:
15     mov ax, stacksg
16     mov ss, ax      
17     mov sp, 16
18 
19     mov ax, datasg 
20     mov ds, ax
21 
22     mov ax, 0B800H
23     mov es, ax
24 
25     mov cx, 3       ;外循环循环三次
26     mov bx, 16     ; 颜色从数据段的16个字节开始
27     mov di, 32      ; 显示位置从数据段的32个字节开始
28 
29 s0: push cx     
30     mov cx, 16      ;内循环循环16次
31     mov bp, [di]    
32     mov si, 0
33 
34 s1: 
35     mov al, [si]        ; 低位字节写存储字符的ASCII码
36     mov ah, [bx]      ; 高位字节写存储字符的属性
37     mov es:[bp], ax
38 
39     inc bp
40     inc bp          ; 1个字符占用的是2个字节,需要+2
41     inc si          ; 下一个显示的字符
42     loop s1
43 
44     pop cx
45     add bx, 1       ; 使用下一个颜色
46     add di, 2       ; 下一个显示字符开始位置
47     loop s0
48 
49     mov ax, 4c00H
50     int 21H
51 
52 code ends
53 end start

分析:

  在80*25彩色字符模式下,显示器可以显示25行,那么中间位置设置为11,12,13行来显示字符串。又因为每行80个字符,目标字符串16个字符,所以每行的开始位置设置成从第32个字符开始,又因为每个字符占用2个字节,所以计算字符位置时要在每行的初始位置上再加上64。

  计算显示字符的位置:(第一行)11*160+64=1824==>07C0H(第二行)12*160+64=1984==>07C0H(第三行)13*160+64=2144==>0860H

  根据书上属性字节的格式可以按位设置属性字节,配出各种不同的前景色和背景色:

    黑底绿字:0000 0010B==>02H   绿底红字:0010 0100B==>24H   白底蓝字:0111 0001B==>71H

  cx:参与内外循环,bx:颜色在数据段的索引,di:每行开始位置在数据段的索引,si:字符在数据段的索引,bp:每个字符具体的显示位置,al:存储字符   ASCII码,ah:存储字符的属性。

  运用两层循环解决问题。

运行结果:

  2. 实验任务2
  编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
  子程序printSar
    功能:以指定颜色在屏幕上(从屏幕左上角开始)输出字符串
    要求:字符串以0结尾
    入口参数
      字符串的起始地址—> ds: si (其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si字符串颜色—> al
    出口参数:无 
  使用任意文本编辑器,录入汇编源程序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                 ;设置入口参数ds
10 
11     mov si, offset str       ;设置入口参数si
12     mov al, 2                    ;设置入口参数al
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改为: 1 str db 'another try', 0 
  把line12改为:  1 mov al, 4 
基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在line18-40中:
  • line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
  答:用于保存和恢复寄存器的值。在用寄存器前先将寄存器的值入栈,保留原本寄存器的内容,使用完后出栈恢复寄存器里的内容,防止出现意外情况。
  • line30 mov ch, al 的功能是什么?
   答:将属性写入显存空间。
3. 实验任务3
使用任意文本编辑器,录入汇编源程序task3.asm。
  子程序num2str:
    功能:把0~2559之间的任意整数转换成数字字符串,例如,把1984转换成'1984'
    入口参数
      要转换的整数 —> ax
    数字字符串的起始地址 —> ds:di (其中:数字字符串所在段的段地址—> ds,字符串起始地址的偏移地址—>di)
    出口参数:无 
 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 ah, 4ch
16         int 21h
17 
18 num2str:
19         push ax
20         push bx
21         push cx
22         push dx
23         
24         mov cx, 0
25         mov bl, 10
26 s1:      
27         div bl
28         inc cx
29         mov dl, ah
30         push dx
31         mov ah, 0
32         cmp al, 0
33         jne s1
34 s2:        
35         pop dx
36         or dl, 30h
37         mov [di], dl
38         inc di
39         loop s2
40         
41         pop dx
42         pop cx
43         pop bx
44         pop ax
45 
46         ret
47 code ends
48 end start
阅读源代码,理解子程序num2str的汇编实现。
  • 子任务1
  对task3.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编,使用g命令执行到line15(程序退出之前),使用d命令查看数据段内容,观察是否把转换后的数字字符串'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         mov si, offset str
15         call printfstr        
16 
17         mov ah, 4ch
18         int 21h
19 
20 num2str:
21         push ax
22         push bx
23         push cx
24         push dx
25         
26         mov cx, 0
27         mov bl, 10
28 s1:      
29         div bl
30         inc cx
31         mov dl, ah
32         push dx
33         mov ah, 0
34         cmp al, 0
35         jne s1
36 s2:        
37         pop dx
38         or dl, 30h
39         mov [di], dl
40         inc di
41         loop s2
42         
43         pop dx
44         pop cx
45         pop bx
46         pop ax
47 
48         ret
49 
50 printfstr:
51     push ax
52     push bx
53     push cx
54     push si
55     push di
56     
57     mov ax,2
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     pop ax
75     ret
76 code ends
77 end start
  把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,观察结果 
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实现的功能是?
  答: mov ah, 1 是功能号,表示键盘输入并回显al(输入字符), int 21h 表中断。line12-19实现的功能是循环读入,直到遇到‘#’跳转到next。
  • line21-27实现的功能是? 
  答:使用 int 21h 的二号子功能,实现字符的输出。line21-27利用循环和int 21h的二号子功能实现了刚才输入字符的输出。
附:task4.asm中用到的两个系统功能调用
  • int 21h中的1号子功能
  功能:从键盘输入单个字符
  用法:
1 mov ah, 1 
2 int 21h ; 出口参数为al, 从键盘输入的字符保存在al中
  • int 21h中的2号子功能
  功能:从键盘输入单个字符
  用法:
1 mov ah, 2 
2 mov dl, ; ××是待输出的字符,或其ASCⅡ码值 
3 int 21h
5. 实验任务5
  在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
 1 #include <stdio.h>
 2 int sum(int, int); 
 3 int main() 
 4 {
 5      int a = 2, b = 7, c; 
 6     c = sum(a, b); 
 7     return 0; 
 8 }
 9 int sum(int x, int y) 
10 { 
11     return (x + y); 
12 }
在line7, line13分别设置断点,在调试模式下,查看反汇编代码。
  分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,以及,参数入栈顺序,返回值的带回方式,等等。
 

 

  c = sum(a, b);
00DF13AC mov eax,dword ptr [b]    // 把内存地址b中的双字型数据赋给eax
00DF13AF push eax                         //将eax入栈
00DF13B0 mov ecx,dword ptr [a]
00DF13B3 push ecx
00DF13B4 call sum (0DF1055h)    // 通过call指令调用函数sum
00DF13B9 add esp,8
00DF13BC mov dword ptr [c],eax   // 将结果存放在c中

  return (x + y);
00DF140E mov eax,dword ptr [x]     
00DF1411 add eax,dword ptr [y]       //  x,y相加后赋值给eax

posted @ 2020-12-17 20:08  GTOTHED  阅读(90)  评论(1编辑  收藏  举报