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

MIPS汇编程序运行报错Runtime exception地址越界,请求排查

MIPS汇编程序地址越界错误排查与修复

问题描述

编写了一段实现读取用户字符串并支持修改至退出功能的MIPS汇编程序,运行时触发错误:

Error code: Runtime exception at 0x00400010: address out of range 0x00000000

错误发生在swap_characters函数loop段的lb $t0, 0($s0)指令处,程序无法正常运行。

原代码

.data
prompt1: .asciiz "This program reads in a String from the user and then allows the user to make changes to it until they want to stop.\n"
prompt2: .asciiz "Please enter your string now (maximum of 40 characters):\n"
prompt3: .asciiz "Your current string is:\n"
prompt4: .asciiz "Do you want to make any changes to the string? (Y/N): "
prompt5: .asciiz "Enter the character in the string you would like replaced: "
prompt6: .asciiz "Enter what you would like to change the character to: "
prompt7: .asciiz "Your final string is:\n"

.text
.globl main

swap_characters:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $s0, 0($sp)

move $s0, $a0      

loop:
lb $t0, 0($s0)
beqz $t0, done
beq $t0, $a1, replace

addiu $s0, $s0, 1  
j loop

replace:
sb $a2, 0($s0)
addiu $s0, $s0, 1
j loop

done:
lw $ra, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 8
jr $ra

main:
li $v0, 4
la $a0, prompt1
syscall

li $v0, 4
la $a0, prompt2
syscall

li $v0, 8
la $a0, 0($v1)      
li $a1, 40         
syscall

li $v0, 4
la $a0, prompt3
syscall

li $v0, 4
la $a0, 0($v1)      
syscall

change_loop:
# Prompt for making changes
li $v0, 4
la $a0, prompt4
syscall

li $v0, 12
syscall

beqz $v0, done1       

li $v0, 4
la $a0, prompt5
syscall

li $v0, 12
syscall

move $a1, $v0

li $v0, 4
la $a0, prompt6
syscall

li $v0, 12
syscall

move $a2, $v0

move $a0, $v1      
jal swap_characters

li $v0, 4
la $a0, prompt3
syscall

# Print the updated string
li $v0, 4
la $a0, 0($v1)      
syscall

j change_loop

done1:
li $v0, 4
la $a0, prompt7
syscall

li $v0, 4
la $a0, 0($v1)       

li $v0, 10
syscall

问题根源

  1. 未分配字符串缓冲区:程序没有在.data段为用户输入的字符串预留内存空间,导致读取字符串时没有合法的存储地址。
  2. 错误使用$v1寄存器:系统调用li $v0,8(读取字符串)要求$a0指向预分配的内存,但代码中la $a0, 0($v1)将$a0设为0($v1初始值为0),非法写入地址0的内存区域。后续所有通过0($v1)访问字符串的操作,本质都是访问地址0,最终在swap_characters中执行lb指令时触发地址越界。
  3. 退出逻辑错误:beqz $v0, done1判断无效,因为li $v0,12读取的是字符ASCII值,输入'N'的ASCII为78,不会是0。

修复方案

1. 添加字符串缓冲区

在.data段末尾添加:

input_str: .space 41  # 分配41字节,容纳40字符+字符串结束符'\0'

2. 修正字符串读取逻辑

将main中读取字符串的代码:

li $v0, 8
la $a0, 0($v1)      
li $a1, 40         
syscall

替换为:

li $v0, 8
la $a0, input_str  # 指向预分配的缓冲区
li $a1, 41         # 包含结束符,所以长度设为41
syscall

3. 替换所有非法的字符串引用

将所有la $a0, 0($v1)和move $a0, $v1替换为指向input_str的引用:

  • 第一次打印输入字符串:li $v0,4; la $a0, input_str; syscall
  • 调用swap_characters前:la $a0, input_str
  • 打印更新后字符串:li $v0,4; la $a0, input_str; syscall
  • 打印最终字符串:li $v0,4; la $a0, input_str; syscall

4. 处理字符输入的换行残留

使用li $v0,12读取字符后,输入缓冲区会残留换行符,可能导致后续输入异常。在每次读取字符后添加清除逻辑:

li $v0, 12
syscall
# 清除换行符
li $v0, 12
syscall

5. 修正退出逻辑

将beqz $v0, done1替换为:

beq $v0, 'N', done1        # 判断输入是否为'N',触发退出

修复后的完整代码

.data
prompt1: .asciiz "This program reads in a String from the user and then allows the user to make changes to it until they want to stop.\n"
prompt2: .asciiz "Please enter your string now (maximum of 40 characters):\n"
prompt3: .asciiz "Your current string is:\n"
prompt4: .asciiz "Do you want to make any changes to the string? (Y/N): "
prompt5: .asciiz "Enter the character in the string you would like replaced: "
prompt6: .asciiz "Enter what you would like to change the character to: "
prompt7: .asciiz "Your final string is:\n"
input_str: .space 41  # 预分配字符串缓冲区

.text
.globl main

swap_characters:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $s0, 0($sp)

move $s0, $a0      

loop:
lb $t0, 0($s0)
beqz $t0, done
beq $t0, $a1, replace

addiu $s0, $s0, 1  
j loop

replace:
sb $a2, 0($s0)
addiu $s0, $s0, 1
j loop

done:
lw $ra, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 8
jr $ra

main:
li $v0, 4
la $a0, prompt1
syscall

li $v0, 4
la $a0, prompt2
syscall

li $v0, 8
la $a0, input_str
li $a1, 41         
syscall

li $v0, 4
la $a0, prompt3
syscall

li $v0, 4
la $a0, input_str
syscall

change_loop:
# Prompt for making changes
li $v0, 4
la $a0, prompt4
syscall

li $v0, 12
syscall
# 清除换行符
li $v0, 12
syscall

beq $v0, 'N', done1       

li $v0, 4
la $a0, prompt5
syscall

li $v0, 12
syscall
# 清除换行符
li $v0, 12
syscall

move $a1, $v0

li $v0, 4
la $a0, prompt6
syscall

li $v0, 12
syscall
# 清除换行符
li $v0, 12
syscall

move $a2, $v0

la $a0, input_str      
jal swap_characters

li $v0, 4
la $a0, prompt3
syscall

# Print the updated string
li $v0, 4
la $a0, input_str
syscall

j change_loop

done1:
li $v0, 4
la $a0, prompt7
syscall

li $v0, 4
la $a0, input_str

li $v0, 10
syscall

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:18:05