实验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
- 执行到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存放余数。