实验3 多个段的汇编源程序编写与调试

一、实验目的
1. 理解和掌握将数据、代码、栈放入不同逻辑段的程序的编写和调试
2. 理解具有多个段的汇编源程序对应的目标程序执行时,内存分配方式
3. 掌握大小写字符的转换方法、数字字符和数值之间的转换方法
4. 理解并掌握各种寻址方式的灵活应用
5. 掌握汇编指令loop, and, or,div, mul的用法
二、实验内容
1.实验任务1
2、英文字符的大小写转换!!!!!
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
进行编译连接:
运行task:

 进行debug,使用r命令观察接着根据CX进行反汇编

发现反汇编的结果并不是完全正确,多了很多冗余数据,使用g命令运行到程序结束之前:

 

进行修改:

重新进行编译连接:

 发现NUIST的IST颜色变色了,所以我猜测这里的数据作用是改变字符串的颜色信息

2.实验任务2

1、数字↔数字字符的相互转换!!!!!!

已知数据段data中定义字节数据如下:
data segments
db 23, 50, 66, 71, 35
data ends
编写程序,在屏幕上以十进制整数形式打印输出这5个两位数。
先把ds指向数据段,定好循环次数cx为5次
定义循环s:因为数据段中的每个十位数仅有8个字型数据,所以用al来存储
接着使用div除法命令,商存入al,而余数存在ah中
接着将ax复制到dx中并且加上3030H使得数字转化成数字字符
根据老师所给的int 21h的2号子功能,最后输出的是dl中的内容
所以先直接输出一次接着将dh复制到dl中在输出一次即为一个十进制数的输出过程
一次循环结束,将ds指向向后移一位,开始下一次循环直到五次结束。
代码如下:
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 cx,5
s:      mov ah,0
        mov al,ds:[di]
        mov bl,10
        div bl
        mov dx,ax
        add dx,3030H
        mov ah,2
        int 21h
        mov dl,dh
        mov ah,2
        int 21h
        inc di
        loop s
        mov ah,4CH
        int 21h
code ends
end start

进行编译连接并运行:

 得到了输出结果23,50,66,71和35

3.实验任务3

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

教材问题1:CPU执行程序,程序返回前,data段中的数据为多少?

理论分析来说,不会发生变化

原来data段中存放的数据:到程序返回前,data段中存放的数据为:

运行到程序结束前的数据段:

 

问题2:CPU执行程序,程序返回前,cs=,ss=,ds=

根据问题1的第二张图片可得:cs=076C,ss=076B,ds=076A

问题3:设程序加载后,code段的段地址为X,则data段的段地址为,stack段的段地址为

data段的段地址为X-2,stack段的段地址为X-1,因为程序开始前data定义了16个字节空间的数据,stack定义了16个字节空间的数据,所以每一个段相差16个即10h个字节。

4. 实验任务4
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

1.CPU执行程序,程序返回前,data段中的数据为多少?

进入程序进行反汇编到程序返回前

查看数据段中的值

 

 由程序得,data段中的数据应为4个字节的内容即0123h,0456h

2.CPU执行程序,程序返回前,cs=,ss=,ds=?

由上图得,cs=076C,ss=076B,ds=076A

3.设程序加载后,code段的段地址为X,则data段的段地址为,stack段的段地址为

data:X-2,stack:X-1

4.首先占用的字节数最少为16个且一定为16的倍数,如果N可以整除16,那么

占有的空间就为N个字节,如果不可以,实际占有的空间为(N/16+1)*16

 

5.实验任务5

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

1.CPU执行程序,程序返回前,data段中的数据为多少?

data段仍旧占4个字节,为0123h,0456h

2.CPU执行程序,程序返回前,由运行结果可以看出cs=076A,ss=076E,ds=076D

3.设程序加载后,code段的段地址为X,则data段的段地址为,stack段的段地址为

data段的段地址为X+3,stack段的段地址为X+4

6.实验任务6

如果将实验任务3,4,5中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因

解:只有实验任务5的程序还可以正确执行,因为实验任务5的程序的数据段和栈段都定义在程序的code段后,u命令反汇编的情况下不会影响,而实验任务3,4都定义在code段前,前面定义的data段和栈段中的数据会当作代码进行反汇编,无法正确执行。

7.实验任务7

编写code段中的代码,将a段和b段中的数据依次相加,将结果保存到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

c1 segment   ; 在集成软件环境中,请将此处的段名称由c→改为c1或其它名称
  db 8 dup(0)
c1 ends

code segment
start:
       mov di,0
       mov cx,8
s:     mov si,a
       mov ds,si
       mov al,ds:[di]
       mov si,b
       mov ds,si
       add al,ds:[di]
       mov si,c1
       mov ds,si
       mov ds:[di],al
       inc di
       loop s
       mov ax,4c00h
       int 21h
code ends
end start

运行到程序结束前,用d命令查看现在DS存放的内容

发现结果为02 04 06 08 0A 0C 0E 10,完成了要求

8.实验任务8

编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中

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 di,0
      mov cx,8
s:    mov si,a
      mov ds,si
      push ds:[di]
      inc di
      inc di
      loop s
      mov di,0
      mov cx,8
s1:   mov si,b
      mov ds,si
      pop ds:[di]
      inc di
      inc di
      loop s1
      mov ax,4c00h
      int 21h
code ends
end start

一开始想着逆序输出到b段中就在第二个循环中将bi的初始值设成16,然后dec两次,

尝试了几次发现还是正序,才想到栈的pop函数本身就是先入后出的逆序过程,

我相当于逆序的逆序还是正序了,接着直接进行同样的步骤运行得到了结果

三、实验总结

总体来说这次的实验让我很清晰的理解了段的分配机制,data段和栈段,定义段的位置

都会对结果产生莫大的影响,最后一个实验任务还让我对栈的知识回顾了一下,实验任务2

让我重新看了书本上div指令的部分,商默认存储在al中,ah默认存储余数,int 21h的二号子命令

是输出dl中的内容

 

 

 

 

 
 

 

posted @ 2020-11-23 20:37  Sabertooth  阅读(138)  评论(2)    收藏  举报