mips架构初探(一)
字数 3018 2025-08-22 12:22:48

MIPS架构初探:从基础到调试

1. MIPS架构概述

MIPS架构是一种采用精简指令集(RISC)的处理器架构,由MIPS科技公司于1981年开发。主要特点包括:

  • 固定长度的定期编码指令集
  • 采用导入/存储(Load/Store)数据模型
  • 算术和逻辑运算采用三个操作数的形式
  • 支持32位和64位版本
  • 广泛应用于电子产品、网络设备和个人娱乐装置

2. 环境搭建

2.1 安装必要工具

#!/bin/sh
# 安装QEMU及相关工具
sudo apt install qemu
sudo apt install qemu-system qemu-user-static binfmt-support

# 安装ARM架构编译器和依赖
sudo apt install libncurses5-dev gcc-arm-linux-gnueabi build-essential

# 安装MIPS架构编译器
sudo apt-get install gcc-mips-linux-gnu
sudo apt-get install gcc-mipsel-linux-gnu
sudo apt-get install gcc-mips64-linux-gnuabi64
sudo apt-get install gcc-mips64el-linux-gnuabi64

# 安装多架构gdb调试依赖
sudo apt install gdb-multiarch

2.2 QEMU简介

QEMU是一个快速模拟器,能够:

  • 在单个硬件平台上运行多个操作系统
  • 仿真广泛的客户系统和架构
  • 直接与物理硬件接口
  • 整合Intel VT和AMD-V等硬件虚拟化技术

3. MIPS程序编译

3.1 示例程序

#include <stdio.h>

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

3.2 编译选项

MIPS有大端(mips)和小端(mipsel)两种格式,支持32位和64位指令集:

架构 编译命令 输出文件
32位小端序 mipsel-linux-gnu-gcc -g test.c -o test_mipsel_32 test_mipsel_32
32位大端序 mips-linux-gnu-gcc -g test.c -o test_mips_32 test_mips_32
64位小端序 mips64el-linux-gnuabi64-gcc -g test.c -o test_mipsel_64 test_mipsel_64
64位大端序 mips64-linux-gnuabi64-gcc -g test.c -o test_mips_64 test_mips_64

3.3 运行程序

使用QEMU模拟运行:

qemu-mipsel -L /usr/mips-linux-gnu/ ./test_mipsel_32

如果库路径不正确,可以使用以下命令查找:

dpkg -L libc6-mipsel-cross

4. MIPS指令集

4.1 指令类型

MIPS指令分为三种类型:

  1. R型指令:寄存器-寄存器操作
  2. I型指令:立即数操作
  3. J型指令:跳转操作

4.2 指令分类

算术运算指令

指令 功能 格式
add 有符号整数加法 add rd, rs, rt
addi 有符号整数加法(立即数) addi rt, rs, imm
sub 有符号整数减法 sub rd, rs, rt
mult 有符号乘法 mult rs, rt
div 有符号除法 div rs, rt

逻辑运算指令

指令 功能 格式
and 按位与 and rd, rs, rt
andi 按位与(立即数) andi rt, rs, imm
or 按位或 or rd, rs, rt
ori 按位或(立即数) ori rt, rs, imm
xor 按位异或 xor rd, rs, rt
nor 按位取反或 nor rd, rs, rt

移位指令

指令 功能 格式
sll 左移 sll rd, rt, shamt
srl 逻辑右移 srl rd, rt, shamt
sra 算术右移 sra rd, rt, shamt

数据传输指令

指令 功能 格式
lw 加载字 lw rt, offset(rs)
sw 存储字 sw rt, offset(rs)
lb 加载字节 lb rt, offset(rs)
sb 存储字节 sb rt, offset(rs)

条件分支指令

指令 功能 格式
beq 等于则分支跳转 beq rs, rt, label
bne 不等则分支跳转 bne rs, rt, label
bgtz 大于零则跳转 bgtz rs, label
blez 小于等于零则跳转 blez rs, label

跳转指令

指令 功能 格式
j 无条件跳转 j label
jal 跳转并链接 jal label
jr 寄存器跳转 jr rs

特殊指令

  • syscall:用于系统调用
  • nop:空操作指令

5. MIPS寄存器

MIPS有32个通用寄存器,每个寄存器有特定用途:

寄存器 名称 用途
$0 $zero 恒为零
$1 $at 汇编器保留
\(2-\)3 \(v0-\)v1 函数返回值
\(4-\)7 \(a0-\)a3 函数参数
\(8-\)15 \(t0-\)t7 临时寄存器
\(16-\)23 \(s0-\)s7 保存寄存器
\(24-\)25 \(t8-\)t9 临时寄存器
\(26-\)27 \(k0-\)k1 内核保留
$28 $gp 全局指针
$29 $sp 栈指针
$30 $fp 帧指针
$31 $ra 返回地址

