MIPS汇编数组质数检测异常求助:_prime函数lw指令问题排查
修复MIPS汇编程序中的质数检测函数异常
问题根源分析
你指出的lw $s2,($s0)指令异常,本质是**_prime函数的参数处理逻辑完全错误**:
- 调用
_prime时传入的是数组当前元素的地址(存在$a0),但_prime内部错误地将s0当成数值直接运算,没有先从地址中取出实际元素值。 - 初始化阶段的寄存器赋值逻辑混乱,导致后续除法、判断全部偏离预期。
- 额外存在
_printprime中打印逻辑的小错误:自增s0后再取元素,会打印下一个数组元素而非当前检测的质数。
修复后的完整代码
.data arr: .space 100 input1: .asciiz "Nhap so phan tu: " #input the number elements of the array input2: .asciiz "Nhap mang: \n" #input the array output1: .asciiz "Mang vua nhap: " #print the array output2: .asciiz "\nCac so nguyen to la: " #print the prime in the array output3: .asciiz "\nGia tri lon nhat trong mang: " #print the max element in the array output4: .asciiz "\nGia tri trung binh cua mang la: " #print the average value in the array output5: .asciiz "a[" output6: .asciiz "]: " .text #print input1 li $v0,4 la $a0,input1 syscall #input n li $v0,5 syscall #store n into $s1 move $s1,$v0 #passing parameter into _inputarr move $a1,$s1 la $a0,arr jal _inputarr #store return value into $s0 move $s0,$v0 #passing parameter into _outputarr move $a1,$s1 move $a0,$s0 jal _outputarr #passing parameter into _printprime move $a1,$s1 move $a0,$s0 jal _printprime j exit _inputarr: #initialize stack addi $sp,$sp,-32 #back up register sw $s1,($sp) sw $s0,4($sp) sw $t0,8($sp) #func's body #initialize variable move $s0,$a0 move $s1,$a1 li $t0,0 #i=0 move $s2,$a0 #print input2 li $v0,4 la $a0,input2 syscall _inputarr.loop: beq $t0,$s1,_inputarr.end #print 'a[' li $v0,4 la $a0,output5 syscall #print i li $v0,1 move $a0,$t0 syscall #print '] ' li $v0,4 la $a0,output6 syscall #input a[i] li $v0,5 syscall sw $v0,($s0) addi $t0,$t0,1 addi $s0,$s0,4 j _inputarr.loop _inputarr.end: move $v0,$s2 #restore register lw $s1,($sp) lw $s0,4($sp) lw $t0,8($sp) #restore stack addi $sp,$sp,32 #return jr $ra _outputarr: #initialize stack addi $sp,$sp,-32 #back up register sw $s1,($sp) sw $s0,4($sp) sw $t0,8($sp) #func's body #initialize variable li $t0,0 #i=0 move $s0,$a0 move $s1,$a1 #print output1 li $v0,4 la $a0,output1 syscall _outputarr.loop: beq $t0,$s1,_outputarr.end lw $a0,($s0) li $v0,1 syscall #print space li $v0,11 li $a0,' ' syscall addi $t0,$t0,1 addi $s0,$s0,4 j _outputarr.loop _outputarr.end: #restore register lw $s1,($sp) lw $s0,4($sp) lw $t0,8($sp) #restore stack addi $sp,$sp,32 #return jr $ra _printprime: #initialize stack addi $sp,$sp,-32 #back up register sw $s0,($sp) sw $s1,4($sp) sw $t0,8($sp) sw $t8,12($sp) sw $a0,16($sp) sw $t1,20($sp) #func's body #initialize variable move $s0,$a0 move $s1,$a1 li $t0,0 #i=0 #print output2 li $v0,4 la $a0,output2 syscall _printprime.loop: beq $t0,$s1,_printprime.end # 先保存当前元素地址,避免自增后丢失 move $a0,$s0 jal _prime #store return value move $t8,$v0 # 先判断是否打印,再自增指针 beq $t8,0,_printprime.next # 打印当前元素 lw $a0,($s0) li $v0,1 syscall li $v0,11 li $a0,' ' syscall _printprime.next: addi $t0,$t0,1 addi $s0,$s0,4 j _printprime.loop _printprime.end: #restore register lw $s0,($sp) lw $s1,4($sp) lw $t0,8($sp) lw $t8,12($sp) lw $a0,16($sp) addi $sp,$sp,32 #return jr $ra _prime: #initialize stack addi $sp,$sp,-32 #back up register sw $s0,0($sp) sw $s1,4($sp) sw $t0,8($sp) sw $t8,12($sp) sw $s2,16($sp) sw $t9,20($sp) #func's body # 正确处理参数:$a0是元素的地址,先取出数值到$s2 move $s0,$a0 # 保存传入的元素地址 lw $s2,($s0) # 取出当前要检测的数值 # 边界条件判断:小于2的数不是质数 slti $t8,$s2,2 beq $t8,1,_prime.false # 2是质数,直接返回真 beq $s2,2,_prime.true li $t0,2 # 初始化除数i=2 div $s2,$t0 mflo $s1 # $s1 = n/2,循环上限 _prime.loop: # 如果i超过n/2,说明是质数 sgt $t8,$t0,$s1 beq $t8,1,_prime.true # 取余判断是否能整除 div $s2,$t0 mfhi $t9 beq $t9,0,_prime.false # 能整除则不是质数 addi $t0,$t0,1 j _prime.loop _prime.false: li $v0,0 j _prime.end _prime.true: li $v0,1 #end of func _prime.end: #restore register lw $s0,0($sp) lw $s1,4($sp) lw $t0,8($sp) lw $t8,12($sp) lw $s2,16($sp) lw $t9,20($sp) #restore stack addi $sp,$sp,32 #return jr $ra exit: li $v0,10 syscall # 补充缺失的syscall指令
关键修改点说明
_prime函数参数修正
- 首先将传入的元素地址(
$a0)保存到$s0,再通过lw $s2,($s0)取出实际数值,这是你原代码最核心的错误。 - 补充了边界条件:小于2的数直接判定为非质数,2直接判定为质数,避免无效循环。
- 首先将传入的元素地址(
_printprime函数打印逻辑修正
- 将指针自增操作移到打印判断之后,避免原代码中自增后取到下一个元素的错误。
- 新增
_printprime.next分支统一处理自增逻辑,代码更清晰。
其他细节修复
- 在
exit标签处补充了syscall指令,确保程序能正常退出。 - 调整了
_prime中循环上限的计算逻辑,移除了多余的addi $s1,$s1,1,避免循环次数错误。
- 在
内容的提问来源于stack exchange,提问作者Tandy
相关产品推荐
相关产品推荐

