实验2 多个逻辑段的汇编源程序编写与调试
四、实验结论
1. 实验任务1
任务1-1
task1_1.asm源码
1 assume ds:data, cs:code, ss:stack 2 data segment 3 db 16 dup(0) ; 预留16个字节单元,初始值均为0 4 data ends 5 stack segment 6 db 16 dup(0) ;预留16个字节单元,初始值均为0 7 stack ends 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 mov ax, stack 13 mov ss, ax 14 mov sp, 16 ; 设置栈顶 15 mov ah, 4ch 16 int 21h 17 code ends 18 end start
task1_1调试到line17结束、line19之前截图

问题回答
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A, 寄存器(SS) = 076B, 寄存器(CS) = 076C
② 假设程序加载后,code段的段地址是X,则,data段的段地址是X-2, stack的段地址是X-1。
任务1-2
任务task1_2.asm源码
1 assume ds:data, cs:code, ss:stack 2 data segment 3 db 4 dup(0) ; 预留4个字节单元,初始值均为0 4 data ends 5 stack segment 6 db 8 dup(0) ; 预留8个字节单元,初始值均为0 7 stack ends 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 mov ax, stack 13 mov ss, ax 14 mov sp, 8 ; 设置栈顶 15 mov ah, 4ch 16 int 21h 17 code ends 18 end start
task1_2调试到line17结束、line19之前观察寄存器DS, CS, SS值的截图

问题回答
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A, 寄存器(SS)= 076B, 寄存器(CS) = 076C
② 假设程序加载后,code段的段地址是X,则,data段的段地址是X-2, stack的段地址是X-1。
任务1-3
任务task1_3.asm源码
1 assume ds:data, cs:code, ss:stack 2 data segment 3 db 20 dup(0) ; 预留20个字节单元,初始值均为0 4 data ends 5 stack segment 6 db 20 dup(0) ; 预留20个字节单元,初始值均为0 7 stack ends 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 mov ax, stack 13 mov ss, ax 14 mov sp, 20 ; 设置初始栈顶 15 mov ah, 4ch 16 int 21h 17 code ends 18 end start
task1_3调试到line17结束、line19之前观察寄存器DS, CS, SS值的截图

问题回答
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A, 寄存器(SS)= 076C , 寄存器(CS) = 076E
② 假设程序加载后,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 mov ax, stack 7 mov ss, ax 8 mov sp, 20 9 mov ah, 4ch 10 int 21h 11 code ends 12 data segment 13 db 20 dup(0) 14 data ends 15 stack segment 16 db 20 dup(0) 17 stack ends 18 end start
task1_4调试到line17结束、line19之前观察寄存器DS, CS, SS值的截图

问题回答
① 在debug中将执行到line9结束、line11之前,记录此时:寄存器(DS) = 076C, 寄存器(SS) = 076E, 寄存器(CS) = 076A
② 假设程序加载后,code段的段地址是X,则,data段的段地址是X+2, stack的段地址是X+4。
任务1-5
基于上述四个实验任务的实践、观察,总结并回答:
① 对于如下定义的段,程序加载后,实际分配给该段的内存空间大小是 16*(N/16+1) 。
② 如果将程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,伪指令 end start 改成end , 哪一个程序仍然可以正确执行。结合实践观察得到的结论,分析、说明原因。
task1_4.asm仍可以正确执行
task1_4修改前后:
task1_1修改前后:
编译器默认从代码的开始位置执行,因为不论修改前后,task1_4.asm代码开始位置就是代码段,所以两个CS:IP值相同并不影响程序执行。而其余汇编程序起始地址是数据段定义,只有在start:标记地方,编译器才知道是代码段的起始地址,因此两个CS的值不同,所以会影响代码段的执行。
2. 实验任务2
汇编源代码
1 assume cs:code 2 code segment 3 mov ax,0b800h 4 mov ds,ax 5 mov bx,0f00h 6 mov cx,80 7 8 s:mov ds:[bx],0403h 9 add bx,2 10 loop s 11 12 mov ax,4c00h 13 int 21h 14 code ends 15 end
将03 04 当作字单元存储 03低地址 04高地址,因此该字为0403h
运行结果截图

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 cx,16 19 mov bx,0 20 21 s:mov al,ds:[bx] 22 add al,ds:[bx+16] 23 mov ds:[bx+32],al 24 inc bx 25 loop s 26 27 mov ah,4ch 28 int 21h 29 code ends 30 end start
在debug中加载、反汇编、调试截图

要求给出,在数据项依次相加之前,查看逻辑段data1, data2, data3对应的内存空间数据原始值的debug命令和截图

以及,依次相加之后,查看逻辑段data1, data2, data3对应的内存空间数据原始值的debug命令和截图

4. 实验任务4
补充完整后的汇编源代码
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(0) 9 data2 ends 10 11 code segment 12 start: 13 mov ax,data1 14 mov ds,ax 15 mov ax,data2 16 mov ss,ax 17 mov sp,10h 18 mov bx,0 19 mov cx,8 20 21 s : push [bx] 22 add bx,2 23 loop s 24 25 mov ah, 4ch 26 int 21h 27 code ends 28 end start
在debug中加载、反汇编、调试截图

要求给出,在程序退出前,使用d命令查看数据段data2对应的内存空间的截图。

