3.10 栈段
对于8086PC机,可以根据需要,将一组内存单元定义为一个段。我们可以将长度为N(N<=64KB)的一组地址连续、起始地址为16的倍数的内存单元,当作栈空间来用,从而定义了一个栈段。例如10010H~1001FH这段长度为16字节的内存空间当作栈来用,以栈的方式进行访问。这段空间就可以成为一个栈段,段地址为1001H,大小为16字节。
通过将SS:SP指向我们定义的栈段来使得如push
、pop
等栈操作指令访问我们定义的栈段。
问题 1
如果将10000H~1FFFFH这段空间当作栈段,初始状态栈是空的,此时SS=1000H,SP=?
在栈中,一般SP指针会指向栈底部的上一位,因为要输出一个字单元。所以这时指向的是1FFFEH,如下表
1FFFEH |
1FFFFH |
? |
问号中即为本问题的答案,? = SP = 0000H
push、pop等指令在执行时只修改SP, 所以栈顶的变化范围是0~FFFFH,从栈空时候的SP=0,一直压栈,知道栈满时SP=0;如果再次压栈,栈顶将环绕, 覆盖了原来栈中的内容。所以一个栈段的容量最大为64KB。
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。关键在于CPU中寄存器的设置,即CS、IP、SS、SP、DS的指向,如下代码:
mov ax, 1000H
mov ss, ax
mov sp, 0020H ;初始化栈顶
mov ax, cs
mov ds, ax ;设置数据段段地址
mov ax, [0]
mov ax, [2]
mov bx, [4]
mov bx, [6]
push ax
push bx
pop ax
pop bx
问题 2
写代码将10000H~1000FH中的8个字,逆序复制到20000H~2000FH中,如图
mov ax, 1000H
mov ds, ax ;数据段定义到1000H
mov ax, 2000H
mov ss, ax
mov sp, 10H ;定义栈偏移地址, 使其空栈(栈底部的下一位)
push [0] ;按顺序push进数据段地址之中从高到底的数据
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
mov ax, 2000H ;定义数据段为2000H
mov ds, ax
mov ax, 1000H ; 定义栈地址
mov ss, ax
mov sp, 0 ; 这里之所以将sp规定为0,是因为pop命令的行为是在从数据段弹出并复制到栈中一个字型大小后,执行sp = sp + 2,向下行。
pop [E] ; 从数据段按顺序pop出数据到栈地址
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]