據我所知,葉函式和非葉函式的主要區別在于葉函式不呼叫另一個函式,非葉函式呼叫其他函式。因此,葉函式不需要像
begin
push $ra
~ ( some random bits of code) ~
pop $ra
end
但是“呼叫函式”到底是什么意思呢?似乎我只知道這兩者之間的區別作為定義,并沒有真正理解整個事情。
uj5u.com熱心網友回復:
葉函式不使用jal,或者任何其他可以運行您在撰寫該函式時看不到的代碼的任何東西。這就是不呼叫任何其他函式的意思。
在您的程式可以或確實進行的函式呼叫樹中(更一般地說是呼叫圖),它是一個葉節點。 它有呼叫者但沒有被呼叫者。如果您正在查看 C 源代碼與 asm,則行內小函式可以使非葉 C 函式成為 asm 葉函式。
因此它不必$ra在堆疊上保存/恢復,它可以將自己的回傳地址留在該暫存器中并回傳給它自己的呼叫者jr $ra,同時沒有使用$ra任何其他回傳地址。 在呼叫堆疊上永遠不會有另一個函式的堆疊幀。
一個大型函式可能需要使用大量暫存器,因此它實際上可能會 save/restore $ra,并且可能$s0..$s7只是將它們用作暫存空間。但是 MIPS 有很多暫存器,所以通常葉函式只需使用$t0..$t9, $v0..1, , 就可以很好地完成它們的作業$a0..3,而$at無需接觸堆疊空間。如果本地陣列需要比暫存器更多的暫存空間,或者可以索引的空間,則可能除外。
如果您直接使用系統呼叫進行系統呼叫,那么它并不能真正算作呼叫,syscall因此葉函式可以進行系統呼叫。(大多數現實世界的系統與 MARS/SPIM 類似,內核將所有暫存器保存在 周圍syscall,回傳值除外。)
但是,如果您呼叫jal readlibc 中定義的包裝函式(例如在 Unix 系統上,而不是在 MARS/SPIM 中),那么這是一個真正的函式,您必須假設它遵循標準呼叫約定,例如在所有$t0..9和$a / $v 暫存器,以及$ra.
唯一的例外可能是一些私有輔助函式,其中該函式知道它們使用/不使用哪些暫存器,因此您可以將 ajal helper視為此葉函式實作的一部分。在這種情況下,您仍然需要管理$ra,也許將其保存$t9或其他內容。
相關:MIPS:堆疊指標 ($sp) 的相關用途和非葉函式示例的堆疊,該示例使用堆疊空間在對未知函式的兩次呼叫中保存內容。
順便說一句,MIPS 沒有push和pop說明。您通常addiu $sp, $sp, -16或無論您需要多少堆疊空間,并用于sw存盤到保留的空間中。您不會單獨sub或add在??每次加載和存盤之間。
并且end在 MIPS 匯編中不是真實的東西;您需要運行一條跳轉回呼叫方的指令,例如jr $ra. 或者tailcall一些其他函式,比如j fooor b foo,以有效地呼叫它,回傳地址是你的呼叫者最初傳遞的地址。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/512653.html
標籤:功能部件mips
