一步步学习汇编系列(7)

夙愿已清 提交于 2020-01-24 21:45:29
 
寄存器(内存访问)

从访问内存的角度继续学习几个寄存器

首先理解几个要点:

1.内存中字的存储

n        0地址处开始存放20000

71.png

 

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        上面三条指令将10000H1000:0)中的数据读到al中。

mov指令的格式:

      mov 寄存器名,内存单元地址

“[…]”表示一个内存单元, “[…]”中的0表示内存单元的偏移地址。

那么内存单元的段地址是多少呢?就是上面的ds

 

备注:8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器。

 (硬件设计的问题)

mov ds,1000H 是非法的。

数据-一般的寄存器-段寄存器

 

明白了以上原理,我们具体来看看字的传送

3.字的传送

因为8086CPU16位结构,有16根数据线,所以,可以一次性传送16位的数据,也就是一次性传送一个字。

看下面的图清晰的描述了这个过程:

 

内存中的情况如右图,写出下面指令执行后寄存器axbxcx中的值。

72.png

分析后就可以知道

Ax=1000h

Ds=1000h

Ax=1123h

Bx=6622h

Cx=2211h

Bx=6622h+2211h=8833hh

Cx=8833hh

 

现在您可以练习一下,看图写出每行运行后寄存器的结果,如下:

73.png

参考答案提供上来:

74.png

 

通过上面的分析,实际上我们已经接触到了以下几种指令:

mov 寄存器,数据

  mov 寄存器,寄存器

  mov 寄存器,内存单元

  mov 内存单元,寄存器

  mov 段寄存器,寄存器

   mov 内存单元,段寄存器

   mov 段寄存器,内存单元

 

addsub指令同mov一样,都有两个操作对象。

 

4. 数据段

前面讲过,对于8086PC机,我们可以根据需要将一组内存单元定义为一个段。

我们可以将一组长度为NN64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。

比如我们用123B0H~123B9H这段空间来存放数据:

段地址:123BH

长度:10字节

   如何访问数据段中的数据呢?

将一段内存当作数据段,是我们在编程时的一种安排,我们可以在具体操作的时候 ,用 ds 存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。

 

例子:

我们将123B0H~123BAH的内存单元定义为数据段,我们现在要累加这个数据段中的前3个单元中的数据,代码如下:

75.png

5.栈的操作(先进后出)

push 指令的执行过程

先来看入栈的操作,用图来分析:

 

76.png

解释如下:

n        我们将10000H~1000FH 这段空间当作栈段,SS=1000H,栈空间大小为16 字节 ,栈最底部的字单元地址为1000:000E

      任意时刻,SS:SP指向栈顶,当栈中只有一个元素的时候,SS = 1000HSP=000EH。 

n        栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2 SP 原来为 000EH,加 2 SP=10H,所以,当栈为空的时候,SS=1000HSP=10H

 

再来看看出栈的操作:

77.png

解释如下:

n        出栈后,SS:SP指向新的栈顶 1000EHpop操作前的栈顶元素,1000CH 处的2266H 依然存在 ,但是,它已不在栈中。

n        当再次执行push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,它将被覆盖。

 

SSSP只记录了栈顶的地址,依靠SSSP可以保证在入栈和出栈时找到栈顶。

 

可是,如何能够保证在入栈、出栈时,栈顶不会超出栈空间。

栈顶超界的问题

看下面的图:

78.png

下面来解释一下:

n        8086CPU不保证对栈的操作不会超界。

   这就是说, 8086CPU 只知道栈顶在何处(由SS:SP指示),而不知道读者安排的栈空间有多大。这点就好像 CPU 只知道当前要执行的指令在何处(由CS:SP指示)而不知道读者要执行的指令有多少。

   我们在编程的时候要自己操心栈顶超界的问题 ,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防栈空的时候继续出栈而导致的超界。

看下面栈顶超出栈空间的情况:

79.jpg

 

解释如下:

  1/当栈空时,此时ss=1000h,sp=0020h;

当执行了八次压栈后,栈满了,此时ss=1000h,sp=0010h;

如果再执行一次,那么此时ss=1000h,sp=sp-2=000e,这样就把其它内存地址给复盖了,这对程序来讲是致命 的。

 

出栈的原理和入栈原理类似,在此就不用图描述了。读者可自己去体会。



总结如下:
 

n

n        我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。

n        我们可以用一个段存放数据,将它定义为数据段

n        我们可以用一个段存放代码,将它定义为代码段

n        我们可以用一个段当作栈,将它定义为栈段

 

n        我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:

n        对于数据段,将它的段地址放在 DS中,用movaddsub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据段来访问;

n        对于代码段,将它的段地址放在 CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;

n        对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地置放在 SP 中,这样CPU在需要进行栈操作的时候,比如执行 pushpop 指令等,就将我们定义的栈段当作栈空间来用

     

可见,不管我们如何安排 CPU 将内存中的某段内存当作代码 ,是因为CS:IP指向了那里;CPU将某段内存当作栈 ,是因为 SS:IP 指向了那里。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!