四个太阳

导航

实验3 多个段的汇编源程序编写与调试

一、实验结论

1.实验任务1

使用任意文本编辑器,录入汇编源程序task1.asm,如下:

 1 assume cs:code, ds:data
 2 data segment
 3     db 'Nuist'
 4     db 5 dup(2)
 5 data ends
 6 code segment
 7 start:
 8     mov ax, data
 9     mov ds, ax
10     mov ax, 0b800H
11     mov es, ax
12     mov cx, 5
13     mov si, 0
14     mov di, 0f00h
15 s:  mov al, [si]
16     and al, 0dfh
17     mov es:[di], al
18     mov al, [5+si]
19     mov es:[di+1], al
20     inc si
21     add di, 2
22     loop s
23     mov ah, 4ch
24     int 21h
25 code ends
26 end start

使用masm、link对task1.asm进行汇编、链接,得到可执行文件task1.exe,运行效果如下图所示:

使用debug工具对程序进行调试,执行到程序返回前,即line23之前,观察的结果如下图所示:

修改line4里5个字节单元的值,重新汇编、链接、运行,观察的结果如下图所示:

1 db 5 dup(2)
2 --> 改成:
3 db 2,3,4,5,6

问题:基于观察,分析、猜测这里的数值作用是什么?

答:为了便于描述我把源代码中的数据段分成两个小的数据段一个是①db 'Nuist',另外一个是②db 2,3,4,5,6。从代码的一次循环所完成功能来看,首先是将

数据段①中的第一个字节数据也即'N'取出,然后让'N'与0dfh做按位与操作,其目的是让所有的小写字符全部转换为大写字符,而对大写字符无影响。接下来

将转换为大写字符的'N'写入一个字节到显存b8f0h:0的地址空间,之后立马取出数据段②的第一个字节数据(即2)写入一个字节到显存b8f0h:1的地址空间中,

最后进入到下一次循环。从上一个实验二我们已经知道了显存空间是以何种方式组织的:高位字节存储的是字符的颜色,低位字节存储的是字符的二进制表示。

所以数据段①的作用即为存储所有的可显示字符ASCII码的二进制表示,数据段②的作用即为存储对应各个字符的颜色信息。

2.实验任务2
实验任务:已知数据段data中定义字节数据如下:

1 data segments
2     db 23, 50, 66, 71, 35
3 data ends

编写程序,在屏幕上以十进制整数形式打印输出这5个两位数

解答:使用任意文本编辑器,录入汇编源程序task2.asm,内容如下:

 1 ;编写程序,在屏幕上以十进制整数形式打印输出这5个两位数。
 2 ;48为'0',解决办法or 110000,or 30
 3 assume cs:code, ds:data, ss:stack
 4 data segment
 5 db 23, 50, 66, 71, 35
 6 data ends;0~fh全部分配给他了
 7 stack segment
 8 db 16 dup(0)
 9 stack ends;10~1f全部分配给它了
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14     mov ax, stack
15     mov ss, ax
16     mov sp, 10h
17     mov si, 0;间接寻址
18     mov di, 10;除数
19     mov cx, 5;一共循环5次
20 s:  mov dx, 0
21     mov ax, dx;dx:ax全部置零
22     mov al, ds:[si];取出数据段的一个字节数据
23     div di;dx:ax / di然后将商(即十位)放入ax寄存器,将余数(即个位)放入dx寄存器
24     push dx;先将运算出来的个位用栈暂存,因为我们需要使用dx寄存器打印十位上的字符
25     mov dx, ax;将十位上的数字赋值给dx寄存器
26     or dl, 30h;将十位上的数字转换为数字字符
27     mov ah, 2
28     int 21h;启动int 21的2号子功能
29     pop dx;将个位数字取出
30     or dl, 30h;将个位上的数字转换为数字字符
31     int 21h;启动int 21的2号子功能
32     inc si;下一个字节数据
33     loop s
34     mov ah, 4ch
35     int 21h
36 code ends
37 end start

使用masm、link对task1.asm进行汇编、链接,得到可执行文件task1.exe,运行效果如下图所示:

 使用debug对程序task2.exe做进一步的了解,如下图所示:

代码的思路解释:首先要解决十进制数字到十进制数字字符的ASCII值的映射关系,根据ASCII码表中数字字符零'0'的ASCII码值转换为二进制表示为110000

而十进制数字字符'1'的ASCII码值转换为二进制表示为110001,后面字符以此类推,所以我们只需要让数字1与110000做按位或运算即可获得对应的数字字符。

关于各行代码所完成的功能已经在源码中有所体现。

3.实验任务3

使用任意文本编辑器,录入汇编源程序task3.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0, 0, 0, 0, 0, 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start

回答问题:

①CPU执行程序,程序返回前,data数据段中的数据为多少?

答:从源程序代码来看,此代码所完成的功能:将data数据段的第一个字数据和第二个字数据自己给自己赋值,其他数据保持不变,所以data数据段中的数据为:

  0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h

利用debug调试task3.exe,然后使用d命令查看程序退出之前data段的数据是否和理论分析一致:

②CPU执行程序,程序返回前,根据上图显示,cs=0CCDH,ss=0CCCH,ds=0CCBH

③设程序加载后,code段的段地址为X,则data段的段地址为X - 2H,satck段的段地址为X - 1H
4.实验任务4

使用任意文本编辑器,录入汇编源程序task4.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 code ends
26 end start

回答问题:

