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

MIPS中l.s指令触发地址未按字边界对齐错误的求助

MIPS "fetch address not aligned on word boundary" 错误分析与修复

错误根源

你犯了一个核心逻辑错误:把阶乘函数返回的整数结果当成了内存地址。

你的Factorial函数计算完阶乘后,会把整数结果存在$v0寄存器里,但你后续执行了la $t7, ($v0)和l.s $f0, ($t7)——这两行代码的意思是“把$v0的值作为内存地址,从该地址加载单精度浮点数到$f0”。比如当阶乘结果是6时,你试图访问的地址是0x6,而MIPS的内存对齐规则要求:访问字(或浮点数)的地址必须是4的倍数(因为32位数据占4字节),0x6不是4的倍数,所以触发了地址未对齐的错误。

除此之外还有两个次要问题:

  • 读取整数n时用了syscall 6(浮点数读取),但n是整数,应该用syscall 5,否则会导致浮点寄存器和整数寄存器的数据混乱;
  • 阶乘函数的边界分支错误:当输入为1时,你给$v0加1,导致1!的结果变成2,不符合阶乘定义。

修复方案

  1. 修正输入逻辑:用syscall 5读取整数n和r;
  2. 正确转换数据类型:把阶乘返回的整数直接转成浮点数,而非当作地址读取;
  3. 修复阶乘边界与循环逻辑:修正1!、0!的返回值,同时简化乘法循环;

修复后的完整代码

# n and r are assumed to be integers and n > r

.data
    textN: .asciiz "enter n: "
    textR: .asciiz "enter r: "

.text
    main: 
        # 读取整数n
        li $v0, 4
        la $a0, textN
        syscall
        li $v0, 5  # 替换原syscall 6,读取整数
        syscall
        move $t0, $v0
        
        # 读取整数r
        li $v0, 4
        la $a0, textR
        syscall
        li $v0, 5
        syscall
        move $t1, $v0
        
        # 计算n!并转成浮点数
        move $a0, $t0
        jal Factorial
        mtc1 $v0, $f0       # 将整数结果从通用寄存器转到浮点寄存器
        cvt.s.w $f0, $f0    # 把整数转成单精度浮点数
        
        # 计算(n-r)!并转成浮点数
        sub $a0, $t0, $t1
        jal Factorial
        mtc1 $v0, $f1
        cvt.s.w $f1, $f1
        
        # 计算排列数P(n,r)=n!/(n-r)!并输出
        div.s $f12, $f0, $f1
        li $v0, 2
        syscall 
        jr $ra
            
    Factorial:
        # 边界条件:0!和1!都等于1
        beq $a0, 0, Return_One
        beq $a0, 1, Return_One
        
        # 保存现场
        subi $sp, $sp, 8
        sw $t0, ($sp)
        sw $t1, 4($sp)
        
        move $t0, $a0
        move $v0, $a0  # 初始值为输入的n
        
    Loop:
        subi $t0, $t0, 1
        beq $t0, $zero, Exit_Loop
        mul $v0, $v0, $t0  # 连续乘法:n*(n-1)*...*1
        
    Exit_Loop:
        # 恢复现场
        lw $t0, ($sp)
        lw $t1, 4($sp)
        addi $sp, $sp, 8
        jr $ra
        
    Return_One:
        li $v0, 1
        jr $ra

关键修正说明

  • 用mtc1(把通用寄存器数据传到浮点寄存器)和cvt.s.w(整数转单精度浮点数)替代错误的内存加载操作,彻底解决地址对齐问题;
  • 修正阶乘循环的乘法逻辑,原代码中sub $t1, $a0, $t0属于多余操作,直接用当前递减的t0相乘即可;
  • 补充0! = 1的处理,让函数逻辑更完整;
  • 统一用整数系统调用读取输入,避免浮点与整数寄存器混用导致的隐性错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 00:20:38