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