1、MIPS尋址方式
MIPS架構的尋址模式有寄存器尋址、立即數尋址、寄存器相對尋址和PC相對尋址4種,其中寄存器相對尋址、PC相對尋址介紹如下:
1.1、寄存器相對尋址
這種尋址模式主要被加載/存儲指令使用,其對一個16位的立即數進行符號擴展,然后與指定通用寄存器的值相加,從而得到有效地址。
通用寄存器GRP + 16位立即數做符號擴展 = 有效地址
1.2、PC相對尋址
這種尋址模式主要被轉移指令使用。在轉移指令中有一個16位的立即數,將其左移2位並進行符號擴展,然后與程序計數器PC的值相加,可得到有效地址。
程序計數器PC + 16位立即數左移2位並做符號擴展 = 有效地址
2、MIPS指令集
2.1、MIPS指令特點
- MIPS固定4字節指令長度。
- 內存中的數據訪問(load/store)必須嚴格對齊(至少4字節對齊)。
- 跳轉指令只有26位目標地址,加上2位對齊位,可尋址28位尋址空間,即256MB。
- 條件分支指令只有16位跳轉地址,加上2位對齊位,共18位尋址空間,即256KB。
- MIPS默認不把子函數的返回地址(就是調用函數的受害指令地址)存放到棧中,而是存放到$31($ra)寄存器中,這對那些葉子函數(在函數中不再調用其他函數的函數)有利。如果遇到嵌套函數,有其他機制處理。
- 流水線效應。MIPS采用了高度的流水線,其中一個最重要的效應就是分支延遲效應。在分支跳轉語句后面的那條語句叫做分支延遲槽。實際上,在程序執行到分支語句時,當它剛把要跳轉到的地址填充好(填充到代碼計數器里),還沒有完成本條指令時,分支語句后面的那個指令就已經執行了,其原因就是流水線效應 ---- 幾條指令同時執行,只是處於不同的階段。
流水線效應:
mov $a0, $s2
jalr strrchr
move $a0, $s0
在執行第2行跳轉分支時,第3行的move指令已經執行完了。因此,在上面指令序列中,strrchr函數的參數來自第3行的$s0,而不是第1行的$s2。
從流水線效應中可以看出,是否正確理解MIPS指令的這些特點會直接影響我們對MIPS程序逆向分析的結果,因此,我們需要熟悉把握這些特點。
2.2、指令格式
所有MIPS指令的長度相同,都是32位。為了讓指令的格式剛好合適,設計者做了折中:將所有指令定長,但是不同的指令有不同的格式。在MIPS架構中,指令的最高6位均為Opcode碼,剩下的26位可以將指令分為3種類型,分別為R型、I型和J型。
- R型指令用連續3個5位二進制碼表示3個寄存器的地址,然后用1個5位二進制碼表示移位的位數(如果未使用移位操作,則全為0),最后是6位的Function碼(它與Opcode碼共同決定R型指令的具體操作方式)。
- I型指令則用連續2個5位二進制碼表示2個寄存器的地址,然后是由1個16位二進制碼表示1個立即數二進制碼。
- J型指令用26位二進制碼表示跳轉目標的指令地址(實際的指令地址應為32位,其中最低2位為“00”,最高4位由PC當前地址決定)。
| 類型 | 格式 | |||||
| R | Opcode(6) | Rs(5) | Rt(5) | Rd(5) | Shamt(5) | Funct(6) |
| I | Opcode(6) | Rs(5) | Rt(5) | Immediate(16) | ||
| J | Opcode(6) | Address(26) | ||||
- Opcode: 指令基本操作,稱為操作碼。
- Rs: 第一個源操作數寄存器。
- Rt: 第二個源操作數寄存器。
- Rd: 存放操作結果的目的操作數。
- Shamt: 位移量。
- Funct: 函數,這個字段選擇Opcode操作某個特定變體。
3、匯編常用的指令
注意:$Rd表示目的寄存器, $Rs表示源寄存器,$Rt表示作為中間緩存的寄存器,"imm"表示立即數,“MEM[]“表示RAM中的一段內存,“offset"表示偏移量。
3.1、LOAD/STORE指令
LOAD/STORE指令有14條,分別是lb、lbu、lh、lhu、ll、lw、lwl、lwr、sb、sc、sh、sw、swl和swr。
以"l"開頭的都是加載指令,以"s"開頭的都是存儲指令,這些指令用於從存儲器中讀取數據,或者將數據保存在存儲器中。
3.1.1、LA(Load Address) 指令用於將一個地址或標簽存入一個寄存器。
| 語法 | 實例 | 備注 |
| la $Rd, Label | la $t0, val_1 | 復制val_1表示的地址到$t0寄存器中,其中val_1是一個Label |
3.1.2、LI(Load Immediate)指令用於將一個立即數存入一個通用寄存器。
| 語法 | 實例 | 備注 |
| lw $Rt, offset($Rs) | lw $s0, 0($sp) | "$s0 = MEM[$sp+0]",相當於取堆棧地址偏移0內存word長度的值到$s0中 |
3.1.3、LW(Load Word) 指令用於從一個指定的地址加載一個word類型的值到一個寄存器中。
| 語法 | 實例 | 備注 |
| lw $Rt, offset($Rs) | lw $s0, 0($sp) | "$s0=MEM[$sp+0];",相當於取堆棧地址偏移0內存word長度的值到$s0中 |
3.1.4、SW(Store Word)用於將源寄存器中的值存入指定的地址。
| 語法 | 實例 | 備注 |
| sw $Rt, offset($Rs) | sw $a0,0($sp) | "MEM[$sp+0]=$a0;",相當於將$a0寄存器中一個word大小的值存入堆棧,且$sp自動堆棧 |
3.1.5、MOVE指令用於寄存器之間值的傳遞。
| 語法 | 實例 | 備注 |
| move $Rt, $Rs | move $t5, $t1 | $t5=$t1; |
3.2、算術運算指令
MIPS匯編指令的算術運算特點如下:
- 算術運算指令的所有操作數都是寄存器,不能直接使用RAM地址或間接尋址。
- 操作數大小都為word(4 Byte)。
- 算術運算指令有21條,分別為add、addi、sub、subu、clo、clz、slt、slti、sltiu、sltu、mul、mult、madd、maddu、msub、msubu、div和divu,實現了加、減、比較、乘、乘累加、除等運算。
| 指令格式與實例 | 注釋 |
| add $t0,$t1,$t2 | "$t0=$t1+$t2;",帶符號數相加 |
| sub $t0,$t1,$t2 | "$t0=$t2 - $t2;", 帶符號數相減 |
| addi $t0,$t1,5 | $t0 = $t1 + 5; |
| addu $t0,$t1,$t2 | "$t0 = $t1 + $t2;",無符號數相加 |
| subu $t0, $t1, $t2 | "$t0 = $t2 - $t2;",無符號數相減 |
| mult $t3, $t4 | "$t3 * $t4", 把64 Bits的積存儲到"Lo,Hi"中,即"(Hi,Lo)=$t3 * $t4;" |
| div $t5, $t6 | "$LO=$t5/$t6", $LO為商的整數部分;"$HI=$t5 mod $t6", $HI為余數 |
| mfhi $t0 | $t0 = $HI |
| mflo $t1 | $t1 = $LO |
