汇编寄存器(内存访问)基础知识之四----栈

1:栈是一种先进后出的操作

  栈(比喻:碟盘子)。

  8086cpu提供相关的指令来以栈的方式访问内存空间

  也就是说:在基于8086cpu编程 的时候,可以将一段内存当作栈来使用

2:入栈和出栈指令:
  PUSH 入栈
  POP 出栈
例:
  push ax : 将寄存器ax中的数据送入栈中
  pop ax: 从栈顶取出数据送入ax

8086cpu的入栈和出栈操作以 为单元

3:8086cpu的栈操作:   

     

出栈操作pop ax ,ax里面的值变为1122,此时,1000AH和1000BH里的数据还存在的,只是栈顶指针移动了,里面的数据下一次push操作的时候将会覆盖它。

出栈操作pop bx ,bx里面的值变为2266,

出栈操作pop cx ,cx里面的值变为0123,

4:

困惑?

1:cpu怎么栈顶一段内存空间被当做栈使用?

2:执行push和pop的时候,如何知道那个单元是栈顶单元?

根据前面所学知道,cpu怎么知道当前要执行的指令的位置?答: 寄存器CS和IP中存放当前指令的段地址和偏移地址

还有  DS:偏移地址  ----指向---> 数据

所以栈也有段寄存器SS和寄存器SP.

  堆栈段寄存器 SS(Stack Segment) :存放栈顶的段地址

  寄存器SP:    存放栈顶的偏移地址

任意时刻,SS:SP指向栈顶元素

当执行push和pop的时候,栈顶单元改变,cpu怎么知道当前的栈顶单元?

例如:push ax(先偏移地址减-2,后放数据)

  (1)SP=SP-2

  (2)将ax中的内容送入SS:SP指向的内存单元,SS:SP此时是新栈顶

pop ax  则是相反,先取出ss:sp指向的内存单元的数据放到ax里面,然后SP+2;

任意时刻,SS:SP指向栈顶元素,当栈位空的时候,栈中没有元素,也就不存在栈顶元素

所以,SS:SP只能指向栈的最底部单元下面的单元,此单元的偏移地址为栈最底部的字单元的偏移地址+2

例如:栈最底部字单元的地址为1000:000E,所以栈空时,SP=0010H.

5:栈顶越界的问题:

  当栈满的时候在push指令入栈,或者栈空的时候在使用pop指令出栈,都将发生栈顶超界的问题,栈顶超界是危险的

所以,在编程的时候要小心操作栈顶超界的问题,要根据可能用到的最大栈空间,安排栈的大小,防止栈数据太多导致的越界;

 堆(heap):是由程序员分配的,是零碎的内存,堆最后一定要释放内存。

栈与内存:

  栈空间是内存空间的一部分,它只是一段可以特殊(先进后出FILO(First-In/Last-Out))方式进行访问的内存空间

6: push和pop指令

push和pop指令可以在寄存器和内存直接传送数据的。

 push和pop指令的格式(1)

  push  寄存器:将一个寄存器中的数据入栈     例如:push ax

  pop  寄存器:出栈,用一个寄存器接受出栈的数据   例如:pop bx

 push和pop指令的格式(2)

  push  段寄存器:将一个段寄存器中的数据入栈   例如: push ds

    pop   段寄存器:出栈,用一个段寄存器接受出栈的数据 例如:pop es  (ES:附加段寄存器)

 push和pop指令的格式(3)

  push  内存单元:将一个内存单元的字入栈 (栈操作都是以字为单元).   例如:push [0] (也就是 push ds:0)

    pop   内存单元:出栈,用一个内存单元接受出栈的数据.     例如:pop [2]       (也就是 pop ds:2)

执行指令时,cpu要知道内存单元的地址,可以在push,pop指令中给出内存单元的偏移地址,段地址在指令执行时,cpu从ds中取得.

7:问题:如果要在10000H处写入字型数据2266H,可以用下面的代码实现:

  mov ax,1000H

  mov ds,ax    //把内存单元的地址通过ax中介放到段地址中

  mov  ax,2266H   

  mov [0],ax   //把寄存器的数据 放入内存单元(1000:0)中

  还可以用下面的代码完成这个功能,不能使用"mov 内存单元,寄存器 ’这类指令

  mov ax,1000H

  mov ss,ax       //栈的寄存器段地址是1000H

  mov sp,2      //栈的栈顶偏移量要在0的下面,就是高,因为push入栈,先是sp=sp-2,然后在放入数据到栈中,ss:sp指向栈顶元素

    mov ax,2266H

    push ax

结论:

push,pop实质上是一种内存传送指令,可以在寄存器和内存直接传送数据,

与mov指令不同的是,push和mov指令访问的内存的单元地址不是在指令中给出的,而是由SS:SPd指出的。

同时,push和pop还要改变sp中内容.

执行push时,先改变sp=sp-2,后向SS:SP处传送

执行pop, 先读取SS:SP处的数据,后改变SP=sp+2

8注意:

(1)栈的变化范围最大为:0~FFFFH(FFFFH=65535(D),栈的操作是16位模式,2^16=64KB)

(2)SS:SP指向栈顶,改变SP(sp=sp-2)后写入内存 是入栈指令 ;读取内存后改变SP(sp=sp+2) 是出栈指令

9栈的小结:

(1)8086cpu提供了栈操作机制:

  在SS:SP存放栈顶的段地址和偏移地址;

  提供入栈和出栈指令,根据SS:IP指向的地址,按照栈的方式访问内存单元

(2)push指令的步骤:  <1> sp=sp-2;    <2> SS:SP指向的字单元中传入数据

(3)pop指令步骤:<1>从SS:SP指向的字单元读取数据 ;  <2>sp=sp+2

(4)任意时刻,SS:SP指向栈顶元素

(5)8086cpu只记录栈顶,栈空间大小有我们自己管理

(6)push,pop实质上是一种内存传送指令

10: 栈段

  前面讲过,对于8086cpu,在编程时,可以根据需要,在一组内存单元中定义一个段

  所以,我们可以将长度为N(N<=64KB)的一组地址连续,起始地址为16的倍数的内存单元,当做栈的空间使用,从而定义一个栈段。

cpu如何把我们定义的栈段当做栈空间来访问呢?   就要指定 SS:SP指向我们定义的栈段.

原文地址:https://www.cnblogs.com/DonAndy/p/6091043.html