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
相关产品推荐
相关产品推荐

