Инструкция перехода в сборке MIPS

#assembly #mips

#сборка #mips

Вопрос:

Вот некоторый код сборки MIPS, который я написал для проверки инструкции перехода:

 addi $a0, $0, 1
j next
next:
j skip1
add $a0, $a0, $a0
skip1:
j skip2:
add $a0, $a0, $a0
add $a0, $a0, $a0
skip2:
j skip3
loop:
add $a0, $a0, $a0
add $a0, $a0, $a0
add $a0, $a0, $a0
skip3:
j loop
 

Когда я запускаю ассемблер, вот результат:

 [0x000000]  0x20040001  # addi $a0, $zero, 1 ($a0 = 1)
[0x000004]  0x08000002  # j 0x0002 (jump to addr 0x0008)
[0x000008]  0x08000004  # j 0x0004 (jump to addr 0x0010)
[0x00000C]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x000010]  0x08000007  # j 0x0007 (jump to addr 0x001C)
[0x000014]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x000018]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x00001C]  0x0800000B  # j 0x000B (jump to addr 0x002C)
[0x000020]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x000024]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x000028]  0x00842020  # add $a0, $a0, $a0 ($a0 = $a0   $a0)
[0x00002C]  0x08000008  # j 0x0008 (jump to addr 0x0020)
 

Глядя на машинный код для инструкций перехода, я вижу вот что:

 1st jump (just jumps to next instruction) 0x08000002
2nd jump (skips 1 instruction) 0x08000004
3rd jump (skips 2 instructions) 0x08000007
4th jump (skips 3 instructions) 0x0800000B
5th jump (skips 3 instructions backwards) 0x08000008
 

Из этих инструкций видно, что машинный код начинается с 08 для инструкции перехода, а число в конце указывает инструкции перехода, куда идти. Однако я не могу понять, как вычисляется это число. Кроме того, ничто не указывает мне на то, что 5-й переход является обратным переходом.

Как вычисляется значение перехода?

Комментарии:

1. почему вы используете 3 add $a0, $a0, $a0 ? почему бы не использовать sll $a0, $a0, 3

2. @phuclv позвольте мне напомнить вам, что вы заслуживаете печенья за это

Ответ №1:

Просто загляните в справочное руководство для получения более подробной информации о кодировке кода операции.

Краткая версия: в 32-разрядной инструкции вы не можете включить 32-разрядное назначение перехода. Код операции использует 6 бит, что оставляет 26 бит для инструкции. Целевой адрес создается путем взятия первых 4 бит адреса инструкции, следующей за j инструкцией, затем к 26 битам из операнда инструкции перехода добавляются 2 нулевых бита. (Поскольку инструкции состоят из 32 бит, выравнивание полезно и позволяет опустить последние два 0.)

К обратному переходу: адреса являются абсолютными, А НЕ относительными, поэтому это зависит только от адреса инструкции перехода, является ли это прямым или обратным переходом.

РЕДАКТИРОВАТЬ: Более подробное описание: у нас есть по адресу x инструкция перехода j. Пусть t представляет операнд перехода j. t имеет ширину 26 бит. Битовый шаблон адреса следующей команды вычисляется следующим образом:

 upper_6_bits_of(x 4),t,0,0
 

Таким образом, переход ВСЕГДА является абсолютным. Относительных переходов нет. когда результат меньше x, то это прыжок назад, когда он больше, это прыжок вперед (и если вы хотите что-то глупое, вы делаете его равным ;-).

Итак, давайте посмотрим на 5-й переход вашего примера:

Первые 6 битов цели перехода равны: 000000, потому что старшие 6 битов адреса инструкции, стоящей за переходом, равны 000000.

Следующие 26 бит являются младшими 26 битами инструкции перехода, то есть 00000000000000000000001000

Последние 2 бита равны: 00, потому что got всегда добавляется.

Вместе мы имеем: 0000000000000000000000000000100000, что равно шестнадцатеричному значению 20. И по этому адресу находится именно та метка / инструкция, где поток должен продолжаться.

Комментарии:

1. Это не отвечает на вопрос о том, как относительный адрес определяет обратное смещение. Обычно для этого относительное значение jmp должно быть отрицательным. Кроме того, приведенные выше смещения не имеют особого смысла для переходов. Я, как и @z-buffer, также немного смущен разборкой…

2. Ваше редактирование объясняет переход как абсолютный, но смещения по-прежнему не совпадают. Здесь должно быть что-то еще. 1 еще за ответ на полный вопрос.

3. @Michael Dorgan: Обратные переходы и так хороши: они отображаются как … 08. Что 08 сдвинуто влево на два (два 2 нуля, о которых я упоминал), равно 32, что равно шестнадцатеричному 0x20. И инструкция, в которой выполняются переходы, равна 0x ..20. Так что она идеально подходит (то же самое с другими 4 переходами).

4. Другими словами, число в инструкции перехода — это просто шестнадцатеричное значение адреса назначения в двоичном формате, сдвинутое вправо на 2 бита.

5. @z-buffer: да (кроме 6 самых верхних битов).

Ответ №2:

В MIPS — J это инструкция J-типа:

 J-type instructions (Jumps)
3    22
1    65                        0
 ---- ------------------------- 
| op |         target          |
 ---- ------------------------- 
 

Итак, у нас есть a target длиной 26 бит. Она объединяется с ПК следующей инструкции следующим образом:

 I
I 1 PC <- (PC amp; 0xf0000000) | (target << 2)
 

Она сдвинута влево на 2 бита, поскольку инструкции MIPS (игнорирующие расширение MIPS16) имеют длину 32 бита, что означает, что все они начинаются с адреса, младшие 2 бита которого равны нулю.

Комментарии:

1. Другой способ подумать об этом: какое наименьшее ненулевое значение вы можете поместить в инструкцию перехода? Это будет равно 1, и оно соответствует 2-й инструкции в программе, которая равна 0x4. Таким образом, в основном это переход к абсолютному адресу инструкции, деленному на 4, поскольку адреса n-й инструкции всегда (n-1) * 4. Чтобы разделить на 4, вы сдвигаете вправо на 2 бита, потому что сдвиг вправо на n бит делит число на (2 ^ n).