MIPS汇编用heap取两数组对应元素最大值时l.d指令报地址越界错误
问题根因与修复方案
你遇到的地址越界异常核心原因是Arr1的基地址被意外覆盖,同时存在多处逻辑错误,具体问题和修复方法如下:
触发异常的直接原因
- main函数初始阶段你将Arr1的地址存在了
$a0寄存器,但后续执行堆分配(syscall 9)时,执行了li $a0, 64,直接把$a0里的Arr1基地址覆盖为立即数64。进入MaxArray函数后,你尝试从$a0指向的地址加载双精度数,此时$a0的值是0x40(十进制64),循环每次地址加8,第三次访问就会到0x50,这类低地址属于系统保护区域,用户程序没有访问权限,直接触发地址越界异常。
其他需要修复的逻辑错误
- 计算Arr2的元素数量时写错存储目标:
sw $t3, Arr1Count应该改为sw $t3, Arr2Count,否则会直接覆盖Arr1的计数。 - 浮点数比较用错指令:
c.eq.s是单精度浮点数比较指令,双精度需要改为c.lt.d(判断$f0小于$f2的场景),原来的相等判断逻辑也不符合取最大值的需求,正确逻辑是:如果$f0小于$f2就存$f2,否则存$f0。 - 堆分配返回地址没有备份:你直接用存储堆首地址的
$v0做偏移写入,循环结束后$v0已经指向堆数组末尾,后续打印拿到的是末尾地址,无法正确读取元素,需要在分配完堆之后先把首地址备份到其他寄存器。 - 打印函数计数器逻辑错误:PrintLoop里每次累加的是
$t0而非循环计数器$t5,会触发死循环,永远无法满足退出条件。 - 打印逻辑缺少syscall触发:你设置了
$v0=3和$f12的值后没有执行syscall,不会输出任何内容。
修正后的核心代码片段
main函数堆分配部分
# 分配堆内存 li $v0, ALLOC_MEM li $a0, 64 syscall move $s0, $v0 # 备份堆首地址,后续传给打印函数 li $t0, 0 # 循环计数器 # 重新给$a0、$a1赋值为两个数组的基地址 la $a0, Arr1 la $a1, Arr2 lw $t1, Arr1Count # 加载数组长度 jal MaxArray move $a2, $s0 # 传堆首地址给打印函数 move $a3, $t0 # 传元素数量给打印函数
MaxArray比较逻辑部分
Loop: beq $t0,$t1,Continue l.d $f0, ($a0) # 从Arr1加载双精度数 l.d $f2, ($a1) # 从Arr2加载双精度数 c.lt.d $f0, $f2 # 判断f0 < f2是否成立 bc1t store_f2 # 条件成立则存储f2 s.d $f0, ($v0) # 否则存储f0 j increase store_f2: s.d $f2, ($v0) increase: addi $a0, $a0, 8 addi $a1, $a1, 8 addi $v0, $v0, 8 addi $t0, $t0, 1 b Loop Continue: jr $ra
PrintArray打印逻辑部分
PrintArray: li $t5, 0 # 打印循环计数器 PrintLoop: bge $t5, $a3, exit l.d $f2, 0($a2) addi $a2, $a2, 8 # 打印双精度数 li $v0, 3 mov.d $f12, $f2 syscall # 触发打印系统调用 addi $t5, $t5, 1 # 累加打印循环计数器 j PrintLoop exit: li $v0, 10 syscall
内容的提问来源于stack exchange,提问作者Aiden
相关产品推荐
相关产品推荐

