一、实验内容


 

1、实验任务1

编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'。

 1 assume cs:code,ds:data
 2 data segment
 3     db 'Welcome to masm!'
 4 data ends
 5 code segment
 6 start:
 7     mov ax,data
 8     mov ds,ax
 9     
10     mov ax,0b800h
11     mov es,ax
12 
13     mov si,0
14     mov di,0
15     mov ah,2
16     mov cx,16
17 s:
18     mov al,ds:[di]
19     mov es:[1824+si],ax
20     add si,2
21     inc di
22     loop s
23 
24     mov si,0
25     mov di,0
26     mov ah,24h
27     mov cx,16
28 
29 s1:
30     mov al,ds:[di]
31     mov es:[1824+si+160],ax
32     add si,2
33     inc di
34     loop s1
35 
36     mov si,0
37     mov di,0
38     mov ah,71h
39     mov cx,16
40 s2:
41     mov al,ds:[di]
42     mov es:[1824+si+320],ax
43     add si,2
44     inc di
45     loop s2
46 
47     mov ah,4ch
48     int 21h
49 
50 code ends
51 end start
  • 程序正确编写后,预期输出结果如下:

2、实验任务2

  • 编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
  • 子程序printSar
    • 功能:以指定颜色在屏幕上(从屏幕左上角开始)输出字符串
    • 要求:字符串以0结尾
    • 入口参数

      字符串的起始地址—> ds: si (其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si

      字符串颜色—> al

    • 出口参数:无
  • 使用任意文本编辑器,录入汇编源程序task42.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
  •  汇编、运行程序,观察运行结果。
  • 使用u命令对task42.exe 反汇编
  • -u 0 32

  • 实验运行结果

  • 对源程序做如下修改:
  • 把line3改为:
1 str db 'another try', 0
  • 把line12改为:
1 mov al, 4
  • 修改代码后汇编、运行程序
  • 实验结果如下

  基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在
line18-40中:

  • line19-22, line36-39,这组对称使用的push、pop,这样用的目的是什么?
    • 用于保护主程序中寄存器存放的数据不被修改。
    • line19-22在子程序执行之前将寄存器的数据保存至栈中,line36-39子程序执行结束前将寄存器的数据从栈中恢复。
  • line30的功能是什么?
    • 将数据送入显存单元,显示出对应颜色的符号,cx中ch对应颜色,cl值对应符号

3、实验任务3 

  • 使用任意文本编辑器,录入汇编源程序task43.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

  • 对task43.asm进行汇编、链接,得到可执行程序后,在debug中使用u命令反汇编

  • 使用g命令执行到line15(程序退出之前)

  • 使用d命令查看数据段内容,观察是否把转换后的数字字符串'1984'存放在数据段中str标号后面的单元。

  实验结果可以看出成功把转换后的数字字符串'1984'存放在数据段中str标号后面的单元。

二、子任务2

  • 对task43.asm源代码进行修改、完善,把task42.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, 4
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之间的任意数值,运行测试,观察结果。
  • 比如改为75后结果如下

4、实验任务4

  • 使用任意文本编辑器,录入汇编源程序task44.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
  • 汇编、链接、运行程序,输入一个字符串并以#结束观察运行结果如下。

  • 结合运行结果,理解程序功能,了解软中断指令。具体地:
    • mov ax,1  int 21h :从键盘输入单个字符,从键盘输入的字符保存在al中
    • mov ax,2  mov dl,[si]  int 21h :在屏幕上输出单个字符
    • 该程序的功能就是从键盘中输入一个字符串并以#结束,结果回显
  • line12-19实现的功能是?
    • 从键盘中读入字符,直到遇到‘#’结束
  • line21-27实现的功能是?
    • 回显出键盘输入的字符(‘#’除外)

5、实验任务5

  • 在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
 1 #include <stdio.h>
 2 int sum(int, int);
 3 int main() {
 4   int a = 2, b = 7, c;
 5   c = sum(a, b);
 6   return 0;
 7 }
 8 int sum(int x, int y) {
 9   return (x + y);
10 }
  • 在line5, line9分别设置断点,在调试模式下,查看反汇编代码。
 1 #include <stdio.h>
 2 int sum(int, int);
 3 int main() {
 4 011D1760  push        ebp  
 5 011D1761  mov         ebp,esp  
 6 011D1763  sub         esp,0E4h  
 7 011D1769  push        ebx  
 8 011D176A  push        esi  
 9 011D176B  push        edi  
10 011D176C  lea         edi,[ebp-0E4h]  
11 011D1772  mov         ecx,39h  
12 011D1777  mov         eax,0CCCCCCCCh  
13 011D177C  rep stos    dword ptr es:[edi]  
14 011D177E  mov         ecx,offset _F6BB13E8_源@cpp (011DC003h)  
15 011D1783  call        @__CheckForDebuggerJustMyCode@4 (011D1208h)  
16     int a = 2, b = 7, c;
17 011D1788  mov         dword ptr [a],2  
18 011D178F  mov         dword ptr [b],7  
19     c = sum(a, b);
20 011D1796  mov         eax,dword ptr [b]  
21 011D1799  push        eax  
22 011D179A  mov         ecx,dword ptr [a]  
23 011D179D  push        ecx  
24 011D179E  call        sum (011D107Dh)  
25 011D17A3  add         esp,8  
26 011D17A6  mov         dword ptr [c],eax  
27     return 0;
28 011D17A9  xor         eax,eax  
29 }
30 011D17AB  pop         edi  
31 011D17AC  pop         esi  
32 011D17AD  pop         ebx  
33 011D17AE  add         esp,0E4h  
34 011D17B4  cmp         ebp,esp  
35 011D17B6  call        __RTC_CheckEsp (011D1212h)  
36 011D17BB  mov         esp,ebp  
37 011D17BD  pop         ebp  
38 011D17BE  ret  
 1 int sum(int x, int y) {
 2 011D16F0  push        ebp  
 3 011D16F1  mov         ebp,esp  
 4 011D16F3  sub         esp,0C0h  
 5 011D16F9  push        ebx  
 6 011D16FA  push        esi  
 7 011D16FB  push        edi  
 8 011D16FC  lea         edi,[ebp-0C0h]  
 9 011D1702  mov         ecx,30h  
10 011D1707  mov         eax,0CCCCCCCCh  
11 011D170C  rep stos    dword ptr es:[edi]  
12 011D170E  mov         ecx,offset _F6BB13E8_源@cpp (011DC003h)  
13 011D1713  call        @__CheckForDebuggerJustMyCode@4 (011D1208h)  
14     return (x + y);
15 011D1718  mov         eax,dword ptr [x]  
16 011D171B  add         eax,dword ptr [y]  
17 }
18 011D171E  pop         edi  
19 011D171F  pop         esi  
20 011D1720  pop         ebx  
21 011D1721  add         esp,0C0h  
22 011D1727  cmp         ebp,esp  
23 011D1729  call        __RTC_CheckEsp (011D1212h)  
24 011D172E  mov         esp,ebp  
25 011D1730  pop         ebp  
26 011D1731  ret  

  • 分析反汇编代码,从汇编的角度,观察高级语言中参数传递和返回值是通过什么实现的,
  • 以及,参数入栈顺序,返回值的带回方式,等等。

  从汇编角度,高级语言中的参数传递用寄存器保存参数的值,同时从右到左依次压栈,依次压栈之后,

调用函数sum,跳到被调用函数sum地址去执行, 将寄存器eax中保存的函数sum的返回值赋值给c。

 

 posted on 2020-12-16 22:20  路远曦  阅读(178)  评论(0)    收藏  举报