2011-12-25 55 views
1

我的作業我需​​要在C#中編寫一個非常小的虛擬16位彙編語言解釋器。 它用一個字節數組(64k)和變量(A,B,C,...)模擬RAM。 現在我需要一種方法來保存局部變量,谷歌說他們被分配在堆棧上。ASM解釋器:局部變量是如何存儲的?

但是,我不清楚的是,當它們被分配到堆棧(帶有推...)時,解釋器在以後使用時如何訪問它們?

參見下面的2行:

pi INT 3 
mov A, pi 

在第一行中,PI被分配在棧中,在第二行中,PI被使用,但是應該怎樣解釋器知道其中Pi是在堆棧訪問其數據? (我的籌碼是一個字節數組也有2輔助函數(PUSH,POP),還有一個指向堆棧的頂部)

回答

0

通常沒有單獨的堆棧內存,而是堆棧位於常規RAM中,因此您只有跟蹤它的堆棧指針。

而且通常,局部變量是在子程序開始由堆棧指針複製到另一個寄存器,然後移動堆棧指針,以騰出空間變量分配:

mov bp, sp ;copy stack pointer 
sub sp, 4 ;make room for two integer variables 

訪問局部變量完成使用堆棧指針的副本:

mov A, [bp-2] ;get first integer 
mov B, [bp] ;get second integer 

當你離開子程序,你恢復堆棧指針解除分配的局部變量:

mov sp, bp ;restore stack 
ret ;exit from subroutine 

,你在提問中使用的語法通常是用來聲明全局變量,而不是局部變量:

.data 
pi int 3 ;declare a label and allocate room for an int in the program 
.code 
mov A, pi ;use the address of the label to access the int 
+0

感謝這就是我一直在尋找的。 – 2011-12-25 11:54:36

0

「谷歌說,他們在棧上分配的」

這是如何在真實計算機上實現的,但這不是全部內容。

如果你想要一個虛擬的解釋器,你需要使用一個名爲'哈希表'的數據結構。

這是一個家庭作業問題。所以沒有直接的答案:P 但下面的代碼將解釋如何使用哈希表。將變量名稱和值存儲在散列表中。

using System; 
using System.Collections; 

class Program 
{ 
    static Hashtable GetHashtable() 
    { 
    // Create and return new Hashtable. 
    Hashtable hashtable = new Hashtable(); 
    hashtable.Add("Area", 1000); 
    hashtable.Add("Perimeter", 55); 
    hashtable.Add("Mortgage", 540); 
    return hashtable; 
    } 

    static void Main() 
    { 
    Hashtable hashtable = GetHashtable(); 

    // See if the Hashtable contains this key. 
    Console.WriteLine(hashtable.ContainsKey("Perimeter")); 

    // Test the Contains method. It works the same way. 
    Console.WriteLine(hashtable.Contains("Area")); 

    // Get value of Area with indexer. 
    int value = (int)hashtable["Area"]; 

    // Write the value of Area. 
    Console.WriteLine(value); 
    } 
} 
+0

我知道哈希表,但我們不能直接使用這種高層次的結構,我假設彙編標識與變量有些ids(數字)還是我錯了? – 2011-12-25 10:30:58

+0

不,你不是。但是如果你確實分配了'ids',你最終將會使用兩個數組完成一個哈希表實現。兩種使用ID的方法:1)在堆棧中推入一個變量,將其位置(ID)存儲在一個數組中,並存儲在另一個數組存儲變量名稱的相應位置。然後當你的堆棧更新更新這些位置。這不是最終使用低級構造實現的哈希表嗎?第二種方法是爲您的堆棧數據結構添加一些額外的功能,允許您遍歷其內容並搜索您想要的內容。 – Shaunak 2011-12-25 10:41:39

0

答案是:取決於。作爲語言設計者,您應該定義什麼是(如果定義了一個變量名稱,其中的部分源代碼是可用的名稱?)和隱藏(如果存在另一個具有相同的對象在另一個對象的可見性區域中定義的名稱,哪個名稱獲勝?)變量的規則。不同的語言有不同的規則,只是比較Javascript和C++。

所以,我會這樣做。 (1)引入名稱空間的概念:在源文件的某個點可見的名稱列表。 (請注意,這與C++的名稱空間概念不同)。名稱空間應該能夠將名稱解析爲某個適當的對象。 (2)當您的翻譯從一個過程變爲另一個過程,從一個文件到另一個過程,從一個塊到另一個塊,看到一個聲明或塊結束等時,實施更改命名空間的規則。

這些步驟基本上對大多數語言有效,而不僅僅是彙編程序。 (我認爲,谷歌對「在堆棧上分配」的引用是指在一個單獨的子例程中處理每個子例程,並在本地重新定義一個名稱空間,因此「在堆棧上」,因此它會在過程完成)。

1

通常,堆棧數據通過stack pointer,這是一個CPU寄存器相對訪問的指向存儲在堆棧上的最後一個元素。您可以將其視爲仿真CPU內存索引。每次你將一些東西壓入堆棧時,堆棧指針的大小會減少一些,並且在減少之後,某些東西會被存儲在模擬內存中的地址中。每當你從堆棧中彈出某些東西時,該值將從存儲在堆棧指針中的地址中獲取,然後堆棧指針會增加該東西的大小。這就是CPU堆棧在許多不同CPU中的工作方式。

如果您正在實現CPU模擬器或CPU指令模擬器/解釋器,則不需要太多變量。你關心的是操作CPU寄存器和內存的CPU指令,因爲你的程序是用CPU指令表示的。他們(指令)必須跟蹤存儲在堆棧上的所有loacal變量,即它們相對於堆棧指針當前值的位置。例如,如果您考慮一個簡單的子例程,它在堆棧上添加傳遞給它的兩個16位整數值,它可能看起來像這樣。 16位x86彙編:

myadd: 
    push bp ; we'll be accessing stack through bp (can't do that through sp because there's no sp-relative memory addressing in 16-bit mode), so, let's save bp first 
    mov bp, sp ; bp is equal to the stack pointer 
    mov ax, dword ptr [bp + 4] ; load ax with 1st parameter stored at bp+4 (sp+4) 
    add ax, dword ptr [bp + 6] ; add to ax 2nd parameter stored at bp+6 (sp+6) 
    pop bp ; restore bp 
    ret ; near return to the caller at address stored at sp (address after call myadd), the result/sum is in ax 

,主叫方可以是這樣的:

push word 2 ; prepare/store 2nd parameter on the stack 
    push word 1 ; prepare/store 1st parameter on the stack 
    call myadd ; near call, pushes address of next instruction (add), jumps to myadd 
    add sp, 4 ; remove myadd's parameters (1 and 2) from the stack 
    ; ax should now contain 3 
相關問題