一、什么是堆栈
堆栈是一种线性表(
就是像一条线一样存储的序列),堆栈是一种限制的线性表。堆栈只允许在一端进行插入和删除。允许插入和删除的一端称为栈顶(top),另一端称为栈底(button)。堆栈的插入叫做入栈,删除叫做出栈。根据堆栈的特点可知,最先入栈的总是最后出栈的,最后出栈的总是最先出栈的
。


ss段寄存器存储的是堆栈段的基地址,sp则存储堆栈段的栈顶。
为什么说栈底并不存在,假设现在sp指向栈底0x1003,如果再出栈(弹出一字节)的话,sp就会指向0x1004,这也可以。
二、堆栈操作
堆栈操作使用了两个指令:push入栈、pop出栈
1、push 操作数
将sp指向前一个字单元(或字节单元),并把操作数放在sp所指的字单元(或字节单元)中。
2、pop 操作数
将sp所指的字单元(或字节单元)中的数据放到操作数中,这时的操作数不能是立即数,只能是寄存器或内存地址,然后让sp指向下一个字单元(或字节单元)。
当然,也可以使用mov指令把sp所指向的数据挪到目的操作数中,只不过不改变sp的值。

现在假设堆栈为(b)的情况,sp指向0x1004,再假设0x1002中存储的数据为0x5555。问题:mov ax, [sp+2]之后,ax中的数据是什么?mov ax,[sp-2]之后,ax中的数据是什么?

sp+2指向0x1006(0x1004+0x2),所以ax中的数据是0x1234,同理sp-2指向0x1002,所以ax中的数据为0x5555。

三、堆栈的作用
这里只是简单的说明一下:
1、调用函数
2、暂时存储数据
3、保护寄存器数据
调用函数必然会有ip寄存器的变化,有时还需要存储参数,所以用到堆栈。有时为了保护一些暂时数据,使用堆栈无疑再好不过。为了防止函数改变寄存器的值,可以在进入函数时把寄存器入栈,离开函数时把寄存器出栈。
四、进出堆栈的顺序
切忌:先进后出,先出后进。
比如,要在某段指令前把ax和bx寄存器的值保护起来,就是压入堆栈,在这段指令之后再把它们恢复,看看下面的指令哪个对?
(a)
push ax
push bx
.....
pop ax
pop bx
(b)
push ax
push bx
.....
pop bx
pop ax
(a)是错的,因为先进后出,ax先入栈,应该最后出栈,而(a)执行后,ax和bx的数据就会颠倒。bx后入栈,应该出栈,却存到了ax中,ax先入栈,应该后出栈,却存到了bx中。
事实上,使用这种方法交换两个寄存器的值也不是不行:

push ax
push bx
pop ax
pop bx
不过还有更好的方法,以后学习。