qtSPIM运行MIPS代码循环后打印字符串输出空字符/空格问题
qtSPIM运行MIPS汇编字符串打印异常排查
问题现象
- 字符串打印逻辑放在循环代码段之后时,qtSPIM控制台输出异常:要么显示形似空心方块的空字符,要么输出多个空格组成的空串
- 将字符串打印逻辑移到所有循环之前执行时,可正常输出
- 尝试在循环结束后重置寄存器,问题未解决
复现代码与输出差异
问题代码
.data arrayY: .word 1, 2, 3, 4, 5 # 5元素数组 arrayZ: .word -5, -4, -3, -2, -1 # 5元素数组 arrayX: .word 20 # 仅分配了1个word空间,不足以存5个元素 var1: .asciiz "X: " var2: .asciiz ", " .text .globl main main: addi $a2, $zero, 5 # 初始化n addi $s0, $zero, 2 # 初始化s addi $s1 $zero, 1 # 语法错误:$s1后漏写逗号 addi $sp, $sp, -12 sw $s1, 4($sp) # 压栈 sw $s0, 0($sp) jal AVA AVA: li $v0, 0 li $v1, 0 addi $t1, $a2, -1 addi $t1, $zero, 20 # 覆盖了上一行计算的数组长度,错误将循环上界设为20 addi $t0, $zero, 0 LOOP: beq $t0, $t1, exit lw $t2, arrayY($t0) lw $t3, arrayZ($t0) subu $t4, $zero, $t3 add $t5, $t4, $t2 addi $t3, $zero, 2 mult $t3, $s0 add $t6, $t3, $s1 lw $s0, 0($sp) lw $s1, 4($sp) addi $sp, $sp, 12 # 错误:每次循环都恢复栈指针,栈分配/释放不成对 add $t7, $t5, $t6 sw $t7, arrayX($t0) addi $t0, $t0, 4 j LOOP exit: addi $t0, $zero, 0 move $a0, $0 move $v0, $0 li $v0, 4 la $a0, var1 syscall LOOP1: beq $t0, $t1, exit1 lw $t2, arrayY($t0) move $a0, $t2 li $v0, 1 syscall addi $t0, $t0, 4 j LOOP1 exit1: li $v0, 10 # 程序退出 syscall
预期输出
X: 12345
实际输出
12345
根因分析
代码存在3处核心错误,直接导致内存被意外覆盖,打印字符串时原始内容已经损坏:
- 栈操作逻辑错误:进入AVA前仅分配了12字节栈空间,但循环体每轮迭代都会执行
addi $sp, $sp, 12抬升栈指针。第一轮循环结束后栈指针就回到了分配前的位置,后续循环读栈、写栈会直接访问栈帧外的内存,甚至篡改数据段存储的内容。 - 数组越界:
arrayX仅用.word 20分配了4字节(1个word)的空间,不足以存储5个int元素,而arrayX后紧邻存储的就是var1字符串,循环写arrayX的后续元素时,直接覆盖了var1的内存,原本存的"X: "被改写为空格/空字符,打印时自然无法正常显示。 - 循环上界设置错误:代码先计算了数组合法偏移上界,随即又用
addi $t1, $zero, 20将上界改为20,5个word元素的数组合法偏移为0/4/8/12/16,偏移到20时已经访问到数组外的内存,进一步加剧了内存越界篡改问题。
修复要点
- 栈操作成对出现:将循环内的
lw $s0, 0($sp)、lw $s1, 4($sp)、addi $sp, $sp, 12栈恢复逻辑移到循环外、函数返回前执行,禁止在循环内反复调整栈指针。 - 给
arrayX分配足够空间:将定义改为arrayX: .word 20, 0, 0, 0, 0或arrayX: .space 20,预留5个word共20字节的存储空间,避免数组写越界覆盖后续字符串。 - 修正循环上界:删除
addi $t1, $zero, 20这行覆盖上界的代码,根据数组实际长度计算循环终止的偏移值。 - 补上指令中遗漏的逗号,修正语法错误。
内容的提问来源于stack exchange,提问作者spencer
相关产品推荐
相关产品推荐

