GitHub

第六章实验

实验1

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

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

                23 01 56 04 89 07 BC 0A EF 0D ED 0F BA 0C 87 09

 

(2)CPU执行程序,程序返回前,cs=0772   ,ss=  0771  ,ds=   0770  

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

 


 实验2

调试

 

 

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

           23 01 56 04

(2)CPU执行程序,程序返回前,cs=0772   ,ss=  0771  ,ds=   0770  

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

(4)对于定义的段

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


 

实验3

调试

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

               23 01 56 04

(2)CPU执行程序,程序返回前,cs=0770   ,ss=  0774  ,ds=   0773

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


 

实验4

调试结果

(1)

(2)

 

(3)

前两个程序不能正确执行,最后一个可以正确执行

因为如果不指明程序的入口,CPU就会默认从头执行,我们从调试的结果就可以看出前两个开始执行的不是我们指定的代码段


 

实验5

源代码

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
  inc bx
  loop s
  
  mov ax,b
  mov ds,ax
  mov bx,0
  mov cx,8
  
s:mov al,[bx]
  add es:[bx],al
  inc bx
  loop s
  
code ends
end start

调试

在实现数据相加前,逻辑段c 的8 个字节

执行完实现加运算的代码后,逻辑段c 的8 个字节

正确实现数据相加


 

实验6

源代码

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,a
  mov ds,ax
  mov ax,b
  mov ss,ax
  mov sp,16
  mov cx,8
  mov bx,0

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

调试

在push 操作执行前,查看逻辑段b 的8 个字单元信息截图

 

执行push 操作,然后再次查看逻辑段b 的8 个子单元信息截图

 

     成功实现将a段中前8个字型数据逆序存储到b段中


 

总结与体会

1.前三个实验在寻找代码段,数据段,堆栈段之间的关系和联系,他们可以共用一段内存空间,并且有一定的关系,但是并没有找到确切的代数关系,在网上找到了下面这个图

(摘自https://blog.csdn.net/ywcpig/article/details/52303745)

2.段中实际数据占用大小的分析

在8086CPU架构上,段是以paragraph(16-byte)对齐的。程序默认以16字节为边界对齐,所以不足16字节的部分数据也要填够16字节。“对齐”是alignment,这种填充叫做padding。16字节成一小段,称为节

详解

一、这首先要从8086处理器寻址原理说起。
      8086这种处理器有二十根地址线(20个用于寻址的管脚),可以使用的外部存储器空间可达1MB(00000H~FFFFFH)。 但是,8086内部的寄存器都是16位的,用任何一个寄存器(比如BX或SI),都无法直接寻址8086所支持的1M地址空间,因为16位寄存器只能表示640KB的空间范围(0000~FFFFH)。
      所以,Intel想了一个方法,设计出了CS/DS/ES/SS这几个段地址寄存器,用段地址寄存器与普通寄存器组合,来寻址1MB的地址范围,即:对于CPU取指来说,用CS:IP组合来寻址下一个要执行的指令(也在存储器中);对于堆栈操作PUSH/POP来说,用SS:SP组合来表示当前栈指针(栈也在存储器中);对于数据操作指令来说,用默认的DS/ES或指定的段地址(段前缀指令)与偏移量寄存器组合寻址。
组合后的实际地址=段寄存器内容×16+偏移量寄存器内容
      从这个公式可以看到,每一个段的地址都对齐在16的倍数上。比如DS=1234H,则这个段就从 1234H×16+0000H=12340H开始,最大到1234H×16+0FFFFH=2233FH为止。
二、对同一个内存地址,有不同的段:偏移量组合方法,比如2233FH这个地址,既可以表示为1234H:0FFFFH(在1234H段中),也可以表示为2233H:0000FH(在2233H段中)。
那么,如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment 
d1 db 0 
name1 ends 
name2 segment 
d2 db 0 
name2 ends
  编译程序可以将name1和name2编译成一个段,d1和d2在内存中连续存放,这样可以节省内存空间。比如编译程序以name1为基准,将name1作为一个段的起始,程序加载后会被放在xxxx0H的地方,那么d1就放在该段偏移地址为0字节的位置,d2就放在该段偏移为1字节的位置。 
  这样的处理方式虽然可能会节省一点内存空间,但是对于编译器的智能化要求太高了,它必须将源程序中所有引用到name2和d2的地方,全部调整为以name1段为基准,这实在是太难了,而且也节省不了几个字节的空间,编译器是不会干这种吃力不讨好的事的。
      编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处,name2里的所有内容放在后续一个段的起始地址处(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=(段中字节数+15)/ 16。
  所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。
(摘自https://blog.csdn.net/friendbkf/article/details/48212887)
 

 

posted @ 2018-11-22 11:29  繁华似锦觅安宁  阅读(313)  评论(0编辑  收藏  举报