MIPS汇编如何实现寄存器值传入传出 函数调用后值丢失怎么解决
问题原因与修复方案
1. 核心错误:循环变量被意外覆盖
你当前用$s6作为遍历数值范围的循环变量,但是在第一次调用isFactor获取到待检查数的真因数和$s3后,直接执行了move $s6, $s3,把循环变量直接修改为了因数和,这直接打乱了原有的遍历逻辑,是导致无限循环的主要原因。
正确的做法是:调用isFactor计算第二个数的因数和时,仅临时把参数传给isFactor的入参寄存器,不要修改循环变量$s6的值。
2. 寄存器使用不符合MIPS调用约定
MIPS架构中,$s0~$s7属于被调用者保存寄存器:如果子函数(比如你这里的isFactor)要使用这类寄存器,必须先在栈上保存寄存器的原始值,函数返回前再恢复原值,否则父函数存在这些寄存器里的数据会被意外覆盖。
你当前isFactor函数里直接修改了$s2、$s4,没有做栈保存/恢复操作,会导致父函数的相关寄存器值丢失。
建议优化:子函数的临时变量优先使用$t0~$t9这类调用者保存寄存器,不需要额外保存,用完即丢,更适合子函数内部的临时计算。
3. 函数传参逻辑不规范
你当前通过$s6给isFactor传递待计算的参数,既容易误改循环变量,也不符合MIPS的传参约定。MIPS默认用$a0~$a3传递函数入参,用$v0~$v1传递返回值,遵循这个约定可以避免很多变量覆盖问题。
修改后的代码参考
isAmicable: li $s5, 0 # 亲和数对计数器 add $s6, $s0, $zero # 循环变量,遍历[s0, s1]区间 amicableLoop: bge $s6, $s1, final_output # 第一次调用:计算当前数$s6的真因数和 move $a0, $s6 # 用$a0传参 jal isFactor move $s3, $v0 # 用$v0拿返回值,存到$s3 # 第二次调用:计算$s3的真因数和,不要修改$s6 move $a0, $s3 # 把$s3作为参数传给isFactor jal isFactor move $s4, $v0 # 拿到$s3的真因数和 # 亲和数判断逻辑 bne $s6, $s4, increment # a的因数和是b,b的因数和不是a,跳过 bge $s6, $s3, increment # 避免重复计数,只保留a<b的对 bge $s3, $s1, increment # 超出范围,跳过 # 是亲和数对的处理逻辑 addi $s5, $s5, 1 # 此处可自行添加存储亲和数对的逻辑 increment: addi $s6, $s6, 1 j amicableLoop # isFactor函数:计算$a0的所有真因数和,返回值存在$v0 isFactor: li $v0, 0 # 真因数和,用返回值寄存器存储 li $t0 , 1 # 除数,用临时寄存器存储,不需要额外保存 sumLoop: bge $t0, $a0, return_sum # 除数大于等于待计算数,结束循环 rem $t1, $a0, $t0 # 求余 bne $t1, $0, while addu $v0, $v0, $t0 # 能整除,加到和里 while: addi $t0, $t0, 1 j sumLoop return_sum: jr $ra
内容的提问来源于stack exchange,提问作者Greedy-Boogster
相关产品推荐
相关产品推荐

