You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MIPS递归阶乘代码$ra调用问题:无法返回至branch分支输出结果

问题:MIPS递归阶乘无法返回至输出分支

编写MIPS递归阶乘汇编代码时,输入factorial(1)递归执行符合预期,但进入end:分支后,返回地址无法回到branch:分支后的输出逻辑,导致计算结果无法输出。项目要求不能修改现有代码格式,需要明确$ra寄存器的存储/调用方式来解决这个问题。

相关代码:

.data
prompt1:    .asciiz "\nPlease enter an integer: \n"
negativePrompt: .asciiz "\nYour input must be greater than or equal to 0 in order to function.\n"
factorialIs:    .asciiz "\nThe factorial of your input number is: \n"

.globl main
.text
main:

    subu $sp, $sp, 32   # push memory for 8 values
    sw $ra, 20($sp)     # save return address
    sw $fp, 16($sp)     # save old frame pointer 
    addiu $fp, $sp, 28  # set up frame pointer

branch:

    li $v0, 4           # load macro for print_str 
    la $a0, prompt1     # pass argument to string
    syscall             # print string prompt1

    li $v0, 5           # load macro for read_int
    syscall             # get N value from user 

    move $a0, $v0               # store N as arg
    blt $a0, 0, negBranch       # if N is negative, handles case    
    jal factorial               # calls factorial function

    li $v0, 4               # macro for print string
    la $a0, factorialIs     # print string
    syscall

    li $v0, 1               # macro for print int
    move $a0, $v0           # print output int in v0
    syscall 

    lw $ra, 20($sp)         # restore return address of caller
    lw $fp, 16($sp)         # restore frame pointer
    addiu $sp, $sp, 32      # pop stack
    jr $ra                  # return to caller 
#exit:
#   "would you like to calculate again?" 
#   li $v0, 10              # load macro to exit
#   syscall                 # execute exit
    
negBranch: 
    li $v0, 4                   # load macro for print_str 
    la $a0, negativePrompt              # pass argument to string
    syscall                     # print string prompt1  
    li $t0, 0                   # initialize input value to 0
    j branch                        # ask user to input new number
    
factorial: 
    subu $sp, $sp, 32       # pushes memory for variables
    sw $ra, 12($sp)         # stores return address of recursion
    sw $fp, 8($sp)          # save frame pointer
    addiu $fp, $sp, 28      # set up frame pointer
    sw $a0, 0($fp)          # stores n in frame pointer

    lw $v0, 0($fp)
    bgtz $v0, zeroBranch        # if N is greater than 0, recurse
    li $v0, 1                   # return 1
    jr end

zeroBranch:
    lw $v1, 0($fp)          # load n value
    subu $v0, $v1, 1        # v0 = n - 1 
    move $a0, $v0           # a0 = v0 = n - 1 
    jal factorial           # recursive function call
    lw $v1, 0($fp)          # load original n value to v1
    mul $v0, $v0, $v1       # v0 = n * fact(n-1)    

end: 
    lw $ra, 12($sp)         # loads return address of main call
## this ^ line does not access the address from "jal factorial"
    lw $fp, 16($sp)         # loads initial n value
    addiu $sp, $sp, 32      # collapses stack frame
    jr $ra                  # return to main then exit

错误分析

  1. 帧指针恢复偏移错误:在factorial函数中,sw $fp, 8($sp)将旧帧指针存在栈的8偏移位置,但end:分支里用lw $fp, 16($sp)读取,偏移量不匹配,导致帧指针恢复错误,进而破坏栈结构,让返回地址的读取逻辑失效。
  2. 结果寄存器被覆盖:jal factorial执行后,阶乘结果存在$v0中,但后续执行li $v0, 4(打印字符串的系统调用编号)直接覆盖了$v0,导致最终打印的不是阶乘结果。
  3. 返回地址逻辑误解:lw $ra, 12($sp)本身是正确的(对应factorial中sw $ra,12($sp)的存储位置),但因为帧指针恢复错误,才导致返回地址无法正确回到branch:分支后的输出逻辑。

修复方案(不修改现有代码格式,仅调整错误指令)

  • 修正帧指针恢复偏移:将end:分支中的lw $fp, 16($sp)改为lw $fp, 8($sp),对应factorial函数中存储$fp的位置。
  • 保护阶乘结果寄存器:在main中调用jal factorial后,先将结果存入临时寄存器,避免被后续系统调用覆盖:
    jal factorial               # calls factorial function
    move $t0, $v0               # 临时存储阶乘结果,防止被后续syscall覆盖
    
    li $v0, 4               # macro for print string
    la $a0, factorialIs     # print string
    syscall
    
    li $v0, 1               # macro for print int
    move $a0, $t0           # 打印存储的阶乘结果
    syscall 
    
  • 可选:修复main的返回逻辑:main中的jr $ra在首次执行时,$ra的值是操作系统入口的不确定地址,若要实现重复计算,可将jr $ra改为j branch,或者启用注释的exit分支执行退出。

修改后,递归返回时$ra会正确指向jal factorial的下一行,执行输出逻辑,成功打印阶乘结果。

内容的提问来源于stack exchange,提问作者kaili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:14:57