MIPS基础入门

MIPS基础入门

MIPS基础入门基础介绍 首先我们来介绍一下什么是mips,MIPS架构是一种采取 精简指令集(RISC)的处理器架构,1981年出现,由MIPS科技公司开发并授权,它是基于一种固定长度的定期编码指令集,并采用 导入/存储(Load/Store)数据模型。经改进,这种架构可支持高级语言的优化执行。其算术和逻辑运算采用三个操作数的形式,允许编译器优化复杂的表达式。

如今基于该架构的芯片广泛被使用在许多电子产品、网络设备、个人娱乐装置与商业装置上。最早的MIPS架构是32位,最新的版本已经变成64位。

环境模拟 我们的虚拟机基本都是ubuntu,也就是基于8086架构,所以这里我们学习mips需要理由qemu来模拟这个架构,而QEMU代表快速模拟器,是虚拟化领域的一个重要工具,能够在单个硬件平台上同时运行多个操作系统。以其能够仿真广泛的客户系统和架构而闻名,QEMU是创建和管理虚拟环境的多功能解决方案。它作为一个类型1虚拟机运行,直接与物理硬件接口,这与其他虚拟化技术有显著的不同。通过整合像Intel VT和AMD-V这样的硬件虚拟化技术,QEMU优化了虚拟机的性能,为开发人员和IT专业人员提供了一个强大的平台,用于模拟各种计算环境,无需为每个系统提供专用硬件。

下面是一个自动化脚本,运行可以得到完整配置的qemu和mips,现在我们来编译一个demo,看看怎么个事儿。

123456#include int main() { printf("Hello, MIPS!\n"); return 0;}

对于MIPS来说,有大端和小端两种格式,mips是大端,mipsel是小端,且都支持32位和64位的指令集。

1234567891011121314151617#32位小端序:mipsel-linux-gnu-gcc -g test.c -o test_mipsel_32#使用小端 MIPS 架构的编译器生成 32 位小端格式的可执行文件。#32位大端序:mips-linux-gnu-gcc -g test.c -o test_mips_32#使用大端 MIPS 架构的编译器生成 32 位大端格式的可执行文件。#64位小端序:mips64el-linux-gnuabi64-gcc -g test.c -o test_mipsel_64#使用小端 MIPS 64 位架构的编译器生成小端 64 位的可执行文件。#64位大端序:mips64-linux-gnuabi64-gcc -g test.c -o test_mips_64#使用大端 MIPS 64 位架构的编译器生成大端 64 位的可执行文件。

现在我们测试一下其中一个

然后我们就能模拟运行这个mips框架的elf文件了

12qemu-mips64el-static -L /usr/mips64el-linux-gnuabi64 ./test_mipsel_64

这里的-L /usr/mips-linux-gnu/指向MIPS库的位置,根据具体环境可能需要调整。这里是默认的位置,当然如果你的并不可以,那可以选择使用如下的语句来寻找

12dpkg -L libc6-mipsel-cross

MIPS指令集1. MIPS 指令集结构MIPS 指令集是精简指令集(RISC)架构的典型代表,所有指令长度为 32 位。指令分为三种类型:R 型、I 型 和 J 型,每种类型有不同的操作码格式。

R 型指令(寄存器-寄存器操作):适用于寄存器之间的运算,通常包括算术和逻辑操作。Op段为0,使用funct字段区分指令

I 型指令(立即数操作):适用于需要立即数或地址的操作。使用Op字段区分load/store指令

J 型指令(跳转操作):用于跳转指令。使用Op字段区分指令

2. 指令分类MIPS 指令集主要分为以下几类:

以下是 MIPS 指令的详细执行表,包括操作数的来源和结果存储位置:

(1)算术运算指令

指令

功能

格式

执行描述

add

有符号整数加法

add rd, rs, rt

rd = rs + rt

addi

有符号整数加法(立即数)

addi rt, rs, imm

rt = rs + imm

sub

有符号整数减法

sub rd, rs, rt

rd = rs - rt

mult

有符号乘法

mult rs, rt

HI, LO = rs × rt(结果存储在 HI/LO 寄存器)

div

有符号除法

div rs, rt

