2012-01-19 91 views
0

我想在程序集中使用局部變量遞歸處理(intel 8086)。所以我不喜歡它下面的代碼:在程序集中使用局部變量遞歸處理

MOEIN PROC NEAR 
     IPTEMP DW ? 
     NUM DW ? 
     POP IPTEMP 
     POP NUM 
     DEC NUM 
     CMP NUM,0H 
     JZ EXIT 

     PUSH NUM 

     CALL MOEIN 

     EXIT: 
     PUSH IPTEMP 
     RET 
     MOEIN ENDP

它應該做下面的代碼:

void moein(int x) 
{ 
x--; 
if (x != 0) 
    moein(x); 
}

,但它不能做it.it將失去回來的路上。 我怎麼可以像我在C寫的那樣進行彙編呢?

回答

2

作業?

您的代碼的主要問題是聲明的變量(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寄存器中的寄存器
  • 之一用於定義堆棧幀

所有這些都有多種來源 - 或者只是讀取已編譯的代碼並嘗試使用編譯器選項:您會在那裏找到許多方法。祝你好運:這很有趣!

1

您可以在堆棧上明確分配空間,或者使用MASM或兼容的彙編程序,您可以使用LOCAL指令來創建本地變量。

+0

我認爲LOCAL只適用於宏。請你舉個例子。 –