从访问内存的角度继续学习几个寄存器
首先理解几个要点:
1.内存中字的存储
n 在0地址处开始存放20000:
n 0号单元是低地址单元,1号单元是高地址单元。
备注:任何两个地址连续的内存单元,N号单元和 N+1号单元,可以将它们看成两个内存单元 ,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。
2. DS和[address]
n CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址;
n 在8086PC中,内存地址由段地址和偏移地址组成。
n 8086CPU中有一个 DS寄存器,通常用来存放要访问的数据的段地址。
n 例如:我们要读取10000H单元的内容可以用如下程序段进行:
mov bx,1000H
mov ds,bx
mov al,[0]
n 上面三条指令将10000H(1000:0)中的数据读到al中。
mov指令的格式:
mov 寄存器名,内存单元地址
“[…]”表示一个内存单元, “[…]”中的0表示内存单元的偏移地址。
那么内存单元的段地址是多少呢?就是上面的ds
备注:8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器。
(硬件设计的问题)
mov ds,1000H 是非法的。
数据-一般的寄存器-段寄存器
明白了以上原理,我们具体来看看字的传送
3.字的传送
因为8086CPU是16位结构,有16根数据线,所以,可以一次性传送16位的数据,也就是一次性传送一个字。
看下面的图清晰的描述了这个过程:
内存中的情况如右图,写出下面指令执行后寄存器ax,bx,cx中的值。
分析后就可以知道
Ax=1000h
Ds=1000h
Ax=1123h
Bx=6622h
Cx=2211h
Bx=6622h+2211h=8833hh
Cx=8833hh
现在您可以练习一下,看图写出每行运行后寄存器的结果,如下:
参考答案提供上来:
通过上面的分析,实际上我们已经接触到了以下几种指令:
mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 内存单元,寄存器
mov 段寄存器,寄存器
mov 内存单元,段寄存器
mov 段寄存器,内存单元
add和sub指令同mov一样,都有两个操作对象。
4. 数据段
前面讲过,对于8086PC机,我们可以根据需要将一组内存单元定义为一个段。
我们可以将一组长度为N(N≤64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。
比如我们用123B0H~123B9H这段空间来存放数据:
段地址:123BH
长度:10字节
如何访问数据段中的数据呢?
将一段内存当作数据段,是我们在编程时的一种安排,我们可以在具体操作的时候 ,用 ds 存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。
例子:
我们将123B0H~123BAH的内存单元定义为数据段,我们现在要累加这个数据段中的前3个单元中的数据,代码如下:
5.栈的操作(先进后出)
push 指令的执行过程
先来看入栈的操作,用图来分析:
解释如下:
n 我们将10000H~1000FH 这段空间当作栈段,SS=1000H,栈空间大小为16 字节 ,栈最底部的字单元地址为1000:000E。
任意时刻,SS:SP指向栈顶,当栈中只有一个元素的时候,SS = 1000H,SP=000EH。
n 栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2 ,SP 原来为 000EH,加 2 后SP=10H,所以,当栈为空的时候,SS=1000H,SP=10H。
再来看看出栈的操作:
解释如下:
n 出栈后,SS:SP指向新的栈顶 1000EH,pop操作前的栈顶元素,1000CH 处的2266H 依然存在 ,但是,它已不在栈中。
n 当再次执行push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,它将被覆盖。
SS和SP只记录了栈顶的地址,依靠SS和SP可以保证在入栈和出栈时找到栈顶。
可是,如何能够保证在入栈、出栈时,栈顶不会超出栈空间。
栈顶超界的问题
看下面的图:
下面来解释一下:
n 8086CPU不保证对栈的操作不会超界。
这就是说, 8086CPU 只知道栈顶在何处(由SS:SP指示),而不知道读者安排的栈空间有多大。这点就好像 ,CPU 只知道当前要执行的指令在何处(由CS:SP指示)而不知道读者要执行的指令有多少。
我们在编程的时候要自己操心栈顶超界的问题 ,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防栈空的时候继续出栈而导致的超界。
看下面栈顶超出栈空间的情况:
解释如下:
1/当栈空时,此时ss=1000h,sp=0020h;
当执行了八次压栈后,栈满了,此时ss=1000h,sp=0010h;
如果再执行一次,那么此时ss=1000h,sp=sp-2=000e,这样就把其它内存地址给复盖了,这对程序来讲是致命 的。
出栈的原理和入栈原理类似,在此就不用图描述了。读者可自己去体会。
总结如下:
n 我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。
n 我们可以用一个段存放数据,将它定义为“数据段”;
n 我们可以用一个段存放代码,将它定义为“代码段”;
n 我们可以用一个段当作栈,将它定义为“栈段”;
n 我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:
n 对于数据段,将它的段地址放在 DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据段来访问;
n 对于代码段,将它的段地址放在 CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
n 对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地置放在 SP 中,这样CPU在需要进行栈操作的时候,比如执行 push、pop 指令等,就将我们定义的栈段当作栈空间来用
可见,不管我们如何安排 ,CPU 将内存中的某段内存当作代码 ,是因为CS:IP指向了那里;CPU将某段内存当作栈 ,是因为 SS:IP 指向了那里。
来源:https://www.cnblogs.com/mfm11111/archive/2009/03/26/1422648.html