LO = rs / rt, HI = rs % rt(商存 LO,余数存 HI)

(2)逻辑运算指令

指令

功能

格式

执行描述

and

按位与

and rd, rs, rt

rd = rs & rt

andi

按位与(立即数)

andi rt, rs, imm

rt = rs & imm

or

按位或

or rd, rs, rt

rd = rs

ori

按位或(立即数)

ori rt, rs, imm

rt = rs

xor

按位异或

xor rd, rs, rt

rd = rs ^ rt

nor

按位取反或

nor rd, rs, rt

rd = ~(rs

(3)移位指令

指令

功能

格式

执行描述

sll

左移

sll rd, rt, shamt

rd = rt << shamt

srl

逻辑右移

srl rd, rt, shamt

rd = rt >> shamt(高位补 0)

sra

算术右移

sra rd, rt, shamt

rd = rt >> shamt(高位补符号位)

(4)数据传输指令

指令

功能

格式

执行描述

lw

加载字

lw rt, offset(rs)

rt = *(rs + offset)(从 rs + offset 地址加载 4 字节到 rt)

sw

存储字

sw rt, offset(rs)

*(rs + offset) = rt(将 rt 存到 rs + offset 地址)

lb

加载字节

lb rt, offset(rs)

rt = *(rs + offset)(加载 1 字节,符号扩展到 32 位)

sb

存储字节

sb rt, offset(rs)

*(rs + offset) = rt(仅存储 rt 的低 8 位到 rs + offset)

(5)条件分支指令

指令

功能

格式

执行描述

beq

等于则跳转

beq rs, rt, label

if (rs == rt) goto label

bne

不等则跳转

bne rs, rt, label

if (rs != rt) goto label

bgtz

大于零则跳转

bgtz rs, label

if (rs > 0) goto label

blez

小于等于零则跳转

blez rs, label

if (rs <= 0) goto label

(6)跳转指令

指令

功能

格式

执行描述

j

无条件跳转

j label

goto label

jal

跳转并链接

jal label

ra = PC + 4; goto label(保存返回地址)

jr

寄存器跳转

jr rs

goto rs(跳转到 rs 指向的地址)

3. 特殊指令

syscall:用于系统调用,通常用于程序和操作系统之间的交互。

nop:空操作指令,执行时不产生任何效果,通常用于指令延迟槽。

MIPS 寄存器常用寄存器

名称

编号

作用

说明

$zero

$0

常数 0

值恒为 0,无法更改

$at

$1

汇编器临时寄存器

由汇编器内部使用,不建议手动操作

$v0-$v1

$2-$3

函数返回值

32 位返回值存于 $v0,64 位返回值存于 $v0, $v1

$a0-$a3

$4-$7

函数参数

依次存放第 1-4 个参数,更多参数需使用栈

$t0-$t7

$8-$15

临时寄存器

不需要保持值,函数调用后可能被覆盖

$s0-$s7

$16-$23

保存寄存器

需要保持值,函数调用时需保存和恢复

$t8-$t9

$24-$25

额外临时寄存器

用法同 $t0-$t7

$k0-$k1

$26-$27

内核保留寄存器

仅操作系统使用,用户程序不应修改

$gp

$28

全局指针

指向全局数据区

$sp

$29

栈指针

指向栈顶,函数调用时维护

$fp

$30

帧指针

用于存储栈帧地址(可选)

$ra

$31

返回地址

jal 指令跳转时存储返回地址

特殊寄存器

名称

作用

HI

存储乘法的高 32 位结果或除法的余数

LO

存储乘法的低 32 位结果或除法的商

PC

程序计数器,存储当前执行指令的地址

MIPS特性1. 指令集架构

固定指令长度:所有 MIPS 指令都是 4 字节(32 位),符合 RISC(精简指令集计算机)设计理念。

流水线优化:MIPS 采用 多级流水线,提高指令执行效率,但也带来了分支延迟效应和载入延迟效应。

分支延迟槽(Branch Delay Slot)

由于流水线特性,分支跳转指令后的一条指令仍会执行,称为分支延迟槽。

典型情况下,这条指令是 nop(无操作),但可以替换为对程序无害的有用指令。

2. 内存与栈管理

栈增长方向:MIPS 架构的栈(Stack)从高地址向低地址增长。

缓存(Cache)机制

指令缓存(I-Cache) 和 数据缓存(D-Cache) 独立存储,指令和数据不会混用。

执行代码必须先经过缓存刷新,否则数据缓存中的 shellcode 可能不会被执行,通常执行 sleep(1) 触发缓存刷新。

3. 函数调用约定

叶子函数(Leaf Function):函数内部没有调用其他函数,仅使用 $t0-$t9 作为临时寄存器。

非叶子函数(Non-Leaf Function):函数内部调用了其他函数,需要保存 $ra(返回地址寄存器) 以及可能被覆盖的 $s0-$s7 寄存器。

4. MIPS 代码执行安全性

指令与数据分离

由于指令和数据分别存储在 I-Cache 和 D-Cache,在代码注入攻击中,如果 D-Cache 没有同步刷新到 I-Cache,则 shellcode 可能不会执行。

解决方案:使用 sleep(1) 或 flush cache 触发缓存同步。

5. MIPS 指令特点

RISC 设计:指令种类少,每条指令执行时间固定。

加载/存储架构(Load/Store Architecture)

只有 lw(加载字) 和 sw(存储字) 指令可以访问内存,其他指令只能操作寄存器。

延迟槽优化:跳转指令的下一条指令仍会被执行,需手动填充 nop 或有用的指令。

MIPS 体系结构核心特性概述

特性

说明

指令长度

所有指令都是 4 字节(32 位)

流水线效应

分支延迟槽,跳转指令后的一条指令仍会执行

栈方向

从高地址向低地址增长

缓存结构

独立的 I-Cache 和 D-Cache,代码执行前需刷新缓存

调用约定

叶子函数不保存 $ra,非叶子函数需保存 $ra 和 $s0-$s7

加载存储架构

只有 lw / sw 访问内存,其他指令操作寄存器

安全性

shellcode 可能因缓存未同步导致执行失败,需要 flush

MIPS系统调用码MIPS 系统调用(syscall)使用 $v0 寄存器指定调用码,不同的调用码执行不同的系统功能。以下是常见的 MIPS 系统调用码表:

调用码($v0)

函数名字

功能

调用条件

1

print_int

打印整数

$a0 = 要打印的整数

2

print_float

打印浮点数(单精度)

$f12 = 要打印的浮点数

3

print_double

打印双精度浮点数

$f12 = 要打印的双精度浮点数

4

print_string

打印字符串

$a0 = 字符串地址

5

read_int

读取整数

读取的整数存入 $v0

6

read_float

读取浮点数(单精度)

读取的浮点数存入 $f0

7

read_double

读取双精度浮点数

读取的双精度浮点数存入 $f0

8

read_string

读取字符串

$a0 = 缓冲区地址, $a1 = 最大长度

9

sbrk

分配内存(返回地址)

$a0 = 需要分配的字节数,返回分配的内存地址于 $v0

10

exit

退出程序

11

print_char

打印字符

$a0 = 要打印的字符

12

read_char

读取字符

读取的字符存入 $v0

13

open

打开文件

$a0 = 文件名地址, $a1 = 访问模式, $a2 = 权限(可选),返回文件描述符

14

read

读取文件

$a0 = 文件描述符, $a1 = 读取缓冲区, $a2 = 读取字节数,返回读取的字节数

15

write

写入文件

$a0 = 文件描述符, $a1 = 写入缓冲区, $a2 = 写入字节数,返回写入的字节数

16

close

关闭文件

$a0 = 文件描述符

17

exit2

退出程序(带返回值)

$a0 = 退出码

示例:1234li $v0, 1 # 设置 syscall 码为 1(print_int)li $a0, 123 # 要打印的整数syscall # 执行系统调用

以上代码会打印 123。

MIPS syscall 机制允许程序通过 syscall 指令调用操作系统提供的服务,适用于 MIPS 汇编语言模拟器(如 MARS、SPIM)。

相关创作

双鱼座的花是什么
365资讯下载安装

双鱼座的花是什么

08-29 👁 2889