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
问题分析与修复
错误点梳理
- 非法地址读取:
pop段中使用未初始化的寄存器$s0读取数据,$s0指向随机内存地址,直接读取必然触发地址错误。 - 栈操作顺序颠倒:原代码先将栈指针上移(
addu $sp, $sp, 1)再读取数据,导致读取的是栈顶之外的非法区域,正确顺序应先读取栈顶数据,再移动栈指针。 - 栈空判断逻辑错误:用读取到的字符是否为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
相关产品推荐
相关产品推荐

