关于MIPS汇编的二三事
字数 2960 2025-08-25 22:58:56

MIPS汇编语言全面教程

1. MIPS架构概述

MIPS(Microprocessor without Interlocked Pipeline Stages)是一种精简指令集(RISC)处理器架构,由MIPS科技公司于1981年开发。特点包括:

  • 最早版本为32位,现已发展到64位
  • 广泛应用于电子产品、网络设备和个人娱乐设备
  • 采用无互锁流水级设计

2. 机器周期基础

MIPS处理器执行指令的基本步骤:

  1. 取指令:从内存读取指令(PC寄存器保存当前指令地址)
  2. 更新PC:PC = PC + 4(指向下一条指令)
  3. 执行指令:执行取到的指令

3. 寄存器系统

MIPS有32个通用寄存器,使用$符号开头表示:

3.1 寄存器分类

寄存器 名称 用途
$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 返回地址

3.2 特殊寄存器

  • HI/LO:乘除法专用寄存器
    • 乘法:HI存高位,LO存低位
    • 除法:LO存商,HI存余数
    • 访问指令:mfhi/mflo

4. 程序结构

基本汇编程序框架:

.data       # 数据声明段
    # 变量声明
.text       # 代码段
main:       # 程序入口
    # 指令代码
    # 程序结束

5. 数据声明与内存操作

5.1 数据声明语法

变量名: 存储类型 值

常用数据类型:

  • .word:32位整数
  • .byte:8位字符
  • .space n:分配n字节未初始化空间
  • .asciiz:以null结尾的字符串

示例:

var1: .word 3        # 32位整数,初始值3
array1: .byte 'a','b' # 2字节字符数组
array2: .space 40    # 40字节未初始化空间

5.2 内存访问指令

指令 描述 示例
lw 加载字(4字节) lw $t0, var1
lb 加载字节 lb $t0, var1
sw 存储字 sw $t1, var1
sb 存储字节 sb $t1, var1
li 加载立即数 li $t0, 5
la 加载地址 la $t0, var1

5.3 寻址模式

  1. 直接寻址

    lw $t0, var1
    
  2. 间接寻址

    lw $t2, ($t0)
    
  3. 基址偏移寻址

    lw $t2, 4($t0)    # $t0 + 4地址处加载
    

6. 算术指令

指令 描述 示例
add 有符号加法 add $t0,$t1,$t2
sub 有符号减法 sub $t2,$t3,$t4
addi 立即数加法 addi $t2,$t3,5
addu 无符号加法 addu $t1,$t6,$t7
subu 无符号减法 subu $t1,$t6,$t7
mult 乘法 mult $t3,$t4
div 除法 div $t5,$t6
mfhi 从HI寄存器移动 mfhi $t0
mflo 从LO寄存器移动 mflo $t1
move 寄存器间移动 move $t2,$t3

7. 控制流指令

7.1 分支指令

指令 描述 示例
b 无条件分支 b target
beq 等于分支 beq $t0,$t1,target
bne 不等于分支 bne $t0,$t1,target
blt 小于分支 blt $t0,$t1,target
ble 小于等于分支 ble $t0,$t1,target
bgt 大于分支 bgt $t0,$t1,target
bge 大于等于分支 bge $t0,$t1,target

7.2 跳转指令

指令 描述 示例
j 无条件跳转 j target
jr 寄存器跳转 jr $t3
jal 跳转并链接 jal sub_label

7.3 子程序调用

# 调用子程序
jal sub_label   # 保存返回地址到$ra,跳转到子程序

# 子程序返回
jr $ra          # 跳转回$ra保存的地址

8. 系统调用与I/O

使用syscall指令进行系统调用,参数通过寄存器传递:

服务 $v0值 参数 返回值
print_int 1 $a0=要打印的整数 -
print_float 2 $f12=要打印的浮点数 -
print_double 3 $f12=要打印的双精度 -
print_string 4 $a0=字符串地址 -
read_int 5 - $v0=读取的整数
read_float 6 - $v0=读取的浮点数
read_double 7 - $v0=读取的双精度
read_string 8 \(a0=缓冲区地址,\)a1=缓冲区长度 -
sbrk 9 $a0=要分配的字节数 $v0=分配的内存地址
exit 10 - -

示例:

# 打印整数
li $v0, 1
li $a0, 123
syscall

# 打印字符串
.data
msg: .asciiz "Hello"
.text
li $v0, 4
la $a0, msg
syscall

# 读取整数
li $v0, 5
syscall
move $t0, $v0   # 将输入保存到$t0

