MIPS读取5个整数逆序输出程序$sp栈指针使用问题咨询
MIPS程序栈指针$sp使用问题排查与修正
现有代码的核心问题
1. 寄存器初始化缺失
你在main函数中调用输入子程序while前,没有给循环计数器$t0赋初始值0,输入循环的触发逻辑完全不可控。你观察到输入阶段$sp没有变化,根本原因是默认初始值下$t0等于20,输入循环直接跳过,循环内的栈操作代码根本没有执行,$sp自然保持初始值不变。
2. 栈操作逻辑完全错位
MIPS子程序的栈保存/恢复逻辑应该在子程序的入口和出口各执行一次,而不是放在循环体内:
- 你现在把栈分配代码
addi $sp, $sp, -8放在输入循环内部,每输入1个数就占用8字节栈空间,5次输入就会占用40字节栈空间,最后你只在程序退出前恢复了1次8字节空间,栈完全失衡,不符合$sp始终指向最后一个已占用栈单元的要求。 - 你循环内重复保存
$s0和$ra属于冗余操作,没有任何实际意义,反而会不断下移$sp。
3. 栈恢复时机错误
你把栈恢复逻辑写在了打印结束后的exitOutput段,和输入子程序的栈分配逻辑完全不对应,这也是你观察到打印阶段$sp才发生变化的直接原因。
修正方案
- main函数调用输入子程序前,给
$t0赋值初始值0 - 把输入子程序的栈分配、寄存器保存逻辑移到子程序入口,仅执行一次
- 输入子程序退出前,先恢复寄存器、回收栈空间,再返回主程序
- 删除冗余的栈操作代码,保证栈操作的配对性
修正后完整代码
.data arr: .space 20 # 长度为5的整型数组 inputPrompt: .asciiz "Please enter a whole number: \n" spaceChar: .asciiz " " .text main: # 初始化输入循环计数器 li $t0, 0 # 提示用户输入 li $v0, 4 la $a0, inputPrompt syscall jal while # 初始化打印计数器,从数组最后一个元素开始 addi $t0, $zero, 16 jal whileOutput # 程序正常退出 li $v0, 10 syscall # 输入子程序 while: # 子程序入口:分配8字节栈空间,保存需要用到的寄存器 addi $sp, $sp, -8 sw $s0, 0($sp) sw $ra, 4($sp) inputLoop: beq $t0, 20, exitWhile # 读取输入 li $v0, 5 syscall sw $v0, arr($t0) move $s0, $v0 addi $t0, $t0, 4 j inputLoop exitWhile: # 子程序出口:恢复寄存器,回收栈空间 lw $s0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra # 打印子程序 whileOutput: beq $t0, -4, exitOutput lw $t6, arr($t0) # 打印整数 li $v0, 1 move $a0, $t6 syscall # 打印空格 li $v0, 4 la $a0, spaceChar syscall addi $t0, $t0, -4 j whileOutput exitOutput: jr $ra
修正后$sp的运行逻辑
- 进入输入子程序时,$sp减8指向新分配的栈空间,符合指向最后一个已占用单元的要求
- 整个输入循环过程中$sp不会变化,不需要重复分配栈空间
- 输入子程序退出时,$sp加8恢复到调用前的状态,栈完全平衡
- 打印阶段没有栈操作,$sp保持不变
内容的提问来源于stack exchange,提问作者S. Jilani
相关产品推荐
相关产品推荐

