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

MIPS汇编实现换行分隔字符串反转时栈读取地址错误求助

问题描述

想要在不改变换行符位置的前提下,反转以换行分隔的字符串。采用栈结构实现,逻辑上认为合理,但运行时持续抛出“bad address in data/stack read”异常。输入字符串int_buffer格式类似 "123\n65\n893\n45\n",期望输出为 "321\n56\n398\n54\n",但程序处理完第一个换行前的字符串就触发异常,相关MIPS汇编代码如下:

la $a0, int_buffer
la $a1, str_buffer

push:
    lbu $t0, 0($a0)             # load address of character

    beqz $t0, buffer_end            # branch to end if end of buffer

    beq $t0, 10, pop            # branch to pop if newline

    subu $sp, $sp, 1
    sb $t0, ($sp)               # store char in stack
    addi $a0, $a0, 1            # increment input pointer

    j push

pop:
    lb $t0, 0($s0)              # load char in stack
    addu $sp, $sp, 1

    beqz $t0, add_newline       # branch to add newline after current set of strings

    sb $t0, 0($a1)
    addi $a1, $a1, 1            # increment output pointer
    j pop

add_newline:
    li $t0, 10
    sb $t0, 0($a1)

    addi $a0, $a0, 1            # skip newline
    addi $a1, $a1, 1            # move to next index

    j push                      # push the next set of string


buffer_end:

    # print out contents in str_buffer

    # exit
问题分析与修复

错误点梳理

  1. 非法地址读取:pop段中使用未初始化的寄存器$s0读取数据,$s0指向随机内存地址,直接读取必然触发地址错误。
  2. 栈操作顺序颠倒:原代码先将栈指针上移(addu $sp, $sp, 1)再读取数据,导致读取的是栈顶之外的非法区域,正确顺序应先读取栈顶数据,再移动栈指针。
  3. 栈空判断逻辑错误:用读取到的字符是否为0判断栈空,但输入字符均为数字(非0),栈空后继续读取会访问非法地址。

修正后的代码

la $a0, int_buffer
la $a1, str_buffer
move $initial_sp, $sp  # 保存初始栈指针,用于判断当前行字符是否全部弹出

push:
    lbu $t0, 0($a0)             # 读取当前字符

    beqz $t0, buffer_end        # 到达缓冲区末尾则退出
    beq $t0, 10, pop            # 遇到换行则开始弹出栈中字符

    subu $sp, $sp, 1            # 栈指针下移,分配栈空间
    sb $t0, ($sp)               # 将字符存入栈
    addi $a0, $a0, 1            # 移动输入指针到下一个字符
    j push

pop:
    beq $sp, $initial_sp, add_newline  # 栈已空,跳转至添加换行符
    lb $t0, 0($sp)              # 读取栈顶字符
    addu $sp, $sp, 1            # 栈指针上移,释放栈空间

    sb $t0, 0($a1)              # 将字符写入输出缓冲区
    addi $a1, $a1, 1            # 移动输出指针到下一个位置
    j pop

add_newline:
    li $t0, 10
    sb $t0, 0($a1)              # 写入换行符

    addi $a0, $a0, 1            # 跳过输入中的换行符
    addi $a1, $a1, 1            # 移动输出指针到下一个位置
    j push                      # 继续处理下一行字符串

buffer_end:
    # 打印str_buffer内容
    # 程序退出

关键修改说明

  • 新增move $initial_sp, $sp保存初始栈指针,通过比较$sp与$initial_sp判断当前行的字符是否全部弹出,避免栈空后非法读取。
  • 将pop段的lb $t0, 0($s0)改为lb $t0, 0($sp),从正确的栈顶地址读取字符。
  • 调整栈操作顺序:先读取栈顶字符,再上移栈指针,确保读取的是栈中有效数据。
  • 替换栈空判断逻辑,用栈指针位置替代字符值判断,避免输入无0字符时的错误跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:55:59