帶學生在課堂上觀察在子程序調用時機器內部發生變化的細節。
有同學關注到了棧中的“亂套”。
程序如下:
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中運行後,界面是:
容易推算出,此時的棧空間爲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
運行後的界面:
可見,引起棧變化的,就是MOV SP, 10H
。(這時,沒有給SS寄存器賦正確的值,這是危險的,SS保持初進入時的0769H。但爲了觀察,也就這樣搗亂一下看看。)
再往後走,可以看見CALL指令的執行,是按照我們想到的機制進行。
-----
初步結論:棧段的“亂套”,來自於修改SP的值。
引申解釋:修改SP的值時,存在着某種機制使用了棧,從而給棧中留下了一些數據。其實這些數據應該不是隨便的亂數據,當知道更多時,可以找出這些數據的之所以來。
遺留問題的解決:或許可以從中斷機制中可以找出一些線索,留待以後再說。