①CPU执行程序,程序返回前,data段中的数据为多少?

答:从源程序代码来看,此代码所完成的功能:将data数据段的第一个字数据和第二个字数据自己给自己赋值,其他数据保持不变,所以data数据段中的数据为:

  0123h, 0456h, 0h, 0h, 0h, 0h, 0h, 0h

利用debug调试task4.exe,然后使用d命令查看程序退出之前data段的数据是否和理论分析一致:

②CPU执行程序,程序返回前,根据上图显示,cs=0CCDH,ss=0CCCH,ds=0CCBH

③设程序加载后,code段的段地址为X,则data段的段地址为X - 2H,satck段的段地址为X - 1H

④对于如下定义的段:

1 name segment
2   ......
3 name segment

如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 N % 16 == 0? N: (N / 16 + 1) * 16。至于原因:操作系统为程序分配的数据单元最小为16个字节。

5.实验任务5

使用任意文本编辑器,录入汇编源程序task5.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 code segment
 3 start:  mov ax,stack
 4         mov ss, ax
 5         mov sp,16
 6         
 7         mov ax, data
 8         mov ds, ax
 9         
10         push ds:[0]
11         push ds:[2]
12         pop ds:[2]
13         pop ds:[0]
14         
15         mov ax,4c00h
16         int 21h
17 
18 code ends
19 data segment
20   dw 0123h, 0456h
21 data ends
22 stack segment
23   dw 0,0
24 stack ends
25 end start

回答问题:

①CPU执行程序,程序返回前,data段中的数据为多少?

答:从源程序代码来看,此代码所完成的功能:将data数据段的第一个字数据和第二个字数据自己给自己赋值,其他数据保持不变,所以data数据段中的数据为:

  0123h, 0456h, 0h, 0h, 0h, 0h, 0h, 0h

利用debug调试task5.exe,然后使用d命令查看程序退出之前data段的数据是否和理论分析一致:

②CPU执行程序,程序返回前,根据上图显示,cs=0CCBH,ss=0CCFH,ds=0CCEH

③设程序加载后,code段的段地址为X,则data段的段地址为X + 3H,satck段的段地址为X + 4H

6.实验任务6

实验任务:如果将实验任务3、4、5中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明理由。

答:如果不显示地指明程序的入口,那么只有实验任务5的代码仍会正确执行。究其原因,Debug总是把我们编写的汇编代码(已经汇编成机器码)顺序地加载进

内存并将CS:IP指向我们编写代码段的入口,当然如果没有显示地指明程序入口,默认会指向所编写汇编代码的第一行指令。正是由于此原因,实验任务3、4中代

码的第一行指令并不是属于代码段,而是属于数据段,但是由于没有明确地指明程序入口,致使CPU误把数据段的内容作为代码来执行了,所以导致程序无法运行

我们所编写的代码段。同时,由于实验任务5的源代码虽然没有明确指明代码段的实际入口,但是代码段始终都放在汇编代码的第一行,这样CPU也能正确运行我

们编写的代码段。为了验证以上理论分析,下面分别对三个程序进行debug调试对比,如下图所示:

 

 

 

7.实验任务7

实验任务:编写code段中的代码,将a段和b段中的数据依次相加,将结果存到c段中。

解答:使用任意文本编辑器,录入汇编源程序task6.asm,内容如下:

 1 assume cs:code
 2 a segment
 3     db 1,2,3,4,5,6,7,8
 4 a ends
 5 b segment
 6     db 1,2,3,4,5,6,7,8
 7 b ends
 8 c segment 
 9     db 8 dup(0)
10 c ends
11 code segment
12 start:
13     mov ax, a
14     mov ds, ax;数据从哪里来
15     mov bx, 0;间接寻址
16     mov si, 10h;数据段b的间接寻址
17     mov ax, c
18     mov es, ax;数据到哪里去
19     mov cx, 8;循环8次
20 s:    mov al, ds:[bx];取出数据段a的一个字节数据
21     add al, ds:[bx+si];取出数据段b的一个字节数据并与数据段a的字节数据求和
22     mov es:[bx], al;将求和结果放到数据段c当中
23     inc bx
24     loop s
25     mov ah, 4ch
26     int 21h
27 code ends
28 end start

使用debug对task6.exe进行调试,测试代码是否完成实验任务要求,如下图所示:

8.实验任务8

实验任务:编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存放到b段中。

解答:使用任意文本编辑器,录入汇编源程序task7.asm,内容如下:

 1 assume cs:code
 2 a segment
 3     dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
 4 a ends;一共32个字节0~1fh
 5 b segment
 6     dw 8 dup(0)
 7 b ends;一共16个字节20~2fh
 8 code segment
 9 start: 
10     mov ax, a
11     mov ds, ax;数据从哪里来
12     mov ax, b
13     mov es, ax;数据到哪里去
14     mov bx, 0;数据段a间接寻址
15     mov si, 0eh;数据段b间接寻址
16     mov cx, 8;循环执行次数
17 s:    push ds:[bx];将数据段a的一个字数据入栈
18     pop es:[si];将刚入栈的字数据出栈到数据段b
19     add bx, 2
20     sub si, 2
21     loop s
22     mov ah, 4ch
23     int 21h
24 code ends
25 end start

使用debug对task7.exe进行调试,测试代码是否完成实验任务要求,如下图所示:

posted on 2020-11-22 21:05  四个太阳  阅读(218)  评论(0)    收藏  举报