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

请求协助将C代码转换为MIPS汇编,当前实现陷入死循环

问题:将C递归函数转换为MIPS汇编时遇到死循环

我需要把下面的C代码转换成MIPS汇编,但自己写的代码陷入死循环。我知道死循环的原因,但想不出其他可行的实现方式(假设$a0存储数组地址,$v0为返回寄存器)。

C代码

uint32_t reverse_sum(uint32_t *arr) {
  uint32_t r;

  if(*arr == -1) return 0;
  r = reverse_sum(arr+1) + (uint32_t)*arr;
  *arr = r;        
  return(r);
}

我尝试编写的MIPS代码

reverse_prefix_sum:
   # PROLOGUE
   subu $sp, $sp, 8        # expand stack by 8 bytes
   sw   $ra, 8($sp)        # push $ra (ret addr, 4 bytes)
   sw   $fp, 4($sp)        # push $fp (4 bytes)
   addu $fp, $sp, 8        # set $fp to saved $ra

   lw $t0, 0($a0)          # t0 now stores first array element

   bne $t0, -1, rec        
   li $v0, 0               
   j ret                   

rec:
   subu $sp, $sp, 4        # expand stack by 1 spot 
   sw $t0, 4($sp)          # store t0 (first element in array) on the stack
   lw $a0, 4($a0)          # load arr + 1 element in a0
   jal reverse_prefix_sum
   lw $a0, 4($sp)
   add $t1, $v0, $a0
   sw $t1, 0($t0)
   move $v0, $t1 


ret:
   # EPILOGUE
   move $sp, $fp           # restore $sp
   lw   $ra, ($fp)         # restore saved $ra
   lw   $fp, -4($sp)       # restore saved $fp
   jr   $ra                # return to kernel

问题分析与修正方案

你的代码存在的核心错误

  • 递归参数传递错误:lw $a0, 4($a0)是读取arr[1]的值,而非传递arr+1的地址,导致递归调用时传入的不是下一个数组元素的地址,而是元素值,后续递归逻辑完全混乱,必然引发死循环或内存访问错误。
  • 栈操作与地址恢复错误:递归返回后,你从栈中取出的是原arr[0]的值而非原数组地址,导致sw $t1, 0($t0)是将结果写入以原元素值为地址的内存区域,这会破坏内存,进一步加剧错误。
  • 栈帧维护错误:尾声部分恢复$fp的操作lw $fp, -4($sp)逻辑错误,会导致栈帧混乱,返回时出错。

正确的MIPS实现

reverse_sum:
    # 栈帧初始化:保存$ra、$fp,以及需要保留的寄存器/变量
    subu    $sp, $sp, 16       # 栈帧大小16字节:$ra(4)、$fp(4)、原$a0(4)、原arr[0]值(4)
    sw      $ra, 12($sp)       # 保存返回地址到栈
    sw      $fp, 8($sp)        # 保存帧指针到栈
    addu    $fp, $sp, 16       # 设置帧指针指向栈帧顶部

    sw      $a0, 4($sp)        # 保存当前数组地址到栈,递归返回后需要用它修改数组元素
    lw      $t0, 0($a0)        # 读取当前数组元素值到$t0

    # 终止条件判断:如果当前元素是-1(即0xFFFFFFFF,因为uint32_t),返回0
    li      $t1, 0xFFFFFFFF
    beq     $t0, $t1, base_case

    # 递归调用:传入arr+1的地址
    addu    $a0, $a0, 4        # 计算arr+1的地址(uint32_t占4字节)
    jal     reverse_sum

    # 递归返回后计算r = 返回值 + 原arr[0]值
    lw      $a0, 4($sp)        # 恢复原数组地址
    lw      $t0, 0($a0)        # 再次读取原arr[0]值(也可以提前保存到栈)
    add     $v0, $v0, $t0      # $v0 = reverse_sum(arr+1) + *arr

    # 修改当前数组元素为r
    sw      $v0, 0($a0)

    j       epilogue

base_case:
    li      $v0, 0             # 终止条件返回0

epilogue:
    # 恢复栈帧与寄存器
    lw      $ra, 12($sp)       # 恢复返回地址
    lw      $fp, 8($sp)        # 恢复帧指针
    addu    $sp, $sp, 16       # 收缩栈
    jr      $ra                # 返回

代码说明

  1. 栈帧管理:提前分配足够的栈空间,保存当前数组地址和元素值,确保递归返回后能正确恢复上下文。
  2. 递归参数传递:通过addu $a0, $a0, 4计算下一个数组元素的地址,而非读取元素值,保证递归调用的参数正确。
  3. 终止条件判断:因为uint32_t的-1实际是0xFFFFFFFF,所以用li $t1, 0xFFFFFFFF来比较,避免符号扩展问题。
  4. 结果写入:递归返回后,用保存的原数组地址修改当前元素,确保写入的是正确的内存位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 19:05:28