#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).