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

MARS汇编递归求LCS函数遇内存越界错误,求解决方案

MARS汇编LCS程序内存越界问题修复

问题描述

汇编操作成功完成,但运行时触发内存越界错误:

C:\Users\HP Laptop\Downloads\Assembly Assignment 2,\assign2_lcs.s第17行:运行时异常,地址0x00400010处访问地址0x00000000越界

错误原因分析

  1. 错误的指针加载逻辑:find_lcs函数开头的lw $a0, 0($a0)和lw $a1, 0($a1)完全错误。从main传入的$a0/$a1已经是字符串的直接内存地址,而非指针的指针,用lw去读取该地址的内容(实际是字符串的第一个字符),会把字符值当作内存地址访问,直接导致非法内存访问。
  2. 违反MIPS调用约定:函数中使用了$s0/$s1寄存器,但未在函数开头保存、结尾恢复,会破坏调用者的寄存器状态。
  3. 硬编码内存地址:直接使用0x10010000这类固定地址,容易和MARS的内存布局冲突,也不符合规范。

修正后的完整代码

.data
prompt1: .asciiz "Enter the first string (max 1024 characters): "
prompt2: .asciiz "Enter the second string (max 1024 characters): "
result: .asciiz "The length of LCS is: "
# 定义字符串缓冲区,避免硬编码地址
str1_buffer: .space 1024
str2_buffer: .space 1024

.text
.globl find_lcs

find_lcs:
# Prologue:保存需要用到的寄存器,包括$s0/$s1
addi $sp, $sp, -20
sw $ra, 0($sp)
sw $a0, 4($sp)
sw $a1, 8($sp)
sw $s0, 12($sp)
sw $s1, 16($sp)

# 移除错误的lw指令,$a0/$a1已经是字符串的直接地址
# 防御性检查:判断传入地址是否为空
beqz $a0, end_lcs
beqz $a1, end_lcs

# Base case: 任一字符串为空则返回0
lb $t0, 0($a0)
beq $t0, $zero, end_lcs
lb $t0, 0($a1)
beq $t0, $zero, end_lcs

# 比较两个字符串的首字符
lb $t0, 0($a0)
lb $t1, 0($a1)
beq $t0, $t1, equal_chars

# 字符不相等时,分两种情况递归计算
# 情况1:去掉s1的首字符
addi $a0, $a0, 1
jal find_lcs
move $s0, $v0

# 情况2:去掉s2的首字符
lw $a0, 4($sp)    # 恢复s1的原始地址
addi $a1, $a1, 1
jal find_lcs
move $s1, $v0

# 取两种情况的最大值
bge $s0, $s1, case1_result
move $v0, $s1
j end_lcs

case1_result:
move $v0, $s0
j end_lcs

equal_chars:
# 字符相等时,递归计算剩余子串的LCS并+1
addi $a0, $a0, 1
addi $a1, $a1, 1
jal find_lcs
addi $v0, $v0, 1
j end_lcs

end_lcs:
# Epilogue:恢复保存的寄存器
lw $ra, 0($sp)
lw $a0, 4($sp)
lw $a1, 8($sp)
lw $s0, 12($sp)
lw $s1, 16($sp)
addi $sp, $sp, 20
jr $ra

# 测试主函数
main:
# 提示输入第一个字符串
li $v0, 4
la $a0, prompt1
syscall

# 读取第一个字符串
li $v0, 8
la $a0, str1_buffer
li $a1, 1024
syscall

# 去除字符串末尾的换行符(避免影响LCS计算)
move $t0, $a0
remove_newline1:
lb $t1, 0($t0)
bne $t1, 10, remove_newline1_cont
sb $zero, 0($t0)
remove_newline1_cont:
addi $t0, $t0, 1
bnez $t1, remove_newline1

# 提示输入第二个字符串
li $v0, 4
la $a0, prompt2
syscall

# 读取第二个字符串
li $v0, 8
la $a0, str2_buffer
li $a1, 1024
syscall

# 去除字符串末尾的换行符
move $t0, $a0
remove_newline2:
lb $t1, 0($t0)
bne $t1, 10, remove_newline2_cont
sb $zero, 0($t0)
remove_newline2_cont:
addi $t0, $t0, 1
bnez $t1, remove_newline2

# 调用find_lcs计算LCS长度
la $a0, str1_buffer
la $a1, str2_buffer
jal find_lcs

# 输出结果提示
li $v0, 4
la $a0, result
syscall

# 输出LCS长度
move $a0, $v0
li $v0, 1
syscall

# 程序退出
li $v0, 10
syscall

关键修改点

  • 移除错误的指针加载:删掉lw $a0, 0($a0)和lw $a1, 0($a1),直接使用传入的字符串地址。
  • 遵守调用约定:在函数栈帧中保存$s0和$s1,避免破坏调用者寄存器。
  • 替换硬编码地址:在.data段定义str1_buffer和str2_buffer,用符号地址替代固定内存值。
  • 添加换行符处理:读取字符串后去除末尾的换行符,避免换行符被当作有效字符参与LCS计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:58:16