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
,而不恢复它。
我写了一个迷你银行程序,在子程序存款中调用多个函数,这是子程序
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
,而不恢复它。