5. 实验任务5
task5.asm源码
1 assume cs:code, ds:data 2 data segment 3 db 'Nuist' 4 db 2, 3, 4, 5, 6 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 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
运行结果截图
使用debug工具对程序进行调试,使用g命令一次性执行到程序返回前(即ine25执行之后、line27执行之前)的截图

源代码中line19的作用是?
作用是:如果低位地址是小写字母,将其变成大写字母,通过按位与,将对应小写字母的Ascii码二进制的第五位变成0,也就是Ascii值减去32即变成大写字母。
源代码中data段line4的字节数据的用途是?
改成:db 5 dup(2)
改成:db 5 dup(5)
用途是设置显示字符的前景色
6. 实验任务6
task6.asm源代码
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 cx, 4 15 mov bx, 0 16 17 s1: 18 mov dx, cx ; 存储外层循环的cx 19 mov cx, 4 20 mov si, 0 21 s2: 22 or byte ptr [bx+si], 020h 23 inc si 24 loop s2 25 mov cx, dx 26 add bx, 16 27 loop s1 28 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
在debug中加载、反汇编、调试截图

要求给出,在程序退出前,使用d命令查看数据段data对应的内存空间的截图。

7. 实验任务7
task7.asm源码
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(' ') ) ; 11 table ends 12 13 code segment 14 start: 15 mov ax,table;table段首地址赋值给数据段寄存器 16 mov ds,ax 17 18 mov ax,data;data段首地址赋值给附加数据段寄存器 19 mov es,ax 20 21 ;移入年份 22 mov cx,5 23 mov bx,0;ds的偏移地址 24 mov si,0;es的偏移地址 25 s_year: 26 mov ax,es:[si];先移入前一个字单元,即两个字节单元 27 mov [bx],ax 28 mov ax,es:[si+2];再后一个字单元,一行结束 29 mov [bx+2],ax 30 add si,4;指向下一个年份首地址 31 add bx,16;指向第二行 32 loop s_year 33 34 ;移入收入 35 mov cx,5 36 mov bx,5;从空格后开始 37 s_salary: 38 mov ax,es:[si] 39 mov [bx],ax 40 mov word ptr [bx+2],0000h;后两个字节为空 41 add si,2 42 add bx,16 43 loop s_salary 44 45 ;移入雇员数 46 mov cx,5 47 mov bx,10 48 s_employee: 49 mov ax,es:[si] 50 mov [bx],ax 51 add si,2 52 add bx,16 53 loop s_employee 54 55 ;计算并移入人均收入 56 mov cx,5 57 mov bx,5 58 s_gdp: 59 mov ax,[bx];存入被除数的低8位 60 mov dx,[bx+2];存入被除数的高8位 61 div word ptr [bx+5] 62 mov [bx+8],ax 63 add bx,16 64 loop s_gdp 65 66 mov ah, 4ch 67 int 21h 68 code ends 69 end start
调试截图

查看table段原始数据信息截图

在debug中运行到程序退出之前,使用d命令查看table段对应的内存空间的截图,确认信息是
否按要求结构化地写入到指定内存

被除数32位 除数16位
五、实验总结
1.直接写显存 0b800h 显示 字符串
显示字符就是往显存里写进要显示的东西。每个字符占显存中两个字节,低字节是字符的ASCII码,高字节是设置所示字符的属性。
每位都定义有显示属性,从高位到低位依次是:闪烁 背景红 背景绿 背景蓝 高亮 前景红 前景绿 前景蓝
2.当输入一个外部命令或通过EXEC子功能(系统功能调用INF 21h的子功能号为4BH)加载一子程序时,COMMAND确定当时内存可用空间的最低端作为程序段起点。在程序所占内存空间的前256个字节中,系统会为程序创建程序的前缀(PSP)的数据区,DOS要利用PSP来和被加载程序进行通信;PSP内有程序返回、程序文件名等信息,可以通过研究psp定位文件名信息,进而获取文件名。
从这段内存区的256字节处开始(在PSP的后面),将程序装入,程序的地址被设为SA+10H:0 (其中SA为系统为程序分配内存的起始位置的段地址即当前寄存器DS的内容)。
3.汇编语言的DIV指令是除法指令
A / B A是被除数,B是除数
除数B有 8位和16位两种,保存在一个reg寄存器里 或是内存单元中。
被除数A 默认存放在AX中(16位以内) 或 AX和DX中(32位,DX存放高16位,AX存放低16位)
结果:如果除数B是8位,那么除法的结果AL保存商,AH保存余数,
如果除数B是16位,那么除法的结果 AX保存商,DX保存余数。
公式如下:
1: div byte ptr ds:[0]
含义:(al) = (ax)/((ds)*16+0) 的商
(ah) = (ax/(ds)*16+0) 的余数
2:div word ptr es:[0]
含义:(ax) = [(dx)*10000H+(ax)] / ((es)*16+0)的商
(dx) = [(dx)*10000H+(ax)] / ((es)*16+0)的余数
3:div byte ptr [bx+si+8]
含义:(al) = (ax) / ((ds)*16+(bx)+(si)+8) 的商
(ah) = (ax) / ((ds)*16+(bx)+(si)+8) 的余数
4:div word ptr [bx+si+8]
含义:(ax) = [(dx)*10000h+(ax)] / ((ds)*16+(bx)+(si)+8) 的商
(dx) = [(dx)*10000h+(ax)] / ((ds)*16+(bx)+(si)+8) 的余数





浙公网安备 33010602011771号