匯編寄存器(內存訪問)基礎知識之四----棧


 

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指向我們定義的棧段.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM