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,不符合阶乘定义。
修复方案
- 修正输入逻辑:用
syscall 5读取整数n和r; - 正确转换数据类型:把阶乘返回的整数直接转成浮点数,而非当作地址读取;
- 修复阶乘边界与循环逻辑:修正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
相关产品推荐
相关产品推荐

