mips递归如何正确存储函数的返回地址

时间:2016-04-08 17:30:43

标签: mips

我在mips中的递归函数中传递正确的地址时遇到问题

我有一个我无法改变的主要功能基本上设置了值并调用我的函数:

jal findX

我的函数对浮点数执行计算并执行以下操作:

findX:
addi $sp, $sp, -4   #make room on stack
sw $ra, 0($sp)      #save ra

#a series of calculations that are not part of the problem
jal evaluate #gives an output based on the calculations before that triggers various branches

bc1t x_return

jal findX

x_return
mov.s   $f0,$f17    #holds the value to return
lw      $ra, 0($sp) #restore $ra
addi    $sp, $sp, 4 #restore stack pointer
jr  $ra

问题是,一旦找到正确的值,我的返回地址就会搞砸了,并且" jr $ ra"再次调用该函数而不是返回。我如何解决这个问题我认为我正在遵循mips递归约定。

1 个答案:

答案 0 :(得分:1)

findX中的推/弹代码很好,符合ABI标准。并且,无论ABI如何,$sp 的预减法始终

您没有展示evaluate,但这可能是嫌疑人。如果你有,那么检查代码和诊断问题会相当容易。

true 返回后,evaluate已更改$sp或已覆盖findX堆栈帧的部分内容。

您可以在evaluate中为真实案例添加断点。大多数模拟器保留最后N条指令的历史记录,因此您可以查看sp的更改或相对于它的存储。这可能就够了。

但是,另一种方法是将一些调试代码添加到与调试器一起使用的findX。也就是说,失败条件可能太复杂,调试器无法停止(即它没有复杂的 watch 条件,如gdb),因此我们可以添加一些“帮助”代码

我在findX堆栈框架中添加了一些额外的值,允许一些一致性和交叉检查以及额外的代码来检查这些值

以下是为调试而修改的代码。

使用调试器,在所有 nop指令上放置断点。当你点击一个,检查历史,值等。这应该有助于隔离你的问题。

# recursive debug

findX:
    addi    $sp,$sp,-12             # make room on stack

    sw      $ra,8($sp)              # save ra
    sw      $sp,4($sp)              # save sp
    li      $t7,0xdeadbeef          # save a "magic" number
    sw      $t7,0($sp)              # we want this at the old offset for sp

    # a series of calculations that are not part of the problem
    # gives an output based on the calculations before that triggers various
    # branches
    jal     evaluate

    # NOTE/BUG: if this returns "true", then one of two things happened:
    # (1) evaluate changed the sp register contents
    # (2) evaluate overwrote the the return value we stored above

    bc1t    matchfound

    jal     findX

x_return:
    li      $t7,0xdeadbeef          # get the expected magic number
    lw      $t6,0($sp)              # get the stored value
    bne     $t6,$t7,badnews1        # did it get trashed? if yes, fly
ignore1:

    # the sp value must be the same as when we called the function
    lw      $t6,4($sp)              # get the stored value
    bne     $t6,$sp,badnews2        # did it get trashed? if yes, fly
ignore2:

    # NOTE: we take advantage of the fact that evaluate is called from only
    # _one_ place within findX, so we _know_ the ra value
    la      $t7,x_return            # get the expected return value
    bne     $ra,$t7,badnews3        # did it get trashed? if yes, fly
ignore3:

    # NOTE: we take advantage of the fact that evaluate is called from only
    # _one_ place within findX, so we _know_ the ra value
    la      $t7,x_return            # get the expected return value
    lw      $t6,8($sp)              # get the saved return value
    bne     $t6,$t7,badnews4        # did it get trashed? if yes, fly
ignore4:

    mov.s   $f0,$f17                # holds the value to return

    lw      $ra,8($sp)              # restore $ra

    addi    $sp,$sp,12              # restore stack pointer
    jr      $ra

# trap for success
matchfound:
    nop                             # put a breakpoint here
    j       x_return

# trap for error
badnews1:
    nop                             # put a breakpoint here
    j       ignore1

# trap for error
badnews2:
    nop                             # put a breakpoint here
    j       ignore2

# trap for error
badnews3:
    nop                             # put a breakpoint here
    j       ignore3

# trap for error
# NOTE: this one is special
# we may get a false positive on the first call to findX
# that is, (e.g.) main does "jal findX" and so we'd fail here
# for that case, just continue
badnews4:
    nop                             # put a breakpoint here
    j       ignore4