mips递归如何正确存储函数的返回地址 [英] mips recursion how to correctly store return address for a function

查看:381
本文介绍了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递归约定.

解决方案

您在findX中的推送/弹出代码很好,并且符合ABI.而且,$sp 始终的预减法始终有效,而与ABI无关.

您没有显示evaluate,但这很可能是可疑的.如果有的话,检查代码并诊断问题将非常容易.

true 返回上,evaluate更改了$sp或覆盖了findX堆栈框架的某些部分.

您可以在evaluate中为实际情况添加断点.大多数模拟器都保留最后N条指令的历史记录,因此您可以查看对sp的更改或相对于sp的存储.那可能就足够了.

但是,另一种方法是将一些调试代码添加到与调试器一起工作的findX中.也就是说,失败条件可能太复杂了,调试器无法停止(即它没有像gdb这样的复杂的 watch 条件),因此我们可以添加一些帮助程序"代码. /p>

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

下面是修改后的代码以供调试.

使用调试器,将断点放在nop指令的 all 上.当您遇到问题时,请检查历史记录,值等.这应该有助于找出问题所在.

# 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

I have a problem passing the correct address in a recurssive function in mips

I have a main function I can't alter that goes essentially sets up values and calls my function like this:

jal findX

my function performs calculations on floats and does the following:

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

The problem is that once the correct values are found it appears that my return address is messed up and "jr $ra" calls the function again instead of returning. How do I fix this I think I am following mips recursive convention correctly.

解决方案

Your push/pop code in findX is fine and is ABI conforming. And, the pre-subtract of $sp always works regardless of ABI.

You're not showing evaluate, but it's the likely suspect. If you had, it would be fairly easy to examine the code and diagnose the problem.

Upon a true return, evaluate either has changed $sp or has overwritten parts of the findX stack frame.

You can add a breakpoint in evaluate for the true case. Most simulators keep a history of the last N instructions, so you can look at changes to sp or stores relative to it. That may be enough.

But, another way, is to add some debug code to findX that works in conjunction with the debugger. That is, the failure condition may be too complex for the debugger to stop on (i.e. it doesn't have sophisticated watch conditions like gdb), so we can add some "helper" code.

I've added some extra values to the findX stack frame that allow for some consistency and cross-checking and extra code to check these values

Below is your code modified for debug.

Using the debugger, put breakpoints on all the nop instructions. When you hit one, examine the history, values, etc. This should help isolate your problem.

# 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

这篇关于mips递归如何正确存储函数的返回地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