MARS运行MIPS坐标转内存地址代码时出现无效程序计数器错误
问题原因分析与修复
你的代码出现invalid program counter value: 0x00000000错误,核心问题出在栈帧的建立与恢复流程不符合MIPS栈规范,具体有两个关键错误:
1. 保存旧帧指针时未正确移动栈指针
MIPS栈是向下增长的(栈指针$sp数值越小,指向栈的越深处),压栈操作必须先将$sp减去对应字节数,再存储数据。你直接执行sw $fp, 0($sp),会覆盖调用者(main函数)栈顶的有效数据,破坏栈结构,导致返回时程序计数器无法获取正确的返回地址。
2. 栈恢复时未正确重置栈指针位置
在函数退出阶段,你恢复完寄存器后,仅将$sp移动到$fp位置并恢复$fp,但没有将$sp调整回调用前的状态,导致栈指针始终停留在错误位置,进一步引发程序执行异常。
修复后的translate_coordinates函数
translate_coordinates: # 正确建立栈帧:先分配24字节栈空间(满足8字节对齐要求,适配MARS模拟器) subu $sp, $sp, 24 sw $fp, 20($sp) # 保存旧帧指针到栈中 move $fp, $sp # 帧指针指向当前栈顶 sw $ra, 16($fp) # 保存返回地址 sw $s0, 12($fp) # 保存需要用到的$s寄存器 sw $s1, 8($fp) sw $s2, 4($fp) # 原函数逻辑保持不变 move $s0, $a0 # $s0 = x coordinate move $s1, $a1 # $s1 = y coordinate move $s2, $a2 # $s2 = width for calculations sll $t3, $s1, 5 # y * 32 add $t4, $t3, $s0 # (y * 32) + x = 像素索引 sll $t5, $t4, 2 # 索引 * 4(每个像素占4字节) add $t6, $gp, $t5 # 计算内存地址:全局指针 + 偏移量 move $v0, $t6 # 结果存入返回寄存器$v0 # 恢复寄存器与栈帧 lw $s2, 4($fp) lw $s1, 8($fp) lw $s0, 12($fp) lw $ra, 16($fp) lw $fp, 20($fp) # 恢复旧帧指针 addi $sp, $sp, 24 # 释放栈空间,栈指针回到调用前位置 jr $ra
额外说明
- MIPS栈要求8字节对齐,所以分配栈空间时尽量使用8的倍数(比如这里用24字节,而非你原来的20字节),避免模拟器出现隐性错误。
- 栈帧操作的核心原则:建立时先分配空间再保存寄存器,退出时先恢复寄存器再释放空间,严格遵循这个流程就能避免多数栈相关问题。
内容的提问来源于stack exchange,提问作者Lykoto
相关产品推荐
相关产品推荐

