You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MIPS字节对齐问题求助:QtSPIM中sb指令执行报错

PPM文件头解析MIPS代码错误排查与修复

问题描述

我正在解析PPM文件头,需要提取宽度、高度、最大值并转成整数存储。已经把完整文件头读到缓冲区里,但运行MIPS代码时,sb $t2, 0($t7)这一行在QtSPIM里一直报错。试过修改$t7的用法,比如换临时缓冲区、调整空间分配,怀疑是字节对齐问题,但不知道怎么解决。

错误根本原因

你把$t7初始化为0(li $t7, 0),然后用它作为内存地址执行sb $t2, 0($t7)——这相当于往内存地址0写入数据,而MIPS架构中地址0属于内核保留的非法访问区域,必然触发内存访问错误,和字节对齐无关。

修正方案

需要给宽度、高度、最大值的字符序列分配合法的内存缓冲区,比如在.data段新增临时缓冲区,或者复用已有缓冲区的剩余空间。核心是让$t7指向合法的内存地址,而非0。

修正后的完整代码

.data
    header_buffer:  .space 256     # 存储文件头的缓冲区
    width_str:      .space 10      # 新增:存储宽度字符串的临时缓冲区
    height_str:     .space 10      # 新增:存储高度字符串的临时缓冲区
    maxval_str:     .space 10      # 新增:存储最大值字符串的临时缓冲区
    width:          .word 0
    height:         .word 0 
    max_val:        .word 0
    filename: .asciiz "input.ppm" 

.text
    .globl main
    
main:
    # 打开文件
    li $v0, 13              # 打开文件的系统调用号
    la $a0, filename        # 加载文件名到$a0
    li $a1, 0               # 只读模式
    syscall
    move $s0, $v0           # 保存文件描述符到$s0

    la $t1, header_buffer   # 加载header_buffer地址
    

# 读取第一行(P2/P3标识)
read_head:
    li $v0, 14              # 读取文件的系统调用号
    move $a0, $s0           # 文件描述符
    move $a1, $t1           # 缓冲区地址
    li $a2, 1               # 每次读1个字符
    syscall
    
    lb $t4, 0($t1)              # 读取当前字符
    addi $t1, $t1, 1
    beq $t4, 10, read_comment   # 遇到换行则跳转到读取注释行
    j read_head
    
# 读取第二行,检查是否为注释
read_comment:
    li $v0, 14              # 读取文件的系统调用号
    move $a0, $s0           # 文件描述符
    move $a1, $t1           # 缓冲区地址
    li $a2, 1               # 每次读1个字符
    syscall
    
    lb $t4, 0($t1)                      # 读取当前字符
    addi $t1, $t1, 1
    bne $t4, 35, read_width     # 首字符不是#则跳转到读取宽度
    
read_comment_loop:
    li $v0, 14              # 读取文件的系统调用号
    move $a0, $s0           # 文件描述符
    move $a1, $t1           # 缓冲区地址
    li $a2, 1               # 每次读1个字符
    syscall
    
    lb $t4, 0($t1)                      # 读取当前字符
    addi $t1, $t1, 1
    beq $t4, 10, read_width     # 遇到换行则跳转到读取宽度
    j read_comment_loop

# 初始化变量:指向各临时字符串缓冲区
init_values:
    la $t7, width_str       # 修改:让$t7指向width_str缓冲区的地址
    la $t8, height_str      # 修改:让$t8指向height_str缓冲区的地址
    la $t9, maxval_str      # 修改:让$t9指向maxval_str缓冲区的地址
    
read_width: 
    li $v0, 14              # 读取文件的系统调用号
    move $a0, $s0           # 文件描述符
    move $a1, $t1           # 缓冲区地址
    li $a2, 1               # 每次读1个字符
    syscall
    
    lb $t2, ($t1)                       # 读取当前字符
    sb $t2, 0($t7)                      # 现在写入的是合法的缓冲区地址
    addi $t7, $t7, 1                    # 修改:移动缓冲区指针,准备存储下一个字符
    addi $t1, $t1, 1
    beq $t2, 32, store_width            # 遇到空格则跳转到存储宽度
    j read_width
    
store_width:
    sb $zero, 0($t7)                    # 新增:给字符串添加结束符,确保str_to_int能正确解析
    la $t0, width_str                   # 修改:传入width_str的地址给str_to_int
    jal str_to_int
    sw $t6, width

额外注意事项

  • 写入字符到缓冲区后,必须移动$t7指针(addi $t7, $t7, 1),否则每次都会覆盖同一个位置的字符,导致字符串内容错误。
  • 在调用字符串转整数的str_to_int函数前,必须给字符串添加结束符(sb $zero, 0($t7)),否则解析函数会读取到缓冲区外的垃圾数据,引发未知错误。

内容的提问来源于stack exchange,提问作者studentinneed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:15:23