彙編語言-第三章 寄存器(棧存儲)

3.6 棧

棧是一種具備特殊的訪問方式的存儲空間。
棧有兩個最基本的操做:入棧和出棧。
棧的操做規則爲:LIFO(後進先出,Last In First Out)程序員

3.7 CPU提供的棧機制

現今的CPU中都有棧的設計。
8086CPU提供相關的指令來以棧的方式訪問內存空間。這意味着,咱們在基於8086CPU編程的時候,能夠將一段內存看成棧來使用。
8086CPU的入棧和出棧操做都是以字爲單位進行的。
在內存中劃分一塊出來看成棧,這就是棧的本質。
CPU如何知道棧頂的具體位置?顯然,也應該有相應的寄存器來存放棧頂的地址。
8086寄存器中有兩個寄存器:段寄存器SS寄存器SP
棧頂的段地址存放在SS中,偏移地址存放在SP中。在任意時刻,SS:SP指向棧頂元素。
push指令和pop指令執行時,CPU從SS和SP獲得棧頂的地址。編程

push ax的執行,由下面兩步之行:設計

  • SP=SP-2,SS:SP指向的內存單元處,以當前棧頂前面的單元爲新的棧頂
  • 將ax中的內容送入SS:SP指向的內存單元出,SS:SP此時指向新棧頂。

pop ax 的執行過程和push ax相反,由如下兩步完成:code

  • 將SS:SP指向的內存單元處的數據送入ax中
  • SP=SP+2.SS:SP指向當前棧頂下面的單元,以當前棧頂下面的單元爲新的棧頂。

3.8棧頂超界問題

棧頂越界是超級危險的。咱們將一段內存空間安排爲棧,那麼在棧空間以外的空間裏極可能存放了具備其餘用途的數據、代碼等,這些數據、代碼多是咱們本身程序中的,也多是別的程序中的(畢竟一個計算機系統中並非只有咱們本身的程序在運行)。
可是,因爲咱們在入棧、出棧時的不當心,而將這些數據、代碼意外的改寫,將會引起一連串的錯誤。
8086CPU並不保證咱們對棧的操做不會越界。也就是說,8086CPU只知道棧頂在何處(由SS:SP指示),而不知道程序員安排的棧空間有多大。這就比如,CPU只知道當前要執行的指令在何處(由CS:IP指示),而不知道讀者要執行的指令由多少。
因此咱們在編程的時候要本身考慮棧頂越界的問題,要根據可能用到的最大棧空間發,來安排棧的大小,防止入棧的數據太多而致使的越界;執行出棧操做的時候也要注意,以防棧空的時候繼續出棧而致使的越界。內存

3.9 push、pop指令

棧空間也是內存空間的一部分,它只是一段能夠以一種特殊的方式進行訪問的內存空間。ast

push和pop指令的格式能夠是以下形式:程序

push 寄存器    //將一個寄存器中的數據入棧    
pop  寄存器      //用一個寄存器來接收出棧的數據

還能夠是以下的形式:方法

push 段寄存器    // 將一個段寄存器中的數據入棧
pop  段寄存器      //用一個段寄存器接收出棧的數據

push和pop也能夠在內存單元和內存單元之間傳送數據,咱們能夠:數據

push 內存單元     //將一個內存字單元處的字入棧(注意,棧操做都是以字爲單位)
pop  內存單元      //用一個內存字單元接收出棧的數據

指令執行時,CPU要知道內存單元的地址,能夠在push、pop指令中只給出內存單元的偏移地址,段地址在指令執行時,CPU從ds中得到。計算機

例子

mov ax,1000H
mov ds,ax      //內存單元的段地址要放在ds中
push [0]          //將1000:0處的字壓入棧中
pop [2]          //出棧的數據送入1000:2處

例子

將10000H~1000FH這段空間當作棧,初始狀態是空的,將AX、BX、DS中的數據入棧。

mov ax,1000H
mov ss,ax      //設置棧的段地址,SS=1000H,不能直接向段寄存器SS送入數據,因此用AX中轉
mov sp,0100H    //設置棧頂的偏移地址,由於棧空, 因此sp=0010H。
push ax
push bx
push ds

例子

編程:
(1)將10000H~1000FH這段空間當作棧,初始狀態棧是空的
(2)設置AX=001AH,BX=001BH
(3)將AX、BX中的數據入棧
(4)而後將AX、BX清零
(5)從棧中恢復AX、BX原來的內容

mov ax,1000H
mov ss,ax
mov sp,0010H      //初始化棧頂
mov ax,001AH
mov bx,001BH
push ax
push bx
sub ax, ax        //將ax清零,也能夠用mov ax,0
                       //sub ax,bx 的機器碼爲兩個字節
                         //mov ax,0的機器碼爲3個字節
sub bx,bx
pop bx             //從棧中恢復ax、bx原來的數據,當前棧頂的內容是bx
pop ax

例子

(1)將10000H~1000FH這段空間當作棧,初始狀態棧是空的
(2)設置AX=002AH,BX爲002BH
(3)利用棧,交換AX和BX中的數據