# 程序退出
li $v0, 10
syscall

9. 栈操作

MIPS栈特点:

  • 从高地址向低地址增长
  • $sp寄存器指向栈顶

基本操作:

# 压栈(分配空间)
addi $sp, $sp, -4
sw $t0, 0($sp)

# 弹栈(释放空间)
lw $t0, 0($sp)
addi $sp, $sp, 4

10. 数组处理

数组定义与访问:

.data
array: .space 20   # 5个字的数组

.text
# 初始化数组
li $t0, 0          # 索引
li $t1, 1          # 值
sw $t1, array($t0) # array[0] = 1

addi $t0, $t0, 4   # 索引+4
li $t1, 2
sw $t1, array($t0) # array[1] = 2

# 访问数组元素
la $s1, array      # 基地址
li $a0, 2          # 索引
mul $a0, $a0, 4    # 偏移量
add $s1, $s1, $a0  # 计算元素地址
lw $a0, 0($s1)     # 加载元素

11. 宏定义与使用

11.1 宏匹配

.macro 宏名(参数)
    # 指令
.end_macro

# 示例:打印整数宏
.macro print_int(%param)
    li $v0, 1
    li $a0, %param
    syscall
.end_macro

# 使用
.text
print_int(1)
print_int(2)

11.2 宏定义

.eqv 别名 值/寄存器/指令

# 示例
.eqv LIMIT 20
.eqv CTR $t2
.eqv CLEAR_CTR add CTR, $zero, 0

.text
li $t0, LIMIT
CLEAR_CTR

12. 多文件处理

使用.include指令包含其他文件:

.text
jal fun
.include "A.asm"   # 包含A.asm文件

13. 浮点操作

13.1 浮点寄存器

  • 32个浮点寄存器(包含16个双精度寄存器)

13.2 浮点指令

# 单精度
lwc1 $f2, f1      # 加载单精度
swc1 $f2, 0x10010000 # 存储单精度

# 双精度
ldc1 $f2, d1      # 加载双精度(使用两个寄存器$f2+$f3)
sdc1 $f2, 0x10010000 # 存储双精度

14. 内存布局

典型MIPS内存布局:

  1. 代码段(.text):存放程序指令
  2. 数据段(.data):初始化的全局/静态变量
  3. 堆(heap):动态分配的内存
  4. 栈(stack):函数调用、局部变量,从高地址向低地址增长

15. 完整示例

15.1 条件判断

.data
msg_yes: .asciiz "YES"
msg_no: .asciiz "NO"

.text
main:
    # 读取a
    li $v0, 5
    syscall
    move $t0, $v0
    
    # 读取b
    li $v0, 5
    syscall
    move $t1, $v0
    
    # 比较a > b
    bgt $t0, $t1, a_greater
    
    # 输出NO
    li $v0, 4
    la $a0, msg_no
    syscall
    j exit
    
a_greater:
    # 输出YES
    li $v0, 4
    la $a0, msg_yes
    syscall
    
exit:
    li $v0, 10
    syscall

15.2 循环求和

.text
main:
    li $t0, 1       # i = 1
    li $t1, 0       # sum = 0
    
loop:
    add $t1, $t1, $t0   # sum += i
    addi $t0, $t0, 1    # i++
    ble $t0, 100, loop  # if i <= 100, continue
    
    # 输出结果
    move $a0, $t1
    li $v0, 1
    syscall
    
    # 退出
    li $v0, 10
    syscall

16. 最佳实践

  1. 使用有意义的标签名
  2. 合理使用宏减少重复代码
  3. 遵循寄存器使用约定
  4. 注意栈平衡(函数调用前后保持$sp一致)
  5. 为关键代码添加注释
  6. 使用.include组织大型项目

17. 参考资源

  1. MIPS官方文档
  2. 《计算机组成与设计:硬件/软件接口》
  3. MARS模拟器帮助文档
  4. 在线MIPS汇编教程和参考手册
