汇编语言复习摘要三——寄存器的内存访问

1. DS和[address]:8086CPU中寻址是用段地址×16+偏移地址来实现的。8086CPU有一个DS寄存器,通常用来存放要访问数据的段地址。而偏移地址则由[address]来决定。举例:

mov bx, 1000H

mov ds, bx

mov al, [0]

表示寻址到1000:0,把该字节送给寄存器al。注意,不能直接用:mov ds, 1000H。这是硬件上的设计。

 

2. 数据段:8086CPU可以根据需要,将一组内存单元定义一个段。比如,我们可以将123B0H~123B9H这段内存空间用来存放数据,段地址为123BH,长度为10个字节。存放数据段的段地址,可以用DS寄存器来保存。

 

3. 8086CPU的栈机制:8086CPU提供了两个栈的基本操作:PUSH和POP,如栈和出栈;这里要注意的是,8086CPU
的入栈和出栈操作都是以字为单位来进行的。比如,我们在10008H~1000FH这段栈空间进行如下操作:

mov ax, 0123H

push ax

mov bx, 2266H

push bx

mov cx, 1122H

push cx

pop ax

pop bx

pop cx

从1000FH这个地址开始,进行入栈操作,所以1000FH~10009H的数据分别是:

01H 23H 22H 66H 11H 22H 高地址存放高字节,8086CPU是大端。

pop ax 是从把出栈的数据存放到寄存器ax中,并非是选择ax中的数据出栈。

8086CPU有两个寄存器,分别是段寄存器SS和寄存器SP,这两个寄存器将决定了PUSH和POP操作在哪里进行。栈顶的段地址存放在SS中,偏移地址存放在SP中,所以:任意时刻,SS:SP指向了栈顶元素。CPU从SS:SP中得到栈顶的地址。

 

例如,push ax的执行,分为两个步骤:

1)SP = SP - 2, SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶元素;

2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP辞职指向新栈顶;

例如,pop ax 的执行,分为两个步骤,和push刚好相反:

1)将SS:SP指向的内存单元处的数据送入到ax中;

2)SP = SP + 2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶;

 

4. 栈顶越界的问题:由于栈空间是有限的,所以当你不断进行PUSH操作,总有一个时候,栈顶指针超过了栈的空间,这个时候就发生了栈顶越界的问题了。栈顶越界是危险的,因为在栈空间之外往往存放了其他的数据和代码等等,栈顶越界将会覆盖其他数据,从而导致计算机系统出现问题。8086CPU的工作原理其实只是考虑当前的情况:当前的栈顶在何处,当前要执行的指令是哪一条。所以,我们在编程的时候要自己操心栈顶越界的问题,要合理地安排栈空间的大小,谨防栈越界。

 

5. 栈段:8086CPU中,可以根据需要,将一组内存单元定义为一个段,然后对这个段上的数据进行相关操作。所以,我们可以通过修改SS:SP的值来让push, pop等栈操作指令访问我们自己定义的栈段。

问题1:如果将10000H~1FFFFH这段空间当作栈段,初始状态为空,SS = 1000H, 则SP = ?

当栈里面只有一个元素的时候,SP = FFFEH;当栈为空的时候,就是SP = SP + 2,这时候SP = 0000H。

问题2:一个栈段最大可以设为多大?

显而易见,0~FFFFH。从栈空的时候,SP = 0,一直压栈,知道栈满SP = 0;如果再次压栈,栈顶指针重新指向了FFFEH,这时候将会覆盖原来的内容。

 

6. 段总结:

用一个段存放数据,将它定义为“数据段”;

用一个段存放代码,将它定义为“代码段”;

用一个段当作栈,将它定义为“栈段”;

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

对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址放在IP中,CPU将执行CS:IP的指令;

对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,CPU执行栈操作的时候,push, pop等,将我们定义的栈段当作栈空间来用。

所以,CPU将内存中的某段内容当作代码,是因为CS:IP指向那里;CPU将某段内容当作栈,是因为SS:SP指向了那里;CPU将某段内容当作数据,是因为该段内容的地址是DS中存放的地址。

posted @ 2010-09-24 11:29  Linjian  阅读(841)  评论(0编辑  收藏  举报