MIPS栈式链接子例程:$a0寄存器冲突引发QTSpim内存错误排查
问题描述
需编写采用栈式链接的MIPS子例程,实现提示用户输入字符串的功能:
- 通过
$a0传入输入缓冲区地址 - 通过
$a1传入缓冲区大小 - 通过
$a2传入提示信息地址
用户遇到的问题:$a0寄存器需同时用作系统调用8(读字符串)的缓冲区地址参数,以及系统调用4(打印字符串)的提示信息地址参数。尝试用move指令将$a0暂存到$s0,打印后恢复$a0,但在QTSpim中出现内存越界错误,相关代码如下:
.text .globl main main: la $a0, str1 # prompting for two different strings li $a1, 100 la $a2, prmpt1 jal prompt nop la $a0, str2 li $a1, 100 la $a2, prmpt2 jal prompt nop li $v0, 10 syscall prompt: move $s0, $a0 # save passed $a0 li $v0, 4 # print prompt move $a0, $a2 syscall move $a0, $s0 li $v0, 8 # read input syscall jr $ra nop .data str1: .space 120 str2: .space 120 prmpt1: .asciiz "enter the first string : \n" prmpt2: .asciiz "enter the second string : \n"
问题分析与解决
错误原因
MIPS的s寄存器(如$s0)属于被调用者保存寄存器,子例程若要修改这类寄存器,必须先将原值保存到栈中,使用完毕后恢复。直接修改$s0会破坏主程序中该寄存器的原有数据,进而引发内存访问异常。同时,题目要求的栈式链接也要求子例程正确维护栈帧,保存关键寄存器。
修正后的代码
.text .globl main main: la $a0, str1 # 提示输入第一个字符串 li $a1, 100 la $a2, prmpt1 jal prompt nop la $a0, str2 # 提示输入第二个字符串 li $a1, 100 la $a2, prmpt2 jal prompt nop li $v0, 10 syscall prompt: # 构建栈帧:分配空间保存$ra和$a0 addi $sp, $sp, -8 sw $ra, 4($sp) # 保存返回地址 sw $a0, 0($sp) # 保存输入缓冲区地址到栈 li $v0, 4 # 打印提示信息 move $a0, $a2 syscall lw $a0, 0($sp) # 从栈恢复输入缓冲区地址 li $v0, 8 # 读取用户输入 syscall lw $ra, 4($sp) # 恢复返回地址 addi $sp, $sp, 8 # 销毁栈帧 jr $ra nop .data str1: .space 120 str2: .space 120 prmpt1: .asciiz "enter the first string : \n" prmpt2: .asciiz "enter the second string : \n"
关键说明
- 栈帧维护:子例程
prompt先扩展栈空间,保存$ra(返回地址)和$a0(缓冲区地址),避免寄存器值被意外覆盖。 - 寄存器安全:改用栈暂存
$a0,不再直接修改s寄存器,符合MIPS寄存器使用规范。 - 栈式链接实现:通过栈保存和恢复关键寄存器,保证主程序与子例程的寄存器状态互不干扰,满足题目要求的栈式链接逻辑。
内容的提问来源于stack exchange,提问作者oscamosca_
相关产品推荐
相关产品推荐

