实验3 多个段的汇编源程序编写与调试
一、实验目的
1. 理解和掌握将数据、代码、栈放入不同逻辑段的程序的编写和调试 2. 理解具有多个段的汇编源程序对应的目标程序执行时,内存分配方式 3. 掌握大小写字符的转换方法、数字字符和数值之间的转换方法
4. 理解并掌握各种寻址方式的灵活应用
5. 掌握汇编指令loop, and, or,div, mul的用法
二、实验准备
复习教材chapter 6-8章。
chapter 6 包含多个段的程序
chapter 7 更灵活的定位内存地址的方法
chapter 8 数据处理的两个基本问题
三、实验内容与结论
1. 实验任务1
使用任意文本编辑器,录入汇编源程序task1.asm。
assume cs:code, ds:data data segment db 'Nuist' db 5 dup(2) data ends code segment start: mov ax, data mov ds, ax mov ax, 0b800H mov es, ax mov cx, 5 mov si, 0 mov di, 0f00h s: mov al, [si] and al, 0dfh mov es:[di], al mov al, [5+si] mov es:[di+1], al inc si add di, 2 loop s mov ah, 4ch int 21h code ends end start
使用masm、link对task1.asm进行汇编、链接,得到可执行文件task1.exe,运行并观察结果。
使用debug工具对程序进行调试,执行到程序返回前,即line27之前,观察结果。 修改line4里5个字节单元的值,重新汇编、链接、运行,观察结果。
输出结果:

通过阅读程序源代码以及逐步调试可以看出,15-25行的loop从数据段中读出字数据(字符的ascii码值),向显存指定位置输出。
数据段中db 5 dup(2)表示定义5个重复字节,数据值都为十进制2,在loop中使用mov al, [5+si]读出并且输出,用于设置显示颜色。

2. 实验任务2
已知数据段data中定义字节数据如下:
data segments db 23, 50, 66, 71, 35 data ends
注意这里字节数据为十进制,在d命令查看内存时显示十六进制的数据

task2代码
assume cs:code, ds:data data segment db 23,50,66,71,35 data ends code segment start: mov ax, data mov ds, ax mov ax, 0b800H mov es, ax mov cx, 5 mov si, 0 mov di, 0f00h s: mov al, [si] mov dx,0 mov ah,0 mov bx,10 div bx add al,48 add dl,48 mov es:[di], al mov al,dl mov es:[di+2], al inc si add di, 6 loop s mov ah, 4ch int 21h code ends end start
task2代码基于task1代码进行理解修改得出
思路:
循环之前先把数据段地址存放到ds,输出的显存地址存放到
循环时先读出数据,数据在数据段中db存放,是单字节数据,所以将存放数据的寄存器高位设置为0。
被除数存放在ax,除数存放在bx,利用除法指令div,商存放在ax中,余数存放在dx中,计算出十位和个位上的数值。
利用数值和数字字符之间ascII码的关系,把各位上的数值加上48,十六进制0030h,得出相应字符
利用系统功能调用int 21h中的2号子功能,输出单个字符,显存位置自增6字节(两个数据,一个空格),数据段循环偏移量自增1个字节。
输出效果:
需要注意的是,dx初始为0,第一次运算后有垃圾数据残余,为了防止程序出错每次循环后dx需要赋值为0。
参考:https://stackoverflow.com/questions/13028561/assembly-division
3. 实验任务3
程序源码task3.asm
assume cs:code, ds:data, ss:stack data segment dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h data ends stack segment dw 0, 0, 0, 0, 0, 0, 0, 0 stack ends code segment start: mov ax,stack mov ss, ax mov sp,16 mov ax, data mov ds, ax push ds:[0] push ds:[2] pop ds:[2] pop ds:[0] mov ax,4c00h int 21h code ends end start
课本填空:
程序返回前,data段中的数据:

程序返回前,cs、ss和ds的值:

程序加载后,code段地址为X,data段地址为X-32,stack段地址为X-16。
4. 实验任务4
程序源码task4.asm:
assume cs:code, ds:data, ss:stack data segment dw 0123h, 0456h data ends stack segment dw 0, 0 stack ends code segment start: mov ax,stack mov ss, ax mov sp,16 mov ax, data mov ds, ax push ds:[0] push ds:[2] pop ds:[2] pop ds:[0] mov ax,4c00h int 21h code ends end start
程序返回前,data段中数据:

