实验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

 

posted @ 2020-11-22 19:08  RW_NEO  阅读(275)  评论(2)    收藏  举报