前面我们一直在使用push ax和pop ax,显然push和pop指令是可以在寄存器和内存(栈空间当然也是内存空间的一部分,它只是一段可以以一种特殊的方式进行访问的内存
空间。)之间传送数据的。
push和pop指令的格式可以是如下形式:
push 寄存器 ;将一个寄存器中的数据入栈 pop 寄存器 ;出栈用一个寄存器接收出栈的数据
当然也可以是如下形式:
push 段寄存器 ;将一个段寄存器中的数据入栈 pop 段寄存器 ;出栈,用一个段寄存器接收出栈的数据 push和pop也可以在内存单元和内存单元之间传送数据,我们可以: push 内存单元 ;将一个内存字单元处的字入栈(注意:栈操作都是以字为单位) pop 内存单元 ;出栈,用一个内存字单元接收出栈的数据
比如
mov ax,1000H mov ds,ax ;内存单元的段地址要放在ds中 push [0] ;将1000:。处的字压入栈中 pop [2] ;出栈,出栈的数据送入1000:2处
指令执行时,CPU要知道内存单元的地址,可以在push, pop指令中只给出内存单元的偏移地址,段地址在指令执行时,CPU从ds中取得。
问题3.7
编程,将10000H-1 000FH这段空间当作栈,初始状态栈是空的,将AX, BX, DS中的数据入栈。
分析代码如下:
mov ax,1000H mov ss,aX ;设置栈的段地址,SS=1000H,不能直接向段寄存器SS中送入 ;数据,所以用ax中转。 mov sp,0010H ;设置栈顶的偏移地址,因栈为空,所以sp=OOlOH。如果 ;对栈为空时SP的设置还有疑问,复习3.,节、问题3.6 ;上面的3条指令设置栈顶地址。编程中要自己注意栈的大小。 push ax push bX push ds
问题3.8
编程
(1)将1 0000H-1000FH这段空间当作栈,初始状态栈是空的;
(2)设置AX=001 AH , BX=001 BH
(3)将AX, BX中的数据入栈;
(4)然后将AX, BX清零;
(5)从栈中恢复AX, BX原来的内容。
分析代码如下:
mov ax,1000H mov ss,aX m0V sp,0010H ;初始化栈顶,栈的情况如图3.15(a)所示 mov ax,001AH mov bx,001BH push aX push bx ;ax. bx入栈,栈的情况如图3.15 (b)所示 sUb ax,ax ;将ax清零,也可以用mov ax,0, ;sub ax,ax的机器码为2个字节, ;mov ax,。的机器码为3个字节。 sub bx,bx pop bx ;从栈中恢复ax, bx原来的数据,当前栈顶的内容是bx PoP dx ;中原来的内容:OO1BH} ax中原来的内容OOIAH在栈顶 ;的下面,所以要先pop bx,然后再pop axo
从上面的程序我们看到,用栈来暂存以后需要恢复的寄存器中的内容时,出栈的顺序要和入栈的顺序相反,因为最后入栈的寄存器的内容在栈顶,所以在恢复时,要最先出栈。
问题3.9
编程
(1)将10000H-1 000FH这段空间当作栈,初始状态栈是空的:
(2)设置AX=001 AH , BX=001 BH
(3)利用栈,交换AX和BX中的数据。
分析代码如下:
mov ax,1000H moV ss,ax mov sp,0010H ;初始化栈顶,栈的情况如图3.16(a)所示 mov ax,001AH mov bx,001BH push ax push bx ;ax. bx入栈,栈的情况如图3.16 (b)所示 pop ax ;当前栈顶的数据是bx中原来的数据:001BH; ;所以先pop ax, ax=00O1BH; pop bx ;执行pop ax后,栈顶的数据为ax原来的数据; ;所以再pop bx, bx=00lAH;
问题3.10
如果要在10000H处写入字型数据2266H,可以用以下的代码完成:
mov ax,1000H mov ds,ax mov ax,2266H moV [0],ax
补全下面的代码,使它能够完成同样的功能:在10000H处写入字型数据2266H
要求:不能使用“mov内存单元,寄存器”这类指令。
分析
我们来看需补全代码的最后两条指令,将ax中的2266H压入栈中,也就是说,最终应由push ax将2266H写入1 0000H处。问题的关键就在于:如何使push ax访问的内存单元是1 0000H
push ax是入栈指令,它将在栈顶之上压入新的数据。是,先将记录栈顶偏移地址的SP寄存器中的内容减2,使得然后再将寄存器中的数据送入SS:SP指向的新的栈顶单元。
一定要注意:它的执行过程SS:SP指向新的栈顶单元,
所以,要在执行push ax之前,将SS:SP指向10002H(可以设SS=1000H ,SP=0002H),这样,在执行push ax的时候,CPU先将SP=SP-2,使得SS:SP指向10000H,再将ax中的数据送入SS:SP指向的内存单元处,即10000H处
完成的程序如下:
mov ax,1000H mov ss,aX mov sp, 2 mov aX,2266H push ax
从问题3.10的分析中可以看出,push, pop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与mov指令不同的是,push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出的。同时,push和pop指令还要改变SP中的内容。
我们要十分清楚的是,push和pop指令同mov指令不同,CPU执行mov指令只需一步操作,就是传送,而执行push, pop指令却需要两步操作。执行push时,CPU的两步
操作是:
先改变SP,后向SS:SP处传送。
执行pop时,CPU的两步操作是:
先读取SS:SP处的数据,后改变SP
注意
注意,push, pop等栈操作指令,修改的只是SP。也就是说,栈顶的变化范围最大为:O-FFFFH
提供:SS, SP指示栈顶;改变SP后写内存的入栈指令;读内存后改变SP的出栈指令。这就是8086CPU提供的栈操作机制。
栈的综述
(1)8086CPU提供了栈操作机制,方案如下:
在ss、sp中存放栈顶的段地址和偏移地址
提供入栈和出栈指令,他们根据SS:SP指示的地址,按照栈的方式访问内存单元
(2) Push指令的执行步骤
①SP=SP-2;
②向S5:SP指向的字单元中送入数据。
(3)pop指令的执行步骆
①从SS:SP指向的字单元中读取数据:
②Sp=SP+2
(4)任意时刻SS: SP指向栈顶元素。
(5) 8086cPU只记录栈顶,一栈空间的大小我们要自己管理。
(6)用找来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
(7)push、pop实质上是一种内存传送指令,注意它们的灵活应用。