2016-04-08 3 views
1

У меня есть проблема, проходящая правильный адрес в recurssive функции в трудоемкости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» снова вызывает функцию вместо возврата. Как исправить это, я думаю, что правильно соблюдаю рекурсивное соглашение.

+0

Имеет ли ваш ABI указатель стека на первый пустой слот в стеке или последний использованный слот? – EOF

+0

Что такое ABI? –

+0

* Application Binary Interface *. Помимо прочего, он указывает, как функции называют друг друга, который регистрируется, чтобы сохранить, как передать слишком большие для регистров аргументы. – EOF

ответ

1

Ваш код push/pop в findX в порядке и соответствует ABI. И, предварительный вычет $spвсегда работает независимо от ABI.

Вы не показываете evaluate, но это вероятный подозреваемый. Если бы у вас было, было бы довольно легко изучить код и диагностировать проблему.

После возвращения истинного, evaluate либо изменилось $sp или имеет перезаписаны части рамы findX стека.

Вы можете добавить контрольную точку в evaluate для истинного случая. Большинство симуляторов сохраняют историю последних N инструкций, поэтому вы можете посмотреть изменения на sp или сохранить их по отношению к ним. Этого может быть достаточно.

Но, еще один способ - добавить код отладки в findX, который работает совместно с отладчиком. То есть условие отказа может быть слишком сложным, чтобы отладчик остановился (т. Е. Он не имеет сложных часов таких условий, как 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 
Смежные вопросы