2016-05-02 5 views
2

В настоящее время я пишу некоторые вещи в MIPS-ассемблере и у меня есть некоторые проблемы: Я написал эту функцию:Ассемблер - пропуск инструкции

PRINT_FLOAT: 

     addi $sp, $sp, -4  #stackpointer um ein wort weiterrücken 
     sw $ra, 0($sp)   #rücksprungadresse auf stack speichern 
     la $a0, strFloat 
     add $a1, $s0, $zero 
     jal printf 
     lw $ra, 0($sp)   #rücksprungadresse aus stack holen 
     addi $sp, $sp, 4  #stackpointer um ein wort zurückrücken 
     jr $ra 

если я запускаю эту программу инструкции добавить $ a1, $ s0, $ ноль пропускается, и я не знаю, почему ...

Еще одна забавная вещь, если я отлаживать эту программу с помощью GDB:

main: 

     addi $t0, $zero, 3 
     addi $t0, $zero, 3 
     addi $t0, $zero, 3 
     jal READ_FLOAT 

     jal PRINT_FLOAT 

и установить контрольную точку на основной, то точка останова установленный на третьем «addi $ t0, $ zero, 3» Что здесь происходит?

+0

Собираетесь ли вы с оптимизацией? Это имело бы смысл с тремя заявлениями «addi», поскольку все они делают одно и то же, делая два из них лишними. –

+0

- это ваш ассемблер, добавляющий в слот задержки ветвления? что делает ваша демонстрация для этого кода? привыкший к вам, должен был явно сделать это, в последний раз, когда я использовал ассемблер gnu, он просто поменял инструкцию перед веткой, должен был явно сказать это не так. или сказать, что архитектура не имеет слота задержки ветвления. –

ответ

1

gdb - отладчик исходного уровня высокого уровня, поэтому немного сложнее справиться с инструкцией по инструкции на основе инструкций.

Например, для выполнения кода C обычно используется команда «s» [step]. Но, gdb будет «перешагивать» любую последовательность asm, которую он считает частью одного оператора C.

Чтобы выполнить индивидуальные инструкции asm, вы хотите выполнить команду «si» [step command]. См. help si

Аналогичным образом, при установке точек останова вы хотите использовать измененную форму команды. break * whatever, чтобы установить контрольную точку на адресwhatever. См. help break

Для того, чтобы получить правильные адреса, вам, возможно, потребуется немного разобрать, см. help disassemble и help x. Для разборки одной команды также работает x/i ....

Как отметил dwelch, ваш ассемблер может «получить симпатичный» и изменить порядок вещей. Имея gdb, выполните разборку, вы сможете узнать, произошло это или нет. И, если интервалы задержки ветвления : активны на фактическом процессоре, вам нужно будет их учитывать. Например, при работе с симулятором, например spim или mars, использование интервалов задержки ветвления настраивается [и отключено по умолчанию], но с реальным процессором выбора не может быть.

если я запускаю эту программу инструкция добавить $ a1, $ s0, $ ноль пропускается, и я не знаю, почему ...

Это может быть, почему вы думаете, в add $a1,$s0,$zero инструкция пропускается. gdb [с «шагом»] будет относиться следующее в качестве одного блока:

la  $a0,strFloat 
    add  $a1,$s0,$zero 
    jal  printf 

точка останова устанавливается на третьем addi $t0, $zero, 3

Еще раз, по той же причине, что и выше. Используйте альтернативную форму команды breakpoint.

0

Когда вы устанавливаете точку останова в функции и нет доступной информации об отладке, gdb пытается установить точку останова после function prologue.

Gdb анализирует машинные инструкции для обнаружения пролога. «addi $ sp, $ sp, -4» выглядит так, будто его можно признать прологом (но я не эксперт MIPS, поэтому я могу ошибаться).

Включить отладочную информацию при сборке/компоновке и gdb, чтобы иметь больше информации о доступных фреймах.

Вы также можете разобрать основную (disas main) и установить точку останова на адрес первой команды (например: break * 0xabcdef) вместо «break main».

+0

Основываясь на разборке MIPS, я рассмотрел «addi $ sp, $ sp, -4», увеличивая размер стека на 4 байта. Обычно в конце функции «addi $ sp, $ sp, 4» есть дополнительная линия, чтобы уменьшить стек на ту же сумму. – James

Смежные вопросы