带学生在课堂上观察在子程序调用时机器内部发生变化的细节。

  有同学关注到了栈中的“乱套”。

  程序如下:

assume cs:code, ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,1000
call s ;调用子程序
mov ax,4c00h
int 21h
s: add ax,ax ;子程序开始
ret ;子程序返回
code ends
end start

编译、连接,并在debug中运行后,界面是:

8086汇编栈段为何“乱套”了_中断机制

  容易推算出,此时的栈空间为076A:0到076A:F。

  乱子始于执行​​MOV SS, AX​​。并且,本来单步执行一条指令,但​​MOV SP, 10H​​没有出现,但,SP的值的确已经变了。

  ​​MOV SP, 10H​​执行过了——是debug自己干了,没有给程序员单步的机会。这个和中断机制相关(在王爽教材12.11和12.12有详细解释,在此不详述)。

  再往后走,可以看见CALL指令执行过程中,栈是按照我们想到的机制进行。

把程序改一下:

assume cs:code, ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start: mov ax,stack
;mov ss,ax ;把这一句加了注释
mov sp,16
mov ax,1000
call s ;调用子程序
mov ax,4c00h
int 21h
s: add ax,ax ;子程序开始
ret ;子程序返回
code ends
end start

运行后的界面:

8086汇编栈段为何“乱套”了_数据_02

  可见,引起栈变化的,就是​​MOV SP, 10H​​。(这时,没有给SS寄存器赋正确的值,这是危险的,SS保持初进入时的0769H。但为了观察,也就这样捣乱一下看看。)

  再往后走,可以看见CALL指令的执行,是按照我们想到的机制进行。

  -----