实验2 多个逻辑段的汇编源程序编写与调试
实验任务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
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 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
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 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
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 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
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 · ceil(N/16)。(ceil(x)表示对x向上取整)
1 xxx segment 2 db N dup(0) 3 xxx ends
②问:如果将程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,伪指令end start 改成 end , 哪一个程序仍然可以正确执行。结合实践观察得到的结论,分析、说明原因。
答:将task1_1.asm的伪指令end start 改成 end,编译,链接后,在debug中查看到的汇编代码的截图如下:
显然,这个程序在修改伪指令后是不能正确执行的。
将task1_2.asm的伪指令end start 改成 end,编译,链接后,在debug中查看到的汇编代码的截图如下:
和task1_1.asm修改伪指令的情形类似,该程序不能正确执行。
将task1_3.asm的伪指令end start 改成 end,编译,链接后,在debug中查看到的汇编代码的截图如下:
可见,该程序在修改伪指令后不能正确执行。
将task1_4.asm的伪指令end start 改成 end,编译,链接后,在debug中查看到的汇编代码的截图如下:
此时,修改伪指令后的程序可以正确执行。
出现上面这些现象的原因是:伪指令 end 描述程序的结束和程序的入口,start正是用于指示程序段入口信息的,修改伪指令后,操作系统无法确定程序的入口地址,只能将CS:IP一律设置成076A:0000。对于task1_1.asm, task1_2.asm, task1_3.asm而言,076A:0000处存储的是数据而不是程序,而task1_4.asm在076A:0000恰好是程序段的入口,故能正确执行。
实验任务2
实现的源码如下:
1 assume cs:code 2 code segment 3 start: 4 mov ax, 0b800H 5 mov ds, ax 6 mov bx, 0f00H 7 mov ax, 0304H 8 mov cx, 80 9 s: mov [bx], ax 10 add bx, 2 11 loop s 12 13 mov ax, 4c00H 14 int 21H 15 code ends 16 end start
运行结果截图如下:
实验任务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 stack1 segment 15 db 16 dup(0) 16 stack1 ends 17 18 code segment 19 start: 20 mov ax, data1 21 mov ds, ax 22 23 mov ax, data2 24 mov es, ax 25 26 mov ax, stack1 27 mov ss, ax 28 mov sp, 16 29 30 mov bx, 0 31 mov cx, 5 32 s1: mov ax, ds:[bx] 33 add ax, es:[bx] 34 push ax 35 add bx, 2 36 loop s1 37 38 mov ax, data3 39 mov ds, ax 40 mov bx, 8 41 mov cx, 5 42 s2: pop ds:[bx] 43 sub bx, 2 44 loop s2 45 46 mov ax, 4c00H 47 int 21H 48 code ends 49 end start
在数据项依次相加之前,查看逻辑段data1, data2, data3对应的内存空间数据原始值的 debug命令和截图如下:
上图中 076A:0000 - 076A:000f 中内容对应data1内存空间数据,076A:0010 - 076A:001f 对应data2内存空间数据,076A:0020 - 076A:002f 对应data3内存空间数据。
依次相加之后,查看逻辑段data1, data2, data3对应的内存空间数据原始值的debug命令和截图如下:
类似地,data1, data2, data3内存空间数据分别是 076A:0000 - 076A:000f,076A:0010 - 076A:001f,076A:0020 - 076A:002f 中对应的内容。
可以看到,程序成功实现了把逻辑段data1和逻辑段data2的数据依次相加,结果保存到逻辑段data3中的要求。
实验任务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(?) 9 data2 ends 10 11 code segment 12 start: 13 mov ax, data1 14 mov ds, ax 15 16 mov ax, data2 17 mov ss, ax 18 mov sp, 16 19 20 mov bx, 0 21 mov cx, 8 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
在程序退出前,使用d命令查看数据段data2对应的内存空间的截图如下:
在上图中,076A:0000 - 076A:000f 中内容对应data1内存空间数据,076A:0010 - 076A:001f 对应data2内存空间数据。
可见,程序成功实现了将把逻辑段data1中的8个字数据逆序存储到逻辑段b中的功能。
实验任务5
- task5.asm的源码如下:
1 assume cs:code, ds:data 2 data segment 3 db 'Nuist' 4 db 2, 3, 4, 5, 6 5 ;db 5 dup(2) 6 ;db 5 dup(5) 7 data ends 8 9 code segment 10 start: 11 mov ax, data 12 mov ds, ax 13 14 mov ax, 0b800H 15 mov es, ax 16 17 mov cx, 5 18 mov si, 0 19 mov di, 0f00h 20 s: mov al, [si] 21 and al, 0dfh 22 mov es:[di], al 23 mov al, [5+si] 24 mov es:[di+1], al 25 inc si 26 add di, 2 27 loop s 28 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
- 运行结果:
line4是 db 2,3,4,5,6 时,运行结果截图如下:
可以看到,五个字符呈现不同颜色。
line4是 db 5 dup(2) 时,运行结果截图如下:
可以看到, 五个字符均呈绿色。
line4是 db 5 dup(2) 时,运行结果截图如下:
可以看到, 五个字符均呈紫色。
- 使用debug工具对程序进行调试,使用g命令一次性执行到程序返回前(即ine25执行之后、line27 执行之前)的截图如下:
- 问:源代码中line21(对应于原题中line19)的作用是?
答:将字母从小写转为大写。
- 问:源代码中data段line4的字节数据的用途是?
答:用于程序中设置显示字符的颜色,不同字节数据值对应了不同的颜色。
实验任务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 si, 0 15 16 mov cx, 4 17 s: mov al, ds:[si] 18 or al, 20H 19 mov ds:[si], al 20 add si, 16 21 loop s 22 23 mov ah, 4ch 24 int 21h 25 code ends 26 end start
- 程序退出前,在debug中使用d命令查看数据段data对应的内存空间的截图如下:
可以看到,程序成功实现了将data段中的每行第一个单词从大写转为小写的功能。
实验任务7
- task7.asm的源码如下:
1 assume cs:code, ds:data, es:table 2 3 data segment 4 db '1975', '1976', '1977', '1978', '1979' ;一个数字占4个字节,0起步,每次偏移量为4 5 dw 16, 22, 382, 1356, 2390 ;一个数字占一个字,20起步,每次偏移2 6 dw 3, 7, 9, 13, 28 ;一个数字占一个字,30起步,每次偏移2 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,data 16 mov ds,ax 17 mov ax,table 18 mov es,ax 19 20 mov si,0 21 mov bx,0 22 mov cx,5 23 s: 24 mov ax,[bx+2] ;写入年份 25 mov es:[di+2],ax 26 mov ax,[bx] 27 mov es:[di],ax 28 29 mov ax,[si+20] ;写入收入 30 mov es:[di+5],0 31 mov es:[di+7],ax 32 33 mov ax,[si+30] ;写入雇员数 34 mov es:[di+11],ax 35 mov es:[di+9],0 36 37 mov ax,es:[di+7] ;计算人均收入并写入 38 div byte ptr es:[di+11] 39 mov byte ptr es:[di+13],0 40 mov es:[di+14],al 41 42 add bx,4 43 add si,2 44 add di,16 45 loop s 46 47 mov ah, 4ch 48 int 21h 49 code ends 50 end start
- 在debug中运行到程序退出之前,使用d命令查看table段对应的内存空间的截图如下:
可见,信息已经成功结构化地写入到了指定内存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~