实验2 多个逻辑段的汇编源程序编写与调试

一、实验目的

1. 理解和掌握8086多个逻辑段的汇编源程序

2. 理解和熟练应用灵活的寻址方式

3. 通过汇编指令loop的使用理解编程语言中循环的本质,掌握其在嵌套循环中的正确使用

4. 掌握使用debug调试8086汇编程序的方法

 

二、实验准备

复习教材5-8章: 包含多个逻辑段的汇编源程序结构 寻址方式 汇编指令loop, div用法

 

三、实验内容

 1.实验任务1

  任务1-1:

  task1_1.asm源码如下:

 1 assume ds:data, cs:code, ss:stack
 2 
 3 data segment
 4     db 16 dup(0)
 5 data ends
 6 
 7 stack segment
 8     db 16 dup(0)
 9 stack ends
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14 
15     mov ax, stack
16     mov ss, ax
17     mov sp, 16
18 
19     mov ah, 4ch
20     int 21h
21 code ends
22 end start

 

  1. 执行到line17结束,line19之前ds=076A   ss=076B   cs=076C

  

  2. 在程序加载后,若code=x,则data=x-2,stack=x-1

  

 任务1-2:

  task1_2.asm源码如下:

 1 assume ds:data, cs:code, ss:stack
 2 
 3 data segment
 4     db 4 dup(0)
 5 data ends
 6 
 7 stack segment
 8     db 8 dup(0)
 9 stack ends
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14 
15     mov ax, stack
16     mov ss, ax
17     mov sp, 8
18 
19     mov ah, 4ch
20     int 21h
21 code ends
22 end start

  1.执行到line17结束,line19之前ds=076A   ss=076B   cs=076C

  

  2.在程序加载后,若code=x,则data=x-2,stack=x-1

 

 任务1-3:

  task1_3.asm源码如下:

 1 assume ds:data, cs:code, ss:stack
 2 
 3 data segment
 4     db 20 dup(0)
 5 data ends
 6 
 7 stack segment
 8     db 20 dup(0)
 9 stack ends
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14 
15     mov ax, stack
16     mov ss, ax
17     mov sp, 20
18 
19     mov ah, 4ch
20     int 21h
21 code ends
22 end start

  1.执行到line17结束,line19之前ds=076A   ss=076C   cs=076E

  

  2.在程序加载后,若code=x,则data=x-4,stack=x-2

 

 任务1-4:

  task1_4.asm源码如下:

 1 assume ds:data, cs:code, ss:stack
 2 code segment
 3 start:
 4     mov ax, data
 5     mov ds, ax
 6 
 7     mov ax, stack
 8     mov ss, ax
 9     mov sp, 20
10 
11     mov ah, 4ch
12     int 21h
13 code ends
14 
15 data segment
16     db 20 dup(0)
17 data ends
18 
19 stack segment
20     db 20 dup(0)
21 stack ends
22 end start

  1.执行到line9结束,line11之前ds=076C    ss =076E   cs=076A

  

  2.在程序加载后,若code=x 则data=x+2  stack=x+4

 

 任务1-5

  1.根据任务1-1~任务1-4的结果来看程序加载后实际分配的内存空间大小是ceil(N/16)*16   ceil()为向上取整函数个字节。我们可以通过d命令查看

  task1_1:

 

  task1_2:

 

  task1_3:

 

  task1_4:

 

  可以看到,除了task1_4中最后的段地址未给足一段空间外,其余不在程序结尾的段都按不足一段空间补足一段,因为程序中是按段为单位分配空间。

  而在程序结尾的最后一个小段,程序并不会再给足一整段即16个字节的空间。

  2.若将end start改为end后,能像原来一样正确执行的程序只有task1_4.asm,因为task1_1.asm、task1_2.asm、task1_3.asm的开头都为data段和stack段,而修改后debug无法再找到程序的入口在哪,就会从第一个段开始执行,而只有task1_4.asm的开头段是code段,所以可以正确执行。

 

 2.实验任务2

  task2.asm源码如下:

 1 assume cs:code
 2 
 3 code segment
 4 start:
 5     mov ax, 0b800h
 6     mov ds, ax
 7     mov bx, 0f00h
 8     mov cx, 50h
 9 s:    mov al, 03h
