看的《揭秘家用路由器 0day 漏洞挖掘技术》这本书
寄存器
MIPPS32 为例,指令中使用了大量的寄存器,除了加载/存储指令以外,都是用寄存器或者立即数作为操作数
MIPS32 中寄存器分为两类
通用寄存器
32 个,以 $ 表示
编号 | 寄存器名称 | 寄存器描述 |
---|---|---|
0 | $zero | 始终为 0 |
1 | $at | 保留寄存器,用作暂时变量 |
2~3 | $v0-$v1 | 保存表达式或函数的返回值,当两个寄存器不够用时通过内存来完成 |
4~7 | $a0~$a3 | 作为函数的前四个参数,不够的用栈处理 |
8~15 | $t0~$t7 | 供汇编程序使用放入临时寄存器 |
16~23 | $s0~$s7 | 供子程序使用时保存原寄存器的值 |
24~25 | $t8~$t9 | 供汇编程序使用的临时寄存器(补充 $t0~$t7) |
26~27 | $k0~$k1 | 保留,供中断或异常处理函数使用 |
28 | $gp | 全局指针 |
29 | $sp | 栈指针,指向栈顶 |
30 | $fp | 保存栈指针 |
31 | $ra | 返回地址寄存器 |
MIPS 并不直接支持栈,发生函数调用时调用者把函数调用之后的寄存器压入栈,被调用者把返回地址 $ra 和保留寄存器压入栈同时调整栈指针,返回时从栈中恢复寄存器
流水线效应:在跳转分支后面的语句叫分支延迟槽,程序还没有执行跳转,知识把跳转的地址填充好的时候,下一条语句就已经执行了
例如:
1 | mov $a0,$s2 |
在执行第二行的时候,第三行的 move 指令就已经完成了,所以第二行的跳转实际上是受第三行的 $s0 影响的
特殊寄存器
3 个 PC(程序计数器)、HI(乘除结果高位寄存器)、LO(乘除结果低位寄存器))
乘法运算中 HI 保存高 32 位,LO 保存低 32 位,除法运算中 HI 保存余数,LO 保存商
指令格式
MIPS 所有指令长度相同,都是 32 位,高六位都是 Opcode 码,剩下的 24 位可以将指令分为 3 类
R 型
连续 3 个 5 位的二进制码表示 3 个寄存器的地址,然后 1 个 5 位的二进制码表示移位位数(未使用移位则全为 0),最后六位是 Function 码与 Opcode 码共同决定 R 型指令的具体操作方式
I 型
连续 2 个 5 位二进制码表示 2 个寄存器的地址,然后是 1 个 16 位二进制码表示的 1 个立即数二进制码
J 型
26 位二进制码表示跳转目标的指令地址(实际的指令地址位 32 位,其中最低 2 位为 00,高四位由 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) | |||||
跳转目标的指令地址 |
汇编指令
寄存器都是用 $ 标注,imm 表示立即数,MEM[] 表示内存,offset 表示偏移量
LOAD/STORE 指令
以 l 开头的是加载指令,以 s 开头的 hi 存储指令,用来读取或存储数据
la 表示将地址或标签存入寄存器,la $Rd, Label,例如la $t0,val_1
表示把 val_1 复制到 $t0 寄存器
li 表示将一个立即数存入寄存器,li $Rd, imm,例如li $t1,40
表示把 $t1 赋值位 40
lw 表示从一个指定地址加载 word 类型的值到寄存器:lw $Rt, offset($Rs),例如lw $s0,0($sp)
表示 $s0 = MEM[$sp+0],相当于取堆栈地址偏移为 0 内存长度值到 $s0 中
sw 表示将源寄存器的值存入指定地址,sw $Rt, offset($Rs),例如sw $a0,0($sp)
表示 MEM[$sp+0] = $a0,将 $a0 中 word 大小的值放在堆栈中,且 $sp 自动抬栈
move 用于寄存器之间传值,move $Rt, $Rs 例如move $t5,$t1
表示把 $t1 的值赋给 $t5
算术运算指令
算术运算指令的所有操作数都是寄存器,不能直接使用 RAM 地址或间接寻址,操作数大小都是 word
正常的是带符号的,后面带 i 的立即数,带 u 的是无符号的
类比较指令
SLT 系列指令可以通过比较设置某个寄存器的值与分支跳转指令联合使用
SLT (有符号比较)表示 $Rs 小于 $Rt 时设置寄存器 $Rd 为 1,否则设置为 $Rd 为 0,slt $Rd, $Rs, $Rt
例如:slt $v0,$a0,$s0
表示如果如果 $a0 小于 $s0,则把 $v0 设置为 1
SLTI (有符号比较)表示 $Rs 小于立即数时设置 $Rt 为 1,否则为 0,stli $Rt, $Rs, imm
例如:stli $v0,$a0,255
表示如果 $a0 小于 255 就把 $v0 设置为 1 SLTU (无符号比较)表示 $Rs 小于 $Rt 时设置 $Rd 为 1,slt $Rd, $Rs, $Rt 例如:stlu $v0,$a0,$s0
表示在 $a0 小于 $s0 时设置 $v0 为 1
SLTIU(无符号比较)表示 $Rs 小于立即数时设置 $Rt 为 1,否则为 0,stli $Rt, $Rs, imm
例如:stli $v0,$a0,255
表示如果 $a0 小于 255 就把 $v0 设置为 1
看麻了,这指令名字起的多少有点…