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

一、实验目的

1、理解和掌握将数据、代码、栈放入不同逻辑段的程序的编写和调试

2、理解具有多个段的汇编源程序对应的目标程序执行时,内存分配方式

3、掌握大小写字符的转换方法、数字字符和数值之间的转换方法

4、理解并掌握各种寻址方式的灵活应用

5、掌握汇编指令loop,and,or,div,mul的用法

 

二、实验准备

复习教材chapter6-8章

chapter 6包含多个段的程序

chapter 7更灵活的定位内存地址的方法

chapter 8数据处理的两个基本问题

 

三、实验内容及结论

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 
 7 code segment
 8 start:
 9     mov ax, data
10     mov ds, ax
11 
12     mov ax, 0b800H
13     mov es, ax
14 
15     mov cx, 5            ;循环次数为5
16     mov si, 0            ;将0送给si
17     mov di, 0f00h        ;显存的起始地址
18 s:  mov al, [si]         ;将数据段中的前5个字节依次送给al
19     and al, 0dfh         ;将字母转换成大写
20     mov es:[di], al      ;转换后的大写字母存放到显存地址中
21     mov al, [5+si]       ;将数据段中的后5个字节依次送给al
22     mov es:[di+1], al    ;存放到显存地址中
23     inc si               ;数据段偏移地址加1
24     add di, 2            ;显存偏移地址加2
25     loop s               ;跳转
26 
27     mov ah, 4ch
28     int 21h
29 code ends
30 end start

阅读源程序,从理论上分析源代码的功能,尤其是line15-25,循坏实现的功能是什么,逐行理解每条指令的功能。

使用masm、link对task1.asm进行汇编、连接,得到可执行文件task1.exe,运行结果如下:

使用debug工具对程序进行调试,执行到程序返回前,即line27之前,得到如下结果:

 修改line4里5个字节单元的值,重新汇编、连接、运行,观察运行结果:

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

修改后的代码运行结果如下:

基于观察,分析、猜测源代码中data段line4的字节数据的用途是什么?

对比运行结果可以看出,修改后程序运行结果的后3个字母的颜色发生了改变,所以line4中的字节数据应该是用于控制字符的颜色的。

 

2、实验任务2

已知数据段data中定义字节数据如下:

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

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

 1 assume cs:code, ds:data
 2 data segment
 3     db 23, 50, 66, 71, 35
 4 data ends
 5 
 6 code segment
 7 start:
 8     mov ax,data
 9     mov ds,ax
10 
11     mov si,0
12     mov cx,5
13 
14 s:  mov ah,0
15     mov al,ds:[si]
16     mov bl,10
17     div bl
18     mov ds:[16+si],al
19     mov ds:[17+si],ah
20 
21     mov ah,2
22     mov dl,ds:[16+si]
23     add dl,48
24     int 21h
25 
26     mov ah,2
27     mov dl,ds:[17+si]
28     add dl,48
29     int 21h
30 
31     mov ah,2
32     mov dl,32
33     int 21h
34     
35     inc si
36     loop s
37 
38     mov ax,4c00h
39     int 21h
40 code ends
41 end start

汇编、连接之后的运行结果如下:

 

3、实验任务3

教材[实验5 编写、调试具有多个段的程序](1)

源代码:

 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段的数据为:23 01 56 04 89 07 BC 0A EF 0D ED 0F BA  0C 87 09

②CPU执行程序,程序返回前,cs= 076C ,ss= 076B ,ds=076A 

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

把上面的程序进行汇编、连接,并用debug工具进行调试:

将源程序进行反汇编,并使用g命令将程序执行到程序返回前,此时可以看到CS=076C,SS=076B,DS=076A。再用d命令查看data段中的数据,发现data段中的数据没有发生变化。

 

4、实验任务4

教材[实验5 编写、调试具有多个段的程序](2)

源程序:
 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 
26 code ends
27 end start

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

data段的数据为:23 01 56 04 00 00 00 00 00 00 00 00 00  00 00 00

②CPU执行程序,程序返回前,cs= 076C ,ss= 076B ,ds= 076A 

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

④对于如下定义的段:
name segment
…
name ends

