MIPS彙編小貼示

2021-05-23 13:27:34 字數 4461 閱讀 2377

各欄位含義:

op:指令基本操作,稱為操作碼。

rs:第乙個源運算元暫存器。

rt:第二個源運算元暫存器。

rd:存放操作結果的目的運算元。

shamt:位移量

funct:函式,這個字段選擇op操作的某個特定變體。

有32個通用暫存器,$0到$31:

$0:即$zero,該暫存器總是返回零,為0這個有用常數提供了乙個簡潔的編碼形式。mips編譯器使用slt,beq,bne等指令和由暫存器$0獲得的0來 產生所有的比較條件:相等,不等,小於,小於等於,大於,大於等於。還可以用add指令建立move偽指令,即

move $t0,$t1

實際為add $t0,$0,$t1

焦林前輩提到他移植fpc時move指令出錯,轉而使用add代替的。

使用偽指令可以簡化任務,匯程式設計序提供了比硬體更豐富的指令集。

$1:即$at,該暫存器為彙編保留,剛才說到使用偽指令可以簡化任務,但是代價就是要為匯程式設計序保留乙個暫存器,就是$at。

由於i型指令的立即數字段只有16位,在載入大常數時,編譯器或匯程式設計序需要把大常數拆開,然後重新組合到暫存器裡。比如載入乙個32位立即數需要lui(裝入高位立即數)和addi兩條指令。像mips程式拆散和重灌大常數由匯程式設計序來完成,匯程式設計序必需乙個臨時暫存器來重組大常數,這也是為彙編保留$at的原因之一。

$2..$3:($v0-$v1)用於子程式的非浮點結果或返回值,對於子程式如何傳遞引數及如何返回,mips範圍有一套約定,堆疊中少數幾個位置處的內容裝入cpu暫存器,其相應記憶體位置保留未做定義,當這兩個暫存器不夠存放返回值時,編譯器通過記憶體來完成。

$4..$7:($a0-$a3)用來傳遞前四個引數給子程式,不夠的用堆疊。a0-a3和v0-v1以及ra一起來支援子程式/過程呼叫,分別用以傳遞引數,返回結果和存放返回位址。當需要使用更多的暫存器時,就需要堆疊(stack)了,mips編譯器總是為引數在堆疊中留有空間以防有引數需要儲存。

$8..$15:($t0-$t7)臨時暫存器,子程式可以使用它們而不用保留。

$16..$23:($s0-$s7)儲存暫存器,在過程呼叫過程中需要保

留(被呼叫者儲存和恢復,還包括

$fp和$ra),mips提供了臨時暫存器和儲存暫存器,這樣就減少了暫存器溢位(spilling,即將不常用的變數放到儲存器的過程),編譯器在編譯乙個葉(leaf)過程(不呼叫其它過程的過程)的時候,總是在臨時暫存器分配完了才使用需要儲存的暫存器。

$24..$25:($t8-$t9)同($t0-$t7)

$26..$27:($k0,$k1)為作業系統/異常處理保留,至少要預留乙個。異常(或中斷)是一種不需要在程式中顯示呼叫的過程。mips有個叫異常程式計數器(exception program counter,epc)的暫存器,屬於cp0暫存器,用於儲存造成異常的那條指令的位址。檢視控制暫存器的唯一方法是把它複製到通用暫存器裡,指令mfc0(move from system control)可以將epc中的位址複製到某個通用暫存器中

,通過跳轉語句(jr),程式可以返回到造成異常的那條指令處繼續執行。仔細分析一下會發現個有意思的事情:

為了檢視控制暫存器epc的值並跳轉到造成異常的那條指令(使用jr),必須把epc的值到某個通用暫存器裡,這樣的話,程式返回到中斷處時就無法將所有的暫存器恢復原值。如果先恢復所有的暫存器,那麼從epc複製過來的值就會丟失,jr就無法返回中斷處;如果我們只是恢復除有從epc複製過來的返回位址外的暫存器,但這意味著程式在異常情況後某個暫存器被無端改變了,這是不行的。為了擺脫這個兩難境地,mips程式設計師都必須保留兩個暫存器$k0和$k1,供作業系統使用。發生異常時,這兩個暫存器的值不會被恢復,編譯器也不使用k0和k1,異常處理函式可以將返回位址放到這兩個中的任何乙個,然後使用jr跳轉到造成異常的指令處繼續執行。

$28:($gp)c語言中有兩種儲存型別,自動型和靜態型,自動變數是乙個過程中的區域性變數。靜態變數是進入和退出乙個過程時都是存在的。為了簡化靜態資料的訪問,mips軟體保留了乙個暫存器:全域性指標gp(global pointer,$gp),如果沒有全域性指標,從靜態資料去裝入資料需要兩條指令:一條有編譯器和聯結器計算的32位位址常量中的有效位;令一條才真正裝入資料。全域性指標只想靜態資料區中的執行時決定的位址,在訪問位於gp值上下32kb範圍內的資料時,只需要一條以gp為基指標的指令即可。在編譯時,資料須在以gp為基指標的64kb範圍內。

$29:($sp)mips硬體並不直接支援堆疊,例如,它沒有x86的ss,sp,bp暫存器,mips雖然定義$29為棧指標,它還是通用暫存器,只是用於特殊目的而已,你可以把它用於別的目的,但為了使用別人的程式或讓別人使用你的程式,還是要遵守這個約定的,但這和硬體沒有關係。x86有單獨的push和pop指令,而mips沒有,但這並不影響mips使用堆疊。在發生過程呼叫時,呼叫者把過程呼叫過後要用的暫存器壓入堆疊,被呼叫者把返回位址暫存器$ra和保留暫存器壓入堆疊。同時調整堆疊指標,當返回時,從堆疊中恢復暫存器,同時調整堆疊指標。

