实验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
阅读源程序,从理论上分析源代码的功能,尤其是line15-25,循环实现的功能是什么,逐行理解每条指令的功能。
答:cx赋值指定循环次数,初始化si和di后进入循环,将数据段中对应的字符改为大写,写入显存,高位赋值2对应相应字符的颜色,5次循环后将Nuist写入显存每个字符占两位高位对应颜色,低位对应字符。
使用masm、link对task1.asm进行汇编、链接,得到可执行文件task1.exe,运行并观察结果。
使用debug工具对程序进行调试,执行到程序返回前,即line27之前,观察结果。
修改line4里5个字节单元的值,重新汇编、链接、运行,观察结果。
基于观察,分析、猜测这里的数值作用是什么。
答:两字节数据的高位对应低位所代表的字符的颜色。
2.实验任务2
已知数据段data中定义字节数据如下:
data segments
    db 23, 50, 66, 71, 35
data ends

编写程序,在屏幕上以十进制整数形式打印输出这5个两位数。

利用除法指令div,计算出每个数位上的数值:

利用数值和数字字符之间ascII码的关系,把各位上的数值加上48,得出相应字符

利用系统功能调用int 21h中的2号子功能,输出单个字符  字符之间用 mov dl,32   int 21h   的方式输出空格

mov dl,xx
int 21h

 3.实验任务3

 将下面的程序编译、链接、用debug加载、跟踪,然后回答问题。
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
编译 链接文件

 debug加载跟踪

 

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

 8个字型数据占16个字节,由d命令查看,发现data段中的数据为16字节,data段中的数据为:0123 0456 0789 0ABC 0DEF 0FED 0CBA 0987

②CPU执行程序,程序返回前,cs=076CH,ss=076BH,ds=076AH。

③设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

076B-076A=1         076C-076A=2

data段定义了8个字(16个字节)数据的空间,stack段同样定义了16个字节的空间,而且程序一次最少分配16个字节的空间,所以data段与stack段相差10h个字节,stack段与code段相差10H个字节,data段与code段相差20H个字节。又因为段地址*10H+偏移地址=物理地址所以答案得出。

4.实验任务4

将下面的程序编译、链接、用debug加载、跟踪,然后回答问题。

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

编译 链接程序

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

 2个字型数据占4个字节,由d命令查看,发现data段中的数据为4字节,data段中的数据为0123 0456

②CPU执行程序,程序返回前,由运行结果可以看出cs=076CH,ss=076BH,ds=076AH。

③设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

④如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为(floor(N/16)+1)*16。

最少占用16个字节且占用的字节数是16的倍数。

测试:

data segment
  dw 0123h,0456h,0789h,0abch
data ends

stack segment
  dw 1,1,1,1,0,0,0,0,0
stack ends
这里stack处有9个字数据
实验结果:

 cx可知整个程序占52H个字节  u命令反汇编得到data段的代码,占用22H个字节可知剩下的空间为30H。data段占10H stack段占20H

 

 

5.实验任务5

将下面的程序编译、链接、用debug加载、跟踪,然后回答问题。

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

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

数据为0123 0456

 

②CPU执行程序,程序返回前,由运行结果可以看出cs=076AH,ss=076EH,ds=076DH。

③设程序加载后,code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4。

6.实验任务6

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

只有(3)的程序中可以正确执行因为(3)的data段和stack段是定义在code段后面的,在反汇编成源代码时code段代码依然可以正确执行。

另外两题的code段代码都定义在data和stack段后面,会先将data和stack段的数据反汇编成要执行的code代码,所以程序不能正确执行。

7.实验任务7

编写code段中的代码,将a段和b段中的数据依次相加,将结果存到c1段中。

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 bx, 0
    mov cx, 8
s:
    mov si, a
    mov ds, si
    mov al, ds:[bx]  ;将a段中的数据存入al
    mov si, b
    mov ds, si
    add al, ds:[bx]  ;将a段与b段的数据相加
    mov si, c1
    mov ds, si
    mov ds:[bx], al  ;将结果存入c1段中

    inc bx
    loop s

    mov ax, 4c00h
    int 21h
code ends
end start

 执行前a段内容

 b段内容

 c段内容:

 

 执行后:

 

 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 bx, 0
    mov cx, 8
    mov si, a
    mov ds, si
s:  push ds:[bx]  ;先将a段的数据压入栈中
    add bx, 2
    loop s
    mov bx, 0
   mov cx, 8 mov si, b mov ds, si s1: pop ds:[bx]  ;出栈存入b段内存 add bx, 2 loop s1 mov ax, 4c00h int 21h code ends end start

 执行前查看b段内容:

 执行后:

四、实验总结

1. 通过本次实验理解了段的含义以及空间分配:在程序中段名代表一个地址这个地址指向存储该段数据的内存空间。

 一个段的空间大小为16字节的整数倍,即使一段中定义使用的字节数不足16个字节也占用至少16个字节的空间。

 对于数据和代码的存放应当存放在不同定义的逻辑段中放置代码混乱,且代码段应当有start 和end start 放置将数据段当做代码段执行。

2. div指令用法:若除数为8位,被除数为16位则被除数默认在ax中存放,运算结果:al存储商,ah存储余数。

posted @ 2020-11-23 10:12  yu136  阅读(240)  评论(0)    收藏  举报