Mips:返回错误的返回地址

Mips:返回错误的返回地址,mips,mips32,mips64,smips,Mips,Mips32,Mips64,Smips,我写了一个迷你银行程序,在子程序存款中调用多个函数,这是子程序 deposit: addi $sp, $sp, -8 #save space on stack addi $s3, $0, 1 #trigger s3 sw $s3, 0($sp) sw $ra, 4($sp) ..... jal AsciiConvert #convert ascii of deposited amount to integer beq $v0, $0, Er

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

deposit:
    addi $sp, $sp, -8 #save space on stack
    addi $s3, $0, 1 #trigger s3
    sw $s3, 0($sp)
    sw $ra, 4($sp)
    .....
    jal AsciiConvert #convert ascii of deposited amount to integer
    beq $v0, $0, Err_ACC #if no value to be deposited was inputed print error message
    beq $t0, $0, 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, $0, 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, $0 #s1 holds previous value
    addi $a1, $a1, 1 #increment adress
    add $v0, $s2, $0 #store the number in the return adress
    j ConvertOP
endConvert:
    jr $ra

当我进入存款时,我jal ASCICONVERT,然后进入存款检查子例程,但是该存款检查的返回地址将我返回到jal ASCICONVERT行,而不是我调用存款检查子例程的行,导致Ascii转换子例程和存款检查子例程之间出现无限循环…有人能帮我吗?

存款检查
看起来像一个子例程,您在帖子中将它标识为一个子例程,但是,我们不使用
beq
指令输入子例程,您应该使用
jal
调用子例程

在机器代码中,MIPS的返回地址,
$ra
实际上是子例程的一个参数-它告诉子例程在调用者中恢复执行的位置,返回到哪里。有几种方法可以使用有意义的返回地址设置
$ra
寄存器,当然,到目前为止,日航是最常见的方式

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

通过不将
$ra
设置为新值,它的旧值将被保留。由于
$ra
寄存器上次是由
jal asciconvert
设置的,因此另一个函数的
jr$ra
返回到那里,没有人知道这不是正确的调用-因为正确设置该参数是调用方的工作

虽然有些指令集允许调用条件,但我们不一定希望所有的
beq
s都捕获返回地址,因为使用
beq
的任何函数都必须考虑保留
$ra

我们还要注意,这些行为在调试期间都是可见的。
jr$ra
,例如,将控制权转移到由
$ra
寄存器中的值寻址的任何机器指令。当您第一次输入子例程/函数时,在
$ra
寄存器中应该提供一个正确的返回地址参数,并且当您使用其最终指令
jr$ra
到达函数末尾时,如果
$ra
寄存器的值已从输入值更改,然后它就不会返回到调用它的地方——因此我们将在这两个更改之间寻找某个地方,
$ra
,而不将其还原回来