Mips:返回错误的返回地址



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

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 AsciiConvert,然后我进入deposit_Checking子例程,但是该deposit_Cecking的返回地址将我返回到jal AsiiConvert的行,而不是我调用deposit_Cchecking子例程的行,导致Ascii转换子例程和deposit_CChecking子例程之间的无限循环。。。有人能帮帮我吗?

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

在机器代码中,返回地址,即MIPS的$ra,实际上是子例程的一个参数-它"告诉"子例程在调用方中的何处恢复执行,返回到何处。有几种方法可以用有意义的返回地址设置$ra寄存器,当然jal是迄今为止最常见的方法。

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

通过不将$ra设置为新值,将保留其旧值。由于$ra寄存器上次是由jal AsciiConvert设置的,因此其他函数的jr $ra会返回到那里,但更不用说这不是正确的调用——因为正确设置该参数是调用方的工作。

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

我们还要注意,这些行为在调试过程中都是可见的。例如jr $ra将控制权转移到由$ra寄存器中的值寻址的任何机器指令。当您第一次输入子例程/函数时,$ra寄存器中应该提供一个适当的返回地址参数,当您到达函数的最后一条指令jr $ra时,如果$ra寄存器的值从条目更改,那么它就不会回到调用它的地方——所以我们会在$ra更改之间寻找一个位置,而不将其恢复回来。

最新更新