10     mov ds:[bx], al
11     inc bx
12     mov al, 04h
13     mov ds:[bx], al
14     inc bx
15     loop s
16     
17     mov ax, 4c00h
18     int 21h
19 code ends
20 end start

  运行结果截图:

  

经过观察发现实验结果与实验1中的任务3结果相同。

 

 3.实验任务3

  补全后的源代码如下:

 1 assume cs:code
 2 data1 segment
 3     db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
 4 data1 ends
 5 
 6 data2 segment
 7     db   0,   0,   0,   0, 47, 0,   0, 47, 0,   0 ; ten numbers
 8 data2 ends
 9 
10 data3 segment
11     db 16 dup(0)
12 data3 ends
13 
14 code segment
15 start:
16         mov ax, data1
17     mov ds, ax
18     mov bx, 0
19     mov cx, 10
20 s:    mov  ax, ds:[bx]
21     add ax, ds:[bx+10h]
22     mov ds:[bx+20h], ax
23     inc bx
24     loop s
25     
26     mov ax, 4c00h
27     int 21h
28     ; ×××
29 code ends
30 end start

  运行截图如下:

  反汇编截图:

  

     运行前内存情况:

  

  运行后内存情况:

  

 

   运行后发现相加后结果正确且存放位置正确,作用为在日期年月日之间添加‘ / ’

 4.实验任务4

  补全后task4.asm代码为:

 1 assume cs:code
 2 
 3 data1 segment
 4     dw 2, 0, 4, 9, 2, 0, 1, 9
 5 data1 ends 
 6 
 7 data2 segment
 8     dw 8 dup(?)
 9 data2 ends
10 
11 code segment
12 start:
13         mov ax, data1
14     mov ds, ax
15     mov bx, 14
16     mov di, 16
17     mov cx, 8
18     mov ss, ax
19     mov sp, 0
20 s:    mov ax, ds:[bx]
21     sub bx, 2
22     mov ds:[di], ax
23     add di, 2
24     loop s
25     ; ×××
26     mov ah, 4ch
27     int 21h
28 code ends
29 end start

  反汇编截图如下:

  

   运行之前内存截图:

   运行之后内存截图:

   发现8个字型数据正确地逆序存放在了data2所在的内存中。

 

 5.实验任务5

  task5.asm源码如下:

 1 assume cs:code, ds:data
 2 data segment
 3         db 'Nuist'
 4         db 5 dup(5)
 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
16         mov si, 0
17         mov di, 0f00h
18 s:      mov al, [si]
19         and al, 0dfh;11011111B
20         mov es:[di], al
21         mov al, [5+si]
22         mov es:[di+1], al
23         inc si
24         add di, 2
25         loop s
26 
27         mov ah, 4ch
28         int 21h
29 code ends
30 end start

  直接运行截图如下:

  

   可以看到屏幕上出现大写的彩色字母NUIST

  执行到line25执行后,line27执行前,结果如下:

  源代码中line19为: and al, 0dfh 是将al中的数据与0dfh进行二进制与计算,0dfh的二进制形式为11011111B,所以与操作后al中的数据第六位如果是1的话会被置0,即相当于做减去100000B的运算,而100000B的十进制值为32,所以可以发现该操作为大写字母不变,小写字母变成大写。

 

  将源码中data改为如下图:

  

  运行结果截图:

  

  将源代码中data改为:

  

  运行结果截图:

  

  猜测:line4这里的数值是控制对应的字母的颜色的数值,不同的数值代表了不同的颜色。

 6.实验任务6

 1 assume cs:code, ds:data
 2 
 3 data segment
 4     db 'Pink Floyd      '
 5     db 'JOAN Baez       '
 6     db 'NEIL Young      '
 7     db 'Joan Lennon     '
 8 data ends
 9 
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14     mov bx, 0
15     mov cx, 4
16 s:    mov ax, ds:[bx]
17     or ax, 20h
18     mov ds:[bx], ax
19     add bx, 16
20     loop s
21    ; ×××
22    mov ah, 4ch
23    int 21h
24 code ends
25 end start

  反汇编截图:

  

   运行前截图:  

  

   可以看到每行的开头字母是大写。

  运行后截图:

  

   每行开头的大写字母都变成了小写。

  

 7.实验任务7

  源代码:

 1 assume cs:code, ds:data, es:table
 2 
 3 data segment
 4     db '1975', '1976', '1977', '1978', '1979' 
 5     dw  16, 22, 382, 1356, 2390
 6     dw  3, 7, 9, 13, 28 
 7 data ends
 8 
 9 table segment
