關于 $gp 語法,我覺得有點混亂,如果 $gp 指向某種地址,然后用 'const5' 抵消它(如果我在這里錯了,請糾正我,因為我不確定),然后會發生什么? 此外, const5 也不是浮點數,所以我想知道這個 lwc1 和 const5($gp) 是如何在幕后作業的。
練習是將以下 C 指令翻譯成 MIPS-Assembly 語言:
float f2c (float fahr)
{
return ((5.0/9.0)*(fahr - 32.0));
}
翻譯后的 MIPS(來自教科書):
f2c:
lwc1 $f16, const5($gp);
lwc1 $f18, const9($gp);
...
uj5u.com熱心網友回復:
lwc1是一條加載指令,其操作方式與加載指令類似lw,但加載到浮點暫存器而不是整數暫存器。 lwc1不檢查、解釋或驗證正在加載的值,它只是將記憶體中有效地址處的 4 位元組(即 32 位)值加載到指定的浮點暫存器中而無需修改。
lwc1可用于將整數或浮點值加載到浮點暫存器中。加載整數后,您可以使用cvt.s.w將浮點暫存器中的整數轉換為浮點值(在相同或另一個浮點暫存器中),這樣您就可以進行浮點加/減等操作。
與lw和一樣sw,MIPS 上的整數加載和存盤,浮點加載和存盤指令只有一種尋址模式。該尋址模式是base offset。有效地址只是基址暫存器的內容 符號擴展立即數/偏移量。盡管lwc1加載到浮點暫存器中,尋址模式仍然需要一個整數暫存器作為基址。
$gp是一個稱為全域(資料)指標的暫存器。當程式啟動環境正確設定時,它指向從加載到記憶體中的全域資料部分的開始 32k。這允許通過對立即數使用負值和正值來訪問 64k 的全域資料。 $gp不應在啟動后由程式修改,以便可以依賴它保持指向全域資料部分。
如果程式被編譯為 use $gp,那么程式的全域資料可能會超過 64k,在這種情況下,您應該會收到聯結器錯誤。 $gp允許機器代碼獨立于資料的實際位置,并且全域資料的訪問序列只有一條指令長度。(64k 限制僅適用于全域資料、變數和常量,但不適用于動態分配的堆資料。)
用于訪問全域資料的替代方法$gp,例如當環境不支持它,或者程式有超過 64k 的全域資料時,是使用絕對尋址,在 MIPS 上它需要 2 條指令,其中第一條是lui和第二個在或addiu之間變化。lwsw
為了讓它lwc1 const5($gp)發揮作用,
- 程式的目標代碼(編譯器輸出)需要將一些浮點常量指定為全域資料,可能帶有 __const5 和 __const9 之類的標簽,
- 程式目標代碼需要在訪問這些標簽時指定適當的重定位,
- 聯結器需要收集全域資料并為 const5 和 const9 等相對于全域資料部分 32k 的名稱賦值,并且
- 啟動代碼需要將正確的值放入
$gp.
(常量 5 被賦予標簽并隨后被參考的確切機制涉及目標代碼中指定的重定位細節,并且可能與這個過于簡化的插圖有所不同。)
RISC V 有類似的指令,lui(加上另一個auipc)和各種lws。它通常使用 2 條指令序列來訪問全域資料,但使用稱為松弛的機制,聯結器可以執行鏈接時間優化,將代碼序列從 2 條指令減少到 1 條指令,只要訪問可以訪問。這種放寬機制解決了程式具有超過 64k 資料的問題,同時仍然盡可能允許 1 條指令訪問。這是相當復雜的,因為聯結器實際上會改變代碼段的大小(即從某些目標代碼的中間洗掉代碼),這意味著編譯器現在也必須為內部分支生成重定位。
聯結器松弛理論上可以應用于任何具有更短方式來表達相同全域訪問的指令集架構。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/486328.html
下一篇:模塊化編程aarch64匯編