程序返回前,cs、ss和ds的值:

程序加载后,code段地址为X,data段地址为X-32,stack段地址为X-16。
对于如下定义的段
name segment
...
name ends
如果段中数据占N个字节,程序加载后,该段实际占有的空间为N/16+16字节,即能容纳数据的最小16字节的整数倍。
5. 实验任务5教材
程序源码task5.asm:
assume cs:code, ds:data, ss:stack code segment start: mov ax,stack mov ss, ax mov sp,16 mov ax, data mov ds, ax push ds:[0] push ds:[2] pop ds:[2] pop ds:[0] mov ax,4c00h int 21h code ends data segment dw 0123h, 0456h data ends stack segment dw 0,0 stack ends end start
程序返回前,data段中数据:

程序返回前,cs、ss和ds的值:

程序加载后,code段地址为X,data段地址为X+48,stack段地址为X+64。
6. 实验任务6
(1)(2)均无法正常运行
(3)不受影响

说明原因:
如果程序末尾为end start,CPU知道程序从start:处开始执行;如果程序末尾end,将从头执行。
参考:王爽教材P126
由于实验(1)task3和实验(2)task4的数据段在code segment之前,将数据段中的数据作为指令读出执行肯定是不正确的。实验(3)task5中从code segment正确执行退出,从而不会进入到code segment一下的数据段中。
7. 实验任务7
教材「实验5 编写、调试具有多个段的程序」(5) 程序源码见task7.asm。
注*: 如果在集成软件环境下编写、汇编这个实验任务,请将段名为c的逻辑段,名称改为c1或别的标识 符。由于早期一些指令集中使用c指代寄存器,如不更正,有些汇编器在汇编时会报错。
assume cs:code a segment db 1,2,3,4,5,6,7,8 a ends b segment db 1,2,3,4,5,6,7,8 b ends c segment db 8 dup(0) c ends code segment start: mov si,0 mov cx,8 s: mov ax,a mov ds,ax mov dl,[si] mov ax,b mov ds,ax add dl,[si] mov ax,c mov ds,ax mov [si],dl mov dx,0 add si,1 loop s mov ah, 4ch int 21h code ends end start
由于知道的寄存器太少,这里实现使用了笨办法,每次从一个数据段中读出数据后,将ds赋值为另一个数据段的其实地址。
这里使用了dl存储数据进行计算,是因为数据段中定义的数据是db单字节数据。然而这里使用dx作为存储数据,一次写入两个byte数据,由于这里数据不存在加法溢出的顾虑,也能达到同样的效果。
执行task7后数据段c中的数据:

8. 实验任务8教材
「实验5 编写、调试具有多个段的程序」(6)
程序源码:task8.asm
assume cs:code a segment dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh a ends b segment dw 8 dup(0) b ends code segment start: mov ax,a mov ds,ax mov ax,b mov ss,ax mov sp,16 mov cx,8 mov si,0 s: push ds:[si] add si,2 loop s mov ah, 4ch int 21h code ends end start
数据段a有16个双字节字数据,占了32byte,该程序题没有设置栈段,所以显然不是用栈段作为中间容器实现逆序。经过思考,栈低为高址,每次push栈顶向低址移动,也可以实现逆序存放,所以将数据段b的末尾设置为栈低ss:sp。用loop重复读取数据压栈操作。
运行结果:
数据段a:076A:0000 ~ 076A:001f
数据段b:076A:0020 ~ 076A:002f
可以看出实现了逆序存储

四、实验总结
1、 看清数据段是dw数据还是db数据,以及题目要求是什么大小的数据。
2、实验2困惑了很久,起初头脑不清醒,找不到数据段中的数据。后来发现.asm源代码中数据段是十进制数据,在debug中-d命令时显示十六进制。
3、dx初始为0,第一次运算后有垃圾数据残余。除法运算为了防止程序出错,每次循环后dx需要重新赋值为0。
4、关于彩色文本模式一般在 B800h 段,单色文本在 B000h 段;图形模式在 A000h 段。task1设置es为0b800h。在文本16色模式下,字符的属性存储在bl中,bl为一个字节大小,共八位。b7控制字符是否闪烁,b6-b4为背景色,b3-b0为前景色。
参考:https://blog.csdn.net/cgzldfend/article/details/80325125

浙公网安备 33010602011771号