实验2 多个逻辑段的汇编源程序编写与调试

1、实验内容与结论

实验任务1

此实验任务中,包含4个子任务。

  • 任务1-1
    对程序task1_1.asm进行汇编、连接,用debug加载、跟踪调试

代码如下:

assume ds:data, cs:code, ss:stack

data segment
    db 16 dup(0)
data ends

stack segment
    db 16 dup(0)
stack ends
code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 16

    mov ah, 4ch
    int 21h
code ends
end start

用u命令反汇编之后,查看到执行到第17行,代码段地址是000a;用g命令调试到该位置。
结果截图:

image
根据调试结果可以得出看出来,代码段和栈段各自预留了16B地址,因此可以看到各个段寄存器相隔的地址数为16B,结果如下:
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076a, 寄存器(SS) = 076b, 寄存器(CS) = 076c ;
② 假设程序加载后,code段的段地址是X,则,data段的段地址是_X-2_,stack的段地址是__x-1__。

  • 任务1-2
    对程序task1_2.asm进行汇编、连接,用debug加载、跟踪调试
    代码如下:
assume ds:data, cs:code, ss:stack

data segment
    db 4 dup(0)
data ends

stack segment
    db 8 dup(0)
stack ends
code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 8

    mov ah, 4ch
    int 21h
code ends
end start

实验过程与实验1-1相似
结果如下:

image
根据调试结果可以得出,当数据段和栈段预留的地址不足16B,系统仍以16B为单位分配,因此各段地址寄存器间隔仍是16B,结果如下:
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076a, 寄存器(SS) = 076b, 寄存器(CS) = 076c ;
② 假设程序加载后,code段的段地址是X,则,data段的段地址是_X-2_,stack的段地址是__x-1__。

  • 任务1-3
    对程序task1_3.asm进行汇编、连接,用debug加载、跟踪调试

代码如下:

assume ds:data, cs:code, ss:stack

data segment
    db 20 dup(0)
data ends

stack segment
    db 20 dup(0)
stack ends
code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 20

    mov ah, 4ch
    int 21h
code ends
end start

实验过程与上述两个任务相似,结果截图如下:

image

该实验区别在于数据段和栈段各预留了20B,超过了16B,因此系统给予了32B的空间,结果如下:
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076a, 寄存器(SS) = 076c, 寄存器(CS) = 076e ;
② 假设程序加载后,code段的段地址是X,则,data段的段地址是_X-4_,stack的段地址是__x-2__。

  • 任务1-4
    对程序task1_4.asm进行汇编、连接,用debug加载、跟踪调试
    代码如下:
assume ds:data, cs:code, ss:stack
code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 20

    mov ah, 4ch
    int 21h
code ends

data segment
    db 20 dup(0)
data ends

stack segment
    db 20 dup(0)
stack ends
end start

调试过程依旧,查看结果,截图如下:

image

该任务改变了几个段在代码中的位置,也就意味着更改了预留这些空间的顺序,导致各个段寄存器的大小顺序变化,但间隔仍与之前的任务一致。结果如下:
① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076c, 寄存器(SS) = 076e, 寄存器(CS) = 076a ;
② 假设程序加载后,code段的段地址是X,则,data段的段地址是_X+2_,stack的段地址是__x+4__。

  • 任务1-5
    基于上述四个实验任务的实践、观察,总结并回答:
    ① 对于如下定义的段,程序加载后,实际分配给该段的内存空间大小是 _ 16 × [数据长度 / 16] Byte_。([ ]为向上取整)

    xxx segment
    db N dup(0)
    xxx ends
    

② 如果将程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,伪指令 end start 改成end , 哪一个程序仍然可以正确执行?
分别修改代码并调试之后,发现只有任务1-4的程序仍可以正确执行,结果截图如下:

image

