在MARS中调试“invalid program counter value: 0x00000000”错误
问题分析与修复方案
错误原因
- 违反MIPS调用规范:使用被调用者保存寄存器
$s0时未提前压栈保存,返回前也未恢复,导致调用者(main)的寄存器状态被破坏,引发程序计数器(PC)异常。 - 最大值计算逻辑错误:调用
getLarger前未正确设置输入参数,且第二次调用后错误地将旧值赋值给$v0,导致最大值结果错误。 - 平均值计算错误:
div指令的商存储在LO专用寄存器中,直接使用$t4获取结果无效,需通过mflo指令读取。 - 未满足作业栈存储要求:使用临时寄存器
$t0-$t3保存参数,而非题目要求的栈存储,不符合作业规范。
修复后的代码
.data .text .globl main # Subprogram getLarger($a0, $a1) getLarger: # $a0 = arg1, $a1 = arg2 move $v0, $a0 # 默认$a0为较大值 bgt $a1, $a0, greater_than # $a1更大则跳转 j end_getLarger nop greater_than: move $v0, $a1 end_getLarger: jr $ra nop # Subprogram largestAndAverage($a0, $a1, $a2, $a3) largestAndAverage: # 函数序言:分配栈空间,保存被调用者寄存器和参数 addi $sp, $sp, -20 # 栈空间:4个参数(16字节) + $s0(4字节) sw $s0, 16($sp) # 保存$s0到栈 sw $a0, 12($sp) # 保存var0到栈 sw $a1, 8($sp) # 保存var1到栈 sw $a2, 4($sp) # 保存var2到栈 sw $a3, 0($sp) # 保存var3到栈 # 计算最大值:依次比较所有参数 jal getLarger # 比较$a0和$a1,结果存$v0 move $s0, $v0 # $s0 = max(a0,a1) move $a0, $s0 lw $a1, 4($sp) # 从栈取var2 jal getLarger # 比较max(a0,a1)和a2 move $s0, $v0 # $s0 = max(max(a0,a1),a2) move $a0, $s0 lw $a1, 0($sp) # 从栈取var3 jal getLarger # 比较当前最大值和a3 move $v0, $v0 # $v0 = 最终最大值 # 计算平均值:从栈读取参数求和 lw $t0, 12($sp) lw $t1, 8($sp) lw $t2, 4($sp) lw $t3, 0($sp) add $t4, $t0, $t1 add $t4, $t4, $t2 add $t4, $t4, $t3 li $t5, 4 div $t4, $t5 mflo $v1 # 从LO寄存器读取商作为平均值 # 函数尾声:恢复寄存器,释放栈空间 lw $s0, 16($sp) addi $sp, $sp, 20 jr $ra nop # Main program main: # 传入参数 2, 5, 8, 11 li $a0, 2 li $a1, 5 li $a2, 8 li $a3, 11 jal largestAndAverage # 退出程序 li $v0, 10 syscall
关键修复点说明
- 栈存储参数:严格按照作业要求将
$a0-$a3全部压入栈中,后续计算从栈读取参数,避免getLarger修改$a0/$a1导致参数丢失。 - 寄存器合规使用:使用
$s0前压栈保存其值,函数返回前恢复,符合MIPS被调用者保存寄存器的规范,避免破坏调用者状态。 - 最大值逻辑修正:每次调用
getLarger前正确设置$a0和$a1参数,确保依次比较所有四个输入值,最终将正确最大值存入$v0。 - 平均值计算修正:使用
mflo指令读取div指令生成的商,确保平均值结果正确。
内容的提问来源于stack exchange,提问作者Sweeney31
相关产品推荐
相关产品推荐

