Mips:回到不正确的 return 地址

Mips: going back to incorrect return address

我写了一个迷你银行程序,在子程序存款中调用多个函数,这是子程序

deposit:
    addi $sp, $sp, -8 #save space on stack
    addi $s3, [=11=], 1 #trigger s3
    sw $s3, 0($sp)
    sw $ra, 4($sp)
    .....
    jal AsciiConvert #convert ascii of deposited amount to integer
    beq $v0, [=11=], Err_ACC #if no value to be deposited was inputed print error message
    beq $t0, [=11=], deposit_checking #if check exists returns a 0
    beq $t0, 1, deposit_saving #if check exists returns a 1
    jal printarray
    lw $s3, 0($sp)
    lw $ra, 4($sp)      # reload $ra so we can return to caller
    addi $sp, $sp, 8   # restore $sp, freeing the allocated space
    jr $ra   
    
deposit_checking:
    ... arithmetic operations...
    jr $ra   

ascii 转换子程序:

AsciiConvert:
    ...normal arithemtics...
    j ConvertOP
ConvertOP:
    lb $s0, 0($a1)
    beq $s0, [=12=], endConvert #end at null terminating
    beq $s0,32,endConvert #if found a space
    addi $s0, $s0, -48 #convert to int
    mul $s2, $s1, 10 #multiply sum by 10
    add $s2, $s2, $s0 #sum = sum + previous number
    add $s1, $s2, [=12=] #s1 holds previous value
    addi $a1, $a1, 1 #increment adress
    add $v0, $s2, [=12=] #store the number in the return adress
    j ConvertOP
endConvert:
    jr $ra

当我进入存款时,我调用 AsciiConvert 然后进入 deposit_Checking 子例程,但是那个 deposit_Checking return 的 return 地址让我回来了到 jal AsciiConvert 的行而不是我调用 deposit_Checking 子程序的行,导致 Ascii 转换子程序和 deposit_Checking 子程序之间的无限循环...有人可以帮我吗?

deposit_checking看起来像一个子程序,你在post中将其标识为子程序,但是,我们不输入带有beq指令的子程序,你应该使用 jal 调用子程序。

在机器代码中,return 地址,对于 MIPS,$ra,实际上是子例程的参数——它告诉子例程在调用者的何处恢复执行,return 到。有几种方法可以用有意义的 return 地址设置 $ra 寄存器,当然 jal 是目前最常用的方法。

beq 通过更改程序计数器 (pc) 将处理器的控制转移到目标标签(当 eq 为真时),但不提供(新的)$ra 值。

通过不将 $ra 设置为新值,它的旧值将被保留。由于 $ra 寄存器最后由 jal AsciiConvert 设置,因此另一个函数的 jr $ra 返回那里,none 更明智的是这不是正确的调用——因为它是调用者正确设置该参数的工作。

虽然一些指令集允许在条件下调用,但我们不一定希望所有 beq 都捕获一个 return 地址,因为这样任何使用 beq 的函数将不得不关注保留 $ra.

我们还要注意,这些行为在调试期间都是可见的。例如,jr $ra 会将控制转移到由 $ra 寄存器中的值寻址的任何机器指令。当您第一次输入 subroutine/function 时,在 $ra 寄存器中应该有一个正确的 return 地址参数,并且当您使用最终指令到达函数末尾时 jr $ra,如果 $ra 寄存器的值从条目开始发生了变化,那么它不会回到调用它的地方——所以我们会在变化之间寻找某个地方 $ra,而不恢复它。