截图中可以看出,代码段的起始地址并不正确,查看书本可以得知,end start不仅仅有着提示程序代码在哪里结束的作用,同时也提醒程序代码从何处开始,若是去掉了start,系统默认地将整个程序的开始作为代码的起始,而实验1-1到1-3,程序的开始是对数据段和栈段的预留,不是代码段,因此程序不可以正确运行,而实验1-4改变了这几段的顺序,将代码段放在了最前,因此没有影响。

实验任务2

编写一个汇编源程序,实现向内存单元b800:0f00 ~ b800:0f9f连续160字节,依次重复填充十六进制数据03 04。
代码如下:

assume cs:code

code segment
start:
    mov ax, 0b800h
    mov ds, ax
    mov bx, 0f00h
    mov cx, 80
    mov ax, 0403h
s:  mov ds:[bx], ax
    add bx, 2
    loop s

    mov ah, 4ch
    int 21h
code ends
end start

编译结果如下:
image
可以看到,对应的空间被成功修改为03 04。

实验任务3

要求:
① 编程实现把逻辑段data1和逻辑段data2的数据依次相加,结果保存到逻辑段data3中。
② 在debug中加载、反汇编、调试。在数据项依次相加前,和相加后,分别查看三个逻辑段data1,
data2, data3对应的内存空间,确认逐一相加后,结果的确保存在了逻辑段data3中。

代码补全

assume cs:code
data1 segment
	db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
data1 ends
data2 segment
	db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0 ; ten numbers
data2 ends
data3 segment
	db 16 dup(0)
data3 ends
code segment
start:
	mov ax, data1
	mov ds, ax
	mov bx, 0
	mov cx, 10			;10组数据
s: 	 mov ax, [bx]			; 写入data1
	add ax, [bx+10h]		; 把data1+data2
	mov [bx+20h], ax		; 存入data3
	inc bx
	loop s

	mov ah, 4ch
	int 21h
code ends
end start

运行结果截图如下:

image
分步调试,首先查看复制之前地址空间的情况:
image
复制之后的结果:
image
结果符合要求。

实验任务4

要求:
① 补全程序,实现把逻辑段data1中的8个字数据逆序存储到逻辑段b中。
② 汇编、连接后,在debug中加载程序,运行到line15程序退出前,使用d命令查看数据段data2对应的内存空间,确认是否实现题目要求。


要求是要实现data1中字数据的逆序存储,自然地考虑到用栈结构去实现;
代码补全:

assume cs:code

data1 segment
    dw 2, 0, 4, 9, 2, 0, 1, 9
data1 ends 

data2 segment
    dw 8 dup(?)
data2 ends

code segment
start:
    mov ax,data1
	mov ds,ax
	mov ax,data2
	mov ss,ax
	mov sp,10h
	mov bx,0
	mov cx,8
s:	push [bx]
	add bx,2
	loop s

    mov ah, 4ch
    int 21h
code ends
end start

结果截图如下:

image
结果符合要求。

实验任务5

代码

assume cs:code, ds:data
data segment
        db 'Nuist'
        db 2, 3, 4, 5, 6
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

执行结果如下:

image

由结果可以看出来,该程序将nuist进行了小写到大写的转换,并且加上了不同的颜色
在debug中调试的结果如下图:
image
分析第19行中 做了一个与运算,并且是00dfh,转换为2进制是1101 1111,这个2进制在程序中与其他2进制数做与运算,得到的结果是其他位置不变,第三位变成0,恰好符合字母在ASCII中小写与大写的对应关系,所以在这里,这第19行的作用是将小写转换为大写。
修改line4里5个字节单元的值,重新汇编、链接、运行,观察结果。

db 2,3,4,5,6
--> 改成:
db 5 dup(2) 或 db 5 dup(5)

结果如下:
image
可以看到,结果变成只有绿色,因此这一段数据决定了最终显示出来的颜色。

实验任务6

要求:
① 补全程序,将data段中的每行第一个单词从大写->小写。
② 在debug中加载程序,反汇编,执行到line13退出前,用d命令查看data段对应的内存空间,确认每
行第一个单词已经由大写->小写。