$30:($fp)gnu mips c編譯器使用了偵指標(frame pointer),而sgi的c編譯器沒有使用,而把這個暫存器當作儲存暫存器使用($s8),這節省了呼叫和返回開銷,但增加了**生成的複雜性。

$31:($ra)存放返回位址,mips有個jal(jump-and-link,跳轉並鏈結)指令,在跳轉到某個位址時,把下一條指令的位址放到$ra中。用於支援子程式,例如呼叫程式把引數放到$a0~$a3,然後jal x跳到x過程,被調過程完成後把結果放到$v0,$v1,然後使用jr $ra返回。

在呼叫時需要儲存的暫存器為$a0~$a3,$s0~$s7,$gp,$sp,$fp,$ra。

跳轉範圍

j指令的位址欄位為26位,用於跳轉目標。指令在記憶體中以4位元組對齊,最低兩個有效位不需要儲存。在mips中,每個位址的最低兩位指定了字的乙個位元組,cache對映的下標是不使用這兩位的,這樣能表示28位的位元組編址,允許的位址空間為256m。pc是32位的,那其它4位從何而來呢?mips的跳轉指令只替換pc的低28位,而高4位保留原值。因此,載入和鏈結程式必須避免跨越256mb,在256m的段內,分支跳轉位址當作乙個絕對位址,和pc無關,如果超過256m(段外跳轉)就要用跳轉暫存器指令了。

同樣,條件分支指令中的16位立即數如果不夠用,可以使用pc相對定址,即用分支指令中的分支位址與(pc+4)的和做分支目標。由於一般的迴圈和if語句都小於2^16個字(2的16次方),這樣的方法是很理想的。

31 ra 子函式的返回地□

這些暫存器的用法都遵循一系列約定。這些約定與硬體確實無關,但如果你想使用別人的**,編譯器和作業系統,你最好是遵循這些約定。

*sp: 堆疊指標的上下需要顯示的通過指令來實現。因此mips

對於浮點暫存器的用法,也有乙個相應的標準的約定。我們將在7.5節。在這裡,我們已經介紹了mips

引入的寄存

1、mips指令集的確很risc,資料類的僅有load、store和move,當然按運算元的長短分許多lw、lh等等,但實際上就這三個。運算類的也僅僅完成基本功能,也根據運算元長短分了許多子指令。跳轉類更少,要麼無條件跳轉,要麼根據運算元跳轉。這些指令確實屬於最常用的80%的。相比intel的lea等指令,由於個人習慣,很少用,而aad、aaa等指令,我幾乎沒用過。

2、mips指令較少,但彙編器為了方便使用,定義了許多偽指令,如li、ror等。最終會被擴充套件成多條實際指令。這樣一來,好處就是能省力,但壞處就是對彙編器要求較高,而且對機器指令反彙編後難以還原為偽指令(反彙編器面對lui $at, 0xabcd和ori r, $at, 0xef00似乎不能自作主張的將其視作li, r, 0xabcdef00);反彙編出來的指令條數多,不利於hack(或許又是好事)。

3、mips的定址方式最簡單,僅有暫存器加偏移定址方式(內嵌16位立即數定址不算在內),這對於飽受intel的八種定址方式折磨的人來說是天大的好事。

4、mips沒有棧操作指令,雖然有約定俗稱的$sp。在做遞迴呼叫時必須手工管理棧,呼叫子程式時沒有自動壓棧的call指令,只能用jal。這對於用慣了intel的push和pop的人又會是一場噩夢。

5、mips的記憶體對映、中斷等功能都做到了協處理器0中,浮點運算做到了協處理器1 中。

6、mips暫存器非常多,對於表示式求值很有利,不過排程演算法就複雜了。而且暫存器雖然有約定俗成的用法,但實際上並沒有限制。

7、mips指令為定長的,很統一,給我的「感覺」非常好。

最終,個人體會,在mips體系下思考又是另一種感覺,由於棧是全手工管理,就不用考慮push、pop是否匹配以及運算元大小,但手工管理棧要求頭腦非常清晰;由於暫存器多了,就更多的考慮暫存器排程,如何發揮出所有暫存器的潛力;也不用去費心思選擇定址方式。mips在暫存器使用、棧、儲存方面提供了更高的靈活性,設計程式可以更加自由,但同時也增大了交流、學習的難度,這點與intel嚴格的體系結構完全相反。

從mips的特性看來,由於mips指令集簡單,容易設計和實現,尺寸可以做小,因此mips的方向除了嵌入式外,應該是多核心,提高並行度,主要面向併發性高的應用,如伺服器。而在桌面應用方面,目前沒有x86的優勢明顯。速度是一方面,mips的應用少,指令集太精簡、對程式設計師的友好程度不夠好也是乙個原因。

mips彙編列印 hello world

mips組合語言列印 hello world 字串。已在pcspim下編印通過 print hello world programed by stevie zou text segment text globl main main la a0,str a0儲存要列印字元的位址 li v0,4 為sy...

mips 彙編入門 helloworld

原始碼如下 hello.s vb view plain copy text segment text globl main main execution starts here la a0,str put string address into a0 li v0,4 system call to p...

MIPS彙編指令集

mips指令集屬於精簡指令集 mips的所有指令都是32位,指令格式簡單,而x86的指令長度不是固定的。簡單的指令和格式易於解碼和流水線操作,但是 密度不高,導致二進位制檔案大 mips有32個通用暫存器reg,為什麼是32個而不是更多呢?因為更多的暫存器需要更多的指令空間對暫存器編碼,也會增加上下...