MIPS汇编中何时需要重置栈指针?亲和数代码栈操作问题排查
栈操作核心错误
IsAmicable循环中addi $a1, $a1, 1后连续写栈的逻辑错误:sw $a2, 0($sp)会直接覆盖栈中存储的循环起始值,导致迭代逻辑完全失效。- 作为全局循环结束值的
$a2存入4($sp)后,代码中多处出现sw $a2, 4($sp)的写操作,直接修改了你要全程保留的结束值,这是你$a2值无法保持不变的直接原因。 - 20字节的栈空间没有明确的偏移使用规划,
IsFactor、IsFactor2的写栈操作经常意外覆盖其他位置的有效数据。 IsFactor中的跳转逻辑错误:bne $a1, $a3, continue会直接跳出求和流程回到上层函数,无法完成真因数累加。
修复方案
- 删去
IsAmicable内addi $a1, $a1, 1后的sw $a2, 0($sp)语句,仅保留sw $a1, 0($sp)更新当前迭代值即可。 - 删去所有
IsFactor、IsFactor2、continue段中的sw $a2, 4($sp)语句,4($sp)位置仅用于存储固定不变的循环结束值,全程禁止写入。 - 调整
IsFactor内的跳转逻辑,将bne $a1, $a3, continue改为bge $a3, $a1, continue,仅当除数超过当前数值时再退出求和返回上层。 - 你当前栈恢复指令放在
Endif中的位置是正确的,退出IsAmicable函数前执行addi $sp, $sp, 20回收栈空间即可。如果需要支持函数正常返回主程序,调用jal IsAmicable前需要额外将$ra返回地址存入栈的空闲偏移位,函数退出前再读取恢复。 - 更稳妥的
$a2保存方案:进入IsAmicable读取到$a2的初始值后,直接存入s系列寄存器,使用前先将s寄存器的原值压栈保存,函数退出前恢复即可,比反复读写栈更不容易出现值被意外覆盖的问题。
.data sent1: .asciiz "Input the start of the range: " sent2: .asciiz "Input the end of the range: " sent4: .asciiz "IN ELSE " sent5: .asciiz " ," userInput: .word 20 userInput2: .word 20 number: .space 20 number2: .space 20 .text main: # Add space on the stack for two words li $v0, 4 # Loads immediate for a sentace to be printed la $a0, sent1 # Loads the address of the sentance to print syscall # System calls and prints out sentance li $v0, 5 syscall move $t1, $v0 li $v0, 4 la $a0, sent2 syscall li $v0, 5 syscall move $t2, $v0 move $a1, $t1 move $a2, $t2 slt $s0, $a2, $a1 bne $s0, $zero, Else addi $sp, $sp, -20 sw $a1, 0($sp) sw $a2, 4($sp) jal IsAmicable Else: move $a3, $a1 move $a1, $a2 move $a2, $a3 addi $sp, $sp, -20 sw $a1, 0($sp) sw $a2, 4($sp) jal IsAmicable IsAmicable: lw $a1, 0($sp) lw $a2, 4($sp) loop: #lw $a2, 4($sp) li $v0, 1 move $a3, $a2 syscall beq $a1, $a2, Endif # Setup for loop from value in a1 to value in a2 addi $a1, $a1, 1 # Adds 1 to a1 to iterate sw $a1, 0($sp) # loads value in a1 to address in a0 to pass to isFactor jal IsFactor continue: lw $a0, 12($sp) lw $a2, 4($sp) move $a3, $a0 sw $a3, 12($sp) sw $a0, 0($sp) jal IsFactor2 continue2: lw $t2, 0($sp) lw $a3, 12($sp) lw $a2, 4($sp) bne $t2, $a3, loop li $v0, 1 move $a0, $a2 syscall j loop IsFactor: lw $a1, 0($sp) lw $a2, 4($sp) move $a3, $0 li $a3, 0 loop2: move $t4, $zero addi $a3, $a3, 1 bge $a3, $a1, continue rem $t4, $a1, $a3 bne $t4, 0,loop2 add $a0, $a0, $a3 sw $a0, 12($sp) j loop2 Endif: add $sp, $sp, 20 li $v0, 10 syscall IsFactor2: lw $a0, 0($sp) lw $a2, 4($sp) move $a3, $0 li $a3, 0 loop3: move $t3, $zero bgt $a3, $a0, continue2 addi $a3, $a3, 1 rem $t3, $a0, $a3 bne $t3, 0,loop3 add $t2, $t2, $a3 sw $t2, 0($sp) j loop3
内容的提问来源于stack exchange,提问作者CodingMan
相关产品推荐
相关产品推荐