参考书本中的案例可知,将大写改成小写需要用到or 对应字符, 20h,再观察data段,每行占16b,第一个单词均只有4个字母,在此基础上进行循环的嵌套。
代码补全如下:

assume cs:code, ds:data

data segment
    db 'Pink Floyd      '
    db 'JOAN Baez       '
    db 'NEIL Young      '
    db 'Joan Lennon     '
data ends

code segment
start:
   mov ax, data
   mov ds, ax
   mov bx, 0

   mov cx, 4
s0:mov ax, cx
   mov cx, 4

s: or byte ptr [bx], 20h
   inc bx
   loop s

   add bx, 12
   mov cx, ax
   loop s0

   mov ah, 4ch
   int 21h
code ends
end start

运行结果如下:

在debug中反汇编,代码段执行之前,查看存储好的字母;

image
执行完之后再检查是否成功修改:
image
修改成功!

实验任务7

问题场景描述:
Power idea公司1975年-1979年的基本情况如下:

年份 收入(千美元) 雇员(人) 人均收入(千美元)
1975 16 3
1976 22 7
1977 382 9
1978 1356 13
1979 2380 28

程序task7.asm的逻辑段data中(line4-6),已经定义好了这些数据。
要求:
① 补全程序,实现题目要求,把年份、收入、雇员人数、人均收入,以结构化方式写入table段中。表格中,每行数据,在逻辑段table中占16个字节,各项数据占据字节大小分配如下。期中,数据之间用空格间隔。
image
② 汇编、连接后,在debug中加载、调试程序。灵活、合理使用u命令、g命令、d命令,显示刚开始逻辑段table的数据信息,以及,结构化存入数据后,数据段table的数据信息,确认实现题目要求。


本实验难点在于数据的对应位置需要进行细化,并且人均收入是需要进行运算得到结果。代码补全如下:

点击查看代码
assume cs:code, ds:data, es:table

data segment
    db '1975', '1976', '1977', '1978', '1979' 
    dw  16, 22, 382, 1356, 2390
    dw  3, 7, 9, 13, 28 
data ends

table segment
    db 5 dup( 16 dup(' ') )
table ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov ax,table
    mov es,ax
    mov bx,0
    mov si,0
    mov cx,5
s1: mov ax,ds:[bx]
    mov es:[si],ax
    add bx,2
    add si,2
    mov ax,ds:[bx]
    mov es:[si],ax
    add bx,2
    add si,14
    loop s1

    mov bx,20
    mov si,5
    mov cx,5
s2: mov ax,ds:[bx]
    mov es:[si],ax
    add si,2
    mov word ptr es:[si],0
    add bx,2
    add si,14
    loop s2

    mov bx,30
    mov cx,5
    mov si,10
 s3:mov ax,ds:[bx]
    mov es:[si],ax
    add bx,2
    add si,16
    loop s3

    mov bx,20
    mov di,30
    mov cx,5
    mov si,13
s4: mov ax,ds:[bx]
    mov dx,0
    div word ptr ds:[di]
    mov es:[si],ax
    add bx,2
    add di,2
    add si,16
    loop s4

    mov ah, 4ch
    int 21h
code ends
end start
实验结果如下: table中的原始数据:

image
处理后的数据:
image
计算结果(table中的数据):

年份 收入(千美元) 雇员(人) 人均收入(千美元)
1975 16 3 05h
1976 22 7 03h
1977 382 9 2ah
1978 1356 13 68h
1979 2380 28 55h

总结

这次实验考察了代码段数据段等段地址直接关系,讨论了预留不同的数据段空间,系统会进行什么操作,此外也综合地考察了多层嵌套循环的使用方式,了解了用较为低级的语言去编程时的特点,需要对各地址空间的熟练掌握。在遇到不解时也可以通过debug进行反汇编,去查看代码是如何一步步运行的。

posted @ 2021-11-08 11:08  斯文小扬  阅读(30)  评论(2编辑  收藏  举报