如今的CPU都有提供棧機制,8086也不例外。

8086提供的最基本的兩個指令就是push and pop.

1push ax ;將寄存器ax中的數據送入棧頂
2pop ax ;將棧頂的數據送入ax

我們知道CS:IP寄存器存放了下一條指令的段地址和偏移地址,那麼CPU是如何知道棧頂在哪吶? 顯然也有兩個寄存器專門存放棧頂的地址,那就是SS:SP寄存器,SS = 段地址, SP = 偏移地址

任意時刻,SS:SP都指向棧頂元素。pushpop指令執行時CPU將從SS和SP中獲得棧頂的地址。

push 有2步:

  • SP -= 2 SS:SP指向棧頂前面的單元,以這個位置為新棧。
  • 將AX中的內容送入 SS:SP 所指的位置.
 110000H  |_______|
 2        |_______|
 3        |_______|
 4        |_______|
 5        |_______|
 6        |_______|
 7        |_______|
 8        |_______|
 9        |_______|
10        |_______|
111000EH  |__23___| <= SS:SP
121000FH  |__01___|
 110000H  |_______|
 2        |_______|
 3        |_______|
 4        |_______|
 5        |_______|
 6        |_______|
 7        |_______|
 8        |_______|
 9        |_______| <= SS:SP: 換個位置
10        |_______|
111000EH  |__23___|
121000FH  |__01___|
 110000H  |_______|
 2        |_______|
 3        |_______|
 4        |_______|
 5        |_______|
 6        |_______|
 7        |_______|
 8        |_______|  ;來自ax寄存器的數據
 9        |__54___| <= SS:SP: 換個位置
10        |__11___|
111000EH  |__23___|
121000FH  |__01___|

假設 10000H -> 1000FH 這段空間是棧,那麼棧空時,SS:SP在吶?

 110000H  |_______|
 2        |_______|
 3        |_______|
 4        |_______|
 5        |_______|
 6        |_______|
 7        |_______|
 8        |_______|
 9        |_______|
10        |_______|
111000EH  |_______|
121000FH  |_______| <= SS:SP: 我在這?
 110000H  |_______|
 2        |_______|
 3        |_______|
 4        |_______|
 5        |_______|
 6        |_______|
 7        |_______|
 8        |_______|
 9        |_______|
10        |_______|
111000EH  |_______|
121000FH  |_______|
1310010H  |_______| <= SS:SP: 其實爺在這裡。

至於為什麼只要想想 SP -= 2 你就知道了。

關於爆棧

棧一旦爆了,SS:SP就會指到別的地方去。 這麼一想CPU應該會知道棧頂在哪裡。

每次push,pop都會檢查棧頂和棧底的位置,保證棧不會超。這麼一想美滋滋。

然而,8086CPU並沒有做這樣的設計。 它只知道棧頂在哪裡。不知道棧有多大。

換個說法就是:只知道下一條指令在哪裡,而不知道要處理的指令有多少條。