MIPS汇编语言全面教程 1. MIPS架构概述 MIPS(Microprocessor without Interlocked Pipeline Stages)是一种精简指令集(RISC)处理器架构,由MIPS科技公司于1981年开发。特点包括: 最早版本为32位,现已发展到64位 广泛应用于电子产品、网络设备和个人娱乐设备 采用无互锁流水级设计 2. 机器周期基础 MIPS处理器执行指令的基本步骤: 取指令 :从内存读取指令(PC寄存器保存当前指令地址) 更新PC :PC = PC + 4(指向下一条指令) 执行指令 :执行取到的指令 3. 寄存器系统 MIPS有32个通用寄存器,使用$符号开头表示: 3.1 寄存器分类 | 寄存器 | 名称 | 用途 | |--------|------|------| | $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 | 返回地址 | 3.2 特殊寄存器 HI/LO :乘除法专用寄存器 乘法:HI存高位,LO存低位 除法:LO存商,HI存余数 访问指令:mfhi/mflo 4. 程序结构 基本汇编程序框架: 5. 数据声明与内存操作 5.1 数据声明语法 常用数据类型: .word :32位整数 .byte :8位字符 .space n :分配n字节未初始化空间 .asciiz :以null结尾的字符串 示例: 5.2 内存访问指令 | 指令 | 描述 | 示例 | |------|------|------| | lw | 加载字(4字节) | lw $t0, var1 | | lb | 加载字节 | lb $t0, var1 | | sw | 存储字 | sw $t1, var1 | | sb | 存储字节 | sb $t1, var1 | | li | 加载立即数 | li $t0, 5 | | la | 加载地址 | la $t0, var1 | 5.3 寻址模式 直接寻址 : 间接寻址 : 基址偏移寻址 : 6. 算术指令 | 指令 | 描述 | 示例 | |------|------|------| | add | 有符号加法 | add $t0,$t1,$t2 | | sub | 有符号减法 | sub $t2,$t3,$t4 | | addi | 立即数加法 | addi $t2,$t3,5 | | addu | 无符号加法 | addu $t1,$t6,$t7 | | subu | 无符号减法 | subu $t1,$t6,$t7 | | mult | 乘法 | mult $t3,$t4 | | div | 除法 | div $t5,$t6 | | mfhi | 从HI寄存器移动 | mfhi $t0 | | mflo | 从LO寄存器移动 | mflo $t1 | | move | 寄存器间移动 | move $t2,$t3 | 7. 控制流指令 7.1 分支指令 | 指令 | 描述 | 示例 | |------|------|------| | b | 无条件分支 | b target | | beq | 等于分支 | beq $t0,$t1,target | | bne | 不等于分支 | bne $t0,$t1,target | | blt | 小于分支 | blt $t0,$t1,target | | ble | 小于等于分支 | ble $t0,$t1,target | | bgt | 大于分支 | bgt $t0,$t1,target | | bge | 大于等于分支 | bge $t0,$t1,target | 7.2 跳转指令 | 指令 | 描述 | 示例 | |------|------|------| | j | 无条件跳转 | j target | | jr | 寄存器跳转 | jr $t3 | | jal | 跳转并链接 | jal sub_label | 7.3 子程序调用 8. 系统调用与I/O 使用 syscall 指令进行系统调用,参数通过寄存器传递: | 服务 | $v0值 | 参数 | 返回值 | |------|-------|------|--------| | print_ int | 1 | $a0=要打印的整数 | - | | print_ float | 2 | $f12=要打印的浮点数 | - | | print_ double | 3 | $f12=要打印的双精度 | - | | print_ string | 4 | $a0=字符串地址 | - | | read_ int | 5 | - | $v0=读取的整数 | | read_ float | 6 | - | $v0=读取的浮点数 | | read_ double | 7 | - | $v0=读取的双精度 | | read_ string | 8 | $a0=缓冲区地址,$a1=缓冲区长度 | - | | sbrk | 9 | $a0=要分配的字节数 | $v0=分配的内存地址 | | exit | 10 | - | - | 示例: 9. 栈操作 MIPS栈特点: 从高地址向低地址增长 $sp寄存器指向栈顶 基本操作: 10. 数组处理 数组定义与访问: 11. 宏定义与使用 11.1 宏匹配 11.2 宏定义 12. 多文件处理 使用 .include 指令包含其他文件: 13. 浮点操作 13.1 浮点寄存器 32个浮点寄存器(包含16个双精度寄存器) 13.2 浮点指令 14. 内存布局 典型MIPS内存布局: 代码段(.text) :存放程序指令 数据段(.data) :初始化的全局/静态变量 堆(heap) :动态分配的内存 栈(stack) :函数调用、局部变量,从高地址向低地址增长 15. 完整示例 15.1 条件判断 15.2 循环求和 16. 最佳实践 使用有意义的标签名 合理使用宏减少重复代码 遵循寄存器使用约定 注意栈平衡(函数调用前后保持$sp一致) 为关键代码添加注释 使用.include组织大型项目 17. 参考资源 MIPS官方文档 《计算机组成与设计:硬件/软件接口》 MARS模拟器帮助文档 在线MIPS汇编教程和参考手册