实验5——编写、调试具有多个段的程序

一、实验内容

(1)将下面的程序编译、连接,用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

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

答: data中的数据为:0123h 0456h 0789h 0abch 0defh 0fedh 0cbah 0987h。与执行程序前data数据段中的数据一致。

②CPU执行程序,程序返回前,cs=076ch,ss=076bh,ds=076ah

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

 

(2)将下面的程序编译、连接,用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段中的数据为多少?

答: data中的数据为:0123h 0456h 。与执行程序前data数据段中的数据一致。

②CPU执行程序,程序返回前,cs=076ch,ss=076bh,ds=076ah

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

④对于如下定义的段:

name segment
...
name ends

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

 

(3)将下面的程序编译、连接,用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 start

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

答: data中的数据为:0123h 0456h 。与执行程序前data数据段中的数据一致。

②CPU执行程序,程序返回前,cs=076ah,ss=076eh,ds=076dh

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

 

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

答:只有(3)中的程序可以正确执行。因为(3)中的程序在逻辑段的一开始就是代码段,即相应的汇编指令,而其余两个一开始为数据段,如果不指明程序入口,则计算机内部会把数据段即栈段中的信息也当做是相应的汇编指令,从而不能正确执行。不过在该实验中,(1)、(2)、(3)如果去掉start,最后data数据段中的结果同正确执行后一样,但这并不能说明未指明程序入口的程序都能如此,在这里,可能是由于data数据段即之后的栈段中的数据被当做汇编指令后不影响执行结果,倘若出现比如jmp bx等发生跳转的指令后,结果就会大变样了。

 

(5)程序如下,编写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   
  db 8 dup(0)
c1 ends        
code segment
start:mov ax,a
      mov ds,ax
   
      mov ax,c1
      mov es,ax
   
      mov bx,0
      mov cx,8
s:    mov al,[bx]
      mov es:[bx],al  ;将a段中的数据放入c段中
      inc bx
      loop s

      mov ax,b
      mov ds,ax

      mov bx,0
      mov cx,8
s1:   mov al,[bx]
      add es:[bx],al   ;此时再将b段与c段相加
      inc bx
      loop s1
   
      mov ax,4c00h
      int 21h    
   
code ends
end start

利用debug调试结果如下:

由debug调试可得:该程序可以正确实现数据相加。

 

(6)程序如下,编写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 ax,b
      mov ss,ax
      mov sp,11h  ;定义栈
      mov ax,a
      mov ds,ax
      
      mov bx,0
      mov cx,8

s:    mov ax,[bx]
      push ax
      add bx,2
      loop s
      
      mov ax,4c00h
      int 21h
       
code ends
end start

利用debug调试如下:

由debug调试可得:a段中的前8个字型数据已逆序存储到b段中。

 

在该实验的debug调试中,在一个比较愚蠢的问题上纠结了好久,决定记录下来。一开始在b段中定义了8个字型数据,全为0,然后在执行push ax这一指令之前,我用d命令查看此时b段中的数据为多少,我理所当然的认为此时应该是16个字节全为0,结果却我和想的有所差异,一开始百思不得其解......后来在和同学讨论中发现,此时并没有入栈的操作,故此时栈中的数据全是初始时的数值,并不一定16个字节全为0,而之所以在b段中要定义8个全为0 的字单元,是因为要分配一块内存空间为接下来入栈等操作做准备,而这并不意味这此时栈中全为0。

为此,我还另写了一小段程序来验证是否正确。

assume cs:code
a segment
    dw 8 dup(0)
a ends

code segment
start:mov ax,a
      mov ss,ax
      mov sp,10h
      mov bx,0
      mov cx,8
s:    push bx   ;将0压入栈
      loop s
    
      mov ax,4c00h
      int 21h

code ends
end start

 

二、总结与体会

在本次试验中,主要收获有以下几点:

(1)掌握了用u命令准确地反汇编到int 21h结束。其中要用到试验(2)中的结论,不管段中的数据是否占满16个字节,或是否是16的倍数,该段实际占有的空间都是16的倍数,根据该结论将代码段之前的数据段占有的空间算出,再用 [(CX)-1] 减去该值即可得到u反汇编的结束地址。

(2)巩固了之前第3章所学的栈中的相关知识。当把一段内存空间当作栈段来使用时,初始状态栈是空的,SS的值比较好确定,SP的值需要具体分析,该段内存空间的大小及偏移地址的情况。

例如:

assume cs:code,ss:stack,ds:data
...
stack segment
    dw 16 dup(0)
stack ends
code segment
start:mov ax,stack
        mov ss,ax
        mov sp,20h  ;20h=1e+2
...
        mov ax,4c00h
        int 21h
code ends
end start
assume cs:code 
code segment
    dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
    dw 16 dup(0)
start:mov ax,cs
        mov ss,ax
        mov sp,30h  ;30h=2e+2
...
        mov ax,4c00h
        int 21h
code ends
end start

这两段代码都是书上的原代码,用于区分。第一个将数据与代码放入不同的段中,每一个段的偏移地址都是从0开始,而第二个则不然,数据和代码都是在code段中的,故而在计算偏移地址时需要注意叠加。

(3)关于 dw 8 dup(0) 指令,经过查阅资料知道了dup 在汇编中是一条伪指令,用来重复初始化数据。

 

 posted on 2018-11-26 21:01  G_fish  阅读(239)  评论(0编辑  收藏  举报