实验五:编写调试具有多个段的程序

Posted kevin234

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实验五:编写调试具有多个段的程序相关的知识,希望对你有一定的参考价值。

实验任务一

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

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0, 0, 0, 0, 0, 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start 

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

②CPU执行程序,程序返回前,CS=____,SS=____,DS=____。

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


实现:

将代码编译、连接后,用debug工具调试:

技术分享图片

技术分享图片

①可以发现,data段的数据在执行程序后,程序返回前并未改变,仍是原始数据。

②从图中可以看出,CPU执行程序,程序返回前,CS=076C,SS=076B,DS=076A。

③进一步可以发现,若code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

实验任务二

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

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start

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

②CPU执行程序,程序返回前,CS=____,SS=____,DS=____。

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

④对于如下定义的段:

name segment
    ...
name ends

 

如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为____.


实现:

将代码编译、连接后,用debug工具调试:

技术分享图片

技术分享图片

①与(1)的结果一样,data段的数据在执行程序后,程序返回前仍未改变,仍是原始数据。

②从图中可以看出,CPU执行程序,程序返回前,CS=076C,SS=076B,DS=076A。

③与(1)的结果一致,若code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

④对比(1)(2)可以发现,(1)中data段数据有16个字节,占用了16个字节空间,而(2)中data段数据只有4个字节,但实际上(2)也占用了16字节的空间,其中不足的部分都用0补全了。所以推测,若段中数据为N个字节,则该段实际占用的空间为  ([N/16]+1)*16 个字节([]为取整符号)。

实验任务三

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

 1 assume cs:code, ds:data, ss:stack
 2 
 3 code segment
 4 start:  mov ax,stack
 5         mov ss, ax
 6         mov sp,16
 7         
 8         mov ax, data
 9         mov ds, ax
10         
11         push ds:[0]
12         push ds:[2]
13         pop ds:[2]
14         pop ds:[0]
15         
16         mov ax,4c00h
17         int 21h
18 
19 code ends
20 data segment
21   dw 0123h, 0456h
22 data ends
23 
24 stack segment
25   dw 0,0
26 stack ends
27 end start

 

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

②CPU执行程序,程序返回前,CS=____,SS=____,DS=____。

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


实现:

将代码编译、连接后,用debug工具调试:

技术分享图片

技术分享图片

 

①可以发现,data段的数据在执行程序后,程序返回前并未改变,仍是原始数据。

②从图中可以看出,CPU执行程序,程序返回前,CS=076A,SS=076E,DS=076D。

③进一步可以发现,若code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4。

总结:对比(2)(3),发现它们仅仅是data段、stack段和code段的顺序交换了一下,其内容都一样,但是段地址间的相互关系却发生了变化。 进一步观察发现,各段段地址的大小关系与各段在代码中出现的先后关系是一致的,而相邻两段段地址的差值是由前段段占用内存空间大小决定的。实际上,各段在程序中出现的先后顺序是决定了各自被加载进内存的顺序。

实验任务四

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

 答:如果将最后一条伪指令“end start”改为“end”,相当于没有指明程序入口,此时程序就会从加载进内存的第一个单元起开始执行。在(1)(2)题中,都是数据先加载进内存,CPU会误把数据也当成指令执行,最终不能保证被正确执行;而(3)题则是代码段先被加载进内存,因而可以被正确执行。

 

实验任务五

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

 1 assume cs:code
 2 a segment
 3   db 1,2,3,4,5,6,7,8
 4 a ends
 5 
 6 b segment
 7   db 1,2,3,4,5,6,7,8
 8 b ends
 9 
10 c segment   ; 在集成软件环境中,请将此处的段名称由c→改为c1或其它名称
11   db 8 dup(0)
12 c ends        ; 改的时候要成对一起修改
13 code segment
14 start:
15        ;?
16 code ends
17 end start

实现:

此题需要存放数据的段有3个,即a、b、c,但是任意时刻,只有一个 ds 和 es 可用。通过前面的实验可以得知,a段的段地址和b段的段地址 是有联系的,此例中,由于a、b段的数据都小于16个字节,设a段的段地址为X,则b段的段地址为X+1。据此可以得到一种实现方案:

 补充的代码为:

    mov ax,c
    mov ds,ax      ;将ds作为c段的段地址
    mov ax,a  
    mov es,ax      ;将es作为a段的段地址
    mov bx,0

    mov cx,8
s:  mov dl,es:[bx]
    add [bx],dl
    mov dl,es:[bx+16]  ;b:[bx]对应于 a:[bx+16]
    add [bx],dl
    inc bx
    loop s   
    
    mov ax,4c00h
    int 21h

 

 

技术分享图片

 技术分享图片

可以看到,此方案成功实现了a段与b段依次相加的目的。

除此之外,还可以有另一种方案,即分阶段使用ds:

补充的代码为:

    mov ax,a
    mov ds,ax  ;ds作为逻辑段a
    mov ax,c 
    mov es,ax  ;es作为逻辑段c

;阶段一:将逻辑段a的数据复制到逻辑段c中
mov bx,0 mov cx,8 s1: mov al,[bx] mov es:[bx],al inc bx loop s1 mov ax,b mov ds,ax  ;ds作为逻辑段b
;阶段二:将b段的数据依次加到c上
mov bx,0 mov cx,8 s2: mov al,[bx] add es:[bx],al inc bx loop s2 mov ax,4c00h int 21h

 

技术分享图片

技术分享图片

技术分享图片

可以看到,此方案实现了a段复制到c段b段加到c段上两个阶段的任务,最终也实现了将a、b段数据依次相加的目的。

实验任务六

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

 1 assume cs:code
 2 a segment
 3   dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
 4 a ends
 5 
 6 b segment
 7   dw 8 dup(0)
 8 b ends
 9 
10 code segment
11 start: 
12        ;?
13 code ends
14 end start

实现:

补充的代码为:

    mov ax,a
    mov ds,ax
    mov ax,b
    mov ss,ax  ;将b段设置为栈
    mov sp,16  ;栈顶为16
    mov bx,0

    mov cx,8
s:  push [bx]
    add bx,2
    loop s

    mov ax,4c00h
    int 21

 

技术分享图片

技术分享图片

在push之前,b段的内容都为0,入栈全部结束后,b段逆序存储了a段的前8个字节。 

以上是关于实验五:编写调试具有多个段的程序的主要内容,如果未能解决你的问题,请参考以下文章

[汇编语言]实验五:编写,调试具有多个段的程序

汇编实验五 编写调试具有多个段的程序

实验五 编写调试具有多个段的程序

实验五 编写调试具有多个段的程序

实验五 编写调试具有多个段的程序

实验五 编写调试具有多个段的程序