段地址

处理器负责执行指令,内存里面存着CPU要执行的指令。
当CPU通电之后,CPU内部所有的寄存器会进行复位,比如初始化成0000H,CPU就从这个地址开始提取指令,当然这是举例。

为了做某件事而编写的指令,当这样几条,几十条,甚至几百万条,几千万条这样的程序组合在一起,形成了我们平时所说的程序。
程序总要操作大量的数据,这些数据也应该集中在一起,位于内存中的某个地方,形成一个段,叫做数据段。


假定我们有16个数要相加,这些数都是16位的二进制数,分别是0005H、00A0H、00FFH、…。
为了让处理器把它们加起来,我们应该先在内存中定义一个数据段,将这些数字写进去。数据段可以起始于内存中的任何位置,既然如此,我们将它定在0100H处。

这样一来,第一个要加的数位于地址0100H,第二个要加的数位于地址0102H,最后一个数的地址是011EH。
一旦定义了数据段,我们就知道了每个数的内存地址。然后,紧挨着数据段,我们从内存地址0120H处定义代码段。

严格地说,数据段和代码段是不需要连续的,但这里把它们挨在一起更自然一些。为了区别数据段和代码段,我们使用了不同的底色。


代码段是从内存地址0120H处开始的,第一条指令是A1 00 01,其功能是将内存单元0100H里的字传送到AX寄存器。指令执行后,AX的内容为0005H。
第二条指令是03 06 02 01,功能是将AX中的内容和内存单元0102H里的字相加,结果在AX中。由于AX的内容为0005H,而内存地址0102H里的数是00A0H,这条指令执行后,AX的内容为00A5H。
第三条指令是03 06 04 01,功能是将AX中的内容和内存单元0104H里的字相加,结果在AX中。此时,由于AX里的内容是00A5H,内存地址0104H里的数是00FFH,本指令执行后,AX的内容为01A4H。
图2-






我们的程序OK,搞定了。
但是平常我们使用计算机的时候,游戏,视频,操作系统已经把内存占用了。

当我们在操作系统里面,双击一个这样的程序运行的时候,它很可能压根不会运行成功。
因为操作系统,会考虑哪里的内存比较空闲,就把这些指令放到哪里去。
可能把我们这些数据段和代码段放到了1000H的内存地址。

而我们指令相加的内存地址却是0100……0104.。这肯定就出问题了。。








我们让指令运行的时候,定位数据用的是绝对的内存地址。
这样子程序真正执行的知道,被操作系统不知道分配到哪个内存位置了,就出问题了。

所以,我们只能使用相对地址。
当然,CPU的设计者们也为我们考虑到这些问题了,那么如何解决这个问题呢?


在8086 16位CPU中,除了我们刚才学习的几个通用寄存器,再介绍两个寄存器,这两个寄存器分别为:
代码段寄存器  CS  [Code Segment]
数据段寄存器  DS  [Data Segment]
附加段几次器  ES  [Extra Segment]
指令寄存器     IP   它和CS一起使用。

栈段寄存器    SS 










当CPU要运行我们程序的时候,首先把CS和DS的位置确定下来,然后放到这两个寄存器里面。
CS和IP共用形成逻辑地址,并经过CPU的一个部件变成物理地址来取得指令。
访问内存则使用DS加偏移

按照套路8086应该最大只有64KB内存。
但是64KB太小了。

内存的大小取决于CPU可以定位的范围和物理内存本身的大小。


0000 0000 0000 0000
1111 1111 1111 1111  地址定位
FFFF = 65536 =64KB的内存
1111 1111 1111 1111 1111  地址定位。 

这样子可以定位1MB的内存.
00000H到FFFFFH

而寄存器却都是16位的。
CS:0008
IP: 0003
CS:IP= 0008:0003 =000B 真实的内存物理地址。

但却是00080:0003=00083



 


 

所以,这个问题可以这样理解。
我有两个16位寄存器最大都可以表示 FFFF
现在我要通过这两个寄存器的组合,能够表示FFFFF


为了让大家能够理解这种工作模式,我们转换成十进制给大家理解。

A最大可以表示9999,最小为0000 
B最大可以表示9999 , 最小为0000
C最大可以表示99999,最小为00000

我们怎么样可以用A和B来表示C呢?
假如A是1230,B是80
那么A x 10 + B= 12300+80 =12380

A和B   C
9999:0009   99999
9999:0008   99998
9999:0007   99997
9999:0006   99996
9999:0005   99995
9999:0004   99994
9999:0003   99993
9999:0002   99992
9999:0001   99991
9999:0000   99990
...   ...
...   ...
...   ...
0001:0009   00019
0001:0008   00018
0001:0007   00017
0001:0006   00016
0001:0005   00015
0001:0004   00014
0001:0003   00013
0001:0002   00012
0001:0001   00011
0001:0000   00010
0000:0009   00009
0000:0008   00008
0000:0007   00007
0000:0006   00006
0000:0005   00005
0000:0004   00004
0000:0003   00003
0000:0002   00002
0000:0001   00001
0000:0000   00000

 

 

十六进制

A和B   C
FFFF:000F   FFFFF
FFFF:000E   FFFFE
FFFF:000D   FFFFD
FFFF:000C   FFFFC
FFFF:000B   FFFFB
FFFF:000A   FFFFA
FFFF:0009   FFFF9
FFFF:0008   FFFF8
FFFF:0007   FFFF7
FFFF:0006   FFFF6
FFFF:0005   FFFF5
FFFF:0004   FFFF4
FFFF:0003   FFFF3
FFFF:0002   FFFF2
FFFF:0001   FFFF1
FFFF:0000   FFFF0
...   ...
...   ...
...   ...
0001:000F   0001F
0001:000E   0001E
0001:000D   0001D
0001:000C   0001C
0001:000B   0001B
0001:000A   0001A
0001:0009   00019
0001:0008   00018
0001:0007   00017
0001:0006   00016
0001:0005   00015
0001:0004   00014
0001:0003   00013
0001:0002   00012
0001:0001   00011
0001:0000   00010
0000:000F   0000F
0000:000E   0000E
0000:000D   0000D
0000:000C   0000C
0000:000B   0000B
0000:000A   0000A
0000:0009   00009
0000:0008   00008
0000:0007   00007
0000:0006   00006
0000:0005   00005
0000:0004   00004
0000:0003   00003
0000:0002   00002
0000:0001   00001
0000:0000   00000
0000:0000-0000:000F
0001:0000-1000:000F
0002:0000-0002:000F
FFFF:0000-FFFF:000F

把1M的内存分成了65536个段,每个段16个字节。


当然,这只是一种组合定位物理地址的方法。
我们还可以这么定位。
0000:0000 - 0000:FFFF
1000:0000 - 1000:FFFF
2000:0000 - 2000:FFFF
F000:0000 -F000:FFFF 

把1M的内存分成了16个段,每个段64KB

这是两种不同的分法:
比如FFFF:000F和F000:FFFF其实是一个物理地址。


假设现在物理地址00000H-82251H都被其他程序占用了。
二后面82252H-FFFFFH,都是空闲的。
为了让我们的程序能够加载。
我们可以选择82260H这个位置。然后把DS:偏移设置成8226H:0000H
因为我们要让偏移的初值地址为0000
posted @ 2017-07-08 01:14  随意就好欧巴  阅读(442)  评论(0编辑  收藏  举报