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

1. 实验任务1

教材「实验9 根据材料编程」(P187-189)
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。
此部分书写内容:
源程序如下:
 1 assume cs:code,ds:data
 2 data segment
 3     db 'welcome to masm!'    ;
 4     db 00000010B    ;
 5     db 00100100B    ;
 6     db 01110001B    ;
 7 data ends
 8 code segment
 9 start:mov ax,data
10         mov ds,ax
11 
12         mov ax,0b800h
13         mov es,ax    
14 
15         mov si,0        ;
16         mov di,160*11 + 64    ;
17         mov bx,16    ;
18         mov dx,0
19 
20         mov cx,3        ;
21 showMasm:    push bx
22         push cx
23         push si
24         push di
25 
26         mov cx,16    ;
27         mov dh,ds:[bx]    ;
28 
29 showRow:    mov dl,ds:[si]    ;
30         mov es:[di],dx    ;
31         add di,2        ;
32         inc si        ;
33         loop showRow
34 
35         pop di
36         pop si
37         pop cx
38         pop bx
39         add di,160    ;
40         inc bx        ;
41         loop showMasm
42 
43         mov ax,4c00h
44         int 21h
45 code ends
46 end start

代码思路:

        首先确认放入显存中的数据列是welcome to masm!同时要注意到底色和字体颜色的表示,从教材189页和课件的内容可以推出黑底绿字为:00000010B;绿底红字为:00100100B;白底蓝字为:01110001B。

  由(25-3)/2 = 11 可知从第12行开始显示的三行正好是中间行,由于每行160个字节,第12行起始位置的偏移地址是160*11,即:十进制偏移地址为1760~1919。由(160-16*2)/2 = 64 可知每行从第65个字符开始显示在每一行的中间,所以第一行第一个字母的偏移地址为160*11 + 64,即起始位置十进制偏移地址为1824(十六进制720),所以可以确定写入的起始段地址为B8720。接下来的部分就是借用双重循环将数据扫描式写入显存空间。在进入内层循环前用push指令暂存各个寄存器中的数据,其内层循环结束后用pop指令恢复,继续执行外层循环。

运行结果截图:

2. 实验任务2

编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
附上源程序:
 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
再次汇编、运行程序,观察运行结果。
回答任务2中提出的两个问题
基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在
line18-40中:
line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
答:在运行子程序前先将寄存器bx,cx,si,di中的值保存起来,最后在子程序运行结束后恢复,这有效防止数据的丢失
line30的功能是什么?
答:将cx中存放的含有黑底绿字属性的字符写入显存中,在屏幕上的显示。

3. 实验任务3

使用任意文本编辑器,录入汇编源程序task3.asm。
代码如下:
 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
附上子任务1的反汇编截图

 

附上子任务2修改、完善后的完整汇编源代码,及,运行测试截图
代码如下:
 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

运行测试截图:

4. 实验任务4

此部分书写内容:
程序源代码:
 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
运行测试截图:
回答任务中提出的两个问题
line12-19实现的功能是?
答:从键盘读取输入的字符,并判断字符是否为#,若不为#,则保存到ds中,若出现#则继续执行后面的程序。
line21-27实现的功能是?
答:将保存在ds中的字符输出在屏幕上。

5. 实验任务5

此部分书写内容:
总结对这个简单的c代码反汇编后,你对反汇编出来的汇编指令分析的内容总结。可以包括但不限于一
下内容的总结:
比如,高级语言中参数传递,从汇编的角度是如何传递的,返回值是如何返回的;多个参数的入栈顺序
是什么样的;函数调用栈,等等。

------------恢复内容开始------------

1. 实验任务1

教材「实验9 根据材料编程」(P187-189)
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。
此部分书写内容:
源程序如下:
 1 assume cs:code,ds:data
 2 data segment
 3     db 'welcome to masm!'    ;
 4     db 00000010B    ;
 5     db 00100100B    ;
 6     db 01110001B    ;
 7 data ends
 8 code segment
 9 start:mov ax,data
