MIPS指令load word未加载字至寄存器及数组交换程序技术问询
排查MIPS
load word加载失败与数组交换程序问题 我来帮你一步步捋清楚这个问题,先从你提到的lw指令加载失败和未完成的数组程序入手:
先说说lw加载失败的常见坑
你已经用.align 4确保了数组的字对齐,这一点做得很好,但还有几个容易踩的点会导致lw加载异常:
- 地址计算错误:MIPS的每个字占4字节,如果你直接用索引作为字节偏移(而不是索引×4),会访问到非对齐地址或者错误的元素位置,
lw要求地址必须是4字节对齐,非对齐访问会直接触发异常。 - 基址寄存器没正确初始化:如果没把数组起始地址(
list)加载到基址寄存器(比如$s0),后续计算元素地址时用了错误的基址,自然加载不到正确的数据。 - 索引越界:你的数组是6个元素,有效索引是0-5,如果用户输入的索引超出这个范围,
lw会访问数组外的内存(比如后面的字符串区域),加载的是无效数据,看起来就像加载失败。
补全并修正你的程序
你给出的代码里msg4字符串没写完,我帮你补全并完善了整个程序的逻辑,同时规避了lw的常见问题:
.globl main .data list: .align 4 .word 5, 17, 43, 22, 120, 3 # 6个元素,有效索引0-5 endList: space: .asciiz " " newLine: .asciiz "\n" msg1: .asciiz "Array is: " msg2: .asciiz "Enter first index to swap: " msg3: .asciiz "Enter second index to swap: " msg4: .asciiz "Array after swap is: " .text main: # 打印初始数组提示 li $v0, 4 la $a0, msg1 syscall # 打印初始数组 la $s0, list # 把数组起始地址存入$s0作为基址 li $t0, 0 # 循环计数器i=0 li $t1, 6 # 数组长度为6 print_loop: bge $t0, $t1, end_print # i>=6时跳出打印循环 sll $t2, $t0, 2 # 计算字节偏移:i × 4(左移2位等价于乘4,效率更高) add $t3, $s0, $t2 # 得到当前元素的绝对地址 lw $a0, 0($t3) # 正确加载数组元素到$a0 li $v0, 1 # 调用打印整数的系统调用 syscall # 打印分隔空格 li $v0, 4 la $a0, space syscall addi $t0, $t0, 1 # i++ j print_loop end_print: # 打印换行 li $v0, 4 la $a0, newLine syscall # 获取第一个交换索引 li $v0, 4 la $a0, msg2 syscall li $v0, 5 syscall move $s1, $v0 # 保存第一个索引到$s1 # 获取第二个交换索引 li $v0, 4 la $a0, msg3 syscall li $v0, 5 syscall move $s2, $v0 # 保存第二个索引到$s2 # 检查索引合法性,避免越界访问 blt $s1, $zero, exit # 索引小于0则直接退出 bge $s1, $t1, exit blt $s2, $zero, exit bge $s2, $t1, exit # 加载两个需要交换的元素 sll $t2, $s1, 2 add $t3, $s0, $t2 lw $t4, 0($t3) # 第一个索引对应的元素存入$t4 sll $t2, $s2, 2 add $t3, $s0, $t2 lw $t5, 0($t3) # 第二个索引对应的元素存入$t5 # 执行交换操作 sll $t2, $s1, 2 add $t3, $s0, $t2 sw $t5, 0($t3) # 把第二个元素写入第一个索引的位置 sll $t2, $s2, 2 add $t3, $s0, $t2 sw $t4, 0($t3) # 把第一个元素写入第二个索引的位置 # 打印交换后的数组 li $v0, 4 la $a0, msg4 syscall li $t0, 0 print_loop_after: bge $t0, $t1, end_program sll $t2, $t0, 2 add $t3, $s0, $t2 lw $a0, 0($t3) li $v0, 1 syscall li $v0, 4 la $a0, space syscall addi $t0, $t0, 1 j print_loop_after end_program: li $v0, 4 la $a0, newLine syscall exit: li $v0, 10 # 调用退出程序的系统调用 syscall
关键修正点说明
- 正确计算元素地址:用
sll $t2, $t0, 2将索引转换为字节偏移,确保lw访问的是4字节对齐的地址,这是解决加载失败的核心。 - 索引合法性检查:新增了索引范围判断,避免越界访问导致的无效加载或内存异常。
- 寄存器规范使用:用
s寄存器保存数组基址和用户输入的索引,避免被临时寄存器覆盖(虽然这个程序没有子函数,但这是MIPS编程的好习惯)。 - 补全缺失的字符串:完善了
msg4的内容,保证提示信息完整。
排查lw问题的通用步骤
如果以后再遇到lw加载失败的情况,可以按这个顺序排查:
- 检查目标地址的最低两位是否为
00:MIPS要求字访问地址必须4字节对齐,非对齐地址会触发异常。 - 确认基址寄存器的值是否正确:比如用模拟器查看
$s0是否等于list的起始地址。 - 验证偏移计算是否正确:确保是“索引×4”而不是直接用索引作为字节偏移。
- 检查索引是否在有效范围内:避免访问数组外的内存区域。
内容的提问来源于stack exchange,提问作者Van
相关产品推荐
相关产品推荐

