如今的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并没有做这样的设计。 它只知道栈顶在哪里。不知道栈有多大。

换个说法就是:只知道下一条指令在哪里,而不知道要处理的指令有多少条。