如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 ⌈N/16⌉*16

一个段占有的实际空间总是16字节的整数倍,所以公式为段中数据的字节数除以16的向上取整,再乘以16。

将源程序汇编、连接以后,用debug工具进行调试。反汇编以后,用g命令执行到程序返回前,此时可以看到cs、ss和ds的值;再用d命令查看data段的数据,发现前4个字节的数据为data段中给出的数值,后面12个字节都为0,所以data段的实际占用空间还是16个字节。
 
 

5、实验任务5

教材[实验5 编写、调试具有多个段的程序](3)

源程序:

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

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

data段的数据为:23 01 56 04 00 00 00 00 00 00 00 00 00  00 00 00

②CPU执行程序,程序返回前,cs= 076A ,ss= 076E ,ds= 076D

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

将源程序汇编、连接以后,用debug工具进行调试。反汇编以后,用g命令执行到程序返回前,此时可以看到cs、ss和ds的值;再用d命令查看data段的数据:

 

6、实验任务6

教材[实验5 编写、调试具有多个段的程序](4)

如果将(1)、(2)、(3)题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。

分别将task3.asm、task4.asm及task5.asm中的最后一条伪指令“end start”改为“end”,重新汇编、连接,并用debug工具进行反汇编:

 从上面的结果可以看出,3个程序在汇编、连接时都没有报错,但前两个程序反汇编之后,得到的是一些杂乱的指令,只有第3个程序的反汇编结果与原来相同,且能够正确运行。

源程序最后一条伪指令“end start”实际上是指明了程序的入口,可执行文件被加载到内存中后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令。又因为标号“start”在“code”段中,所以CPU就会将code段中的内容当做指令来执行。

将源程序最后一条伪指令“end start”改为“end"之后,当可执行文件被加载到内存中时,就会自动将程序的首地址当做程序的入口。所以对于task3.asm和task4.asm来说,CS:IP指向了数据的首地址,数据段被反汇编以后,得到是杂乱的指令,无法正确执行。而task5.asm之所以能正确执行,只因为源程序将代码段放在了程序的开始,将数据段和栈段放在了后面,所以CS:IP仍是指向代码段的地址。

 

7、实验任务7

教材[实验5 编写、调试具有多个段的程序](5)

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

源程序:

 1 assume cs:code
 2 a segment
 3   db 1,2,3,4,5,6,7,8
 4 a ends
 5 
 6 b segment
 7   db 1,2,3,4,5,6,7,8
 8 b ends
 9 
10 c segment   
11   db 8 dup(0)
12 c ends
13 
14 code segment
15 start:
16     mov ax,a
17     mov ds,ax
18 
19     sub bx,bx
20     mov cx,8
21 
22 s:  mov ax,ds:[bx]
23     add ax,ds:[bx+16]
24     mov ds:[bx+32],ax
25     inc bx
26     loop s
27 
28     mov ax,4c00h
29     int 21h
30 code ends
31 end start

将以上源程序进行汇编、连接,并用debug工具进行调试。将程序反汇编之后,用g命令执行到程序返回之前:

然后用d命令查看数据段a、b、c中的内容,发现逻辑段c中的数据正好是逻辑段a和逻辑段b中对应数据的和,说明该程序编写正确。

 

8、实验任务8

教材[实验5 编写、调试具有多个段的程序](6)

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

源程序:

 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
 5 
 6 b segment
 7   dw 8 dup(0)
 8 b ends
 9 
10 code segment
11 start: 
12     mov ax,a
13     mov ds,ax
14 
15     mov ax,b
16     mov ss,ax
17     mov sp,16
18 
19     sub bx,bx
20     mov cx,8
21 
22 s:  push ds:[bx]
23     add bx,2
24     loop s
25 
26     mov ax,4c00h
27     int 21h
28 code ends
29 end start

将上面的源程序汇编、连接,并用debug工具调试,用u命令将源程序反汇编:

用g命令执行到程序返回之前,此时用d命令查看逻辑段b中的数据,发现逻辑段b中存放得是8到1,说明程序编写正确:

 

posted @ 2020-11-24 19:46  whr09  阅读(115)  评论(3编辑  收藏  举报