MIPS递归幂函数代码输出全为0,请求问题排查
递归幂函数输出全0的问题排查
核心问题分析与修复
1. 参数传递不符合约定
你明确要求参数n传入$a1,但在main循环中却把指数加载到了$a2,这不仅违反约定,还会导致递归逻辑中参数引用混乱:
# 原错误代码 lw $a2 0($s2) # 修正为 lw $a1 0($s2)
2. 栈帧操作错误(覆盖返回地址)
在power函数中,你先将$ra保存到8($sp),紧接着又用s.d指令把$f14写入同一位置——sw是4字节存储,s.d是8字节存储,这会直接覆盖$ra的内容,导致递归返回时跳转到错误地址,彻底打乱程序逻辑。
需要重新规划栈帧空间,给每个寄存器分配独立存储位置:
# 原错误栈操作 power: andi $sp 0xfffffff8 addi $sp $sp -16 s.d $f20 ($sp) sw $ra 8($sp) s.d $f14, 8($sp) # 修正后栈操作 power: andi $sp 0xfffffff8 # 栈对齐到8字节边界 addi $sp $sp -24 # 分配24字节栈帧:$f20(8)、$ra(4)、$f14(8),预留4字节对齐 s.d $f20 0($sp) # 保存$f20到栈底 sw $ra 8($sp) # 保存返回地址到8-11字节 s.d $f14 16($sp) # 保存参数x到16-23字节
3. 递归结果被错误覆盖
在done标签处,你递归计算完成后,又将栈中最初保存的旧$f20加载回来,直接覆盖了刚计算出的幂结果:
# 原错误恢复逻辑 done: lw $ra 8($sp) l.d $f14, 8($sp) l.d $f20 ($sp) # 这行把递归前的初始值重新加载,覆盖计算结果 # 修正后恢复逻辑 done: lw $ra 8($sp) # 先恢复返回地址 l.d $f14 16($sp) # 恢复参数x l.d $f20 0($sp) # 恢复$f20(不影响结果寄存器) addi $sp $sp 24 # 释放栈帧 jr $ra
4. 返回寄存器未按约定使用
你要求结果返回至$f0-$f2,但原代码用$f20存储结果,且打印时直接读取$f20,修正为用$f0作为返回寄存器,符合MIPS调用约定。
修正后的完整代码
.data array1: .double 2.0 2.0 3.0 3.0 4.2 5.0 2.0 0.0 0.0 array2: .word 5 4 2 1 0 2 3 0 10 array_size: .word 9 newLine: .asciiz "\n" one: .double 1.0 .text main: la $s1 array1 la $s2 array2 lw $s3 array_size # s3 = 9 li $s4, 0 loop: beq $s4 $s3 exit l.d $f14 0($s1) lw $a1 0($s2) # 按约定将n传入$a1 jal power li $v0, 3 mov.d $f12, $f0 # 从约定的$f0读取返回结果 syscall # 打印换行分隔结果 li $v0, 4 la $a0, newLine syscall addi $s1 $s1 8 addi $s2 $s2 4 addi $s4, $s4, 1 # 索引自增 j loop power: andi $sp 0xfffffff8 # 栈对齐到8字节 addi $sp $sp -24 # 分配24字节栈帧 s.d $f20 0($sp) # 保存$f20 sw $ra 8($sp) # 保存返回地址 s.d $f14 16($sp) # 保存参数x l.d $f0, one # 初始化结果为1.0(n=0时直接返回) beq $a1, $zero, done # 终止条件:n=0 addi $a1, $a1, -1 # n = n-1 jal power # 递归调用power(x, n-1) mul.d $f0, $f14, $f0 # 计算x * power(x, n-1) done: lw $ra 8($sp) # 恢复返回地址 l.d $f14 16($sp) # 恢复参数x l.d $f20 0($sp) # 恢复$f20 addi $sp $sp 24 # 释放栈帧 jr $ra exit: li $v0, 10 syscall
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