10     db 5 dup( 16 dup(' ') )  ;5行每行16个元素都为空格
11 table ends
12 
13 code segment
14 start:
15     mov ax, data
16     mov ds, ax
17     mov ax, table 
18     mov es, ax
19     mov cx, 5
20     mov bx, 0
21     mov di, 0
22 
23 s:     mov al, ds:[bx]
24     mov es:[di], al
25 
26     mov al, ds:[bx + 1]
27     mov es:[di + 1], al
28 
29     mov al, ds:[bx + 2]
30     mov es:[di + 2], al
31 
32     mov al, ds:[bx + 3]
33     mov es:[di + 3], al
34 
35     add bx, 4
36     add di, 16
37     loop s
38     
39     mov cx, 5
40     mov di, 5
41     
42 s1:    mov al, ds:[bx]
43     mov es:[di], al
44 
45     mov ah, ds:[bx + 1]
46     mov es:[di + 1], ah
47     add bx, 2
48     add di, 16
49     loop s1
50 
51     mov cx, 5
52     mov di, 7
53 
54 s2:    mov al, 0
55     mov es:[di], al
56     mov es:[di+1], al
57     add di, 16
58     loop s2
59 
60     mov cx, 5
61     mov di, 10
62 s3:     mov al, ds:[bx]
63     mov es:[di], al
64     mov ah, ds:[bx+1]
65     mov es:[di+1], ah
66     add bx, 2
67     add di, 16
68     loop s3
69 
70     mov cx, 5
71     mov di, 13
72     mov si, 5
73 s4:    mov al, es:[si]
74     mov ah, es:[si+1]
75     mov dl, es:[si+2]
76     mov dh, es:[si+3]
77     div word ptr es:[si+5]
78     mov es:[di], ax
79     add di, 16
80     add si, 16
81     loop s4
82     
83     
84     mov ah, 4ch
85     int 21h
86 code ends
87 end start

  table段原始数据信息截图:

   运行后table段截图如下

   信息已按要求结构化地写入到指定内存中。

  

 四、实验总结

  通过本次上机实验,我了解并学会了如何编写包含多个逻辑段的汇编源程序,以及如何灵活的使用寻址方式来从内存中获得或向内存中写入自己想要的数据。了解了start、end start的作用:start表明了程序从哪里开始执行。使用and和or命令可以巧妙地将二进制的某一位置0或置1从而达到自己想要的效果。在实验任务7中,要非常明确当前需要计算和存放的数据所在的短地址和偏移地址,才能做到准确的计算和存放。div命令有两种使用方式,一种是16位被除数除以8位除数,ax中al存放商,ah存放余数;另一种是32位被除数除以16位除数,ax存放商,dx存放余数。

 

posted @ 2021-11-03 22:00  蛋白大神  阅读(137)  评论(2编辑  收藏  举报