堆栈:“先进后出”的存储区,存在于堆栈段中,SP在任何时候都指向栈顶。

一、PUSH指令(字入栈)

1、格式:PUSH 源操作数(字)

PUSH AX ;AX进栈

2、功能

(1)首先将栈顶指针减2,即(SP)-2=>SP;

(2)然后将源操作数(字)=>((SP)+1,(SP))。(高字节,低字节)

即执行操作:

(SP)<– (SP)-2((SP)+1,(SP)) <– (源操作数)

3、说明

高字节先进栈,低字节在栈顶

二、POP指令(字出栈)

1、格式:POP 目的操作数

POP AX ;恢复AX

2、功能

(1)首先将栈顶的字((SP)+1,(SP))=>目的操作数;

(2)然后将堆栈指针SP加2,即(SP)+2=>SP。

即执行操作:

(DST)<– ((SP)+1,(SP))(SP) <– (SP)+2

三、堆栈操作说明

1、栈顶SP指向数据

因为堆栈指针SP总是指向已经存入数据的栈顶(不是空单元),所以PUSH指令时先将(SP)减2,后将内容压栈(即先修改SP使之指向空单元,后压入数),而POP是先从栈顶弹出一个字,后将堆栈指针SP加2.

2、对代码段寄存器

PUSH CS是合法的,但POP CS是不合法的。

3、堆栈特点—–FILO

因为SP总是指向栈顶,而用PUSH和POP指令存取数时都是在栈顶进行的,所以堆栈是“先进后出”或叫“后进先出”的。栈底在高地址,堆栈是从高地址向低地址延伸的,所以栈底就是最初的栈顶。

4、按字访问

用PUSH指令和POP指令时只能按字访问堆栈,不能按字节访问堆栈。

5、不影响标志

PUSH和POP都不影响标志。

6、不能用立即寻址方式

PUSH 1234H ;错误!!

小例子:

这里就是对AX清零。

PUSH DS

SUB AX,AX

PUSH AX

...

...

RET

下面就是一个保护现场的代码

PUSH AX

PUSH BX

PUSH CX

......;期间用到了AX、BX、CX

POP CX

POP BX

POP AX

从键盘上键入10个字符,然后与键入字符的先后相反的顺序显示出来。(使用堆栈的办法)

分析:因为堆栈是“后进先出”的,因此,利用堆栈作为输出缓冲区极易实现按逆序输出。

分配一个256个字的堆栈缓冲区,在其低字节中存放从键盘上键入的字符。我们将从键盘上接受来的10个字符依次进栈,存放在这片堆栈区里,然后再从最后一个字单元开始,弹出堆栈,即可逆序把它们显示出来。

STACKS SEGMENT PARA STACK 'STACK'

DW 256 DUP(?) ;堆栈只能是一个字一个字的操作,多预留点栈空间

STACKS ENDS

CODES SEGMENT

ASSUME CS:CODES,SS:STACKS

START:

MOV AX,STACKS ;这里就用STACKS,以前都是DATAS

MOV SS,AX ;这里就用SS了,以前都是用DS

MOV CX,10 ;输入10个字符=>堆栈

READ:

MOV AH,01H

INT 21H

PUSH AX ;堆栈操作都是‘字’,不能用AL,浪费了AH的空间

LOOP READ ;读10个字符

MOV DL,0AH ;显示回车

MOV AH,02H

INT 21H

MOV DL,0DH ;显示换行

INT 21H

MOV CX,10 ;从栈顶依次弹出10个字符输出

DISP:

POP DX ;显示

MOV AH,02H

INT 21H

LOOP DISP ;显示10个字符

MOV AH,4CH

INT 21H

CODES ENDS

END START

四、堆栈操作说明

(1)堆栈指针SP的自动赋值

只要在堆栈段的SEGMENT伪指令中带有组合类型参数和组名参数:STACK ‘STACK’,汇编程序就会自动把栈底(也是最初的栈顶)的位移量赋给堆栈指针SP。

(2)空间有浪费

因堆栈只对字操作,故10个字符的高字节虽然入了栈,但未用,浪费了一半空间。

(3)堆栈大小留有余地

虽然只输入10个字符,但堆栈定义了256个字(100H)。一般定义时适当留有余地。