MIPS汇编出现Runtime exception:地址未按字对齐问题如何解决?
MIPS汇编“fetch address not aligned on word boundary”错误修复
MIPS架构要求所有字操作(lw/sw指令)必须对齐到4字节边界,也就是内存地址的最后两位必须是00(二进制),对应十六进制末位为0、4、8、C。当代码尝试访问非对齐地址时,就会抛出这个运行时异常。
代码中的核心问题
- SwapTwoInts参数传递错误
SwapTwoInts函数要求$a0和$a1传入的是整数的内存地址,但原代码中却把数组元素的值加载到$a0/$a1中:
lw $a0, 0($t3) # 错误:加载的是intArr[i]的值,而非地址 lw $a1, 0($t5) # 错误:加载的是intArr[j]的值,而非地址 jal SwapTwoInts
当这些值是奇数时,作为地址访问就会触发非对齐错误。
ValidateInt参数传递错误
ValidateInt函数要求$a0传入要验证整数的内存地址,但原代码未正确初始化$a0就调用函数,导致lw $t0, 0($a0)访问非法地址。ShowIntArray参数传递错误
ShowIntArray需要三个参数:数组地址($a0)、数组大小($a1)、标签地址($a2),但原调用只传入了大小,导致lw $t1, 0($a0)访问错误地址。GetOneIntByVal错误信息打印逻辑错误
原代码中先设置打印字符串的syscall($v0=4),但立刻改成打印字符($v0=11),导致错误信息无法输出。缺失数组输入逻辑
原代码没有向intArr中输入整数的步骤,直接交换空数组,属于逻辑漏洞。
修复后的完整代码
.data .align 2 # 按字对齐后续数据 intArr: .space 28 # 7个整数的数组(7*4字节) vtdPrompt: .asciiz "vals to do? " entIntPrompt: .asciiz "enter an int: " adjMsg: .asciiz " is bad, make it " origLab: .asciiz "original:\n" backLab: .asciiz "backward:\n" dmPrompt: .asciiz "do more? " invalid_input_msg: .asciiz "Invalid input. Please enter a valid integer.\n" tempVal: .word 0 # 新增:存储valsToDo的临时变量 .text .globl main main: li $v0, 4 # 打印字符串syscall la $a0, vtdPrompt # 加载提示地址 syscall li $v0, 4 # 打印original标签 la $a0, origLab syscall main_loop: jal GetOneIntByVal # 获取valsToDo sw $v0, tempVal # 将值存入tempVal,用于ValidateInt的地址参数 move $t0, $v0 # 保存valsToDo到$t0 # 修复ValidateInt参数传递 la $a0, tempVal # 传入tempVal的地址(要验证的整数地址) li $a1, 1 # 最小值 li $a2, 7 # 最大值 la $a3, adjMsg # 提示信息地址 jal ValidateInt # 验证valsToDo lw $t0, tempVal # 取回验证后的值 beq $t0, $zero, exit_program # 输入0则退出 # 新增:向intArr输入整数 li $t1, 0 # 初始化i=0 input_loop: beq $t1, $t0, end_input li $v0, 4 la $a0, entIntPrompt syscall jal GetOneIntByVal # 获取输入的整数 sll $t4, $t1, 2 # 计算偏移量 la $t3, intArr # 加载数组基地址 add $t3, $t3, $t4 # 计算元素地址 sw $v0, 0($t3) # 存入数组 addi $t1, $t1, 1 j input_loop end_input: # 打印原数组 la $a0, intArr move $a1, $t0 la $a2, origLab jal ShowIntArray # 初始化交换循环变量 move $t1, $zero # i=0 move $t2, $t0 # j=valsToDo swap_loop: beq $t1, $t2, show_backwards # i >= j时退出循环 sll $t4, $t1, 2 # 计算intArr[i]的偏移量 la $t3, intArr # 加载数组基地址 add $t3, $t3, $t4 # 计算intArr[i]的地址 move $a0, $t3 # 修复:传入intArr[i]的地址给SwapTwoInts addi $t4, $t2, -1 # j-1 sll $t5, $t4, 2 # 计算intArr[j-1]的偏移量 la $t5_addr, intArr # 加载数组基地址 add $t5_addr, $t5_addr, $t5 # 计算intArr[j-1]的地址 move $a1, $t5_addr # 修复:传入intArr[j-1]的地址给SwapTwoInts jal SwapTwoInts # 交换两个元素 addi $t1, $t1, 1 # i++ addi $t2, $t2, -1 # j-- j swap_loop show_backwards: # 修复ShowIntArray参数传递 la $a0, intArr # 数组地址 move $a1, $t0 # 数组大小 la $a2, backLab # 标签地址 jal ShowIntArray # 打印反转后的数组 li $v0, 4 # 打印do more提示 la $a0, dmPrompt syscall li $v0, 12 # 读取字符 syscall move $a0, $v0 # 直接保存读取的字符(syscall 12返回值在$v0) li $t6, 'n' li $t7, 'N' beq $a0, $t6, exit_program beq $a0, $t7, exit_program j main_loop exit_program: li $v0, 10 # 退出程序 syscall # 获取整数函数 GetOneIntByVal: li $v0, 5 # 读取整数syscall syscall bltz $v0, invalid_input # 负数视为无效 j input_valid input_valid: jr $ra # 返回 invalid_input: # 修复错误信息打印顺序 li $v0, 4 la $a0, invalid_input_msg syscall # 先打印错误信息 li $v0, 11 li $a0, '\n' syscall # 再打印换行 j GetOneIntByVal # 重新输入 # 验证整数函数 ValidateInt: lw $t0, 0($a0) # 加载要验证的整数 blt $t0, $a1, less_than_min bgt $t0, $a2, greater_than_max jr $ra # 范围内则返回 less_than_min: j set_min greater_than_max: j set_max set_min: sw $a1, 0($a0) # 设置为最小值 jr $ra set_max: sw $a2, 0($a0) # 设置为最大值 jr $ra # 打印整数数组函数 ShowIntArray: li $v0, 4 move $a0, $a2 # 打印标签 syscall li $t0, 0 # k=0 la $t3, intArr # 保存数组基地址(避免$a0被修改) show_loop: beq $t0, $a1, end_show sll $t4, $t0, 2 # 计算偏移量 add $t5, $t3, $t4 # 计算元素地址 lw $t1, 0($t5) # 加载元素值 li $v0, 1 move $a0, $t1 syscall # 打印整数 li $v0, 11 li $a0, ' ' syscall # 打印空格 addi $t0, $t0, 1 # k++ j show_loop end_show: li $v0, 11 li $a0, '\n' syscall # 打印换行 jr $ra # 返回 # 交换两个整数函数 SwapTwoInts: lw $t0, 0($a0) # 加载第一个整数的值 lw $t1, 0($a1) # 加载第二个整数的值 sw $t1, 0($a0) # 保存第二个值到第一个地址 sw $t0, 0($a1) # 保存第一个值到第二个地址 jr $ra # 返回
关键修复细节
- 新增
tempVal变量,为ValidateInt提供合法的内存地址参数 - SwapTwoInts调用时传入数组元素的地址而非值,确保lw/sw操作的地址对齐
- ShowIntArray调用时正确传入数组地址、大小、标签地址三个参数
- 修复GetOneIntByVal中错误信息的打印顺序,确保提示正常输出
- 补充向intArr输入整数的逻辑,避免操作空数组
内容的提问来源于stack exchange,提问作者Ryder
相关产品推荐
相关产品推荐

