2017-10-17 135 views
3

我們正在研究MIPS彙編(我想這個問題可以適用於裝配雖然在一般),老師向我們介紹了幀指針幀指針的優點是什麼?

如果我有一個函數序言,我用來直接做堆棧指針

addiu $sp, $sp, -8 ; alloc 2 words in the stack 
sw $s0, 4($sp)  ; save caller function $s0 value in the stack 
sw $ra, ($sp)  ; save the return address for the callee function 

而在函數尾聲:

move $v0, $0   ; set 0 as return value 
lw $s0, 4($sp)  ; pick up caller $s0 value from the stack 
lw $ra, ($sp)  ; pick up return address to return to the caller 
addiu $sp, $sp, 8 ; dealloc the stack words I used 
jr $ra    ; return back to caller 

老師說,使用幀指針當我們在裝配中編寫功能時對我們人類有用:

addiu $sp, $sp, -12 ; alloc 3 words in the stack 
sw $fp, 8($sp)  ; save caller frame pointer in the stack 
addiu $fp, $sp, 8 ; set $fp to the uppermost address of the activation frame 
sw $ra, -4($fp)  ; saving like the first example, but relative 
sw $s0, -8($fp)  ; to the frame pointer 

老師還說,有時候堆棧指針會繼續分配其他空間,因爲我們需要注意,所以在函數內部引用激活幀是很困難的。 使用幀指針我們將有一個指向激活幀的靜態指針。

是的,但我會永遠需要使用函數內的激活,因爲它只包含調用者函數保存的數據?

我認爲它只是使事情更難實現。有沒有一個真實的例子,幀指針對程序員來說是一個很大的優勢?

+0

對於許多指令集,你不需要使用幀指針,最多它使編譯器作者更容易調試,這不是一個真正有效的藉口,好像浪費了一個寄存器給我。 gcc等可能允許你選擇不使用幀指針,不建立使用它的代碼來節省開銷。一些默認值,一些默認不帶。它使該函數內的偏移量固定,對於該函數,變量X始終爲fp-N。您可以爲整個功能製作X sp + M,或者可以根據需要移動SP以保留空間。 –

+0

不管老師說什麼,結束的時候,對於那個班級來說,通過班級,懷疑一切,然後(重新)發現它,看看你是否相信。是否只是讓老師對作業進行評分更容易一些,還是這種編程規則在某種意義上被教導得「更好」?我同意它使人類更容易,但同時編譯器或人類,如果你移動sp來覆蓋函數的所有用法,沒有幀指針也同樣容易。 –

+1

試試這個:在你的腦海中定義一個C結構,包含5個或更多字段。在堆棧中爲它分配空間。初始化它。將其成員作爲堆棧中的參數傳遞給其他函數。做和沒有框架指針。 –

回答

2

你只絕對需要幀指針時動態地分配不同數量的堆棧空間。 C中使用可變長度數組和/或alloca的函數是需要幀指針的函數的示例。由於函數使用的數量堆棧是變量,因此您無法使用堆棧指針中的常量偏移量訪問變量,並且您需要一種方法在函數返回時撤消變量長度分配。使用幀指針解決了這兩個問題。您可以使用它來使用常量偏移量來處理堆棧變量,並將堆棧指針恢復到函數開始時的值。

在MIPS,它也將使意義僅使用固定大小的堆棧分配,如果總的堆棧分配多於32K使用一個幀指針作爲優化中的功能。 MIPS支持的有限尋址模式只允許相對於堆棧指針或任何其他寄存器的16位符號擴展偏移量。由於堆棧指針指向堆棧的底部,所以堆棧指針只能使用非負偏移量,因此堆棧中只有32k可以通過一條指令訪問。通過使用幀指針並將它指向堆棧幀的中間(而不是幀的頂部),它可以用於在單個指令中尋址多達64k的堆棧。

以其它方式使用幀指針的東西,不僅有利於程序員,而不是程序。如果程序中的所有函數都使用帶有幀指針的標準堆棧幀,則幀指針和存儲在堆棧中的所有保存的幀指針值形成一個堆棧幀的鏈表。這個鏈接列表可以很容易地被橫穿,以在調試時創建函數調用的回溯。但是,使用合適的現代調試器,也可以將元數據(展開信息)嵌入到可執行文件中,即使未使用幀指針,調試器也可以使用這些可執行文件來遍歷堆棧幀。這是現代編譯器可以自動完成的工作,但是在彙編語言中,包含所有必要的額外指令以使其可行是相當痛苦的。

如果堆棧指針在函數期間可以通過固定大小的分配和釋放多次更改,那麼跟蹤程序中任何給定點的變量相對於堆棧指針的位置可能會很痛苦。雖然在任何給定的位置它總是處於固定的偏移量,但會根據位置而改變。確定偏移量可能會非常棘手且容易出錯。由於幀指針值不會改變,所以使用幀指針將爲每個變量賦予相對於從未改變的幀指針的偏移量。

請注意,如果您覺得您需要使用幀指針,因爲最後兩個原因之一您必須考慮爲什麼首先在程序集中進行編程。這些現代編譯器不需要使用幀指針的情況下,所以會生成更好的代碼。

1

幀指針省略是C和C++編譯器實現的standard optimization option。好處是它可以騰出一個寄存器用於其他用途。然而,它經常被禁用,這使得調試程序崩潰過度困難。即使像生成堆棧跟蹤這樣的基本東西也非常困難,您不再知道父函數的框架位於何處,因此不知道在哪裏查找返回地址。檢查局部變量的狀態同樣會變得痛苦。這不僅在調試應用程序時很重要,而且當程序在生產中崩潰時它會回來。

調試元數據需要知道在哪裏看,你必須知道幀的大小。一般來說,使代碼可調試和可診斷的是更多比使其易於編寫更爲重要。典型的程序員花更多時間在調試和測試上,而不是寫作。