Mips程序死循环问题

Mips program infinite loop issue

我目前正在尝试弄清楚为什么我的用于创建数组的 mars 程序陷入无限循环。我正在尝试使用不同的函数创建一个数组,在创建数组函数中,程序应该跳转到获取数字函数和 return 将其存储到数组中的值,但计数器似乎不会递减并且它只是不断要求数组的元素。这是代码:

.data   
str5:   .asciiz "Please enter a number of elements for the array between 0 and 20: "

str6:   .asciiz "Please enter an element: "

array:  .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

.text

main:   

begin:
    li $v0, 4
    la $a0, str5
    syscall

    jal readnum
    add $a0, $v0, [=10=]
    jal verify
    add $a0, $v0, [=10=]
    jal createarray
    la $s1, array
    jal printarray

    li $v0, 10
    syscall

printarray:


createarray:
    add $t0, $ra, [=10=]
    add $s0, $a0, [=10=]
    add $t9, [=10=], [=10=]

    la $s1, array

loop:
    beq $s0, 0, done

    li $v0, 4
    la $a0, str6
    syscall

    jal readnum
    add $t1, $v0, [=10=]

    sw $t1, 0($s1)
    addi $s1, $s1, 4

    addi $s0, $s0, -1
    addi $t9, $t9, 1

    j loop

done:
    add $ra, $t0, [=10=]
    jr $ra

verify:
    add $s0, $a0, [=10=]

    bge $s0, 20, begin
    ble $s0, 0, begin

    add $v0, $s0, [=10=]

    jr $ra

readnum:
    li $v0, 5
    syscall

    jr $ra

编辑:重新阅读代码后,导致错误的实际上是以下代码:

jal printarray

您从未在 printarray 中执行过以下代码:

jr $ra

所以,它会回到其他功能。


使用$sp(在函数内调用函数时处理$ra的正确方法)

以下段是问题的原因:

    syscall

    jal readnum
    add $t1, $v0, [=12=]

更具体地说是 jal 调用。在函数内调用函数需要执行更多步骤。

首先,了解jal指令的作用。 jal 指令,简单地说,标记你当前所在的位置,并将其存储在 $ra 寄存器中。然后,它会跳转到那个函数。

但是有一个问题:您已经希望 $ra 寄存器记住您曾经在哪里,因为实际上您叫 createarray !

因此,您调用了 createarray,使 $ra 存储您曾经所在的位置,然后在您调用 readnum 的函数中,使 $ra 存储您所在的位置createarray。 **但是现在,你已经失去了你在被叫 createarray 之前所在的位置。因此,它将不断循环回到 $ra 曾经是什么,它在你的 createarray 函数中。

幸运的是,$sp 寄存器正是您所需要的

如何使用$sp寄存器

为了存储我们所在的位置,我们压入堆栈:

addi    $sp,    $sp,    -4 # by convention, we use negative numbers when pushing
sw      $ra,    ($sp)

为了在我们调用函数(首先取代我们的 $ra )之后到达我们曾经所在的位置,我们弹出堆栈:

lw      $ra,    ($sp)
addi    $sp,    $sp,    4 # by convention, we use positive numbers when popping

所以在宏大的范围内,这就是你要做的:

# push to the stack
addi    $sp,    $sp,    -4
sw      $ra,    ($sp)

jal     theFunctionWeWantToCallInOurFunction

# pop the stack, get back our $ra
lw      $ra,    ($sp)
addi    $sp,    $sp,    4

让我们将此解决方案应用于您的代码库:

.data   
str5:   .asciiz "Please enter a number of elements for the array between 0 and 20: "

str6:   .asciiz "Please enter an element: "

array:  .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

.text

main:   

begin:
    li $v0, 4
    la $a0, str5
    syscall

    jal readnum
    add $a0, $v0, [=16=]
    jal verify
    add $a0, $v0, [=16=]
    jal createarray
    la $s1, array
    jal printarray # comment off this line and you won't have an infinite loop

    li $v0, 10
    syscall

printarray:


createarray:
    add $t0, $ra, [=16=]
    add $s0, $a0, [=16=]
    add $t9, [=16=], [=16=]

    la $s1, array

loop:
    beq $s0, 0, done

    li $v0, 4
    la $a0, str6
    syscall

    # store where we wish to come back to so that $ra can be overriden without losing data.
    addi $sp, $sp, -4
    sw $ra, ($sp)

    # call the function. jal will replace our current $ra
    jal readnum

    # retrieve what our $ra once was
    lw $ra, ($sp)
    addi $sp, $sp, 4 

    add $t1, $v0, [=16=]

    sw $t1, 0($s1)
    addi $s1, $s1, 4

    addi $s0, $s0, -1
    addi $t9, $t9, 1

    j loop

done:
    add $ra, $t0, [=16=]
    jr $ra

verify:
    add $s0, $a0, [=16=]

    bge $s0, 20, begin
    ble $s0, 0, begin

    add $v0, $s0, [=16=]

    jr $ra

readnum:
    li $v0, 5
    syscall

    jr $ra