mov ax,1000H
mov ss,ax
mov sp 0010H
mov ax,002AH
mov bx,002BH
push ax
push bx
pop ax
pop bx

在10000H處寫入字型數據2266H,能夠用如下的代碼完成:

mov ax,1000H
mov ds,ax
mov ax,2266H
mov [0],ax

或者用下面的方法:
說明 :
入棧的執行過程是:
1.先將記錄棧頂偏移地址的SP寄存器中的內容減2,使得SS:SP指向新的棧頂單元
2.再將寄存器中的數據送入SS:SP指向的內存單元處,即10000H處

mov ax,1000H
mov ss,ax
mov sp,0002H
mov ax,2266H
push ax

push、pop實質上就是一種內存傳送指令,能夠在寄存器和內存之間傳送數據,與mov指令不一樣的是,push和pop指令訪問的內存單元的地址不是在指令中給出的,而是由SS:SP指出的。同時,push和pop還要改變SP中的內容。
push和pop指令同mov指令不一樣,CPU執行mov指令只需一步操做,就是傳送。
執行push、pop指令須要兩步操做。
執行push時,CPU的兩步操做是:
1.先改變SP
2.向SS:SP處傳送
執行pop時,CPU的兩步操做是:
先讀取SS:SP處的數據
後改變SP

注意:

push、pop等棧操做指令,修改的只是SP。也就是說,棧頂的變化範圍最大爲:0~FFFFH
SS、SP指示棧頂:改變SP後寫內存的入棧指令;讀內存後改變SP的出棧指令。這就是8086CPU提供的棧操做機制。

棧的綜述

(1)8086CPU提供了棧操做機制,方案以下:

  • 在SS、SP中存放棧頂的段地址和偏移地址
  • 提供入棧和出棧指令,它們根據SS:SP指示的地址,按照棧的方式訪問內存單元。
    (2)push指令的執行步驟:
  • SP=SP-2
  • 向SS:SP指向的字單元中送入數據
  • POP指令的執行步驟:
  • 從SS:SP指向的字單元中讀取數據
  • SP=SP+2
    (4)任意時刻,SS:SP指向棧頂元素
    (5)8086CPU只記錄棧頂,棧空間的大小要咱們本身管理
    (6)用棧來暫存之後須要恢復的寄存器的內容時,寄存器出棧的順序要和入棧的順序相反。
    (7)push、pop實質上是一種內存傳送指令

棧段

對於8086CPU,在編程時,咱們能夠根據須要,將一組內存單元定義爲一個段。
將一段內存當作棧段,僅僅是咱們在編程時的一種安排,CPU並不會因爲這種安排,就在執行push、pop等棧操做指令時就自動地將咱們定義的棧段當作棧空間來訪問。

一個棧段最大設置爲多少?爲何?
最大容量爲64KB
push、pop等指令在執行的時候只修改SP,因此棧頂的變化範圍是0~FFFFH,從棧空的時候SP=0,一直壓棧,直到棧滿的時候SP=0;若是再次壓棧,棧頂將環繞,覆蓋了原來棧中的內容。

段的綜述

咱們能夠將一段內存定義爲一個段,用一個段地址指示段,用偏移地址訪問段內的單元,這徹底是咱們本身的安排。

  • 咱們能夠用一個段存放數據,將它定義爲「數據段」
  • 咱們能夠用一個段存放代碼,將它定義爲「代碼段」
  • 咱們能夠用一個段當作棧,將它定義爲「棧段」
    咱們能夠這樣安排,但若要想讓CPU按照咱們的安排來訪問這些段,就要:
  • 對於數據段,將它的段地址放在DS中,用mov、add、sub等訪問內存單元的指令時,CPU就將咱們定義的數據段中的內容當作數據來訪問。
  • 對於代碼段,將它的段地址放在CS中,將段中第一條指令的偏移地址放在IP中,這樣CPU就將執行咱們定義的代碼段中的指令
  • 對於棧段,將它的地址放在SS中,將棧頂單元的偏移地址放在SP中國年,這樣CPU在須要進行棧操做的時候,好比執行push、pop等指令,就將咱們定義的棧段當作棧空間來使用。
    CPU將內存中的某段內容當作代碼,是由於CS:IP指向了那裏;CPU將某內存當作棧,是由於SS:SP指向了那裏。
    一段內存,能夠既是代碼的存儲空間,又是數據的存儲空間,還能夠是棧空間,也能夠什麼也不是,關鍵在於CPU中寄存器的設置,即:CS,IP,SS,SP,DS的指向。

例子

咱們將10000H~1001H安排爲代碼段,並在裏面存儲以下代碼:

mov ax,1000H
mov SS,ax
mov SP,0020H
mov ax,cs
mov ds,ax
mov ax[0]
mov ax [2]
mov bx[4]
mov bx[6]
push ax
push bx
pop ax
pop bx

設置CS=1000H,IP=0,這段代碼將獲得執行。在這段代碼中,咱們又將10000H~1001FH安排爲棧段和數據段。10000H~1001F這段內存,既是代碼段,又是棧段和數據段。

相關文章
相關標籤/搜索