我在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递归约定。
答案 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