作業?
您的代碼的主要問題是聲明的變量(IPTEMP和NUM)由函數的所有調用共享,而不是在每次調用該函數時重新創建。因此,每次遞歸調用自己時,變量都會被覆蓋。你能想到的方式是編譯時指令,因此它在編譯期間保留了一點內存。編譯器不知道該函數將被調用多少次,因此它不知道它需要創建多少個變量。
另一個問題是它以錯誤的方式與棧混淆。想象一下,你稱這個函數爲10次。但POP NUM
之後使用的堆棧數量恰好爲零:您爲此實例和以前的每個實例彈出其所有內容。這意味着關於最後9個實例的上下文的所有信息都將丟失。
解決此問題的最簡單方法是使用所謂的「堆棧幀」 - 這是大多數時間高級語言所做的。每個函數的堆棧幀看起來像這樣,從頂部(較高地址)底部(低地址):
- (可選)的函數的參數,由呼叫者
- 的返回地址,通過推壓推在「CALL」指令
- (可選)局部變量
假設我們是在16位模式(因爲8086
標籤),所有下面就用16位整數和16位地址算術。
因此,[SP]指向返回地址,因此[SP + 2]指向第一個(最接近,僅在您的情況下)參數。你需要做的是閱讀的說法,遞減,比較和調用自:
MOEIN PROC NEAR
MOV AX, [SP+2] ; read the argument from the stack
DEC AX
; you don't need CMP AX,0H here, since DEC sets the same flags
JZ EXIT
PUSH AX ; place the argument on the stack for the next call
CALL MOEIN
ADD SP, 2 ; don't forget to clean the passed argument from the stack
EXIT:
RET
MOEIN ENDP
其他變體包括:
- 使用
RET 2
指令清除棧:你將不再需要ADD SP, 2
然後
- 傳遞一個值通過使用
BP
寄存器中的寄存器
- 之一用於定義堆棧幀
所有這些都有多種來源 - 或者只是讀取已編譯的代碼並嘗試使用編譯器選項:您會在那裏找到許多方法。祝你好運:這很有趣!
來源
2012-01-19 23:33:09
Rom
我認爲LOCAL只適用於宏。請你舉個例子。 –