10         mov ds,ax
11 
12         mov ax,0b800h
13         mov es,ax    
14 
15         mov si,0        ;
16         mov di,160*11 + 64    ;
17         mov bx,16    ;
18         mov dx,0
19 
20         mov cx,3        ;
21 showMasm:    push bx
22         push cx
23         push si
24         push di
25 
26         mov cx,16    ;
27         mov dh,ds:[bx]    ;
28 
29 showRow:    mov dl,ds:[si]    ;
30         mov es:[di],dx    ;
31         add di,2        ;
32         inc si        ;
33         loop showRow
34 
35         pop di
36         pop si
37         pop cx
38         pop bx
39         add di,160    ;
40         inc bx        ;
41         loop showMasm
42 
43         mov ax,4c00h
44         int 21h
45 code ends
46 end start

代码思路:

        首先确认放入显存中的数据列是welcome to masm!同时要注意到底色和字体颜色的表示,从教材189页和课件的内容可以推出黑底绿字为:00000010B;绿底红字为:00100100B;白底蓝字为:01110001B。

  由(25-3)/2 = 11 可知从第12行开始显示的三行正好是中间行,由于每行160个字节,第12行起始位置的偏移地址是160*11,即:十进制偏移地址为1760~1919。由(160-16*2)/2 = 64 可知每行从第65个字符开始显示在每一行的中间,所以第一行第一个字母的偏移地址为160*11 + 64,即起始位置十进制偏移地址为1824(十六进制720),所以可以确定写入的起始段地址为B8720。接下来的部分就是借用双重循环将数据扫描式写入显存空间。在进入内层循环前用push指令暂存各个寄存器中的数据,其内层循环结束后用pop指令恢复,继续执行外层循环。

运行结果截图:

2. 实验任务2

编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
附上源程序:
 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
再次汇编、运行程序,观察运行结果。
回答任务2中提出的两个问题
基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在
line18-40中:
line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
答:在运行子程序前先将寄存器bx,cx,si,di中的值保存起来,最后在子程序运行结束后恢复,这有效防止数据的丢失
line30的功能是什么?
答:将cx中存放的含有黑底绿字属性的字符写入显存中,在屏幕上的显示。

3. 实验任务3

使用任意文本编辑器,录入汇编源程序task3.asm。
代码如下:
 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
附上子任务1的反汇编截图

 

附上子任务2修改、完善后的完整汇编源代码,及,运行测试截图
代码如下:
 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

运行测试截图:

4. 实验任务4

此部分书写内容:
程序源代码:
 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
运行测试截图:
回答任务中提出的两个问题
line12-19实现的功能是?
答:从键盘读取输入的字符,并判断字符是否为#,若不为#,则保存到ds中,若出现#则继续执行后面的程序。
line21-27实现的功能是?
答:将保存在ds中的字符输出在屏幕上。

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分别设置断点,在调试模式下,查看反汇编代码。
 
在调试模式下查看反汇编代码:

 

总结对这个简单的c代码反汇编后,你对反汇编出来的汇编指令分析的内容总结。可以包括但不限于一下内容的总结:
        从高级语言的层面看,引用是实参的别名,所以对形参的修改就是直接对实参的改变。引用是变量的地址,可以理解为一个常指针,也就是指向固定的指针,但是与指针还是有区别的,具体使用的时候不同,并且引用于指针有很多不同,引用必须初始化,但是指针可以定义的时候不初始化,另外指针可以指向空NULL,这一方面引用比指针更安全,但是引用还是存在风险的只是风险小一点而已。
       从汇编底层代码的层面看,如果将函数传参的传指针和传引用的方式的函数分别生成汇编代码发现,是一模一样的,主调函数的传参的汇编代码也是一模一样的,所以从底层汇编代码看,传引用就是通过传指针实现的。汇编代码都是通过lea取地址和mov把取到的地址放到一块内存中。
posted @ 2020-12-18 10:56  Winnie77  阅读(184)  评论(3)    收藏  举报