6. MIPS特性

6.1 固定指令长度

所有MIPS指令长度固定为4字节。

6.2 栈增长方向

栈从内存的高地址向低地址方向增长。

6.3 函数分类

  • 叶子函数:函数内部没有再调用其他函数
  • 非叶子函数:函数内部调用其他函数的函数

6.4 流水线效应

MIPS采用高度流水线,导致分支延迟效应

  • 跳转指令后的指令称为分支延迟槽
  • 跳转指令执行时,下一条指令已经被执行
  • 为避免问题,通常在跳转指令后放置nop或其他有用指令

6.5 缓存刷新机制

MIPS CPU有两个独立缓存:

  • 指令cache
  • 数据cache

攻击payload通常存储在数据缓存中,需要触发flush才能写入主内存。通常执行sleep(1)来刷新缓存。

7. 函数调用机制

7.1 函数调用

使用jal(Jump and Link)指令:

  • 跳转到目标地址
  • 将返回地址保存在$ra寄存器中

7.2 函数返回

使用jr $ra指令跳转到$ra寄存器中的地址。

7.3 栈帧管理

函数进入时:

addiu $sp, $sp, -0x20  ; 分配栈空间
sw $ra, 0x1c($sp)      ; 保存返回地址
sw $fp, 0x18($sp)      ; 保存帧指针
move $fp, $sp          ; 设置新帧指针

函数退出时:

lw $ra, 0x1c($sp)      ; 恢复返回地址
lw $fp, 0x18($sp)      ; 恢复帧指针
addiu $sp, $sp, 0x20   ; 释放栈空间
jr $ra                 ; 返回

7.4 参数传递

  • 前4个参数通过$a0$a3传递
  • 多于4个参数通过栈传递
  • 调用者会在栈顶预留空间保存被调用者的参数

8. GDB调试

8.1 调试脚本

#!/bin/bash
# Ensure the script exits on error
set -e

# Define variables for file name, GDB port, and architecture
target_file="test_mipsel_32"
gdb_port="1234"

# Check if the target file exists
if [ ! -f "$target_file" ]; then
    echo "Error: Target file '$target_file' does not exist."
    exit 1
fi

# Step 1: Start QEMU with GDB server enabled
echo "Starting QEMU with GDB server on port $gdb_port..."
qemu-mipsel -L /usr/mipsel-linux-gnu/ -g $gdb_port "$target_file" &
qemu_pid=$!

# Wait for QEMU to be ready
sleep 2
echo "QEMU started with PID $qemu_pid."

# Step 2: Start GDB and connect to QEMU GDB server
mips_gdb="gdb-multiarch"

# Check if GDB is installed
if ! command -v $mips_gdb &> /dev/null; then
    echo "Error: GDB ($mips_gdb) not found. Please install it and try again."
    exit 1
fi

echo "Starting GDB and connecting to QEMU..."
$mips_gdb -ex "target remote :$gdb_port" "$target_file"

# Cleanup after GDB session ends
echo "Stopping QEMU..."
kill $qemu_pid

8.2 调试技巧

  1. 修改目标文件:
target_file="your_new_mips_file"
  1. 修改库路径:
qemu-mipsel -L /path/to/new/lib/ -g $gdb_port "$target_file" &
  1. 添加GDB启动命令:
$mips_gdb -ex "target remote :$gdb_port" -ex "break main" "$target_file"
  1. 设置环境变量:
qemu-mipsel -L /usr/mipsel-linux-gnu/ -g $gdb_port -E VAR_NAME=VALUE "$target_file" &
MIPS架构初探:从基础到调试 1. MIPS架构概述 MIPS架构是一种采用 精简指令集(RISC) 的处理器架构,由MIPS科技公司于1981年开发。主要特点包括: 固定长度的定期编码指令集 采用 导入/存储(Load/Store) 数据模型 算术和逻辑运算采用三个操作数的形式 支持32位和64位版本 广泛应用于电子产品、网络设备和个人娱乐装置 2. 环境搭建 2.1 安装必要工具 2.2 QEMU简介 QEMU是一个快速模拟器,能够: 在单个硬件平台上运行多个操作系统 仿真广泛的客户系统和架构 直接与物理硬件接口 整合Intel VT和AMD-V等硬件虚拟化技术 3. MIPS程序编译 3.1 示例程序 3.2 编译选项 MIPS有大端(mips)和小端(mipsel)两种格式,支持32位和64位指令集: | 架构 | 编译命令 | 输出文件 | |------|----------|----------| | 32位小端序 | mipsel-linux-gnu-gcc -g test.c -o test_mipsel_32 | test_ mipsel_ 32 | | 32位大端序 | mips-linux-gnu-gcc -g test.c -o test_mips_32 | test_ mips_ 32 | | 64位小端序 | mips64el-linux-gnuabi64-gcc -g test.c -o test_mipsel_64 | test_ mipsel_ 64 | | 64位大端序 | mips64-linux-gnuabi64-gcc -g test.c -o test_mips_64 | test_ mips_ 64 | 3.3 运行程序 使用QEMU模拟运行: 如果库路径不正确,可以使用以下命令查找: 4. MIPS指令集 4.1 指令类型 MIPS指令分为三种类型: R型指令 :寄存器-寄存器操作 I型指令 :立即数操作 J型指令 :跳转操作 4.2 指令分类 算术运算指令 | 指令 | 功能 | 格式 | |------|------|------| | add | 有符号整数加法 | add rd, rs, rt | | addi | 有符号整数加法(立即数) | addi rt, rs, imm | | sub | 有符号整数减法 | sub rd, rs, rt | | mult | 有符号乘法 | mult rs, rt | | div | 有符号除法 | div rs, rt | 逻辑运算指令 | 指令 | 功能 | 格式 | |------|------|------| | and | 按位与 | and rd, rs, rt | | andi | 按位与(立即数) | andi rt, rs, imm | | or | 按位或 | or rd, rs, rt | | ori | 按位或(立即数) | ori rt, rs, imm | | xor | 按位异或 | xor rd, rs, rt | | nor | 按位取反或 | nor rd, rs, rt | 移位指令 | 指令 | 功能 | 格式 | |------|------|------| | sll | 左移 | sll rd, rt, shamt | | srl | 逻辑右移 | srl rd, rt, shamt | | sra | 算术右移 | sra rd, rt, shamt | 数据传输指令 | 指令 | 功能 | 格式 | |------|------|------| | lw | 加载字 | lw rt, offset(rs) | | sw | 存储字 | sw rt, offset(rs) | | lb | 加载字节 | lb rt, offset(rs) | | sb | 存储字节 | sb rt, offset(rs) | 条件分支指令 | 指令 | 功能 | 格式 | |------|------|------| | beq | 等于则分支跳转 | beq rs, rt, label | | bne | 不等则分支跳转 | bne rs, rt, label | | bgtz | 大于零则跳转 | bgtz rs, label | | blez | 小于等于零则跳转 | blez rs, label | 跳转指令 | 指令 | 功能 | 格式 | |------|------|------| | j | 无条件跳转 | j label | | jal | 跳转并链接 | jal label | | jr | 寄存器跳转 | jr rs | 特殊指令 syscall :用于系统调用 nop :空操作指令 5. MIPS寄存器 MIPS有32个通用寄存器,每个寄存器有特定用途: | 寄存器 | 名称 | 用途 | |--------|------|------| | $0 | $zero | 恒为零 | | $1 | $at | 汇编器保留 | | $2-$3 | $v0-$v1 | 函数返回值 | | $4-$7 | $a0-$a3 | 函数参数 | | $8-$15 | $t0-$t7 | 临时寄存器 | | $16-$23 | $s0-$s7 | 保存寄存器 | | $24-$25 | $t8-$t9 | 临时寄存器 | | $26-$27 | $k0-$k1 | 内核保留 | | $28 | $gp | 全局指针 | | $29 | $sp | 栈指针 | | $30 | $fp | 帧指针 | | $31 | $ra | 返回地址 | 6. MIPS特性 6.1 固定指令长度 所有MIPS指令长度固定为4字节。 6.2 栈增长方向 栈从内存的高地址向低地址方向增长。 6.3 函数分类 叶子函数 :函数内部没有再调用其他函数 非叶子函数 :函数内部调用其他函数的函数 6.4 流水线效应 MIPS采用高度流水线,导致 分支延迟效应 : 跳转指令后的指令称为 分支延迟槽 跳转指令执行时,下一条指令已经被执行 为避免问题,通常在跳转指令后放置 nop 或其他有用指令 6.5 缓存刷新机制 MIPS CPU有两个独立缓存: 指令cache 数据cache 攻击payload通常存储在数据缓存中,需要触发 flush 才能写入主内存。通常执行 sleep(1) 来刷新缓存。 7. 函数调用机制 7.1 函数调用 使用 jal (Jump and Link)指令: 跳转到目标地址 将返回地址保存在 $ra 寄存器中 7.2 函数返回 使用 jr $ra 指令跳转到 $ra 寄存器中的地址。 7.3 栈帧管理 函数进入时: 函数退出时: 7.4 参数传递 前4个参数通过 $a0 到 $a3 传递 多于4个参数通过栈传递 调用者会在栈顶预留空间保存被调用者的参数 8. GDB调试 8.1 调试脚本 8.2 调试技巧 修改目标文件: 修改库路径: 添加GDB启动命令: 设置环境变量: